C# revit api to Create panels in Revit - c#

I am new to revit api . I want to create a panel in revit empty project. I can create walls . I want to know how can I add panel data (studs , panel name , openings etc ) in the wall . Also I am new to construction terminologies.
here is my code:
UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Document doc = uiapp.ActiveUIDocument.Document;
WallType w = getWallType(doc);
RetrievingLevels(doc);
Level newLevel = CreateLevels(doc);
if(newLevel != null)
{
IList<Curve> curves = new List<Curve>();
XYZ first = new XYZ(0, 0, 0);
XYZ second = new XYZ(20, 0, 0);
XYZ third = new XYZ(20, 0, 15);
XYZ fourth = new XYZ(0, 0, 15);
curves.Add(Line.CreateBound(first, second));
curves.Add(Line.CreateBound(second, third));
curves.Add(Line.CreateBound(third, fourth));
curves.Add(Line.CreateBound(fourth, first));
//Line l = Line.CreateBound(a1, b1);
Transaction trans = new Transaction(doc);
try
{
trans.Start("create walls");
Wall.Create(doc, curves, w.Id,newLevel.Id, true);
trans.Commit();
return Result.Succeeded;
}
catch (Exception ex)
{
trans.Dispose();
return Result.Failed;
}
}
return Result.Failed;
//IList<Curve> curves = new List<Curve>();
}
private WallType getWallType(Document doc)
{
FilteredElementCollector collector = new FilteredElementCollector(doc).OfClass(typeof(WallType));
IList<Element> WallTypes = collector.ToElements();
return WallTypes.First() as WallType;
}
private Level CreateLevels(Document document)
{
double elevation = 33.0;
Transaction t = new Transaction(document);
// Begin to create a level
t.Start("create Level");
try
{
Level level = Level.Create(document, elevation);
if (null == level)
{
throw new Exception("Create a new level failed.");
}
// Change the level name
level.Name = "New level";
t.Commit();
return level;
}
catch (Exception e)
{
}
return null;
}
Also please suggest me from where can I learn about revit APIS .

Well, it will help a lot to understand Revit and BIM from a user point of view before you try to start programming it, cf. before getting started. Then, you should work through the rest of the Revit API getting started material.
Next, you should learn how to research to find a Revit API solution for yourself.
The first step is always definitely to install the RevitLookup interactive Revit BIM database exploration tool to view and navigate element properties and relationships.
With that in place, you can start by manually creating the model that you wish to generate programmatically in the user interface first. Explore that using RevitLookup and other tools such as BipChecker and the element lister to discover what kind of elements have been generated by the manual process and their properties and relationships.
Once you understand all that, you will be all set to generate the same model programatically using the Revit API.
Good luck and have fun!

Related

Revit External application running outside of API context is not allowed

