Author Topic: Add geometry to a duct fitting  (Read 3557 times)

0 Members and 1 Guest are viewing this topic.

Keith Brown

  • Swamp Rat
  • Posts: 601
Add geometry to a duct fitting
« 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?
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Add geometry to a duct fitting
« Reply #1 on: January 30, 2013, 08:13:28 AM »
Why not just make the part look like you want it to in the Part Catalog?
Revit 2019, AMEP 2019 64bit Win 10

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Add geometry to a duct fitting
« Reply #2 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.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

IDabble

  • Guest
Re: Add geometry to a duct fitting
« Reply #3 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
Maybe the Autodesk Architecture Customization Forum can help.
Sorry I can't answer, but I can dig what you're trying to do though.

IDabble

  • Guest
Re: Add geometry to a duct fitting
« Reply #4 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();
    }
}

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Add geometry to a duct fitting
« Reply #5 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. 
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

IDabble

  • Guest
Re: Add geometry to a duct fitting
« Reply #6 on: February 01, 2013, 08:23:35 AM »
I think that's entirely possible.  I can look into that over the weekend.

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Add geometry to a duct fitting
« Reply #7 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.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

IDabble

  • Guest
Re: Add geometry to a duct fitting
« Reply #8 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();
    }
}
« Last Edit: February 03, 2013, 12:33:09 AM by IDabble »