Author Topic: centroid of closed polyline  (Read 22417 times)

0 Members and 1 Guest are viewing this topic.

SEANT

  • Bull Frog
  • Posts: 345
Re: centroid of closed polyline
« Reply #15 on: November 13, 2008, 10:16:33 AM »
In a similar fashion to the Polyline to Region process mentioned earlier, here an alternate method of retrieving centroids.  Sure it’s cheating and ridiculously heavy handed, but isn’t that truly the American way.   Just kidding. :-)

Granted, it is probably even slower still than the Poly/Region method – it does, however, allow for the inclusion of “Curved” Polys, Splines, and Regions.


Code: [Select]
        [CommandMethod("EntCen")]
        static public void centroid()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            PromptEntityOptions opts = new PromptEntityOptions("\nSelect a planar entity: ");
            opts.AllowNone = true;
            opts.AllowObjectOnLockedLayer = true;
            opts.SetRejectMessage("\nEntity not valid.");
            opts.AddAllowedClass(typeof(Polyline), false);
            opts.AddAllowedClass(typeof(Polyline2d), false);
            opts.AddAllowedClass(typeof(Region), false);
            opts.AddAllowedClass(typeof(Spline), false);
            PromptEntityResult per = ed.GetEntity(opts);
            if (per.Status == PromptStatus.OK)
            {
                ObjectId ObjID = per.ObjectId;
                try
                {
                    using (Transaction trans = db.TransactionManager.StartTransaction())
                    {
                        Entity ent = (Entity)trans.GetObject(ObjID, OpenMode.ForRead, false);
                        CentroidViaSol c = new CentroidViaSol(ent);

                        if (c.Success)
                        {
                            Point3d cen = c.DerivedCentroid;
                            DBPoint pt = new DBPoint(cen);
                            BlockTable bTable = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                            BlockTableRecord cSpace = (BlockTableRecord)trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                            cSpace.AppendEntity(pt);
                            trans.AddNewlyCreatedDBObject(pt, true);
                            trans.Commit();
                        }
                    }
                }
                catch (System.Exception ex)
                {
                    ed.WriteMessage("Error: " + ex.Message);
                }
            }
        }



        // New Class //////////////
        class CentroidViaSol
        {
            //Fields
            public Boolean Success;
            private Region m_region;
            private Solid3d m_derivedSolid;
            private Vector3d m_normal;
            private Point3d m_centroid;
            private DBObjectCollection m_entCol;
 
            //Constructor ///////////
            public CentroidViaSol(Entity PlanarEnt)
            {
                m_entCol = new DBObjectCollection();
                string entType = PlanarEnt.GetType().ToString();
                switch (entType)
                {
                    case "Autodesk.AutoCAD.DatabaseServices.Polyline":
                        Polyline poly = PlanarEnt as Polyline;
                        if (poly.Closed)
                        {
                            m_entCol.Add(poly);
                            CreateRegion();
                        }
                        break;
                    case "Autodesk.AutoCAD.DatabaseServices.Polyline2d":
                        Polyline2d poly2d = PlanarEnt as Polyline2d;
                        if (poly2d.Closed)
                        {
                            m_entCol.Add(poly2d);
                            CreateRegion();
                        }
                        break;
                    case "Autodesk.AutoCAD.DatabaseServices.Spline":
                        Spline entSpline = PlanarEnt as Spline;
                        if (entSpline.IsPlanar && entSpline.Closed)
                        {
                            m_entCol.Add(entSpline);
                            CreateRegion();
                        }
                       
                        break;
                    case "Autodesk.AutoCAD.DatabaseServices.Region":
                        m_region = (Region)PlanarEnt;
                        Success = true;
                        break;
                }
                if (!m_region.IsNull)
                {
                    m_normal = m_region.Normal;
                    m_derivedSolid = new Solid3d();
                    m_derivedSolid.Extrude(m_region, 2.0, 0.0);
                    m_centroid = m_derivedSolid.MassProperties.Centroid;
                    m_centroid = m_centroid - m_normal;
                }
            }



            //Properties //////////

            public Point3d DerivedCentroid
            {
                get { return m_centroid; }
            }



            //Internal ////////////

            private void CreateRegion()
            {
                try
                {
                    m_region = (Region)(Region.CreateFromCurves(m_entCol)[0]);
                    Success = true;
                }
                catch
                {
                    Success = false;
                }
            }

        }
« Last Edit: November 13, 2008, 11:29:17 AM by SEANT »
Sean Tessier
AutoCAD 2016 Mechanical

Spike Wilbury

  • Guest

Spike Wilbury

  • Guest
Re: centroid of closed polyline
« Reply #17 on: November 13, 2008, 10:41:02 AM »
In a similar fashion to the Polyline to Region process mentioned earlier, here an alternate method of retrieving centroids.  Sure it’s cheating and ridiculously heavy handed, but isn’t that truly the American way.   Just kidding. :-)

Granted, it is probably slower still than the Poly/Region method – it does, however, allow for the inclusion of “Curved” Polys, Splines, and Regions.


Code: [Select]
                                
if (poly.Closed)
                        {
                            poly.Explode(m_entCol);
                            CreateRegion();
                        }


}


Why you need the explode method?

SEANT

  • Bull Frog
  • Posts: 345
Re: centroid of closed polyline
« Reply #18 on: November 13, 2008, 10:59:11 AM »
Why you need the explode method?

I admit I did not confirm that it was actually needed but the docs seemed to imply that it was.