I'm trying to start a transaction inside my code but, as you can see in the title, it generate an error. I have reading many thread on External Application but don't correctly know how it work.
This is the code I use to start my transaction :
inside my form :
private void Loading_FA_only()//Lance l'import en boucle suivant les items dans la file d'attente
{
foreach(FileInfo fi in selected_rfas_donnees)
{
Loading_Family.famille = fi;
Loading_Family lf = new Loading_Family();
lf.Execute(Command.uiapplication);
Listing_succes(Loading_Family.succes, fi);
}
selected_rfas.Clear();
selected_rfas_donnees.Clear();
Update_Compteur();
}
and that what I try to execute :
public class Loading_Family : IExternalEventHandler
{
public static FileInfo famille;
public static bool succes;
public void Execute(UIApplication uiapp)
{
UIDocument uidoc = uiapp.ActiveUIDocument;
Application app = uiapp.Application;
Document doc = uidoc.Document;
// Access current selection
Selection sel = uidoc.Selection;
// Retrieve elements from database
FilteredElementCollector col
= new FilteredElementCollector(doc)
.WhereElementIsNotElementType()
.OfCategory(BuiltInCategory.INVALID)
.OfClass(typeof(Wall));
// Filtered element collector is iterable
foreach (Element e in col)
{
Debug.Print(e.Name);
}
// Modify document within a transaction
succes = false;
string nom_famille = famille.Name.Remove(famille.Name.Length - 4, 4);
FilteredElementCollector familles_doc = new FilteredElementCollector(doc).OfClass(typeof(Family));
foreach (Element elmt in familles_doc)
{
if (elmt.Name == nom_famille)
{
var result = TaskDialog.Show("CPF - Importation", "Il semblerait que " + nom_famille + " soit déjà présent dans votre projet.\nVoullez-vous le remplacer ?", TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No);
if (result == TaskDialogResult.Yes)
{
using (Transaction tr = new Transaction(doc, "Importer la famille"))
{
tr.Start();
doc.LoadFamily(famille.FullName);
tr.Commit();
tr.Dispose();
}
}
}
else
{
using (Transaction tr = new Transaction(doc, "Importer la famille"))
{
tr.Start();
doc.LoadFamily(famille.FullName);
tr.Commit();
tr.Dispose();
}
}
}
familles_doc = new FilteredElementCollector(doc);
foreach (Element elmt in familles_doc)
{
if (elmt.Name == nom_famille) { succes = true; }
else { succes = false; }
}
using (Transaction tx = new Transaction(doc))
{
tx.Start("Transaction Name");
tx.Commit();
}
}
public string GetName()
{
return "my event";
}
}
I'm desperate with this. I absolutely don't know how theirs "ExternalEventHandler" or "ExternalApplication" work.
Thank for help :)
It is very simple. Use external events and make sure the external event is declared inside the constructor of MyForm. Personally I've never used ShowDialog because it blocks the user access to the rest of the UI.
Please work through the Revit API getting started material. That explains all the required fundamentals of the Revit API and its architecture, including how external applications and commands are implemented and used.
Please note that the Revit API cannot be used at all outside of a valid Revit API context, and such a context is provided exclusively by the callbacks issues by Revit.exe while running and loading a Revit add-in.
Therefore, the statement you make in your description is expected and desired: a Revit external application can never run outside of a valid Revit API context and is therefore indeed not allowed.
Please spell check your texts before submitting them, especially the title, since typos such as the one in your description make it harder to find an issue.

C# Checking if a certain shape exists in Powerpoint

I am trying to find out, if a certain Shape exists in a Powerpoint presentation. I am new to C# and not sure how to cycle through all the shapes. I tried through a foreach loop but got nowhere. Here is what I got:
using pptNS = Microsoft.Office.Interop.PowerPoint;
...
pptNS.Slide pptSlide = null;
bool shapeCheck = false;
pptNS.Presentation pptPresentation = null;
try
{
// Create an instance of PowerPoint.
powerpointApplication = new pptNS.ApplicationClass();
pptPresentation = powerpointApplication.Presentations.Open([pptAddress]);
foreach (pptNS.Shapes sh in pptSlide.Shapes)
{
if (sh.Title.Equals("SlideID"))
{
shapeCheck = true;
}
}
}
catch (Exception ex)
But obviously this throws an System.InvalidCastException. Does somebody know what I should use instead of pptSlide.Shapesin the foreach loop? Or another method to check if a certain shape exists?
I think you should change this:
foreach (pptNS.Shapes sh in pptSlide.Shapes)
to this:
foreach (var sh in pptSlide.Shapes)

How to get Only one acadobject by selection set

