0

I'm doing a Revit Macro to get the center point of a part (floor part) to check if it is inside a room or a space. I couldn't get much of the BoundingBox object which is giving me a point outside the part, so I tried to use the Geometry element internal faces getting the mesh vertices but I'm stuck calculating the mid point. I'm using a rather naive algorithm shown in the snippet below, but it's giving me false results as it seems to be affected by the initial default of min/max variables. Any suggestions?

PS: DebugTools is a custom helper class of my own.

public void ZoneDetect()
{
    Document doc = this.ActiveUIDocument.Document;

    using (Transaction t = new Transaction(doc,"Set Rooms By Region"))
    {
        t.Start();

        FilteredElementCollector fec = 
            new FilteredElementCollector(doc)
                .OfClass(typeof(Part))
                .OfCategory(BuiltInCategory.OST_Parts)
                .Cast<Part>();

        foreach (Part p in fec)
        {


            Options op = new Options();
            op.View=doc.ActiveView;
            op.ComputeReferences=true;

            GeometryElement gm=p.get_Geometry(op);
            Solid so = gm.First() as Solid;
            PlanarFace fc=so.Faces.get_Item(0) as PlanarFace;

            foreach (PlanarFace f in so.Faces)
            {
                if (f.Normal == new XYZ(0,0,-1))  fc=f;
            }
            XYZ max = new XYZ();
            XYZ min = new XYZ();

            int no = 0;
            foreach (XYZ vx in fc.Triangulate().Vertices) 
            {
                // Just for debugging
                DebugTools.DrawModelTick(vx,doc,"Max");
                doc.Regenerate();
                TaskDialog.Show("Point:"+no.ToString(),vx.ToString());
                no++;

                //Comparing points
                if (vx.X>max.X) max=new XYZ (vx.X,max.Y,0);
                if (vx.Y>max.Y) max=new XYZ (max.X,vx.Y,0);
                if (vx.X<min.X) min=new XYZ (vx.X,min.Y,0);
                if (vx.Y<min.Y) min=new XYZ (min.X,vx.Y,0);
            }

            XYZ mid = new XYZ(max.X-min.X,max.Y-min.Y,0);

            DebugTools.DrawModelTick(mid,doc,"Mid");
            DebugTools.DrawModelTick(max,doc,"Max");
            DebugTools.DrawModelTick(min,doc,"Min");
        }

        t.Commit();
    }
}
skeletank
  • 2,880
  • 5
  • 43
  • 75
Samer
  • 11
  • 1
  • 6

2 Answers2

0

It seems like you're looking for the center of gravity of a polygon. An algorithm for that can be found here: Center of gravity of a polygon

Once you have a Face object, you can enumerate its edges to receive a list of vertex points. Use the longest of the EdgeLoops in the face. Collect all the points and make sure that they are in the right order (the start and end points of the edges might need to be swapped).

Community
  • 1
  • 1
Daren Thomas
  • 67,947
  • 40
  • 154
  • 200
  • 1
    That said, there are still going to be hypothetical cases where the center of gravity is not on the floor itself. In some cases you're better off doing a grid of points and determine if a point is inside the face or not. – Matt Mar 06 '14 at 16:25
0

Daren & Matt thanks a lot for your answers, Since I'm dealing with rather simple shapes ( mainly rectangles ) I just needed to get a point roughly near the center to test whether it is inside a room, my problem was with the naive algorithm I was using which turned out to be wrong. I corrected it as follows:

XYZ midSum = Max + Min;
XYZ mid = new XYZ(midSum.X/2 , midSum.Y/2,0);

I will look into refining it using the link you've provided, but as for now I will get into finishing my task in hand.

Many thanks

Samer
  • 11
  • 1
  • 6