And, I should also admit that despite the aforementioned "Heavyhandedness", I think the methodology interesting.  Your link demos the more conventional method of dealing with regions, splines and splined polys.
Sean Tessier
AutoCAD 2016 Mechanical

Spike Wilbury

  • Guest
Re: centroid of closed polyline
« Reply #19 on: November 13, 2008, 11:06:02 AM »
Why you need the explode method?

I admit I did not confirm that it was actually needed but the docs seemed to imply that it was.

And, I should also admit that despite the aforementioned "Heavyhandedness", I think the methodology interesting.  Your link demos the more conventional method of dealing with regions, splines and splined polys.

Sean,

If you can, and have the ObjectARX refererence help (part of the SDK) have a look at AcDbRegion::createFromCurves appears that they change it?.... what version of autocad you are using?


Below it is a quote from the a2009 ARX SDK docs....
Quote
Description
This static member function creates a set of AcDbRegion objects from the closed loops represented by the curves contained in the curveSegments array. The newly created region objects are returned in the regions array.

The curveSegments array must contain only pointers to AcDbLine, AcDbArc, AcDbEllipse, AcDbCircle, AcDbSpline, AcDb3dPolyline, or AcDbPolyline objects.

SEANT

  • Bull Frog
  • Posts: 345
Re: centroid of closed polyline
« Reply #20 on: November 13, 2008, 11:23:02 AM »
Sean,

If you can, and have the ObjectARX refererence help (part of the SDK) have a look at AcDbRegion::createFromCurves appears that they change it?.... what version of autocad you are using?


Cool! It appears that the Autocad 2009: Managed Class Reference Guide may have a misprint.  I'll eliminate that explode call.  It's not much by my "alternate method" needs every bit of optimization it can get.  :wink:
Sean Tessier
AutoCAD 2016 Mechanical

Spike Wilbury

  • Guest
Re: centroid of closed polyline
« Reply #21 on: November 13, 2008, 11:36:28 AM »
Sean,

If you can, and have the ObjectARX refererence help (part of the SDK) have a look at AcDbRegion::createFromCurves appears that they change it?.... what version of autocad you are using?


Cool! It appears that the Autocad 2009: Managed Class Reference Guide may have a misprint.  I'll eliminate that explode call.  It's not much by my "alternate method" needs every bit of optimization it can get.  :wink:

Good.


You can port the arx function (per the link I posted) to C# - and avoid all the hassle :)

SEANT

  • Bull Frog
  • Posts: 345
Re: centroid of closed polyline
« Reply #22 on: November 13, 2008, 11:55:18 AM »
I am indeed looking into it.  It would appear, and correct me again if I’m wrong, that there is no direct way to get at a region’s mass props via the Managed API.  The link you posted shows that it’s all accessible via a port.  Thanks for the pointer. 
Sean Tessier
AutoCAD 2016 Mechanical

Spike Wilbury

  • Guest
Re: centroid of closed polyline
« Reply #23 on: November 13, 2008, 12:16:58 PM »
I am indeed looking into it.  It would appear, and correct me again if I’m wrong, that there is no direct way to get at a region’s mass props via the Managed API.  The link you posted shows that it’s all accessible via a port.  Thanks for the pointer. 

a quick review to the docs they have it in:

Solid3dMassProperties Properties

SEANT

  • Bull Frog
  • Posts: 345
Re: centroid of closed polyline
« Reply #24 on: November 13, 2008, 01:31:53 PM »
Hmm, I can see how to use that with a solid but couldn’t see any hook into that with a region. 
Neither can I avoid an exception with the example below:

Brep brp = new Brep(m_region);
foreach (Autodesk.AutoCAD.BoundaryRepresentation.Face fce in brp.Faces)
{
    double ar = fce.GetArea(); //works okay
    double pl = fce.GetPerimeterLength(); //works okay
    MassProperties mp = fce.GetMassProperties(); //Exception
}
Sean Tessier
AutoCAD 2016 Mechanical

Spike Wilbury

  • Guest
Re: centroid of closed polyline
« Reply #25 on: November 13, 2008, 02:09:20 PM »
Hmm, I can see how to use that with a solid but couldn’t see any hook into that with a region. 
Neither can I avoid an exception with the example below:

Brep brp = new Brep(m_region);
foreach (Autodesk.AutoCAD.BoundaryRepresentation.Face fce in brp.Faces)
{
    double ar = fce.GetArea(); //works okay
    double pl = fce.GetPerimeterLength(); //works okay
    MassProperties mp = fce.GetMassProperties(); //Exception
}

Do you need the Faces ?

- Can you cast As Entity the Region and pass that to the Brep(Entity); ?

Sorry, do not have my tools or code here at the office....

SEANT

  • Bull Frog
  • Posts: 345
Re: centroid of closed polyline
« Reply #26 on: November 13, 2008, 03:03:53 PM »

Do you need the Faces ?

- Can you cast As Entity the Region and pass that to the Brep(Entity); ?

Sorry, do not have my tools or code here at the office....

No need to apologize.  Exploring the various possibilities is kind entertaining.  I know, I need a life:|

I’ve tried various levels of Breps.  I’ve also alternated using the region as entity and as region for the Brep constructor.    The best I was able to do was avoid the exception during the MassProperties assignment, but everything set at 0.  Actually, the RadiiOfGyration had “NaN” values – whatever that means. 

I’ll keep looking.  Something seems likely – given that the info is available via both COM and ARX.
Sean Tessier
AutoCAD 2016 Mechanical