TheSwamp

Code Red => .NET => Topic started by: Keith Brown on January 30, 2013, 12:20:46 AM

Title: Add geometry to a duct fitting
Post by: Keith Brown on January 30, 2013, 12:20:46 AM
I am trying to add extra geometry to a duct fitting.  To get started I am trying to verify that I can even make happen.  I have found a sample where using .net a mass element object is created and modified.  I modified the code to work with a duct fitting and have the following code.

 
Code - C#: [Select]
  1.         [CommandMethod("ACAClassCode", "ExModelerModifyBody", CommandFlags.Modal)]
  2.         public void ModifyBody()
  3.         {
  4.             Database db = HostApplicationServices.WorkingDatabase;
  5.             Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  6.  
  7.             // get a mass element to modify.
  8.             PromptEntityOptions prEntOpts = new PromptEntityOptions("\nSelect duct fitting to modify");
  9.             prEntOpts.SetRejectMessage("\nSelected entity must be of type duct fitting");
  10.             //prEntOpts.AddAllowedClass(typeof(Autodesk.Aec.DatabaseServices.MassElement), false);
  11.             prEntOpts.AddAllowedClass(typeof(DuctFitting), false);
  12.  
  13.             PromptEntityResult prEntRes = ed.GetEntity(prEntOpts);
  14.  
  15.             if (prEntRes.Status != PromptStatus.OK)
  16.                 return;
  17.  
  18.             Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = db.TransactionManager;
  19.  
  20.  
  21.             using (Transaction trans = tm.StartTransaction())
  22.             {
  23.                 // Open the duct fitting
  24.                 //Autodesk.Aec.DatabaseServices.MassElement me = (Autodesk.Aec.DatabaseServices.MassElement)trans.GetObject(prEntRes.ObjectId, OpenMode.ForWrite);
  25.                 DuctFitting me = (DuctFitting)trans.GetObject(prEntRes.ObjectId, OpenMode.ForWrite);
  26.  
  27.                 // Get the body from the duct fitting.
  28.                 Autodesk.Aec.Modeler.Body bBase = me.Body;
  29.  
  30.                 // setup a location to hold the new body.
  31.                 Autodesk.Aec.Modeler.Body bNew = null;
  32.  
  33.                 // create two new bodies
  34.                 Autodesk.Aec.Modeler.Body b1 = Autodesk.Aec.Modeler.Body.Cone(new LineSegment3d(new Point3d(0, 0, 0), new Point3d(0, 0, 5)), 2, 1.5, 10);
  35.                 Autodesk.Aec.Modeler.Body b2 = Autodesk.Aec.Modeler.Body.Sphere(new Point3d(0, 0, 5), 0.5, 10);
  36.  
  37.                 // perform a bolean union via the plus operator... In this case we are unioining the two new bodys we created above.
  38.                 bNew = b1 + b2;
  39.  
  40.                 // Now take the oginal body and subtract our new body.
  41.                 // bNew = bBase - bNew;
  42.                 bNew = bBase + bNew;
  43.  
  44.                 // finally, since we are working on a copy, we need to assign the final body back to the mass element.
  45.                 //me.SetBody(bNew, true);
  46.                 me.Body.Combine(bNew);
  47.  
  48.                 trans.Commit();
  49.             }
  50.  
  51.  
  52.         }

The code runs through just fine but nothing happens to the duct fitting.  Has anyone had any luck trying to do something like this?
Title: Re: Add geometry to a duct fitting
Post by: MexicanCustard on January 30, 2013, 08:13:28 AM
Why not just make the part look like you want it to in the Part Catalog?
Title: Re: Add geometry to a duct fitting
Post by: Keith Brown on January 30, 2013, 08:20:06 AM
The content builder does not have the ability to create certain types of parts.  For instance a drop cheek elbow duct fitting.  It requires a smooth radius on the turn and the ability for the outlet to be at a different elevation than the inlet.  The content builder does not have the ability to modify the angle of a plane on a fly.  You need to "set it and forget it". 