I have some trouble to select the targeted acadObject. I get the input via selectionset.SelectonScreen method.
Here i can get more number of object from modelspace based on my filter condition.But i need only one object from the user.
Here i mentioned my code below:
AcadSelectionSet selset= null;
selset=currDoc.selectionset.add("Selset");
short[] ftype=new short[1];
object[] fdata=new object[1];
ftype[0]=2;//for select the blockreference
fdata[0]=blkname;
selset.selectOnScreen ftype,fdata; // Here i can select any no. of blocks according to filter value but i need only one block reference.
Please help me to solve this problem.
That's possible using other Autocad .NET libraries (instead of Interop library). But fortunately, one does not exclude the other.
You will need to reference the libraries containing the following namespaces:
using Autodesk.Autocad.ApplicationServices
using Autodesk.Autocad.EditorInput
using Autodesk.Autocad.DatabaseServices
(you get those downloading the Object Arx libraries for free from Autodesk):
You will need to access the Editor from an autocad Document.
By the code you've shown, you're probably working with AcadDocument documents.
So, to transform an AcadDocument into a Document, do this:
//These are extension methods and must be in a static class
//Will only work if Doc is saved at least once (has full name) - if document is new, the name will be
public static Document GetAsAppServicesDoc(this IAcadDocument Doc)
{
return Application.DocumentManager.OfType<Document>().First(D => D.Name == Doc.FullOrNewName());
}
public static string FullOrNewName(this IAcadDocument Doc)
{
if (Doc.FullName == "")
return Doc.Name;
else
return Doc.FullName;
}
Once you've got a Document, get the Editor, and the GetSelection(Options, Filter)
The Options contains a property SingleOnly and a SinglePickInSpace. Setting that to true does what you want. (Try both to see wich works better)
//Seleciton options, with single selection
PromptSelectionOptions Options = new PromptSelectionOptions();
Options.SingleOnly = true;
Options.SinglePickInSpace = true;
//This is the filter for blockreferences
SelectionFilter Filter = new SelectionFilter(new TypedValue[] { new TypedValue(0, "INSERT") });
//calls the user selection
PromptSelectionResult Selection = Document.Editor.GetSelection(Options, Filter);
if (Selection.Status == PromptStatus.OK)
{
using (Transaction Trans = Document.Database.TransactionManager.StartTransaction())
{
//This line returns the selected items
AcadBlockReference SelectedRef = (AcadBlockReference)(Trans.GetObject(Selection.Value.OfType<SelectedObject>().First().ObjectId, OpenMode.ForRead).AcadObject);
}
}
this is a direct quote from autocad developer help
http://docs.autodesk.com/ACD/2013/ENU/index.html?url=files/GUID-CBECEDCF-3B4E-4DF3-99A0-47103D10DADD.htm,topicNumber=d30e724932
There is tons of documentation the AutoCAD .NET API.
you will need to have
[assembly: CommandClass(typeof(namespace.class))]
above your namespace if you want to be able to invoke this command from the command line after you NetLoad the .dll, if it is a classLibrary.
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
[CommandMethod("SelectObjectsOnscreen")]
public static void SelectObjectsOnscreen()
{
// Get the current document and database
Document acDoc = Application.DocumentManager.MdiActiveDocument;
Database acCurDb = acDoc.Database;
// Start a transaction
using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
{
// Request for objects to be selected in the drawing area
PromptSelectionResult acSSPrompt = acDoc.Editor.GetSelection();
// If the prompt status is OK, objects were selected
if (acSSPrompt.Status == PromptStatus.OK)
{
SelectionSet acSSet = acSSPrompt.Value;
// Step through the objects in the selection set
foreach (SelectedObject acSSObj in acSSet)
{
// Check to make sure a valid SelectedObject object was returned
if (acSSObj != null)
{
// Open the selected object for write
Entity acEnt = acTrans.GetObject(acSSObj.ObjectId,
OpenMode.ForWrite) as Entity;
if (acEnt != null)
{
// Change the object's color to Green
acEnt.ColorIndex = 3;
}
}
}
// Save the new object to the database
acTrans.Commit();
}
// Dispose of the transaction
}
}

C# Inserting a new Requirement in HP Quality Center - AccessViolationException