I have seen another implementation where they have programmatically added the correct geometry after the fitting was inserted.  I am just trying to figure out how they did it for my own implementation.
Title: Re: Add geometry to a duct fitting
Post by: IDabble on January 30, 2013, 08:29:23 PM
I've never worked with Bodies before, but I assume the example's Union syntax is correct.
I know with 3DSolids, you do it something like this:
http://through-the-interface.typepad.com/through_the_interface/2013/01/performing-boolean-operations-on-autocad-solids-using-net.html (http://through-the-interface.typepad.com/through_the_interface/2013/01/performing-boolean-operations-on-autocad-solids-using-net.html)
Maybe the Autodesk Architecture Customization Forum can help.
Sorry I can't answer, but I can dig what you're trying to do though.
Title: Re: Add geometry to a duct fitting
Post by: IDabble on January 31, 2013, 10:37:48 PM
Hey Keith, good news, Buddy!
I tested your code tonight, and it works in AMEP 2010 with a little modification !
It seems you were missing a bit from the AModelerSample Init method.
The + Boolean operator works OK with MassElements, as does something similar to what I suggested (see AModelerSample).

Now, the two created Bodies are going to unite because they are touching.
The trick to getting your DuctFitting involved is to place the top of the fitting at the origin point before running the command.
Here's the code that I hacked up:

Code: [Select]
[CommandMethod("ACAClassCode", "ExModelerModifyBody", CommandFlags.Modal)]
public static void ModifyBody()
{
    Database db = HostApplicationServices.WorkingDatabase;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

    // get a mass element to modify
    PromptEntityOptions prEntOpts = new PromptEntityOptions("\nSelect duct fitting to modify");
    prEntOpts.SetRejectMessage("\nSelected entity must be of type duct fitting");
    //prEntOpts.AddAllowedClass(typeof(Autodesk.Aec.DatabaseServices.MassElement), false);
    prEntOpts.AddAllowedClass(typeof(AecBldgHvacDbSvcs.DuctFitting), false);
    PromptEntityResult prEntRes = ed.GetEntity(prEntOpts);
    if (prEntRes.Status != PromptStatus.OK)
        return;

    using (Transaction trans = db.TransactionManager.StartTransaction())
    {
        // add code from AModelerSample Init method
        BlockTableRecord btrModelSpace =
            (BlockTableRecord)SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(OpenMode.ForWrite);
        Autodesk.Aec.DatabaseServices.MassElement me =
            Autodesk.Aec.DatabaseServices.MassElement.Create(AecDbSvcs.ShapeType.BoundaryRepresentation);
        // end added AModelerSample code
       
        // open the duct fitting
        //Autodesk.Aec.DatabaseServices.MassElement me =
            //(Autodesk.Aec.DatabaseServices.MassElement)trans.GetObject(prEntRes.ObjectId, OpenMode.ForWrite);
        AecBldgHvacDbSvcs.DuctFitting df =
            (AecBldgHvacDbSvcs.DuctFitting)trans.GetObject(prEntRes.ObjectId, OpenMode.ForWrite);
        // get the body from the duct fitting
        Autodesk.Aec.Modeler.Body bBase = df.Body;

        // add code from AModelerSample Init method
        me.SetBody(bBase, false);
        btrModelSpace.AppendEntity(me);
        trans.AddNewlyCreatedDBObject(me, true);
        // end added AModelerSample code

        // setup a location to hold the new body
        Autodesk.Aec.Modeler.Body bNew = null;
        // create two new bodies
        Autodesk.Aec.Modeler.Body b1 =
            Autodesk.Aec.Modeler.Body.Cone(new LineSegment3d(new Point3d(0, 0, 0), new Point3d(0, 0, 5)), 2, 1.5, 10);
        Autodesk.Aec.Modeler.Body b2 = Autodesk.Aec.Modeler.Body.Sphere(new Point3d(0, 0, 5), 0.5, 10);
        // perform a boolean union via the plus operator... In this case we are unioining the two new bodys we created above
        bNew = b1 + b2;

        me.SetBody(bNew, false); // added

        // now take the oginal body and subtract our new body
        //bNew = bBase - bNew;
        bNew = bBase + bNew;

        me.SetBody(bNew, false); // added

        // finally, since we are working on a copy, we need to assign the final body back to the mass element
        //me.SetBody(bNew, true);
        me.Body.Combine(bNew);
        trans.Commit();
    }
}
Title: Re: Add geometry to a duct fitting
Post by: Keith Brown on January 31, 2013, 11:36:36 PM
What your code does is nice but it is not exactly what I was looking for.  What it does is add the ductfitting geometry to a new mass element and places the mass element into the model.  That is opposite to what I was looking to do.  I want to create a new mass element and add it to the ductfitting. 
Title: Re: Add geometry to a duct fitting
Post by: IDabble on February 01, 2013, 08:23:35 AM
I think that's entirely possible.  I can look into that over the weekend.
Title: Re: Add geometry to a duct fitting
Post by: Keith Brown on February 01, 2013, 11:05:28 AM
What I have actually been exploring doing is creating a 3D solid and then trying to add it to the block reference of the fitting.  I am not entirely sure that the fitting has a block reference but it stands to reason that it does.  I have not gotten much beyond the planning stage because this is all new to me but I believe that the styles of the fitting are essentially nothing more than a block reference that is hidden from the user.  I just need to find this block reference and then add the geometry to it.  It seems easier than going the mass element route.  Again, this is just in idea stage but I believe it to be 100% possible.
Title: Re: Add geometry to a duct fitting
Post by: IDabble on February 02, 2013, 11:03:58 PM
Well, not exactly what I had expected to do...
I was thinking Anchor all the way, but thought I could leave the Body on the surface of the Fitting.
I only type of Anchor I could make stick was literally "to the curve".
Then, you're limited in positioning mobility only in the X direction - along the curve.
Funny...but if you manually use a Curve Anchor, you have X, Y, and Z positioning available ?!?
So, I had to add to the Body, to extend all the way down to the curve, to compensate.
I guess that's why take-offs literally extend back to the curve - there's no other way (at least that I could find).
I tested this code with a 26 x 16 90 degree Rectangular Mitered Elbow.
Oh yeah, I forgot Anchors are like magnets.
So, moving the Fitting to the origin is no longer a prerequisite before running the command.
It's only drawing the Body at the origin.
The Body is stuck on there good until you release it.
You can take the fitting and Rotate 3D, move one or the other, and it all stays together.
And, of course, the Body doesn't have to stick out of the top of the Fitting.
There are options to rotate it off to the side.
With a little planning ahead, you could make this work with whatever Fitting you choose.
Have fun with it.

Code: [Select]
[CommandMethod("ACAClassCode", "ExModelerModifyBody", CommandFlags.Modal)]
public static void ModifyBody()
{
    Database db = HostApplicationServices.WorkingDatabase;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    PromptEntityOptions prEntOpts = new PromptEntityOptions("\nSelect duct fitting to modify");
    prEntOpts.SetRejectMessage("\nSelected entity must be of type duct fitting");
    prEntOpts.AddAllowedClass(typeof(AecBldgHvacDbSvcs.DuctFitting), false);
    PromptEntityResult prEntRes = ed.GetEntity(prEntOpts);
    if (prEntRes.Status != PromptStatus.OK)
        return;
    using (Transaction trans = db.TransactionManager.StartTransaction())
    {
        AecDbSvcs.MassElement me = AecDbSvcs.MassElement.Create(AecDbSvcs.ShapeType.BoundaryRepresentation);
        Autodesk.Aec.Modeler.Body bNew = null;
        Autodesk.Aec.Modeler.Body b1 = Autodesk.Aec.Modeler.Body.Cone(new LineSegment3d(new Point3d(0, 0, 8), new Point3d(0, 0, 13)), 2, 1.5, 10);
        Autodesk.Aec.Modeler.Body b2 = Autodesk.Aec.Modeler.Body.Sphere(new Point3d(0, 0, 13), 0.5, 10);
        Autodesk.Aec.Modeler.Body b3 = Autodesk.Aec.Modeler.Body.Cone(new LineSegment3d(new Point3d(0, 0, 0), new Point3d(0, 0, 8)), 2, 2, 10);
        bNew = b1 + b2 + b3;
        me.SetBody(bNew, true);
        me.Body.Combine(bNew);
        BlockTableRecord btrModelSpace = (BlockTableRecord)SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(OpenMode.ForWrite);
        btrModelSpace.AppendEntity(me);
        trans.AddNewlyCreatedDBObject(me, true);
        AecBldgHvacDbSvcs.DuctFitting df = (AecBldgHvacDbSvcs.DuctFitting)trans.GetObject(prEntRes.ObjectId, OpenMode.ForRead);
        if (df.AnchorId.IsNull)
        {
            ed.WriteMessage("\nAnchoring MassElement to DuctFitting.\n");
            AecBldgDbSvcs.AnchorEntityToMember anchor = new AecBldgDbSvcs.AnchorEntityToMember();
            anchor.SubSetDatabaseDefaults(db);
            anchor.SetToStandard(db);
            anchor.AnchorX.OffsetDistance = 15;
            anchor.CurveId = df.ObjectId;
            me.SetAnchor(anchor);
            anchor.ForceUpdateToAnchorEntityToCurve = true;
        }
        trans.Commit();
    }
}