Trying to create a prototype application that will post a new Requirement to HPQC 11.
I've managed to get a solid connection but when I attempt to add the blank requirement I get an AccessViolationException.
TDConnectionClass td = HPQC_Connect(); //Open a connection
ReqFactory myReqFactory = (ReqFactory)td.ReqFactory; //Start up the Requirments Factory.
Req myReq = (Req)myReqFactory.AddItem(DBNull.Value); //Create a new blank requirement (AccessViolationException)
myReq.Name = "New Requirement"; //Populate Name
myReq.TypeId = "1"; // Populate Type: 0=Business, 1=Folder, 2=Functional, 3=Group, 4=Testing
myReq.ParentId = 0; // Populate Parent ID
myReq.Post(); // Submit
Any ideas? I'm fairly new to C# and coding in general, so it's probably best to assume I know nothing.
After some significant working through the isse the following code works correctly:
private void HPQC_Req_Create_Click()
{
TDConnection td = null;
try
{
td = new TDConnection();
td.InitConnectionEx("server");
td.Login(HPQCUIDTextbox.Text.ToString(), HPQCPassTextbox.Text.ToString());
Console.WriteLine(HPQCPassTextbox.Text.ToString());
td.Connect("DEFAULT", "Test_Automation_Playground");
bool check = td.LoggedIn;
if (check == true)
{
Console.WriteLine("Connected.");
HPQCStatus.Text = "Connected.";
}
ReqFactory myReqFactory = (ReqFactory)td.ReqFactory;
Req myReq = (Req)myReqFactory.AddItem(-1); //Error Here
myReq.Name = "New Requirement 1";
myReq.TypeId = "1"; // 0=Business, 1=Folder, 2=Functional, 3=group, 4=testing
myReq.ParentId = 0;
myReq.Post();
Console.WriteLine("Requirement Created.");
HPQCStatus.Text = "Requirement Created.";
try
{
td.Logout();
td.Disconnect();
td = null;
}
catch
{ }
}
catch (Exception ex)
{
Console.WriteLine("[Error] " + ex);
try
{
td.Logout();
td.Disconnect();
td = null;
}
catch
{ }
}
This code requires that the Server be patched to QC 11 Patch 9 (Build 11.0.0.7274) in order to work. Previous versions cause errors, most notably the error in the question.
Requirements in ALM are hierarchical, when creating requirement you need to create it under some existing requirement.
What you want to do is get a hold of the root requirement, it's Id should be either 0 or 1, you can check it in ALM UI.
And then get an instance of ReqFactory from a property on that Root requirement.
And then add your requirement to that factory.
Also, make sure you are working on STA and not MTA thread.

Taking input from a joystick with C# .NET

I searched around on Google for this, but the only things I came up with were outdated and did not work.
Does anyone have any information on how to get joystick data using C# .NET?
Since this was the top hit I got on google while researching joystick / gamepad input in C#, I thought I should post a response for others to see.
The easiest way I found was to use SharpDX and DirectInput. You can install it via NuGet (SharpDX.DirectInput)
After that, it's simply a matter of calling a few methods:
Sample code from SharpDX
static void Main()
{
// Initialize DirectInput
var directInput = new DirectInput();
// Find a Joystick Guid
var joystickGuid = Guid.Empty;
foreach (var deviceInstance in directInput.GetDevices(DeviceType.Gamepad,
DeviceEnumerationFlags.AllDevices))
joystickGuid = deviceInstance.InstanceGuid;
// If Gamepad not found, look for a Joystick
if (joystickGuid == Guid.Empty)
foreach (var deviceInstance in directInput.GetDevices(DeviceType.Joystick,
DeviceEnumerationFlags.AllDevices))
joystickGuid = deviceInstance.InstanceGuid;
// If Joystick not found, throws an error
if (joystickGuid == Guid.Empty)
{
Console.WriteLine("No joystick/Gamepad found.");
Console.ReadKey();
Environment.Exit(1);
}
// Instantiate the joystick
var joystick = new Joystick(directInput, joystickGuid);
Console.WriteLine("Found Joystick/Gamepad with GUID: {0}", joystickGuid);
// Query all suported ForceFeedback effects
var allEffects = joystick.GetEffects();
foreach (var effectInfo in allEffects)
Console.WriteLine("Effect available {0}", effectInfo.Name);
// Set BufferSize in order to use buffered data.
joystick.Properties.BufferSize = 128;
// Acquire the joystick
joystick.Acquire();
// Poll events from joystick
while (true)
{
joystick.Poll();
var datas = joystick.GetBufferedData();
foreach (var state in datas)
Console.WriteLine(state);
}
}
I hope this helps.
I even got this to work with a DualShock3 and the MotioninJoy drivers.
One: use SlimDX.
Two: it looks something like this (where GamepadDevice is my own wrapper, and the code is slimmed down to just the relevant parts).
Find the joystick / pad GUIDs:
public virtual IList<GamepadDevice> Available()
{
IList<GamepadDevice> result = new List<GamepadDevice>();
DirectInput dinput = new DirectInput();
foreach (DeviceInstance di in dinput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly))
{
GamepadDevice dev = new GamepadDevice();
dev.Guid = di.InstanceGuid;
dev.Name = di.InstanceName;
result.Add(dev);
}
return result;
}
Once the user has selected from the list, acquire the gamepad:
private void acquire(System.Windows.Forms.Form parent)
{
DirectInput dinput = new DirectInput();
pad = new Joystick(dinput, this.Device.Guid);
foreach (DeviceObjectInstance doi in pad.GetObjects(ObjectDeviceType.Axis))
{
pad.GetObjectPropertiesById((int)doi.ObjectType).SetRange(-5000, 5000);
}
pad.Properties.AxisMode = DeviceAxisMode.Absolute;
pad.SetCooperativeLevel(parent, (CooperativeLevel.Nonexclusive | CooperativeLevel.Background));
pad.Acquire();
}
Polling the pad looks like this:
JoystickState state = new JoystickState();
if (pad.Poll().IsFailure)
{
result.Disconnect = true;
return result;
}
if (pad.GetCurrentState(ref state).IsFailure)
{
result.Disconnect = true;
return result;
}
result.X = state.X / 5000.0f;
result.Y = state.Y / 5000.0f;
int ispressed = 0;
bool[] buttons = state.GetButtons();
The bad news is that Microsoft seems to stop supporting their NET libraries for DirectX and focus on XNA instead. I don't work in GameDev so I don't need to use XNA but you may try it if you developing computer games. The good news is that there are other approaches. One is SlimDX the new framework to help you to wok with DirectX from C#. The other way is to directly add references of "Microsoft.DirectX.dll" and "Microsoft.DirectX.DirectInput.dll" to your project. you can find them "..\Windows\Microsoft.NET\DirectX for Managed Code\". if you you are going to use last approach here is a link to codeproject where you can read how to work with a joystick.
EDIT:
If your application is based on NET version newer then 2.0 the application may hang on. To fix this problem change config file and add this:
<startup useLegacyV2RuntimeActivationPolicy="true">
Google led me here and while not a requirement of this question, OpenTK is a good option for Windows and Linux (under mono) support.
From the OpenTK docs, this code works on Raspberry Pi + Raspbian + Mono 3.12.0:
for (int i = 0; i < 4; i++)
{
var state = Joystick.GetState(i);
if (state.IsConnected)
{
float x = state.GetAxis(JoystickAxis.Axis0);
float y = state.GetAxis(JoystickAxis.Axis1);
// Print the current state of the joystick
Console.WriteLine(state);
}
}
This question is old, but it seems to be active even to this day, so I'm posting anyway.
If you need to get input from XInput only, take a look at XInputium. This is a .NET library that is specialized in XInput controllers. It is pretty straightforward, and has many code samples you can look at.

Categories