BuildingCoder.CmdWallProfileArea.GetPolygonPlane C# (CSharp) Метод

GetPolygonPlane() статический приватный Метод

Return the plane properties of a given polygon, i.e. the plane normal, area, and its distance from the origin. Cf. also GetSignedPolygonArea.
static private GetPolygonPlane ( List polygon, XYZ &normal, double &dist, double &area ) : bool
polygon List
normal XYZ
dist double
area double
Результат bool
        internal static bool GetPolygonPlane(
            List<XYZ> polygon,
            out XYZ normal,
            out double dist,
            out double area)
        {
            normal = XYZ.Zero;
              dist = area = 0.0;
              int n = ( null == polygon ) ? 0 : polygon.Count;
              bool rc = ( 2 < n );
              if( 3 == n )
              {

            // the general case returns a wrong result for the triangle
            // ((-1 -1 -1) (1 -1 -1) (-1 -1 1)), so implement specific
            // code for triangle:

            XYZ a = polygon[0];
            XYZ b = polygon[1];
            XYZ c = polygon[2];
            XYZ v = b - a;
            normal = v.CrossProduct( c - a );
            dist = normal.DotProduct( a );
              }
              else if( 4 == n )
              {

            // more efficient code for 4-sided polygons

            XYZ a = polygon[0];
            XYZ b = polygon[1];
            XYZ c = polygon[2];
            XYZ d = polygon[3];

            normal = new XYZ(
              ( c.Y - a.Y ) * ( d.Z - b.Z ) + ( c.Z - a.Z ) * ( b.Y - d.Y ),
              ( c.Z - a.Z ) * ( d.X - b.X ) + ( c.X - a.X ) * ( b.Z - d.Z ),
              ( c.X - a.X ) * ( d.Y - b.Y ) + ( c.Y - a.Y ) * ( b.X - d.X ) );

            dist = 0.25 *
              ( normal.X * ( a.X + b.X + c.X + d.X )
              + normal.Y * ( a.Y + b.Y + c.Y + d.Y )
              + normal.Z * ( a.Z + b.Z + c.Z + d.Z ) );
              }
              else if( 4 < n )
              {

            // general case for n-sided polygons

            XYZ a;
            XYZ b = polygon[n - 2];
            XYZ c = polygon[n - 1];
            XYZ s = XYZ.Zero;

            for( int i = 0; i < n; ++i )
            {
              a = b;
              b = c;
              c = polygon[i];

              normal = new XYZ(
            normal.X + b.Y * ( c.Z - a.Z ),
            normal.Y + b.Z * ( c.X - a.X ),
            normal.Z + b.X * ( c.Y - a.Y ) );

              s += c;
            }
            dist = s.DotProduct( normal ) / n;
              }
              if( rc )
              {

            // the polygon area is half of the length
            // of the non-normalized normal vector of the plane:

            double length = normal.GetLength();
            rc = !Util.IsZero( length );
            Debug.Assert( rc );

            if( rc )
            {
              normal /= length;
              dist /= length;
              area = 0.5 * length;
            }
              }
              return rc;
        }

Usage Example

            Transform.CreateTranslation(_offset); // 2014
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES

        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;

            Options opt = app.Create.NewGeometryOptions();

            XyzEqualityComparer comparer
                = new XyzEqualityComparer(1e-6);

#if CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
            Creator creator = new Creator(doc);

            Transaction t = new Transaction(doc);

            t.Start("Create model curve copies of top face edges");
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES

            IList <Face> topFaces = new List <Face>();

            int n;
            int nWalls = 0;

            //foreach( Element e in uidoc.Selection.Elements ) // 2014

            foreach (ElementId id in uidoc.Selection.GetElementIds()) // 2015
            {
                Element e = doc.GetElement(id);

                Wall wall = e as Wall;

                if (null == wall)
                {
                    Debug.Print("Skipped "
                                + Util.ElementDescription(e));
                    continue;
                }

                // Get the side faces

                IList <Reference> sideFaces
                    = HostObjectUtils.GetSideFaces(wall,
                                                   ShellLayerType.Exterior);

                // Access the first side face

                Element e2 = doc.GetElement(sideFaces[0]);

                Debug.Assert(e2.Id.Equals(e.Id),
                             "expected side face element to be the wall itself");

                Face face = e2.GetGeometryObjectFromReference(
                    sideFaces[0]) as Face;

                if (null == face)
                {
                    Debug.Print("No side face found for "
                                + Util.ElementDescription(e));
                    continue;
                }

                // When there are opening such as doors or
                // windows in the wall, we need to find the
                // outer loop.
                // For one possible approach to extract the
                // outermost loop, please refer to
                // http://thebuildingcoder.typepad.com/blog/2008/12/2d-polygon-areas-and-outer-loop.html

                // Determine the outer loop of the side face
                // by finding the polygon with the largest area

                XYZ       normal;
                double    area, dist, maxArea = 0;
                EdgeArray outerLoop = null;

                foreach (EdgeArray ea in face.EdgeLoops)
                {
                    if (CmdWallProfileArea.GetPolygonPlane(
                            ea.GetPolygon(), out normal, out dist, out area) &&
                        Math.Abs(area) > Math.Abs(maxArea))
                    {
                        maxArea   = area;
                        outerLoop = ea;
                    }
                }

                n = 0;

#if GET_FACES_FROM_OUTER_LOOP
                // With the outermost loop, calculate the top faces

                foreach (Edge edge in outerLoop)
                {
                    // For each edge, get the neighbouring
                    // face and check its normal

                    for (int i = 0; i < 2; ++i)
                    {
                        PlanarFace pf = edge.get_Face(i)
                                        as PlanarFace;

                        if (null == pf)
                        {
                            Debug.Print("Skipped non-planar face on "
                                        + Util.ElementDescription(e));
                            continue;
                        }

                        if (Util.PointsUpwards(pf.Normal, 0.9))
                        {
                            if (topFaces.Contains(pf))
                            {
                                Debug.Print("Duplicate face on "
                                            + Util.ElementDescription(e));
                            }
                            else
                            {
                                topFaces.Add(pf);
                                ++n;
                            }
                        }
                    }
                }
#endif // GET_FACES_FROM_OUTER_LOOP

                List <XYZ> sideVertices = outerLoop.GetPolygon();

                // Go over all the faces of the wall and
                // determine which ones fulfill the following
                // two criteria: (i) planar face pointing
                // upwards, and (ii) neighbour of the side
                // face outer loop.

                Solid solid = wall.get_Geometry(opt)
                              .OfType <Solid>()
                              .First <Solid>(sol => null != sol);

                foreach (Face f in solid.Faces)
                {
                    if (IsTopFace(f))
                    {
                        IList <XYZ> faceVertices
                            = f.Triangulate().Vertices;

                        //if( sideVertices.Exists( v
                        //  => faceVertices.Contains<XYZ>( v, comparer ) ) )
                        //{
                        //  topFaces.Add( f );
                        //  ++n;
                        //}

                        foreach (XYZ v in faceVertices)
                        {
                            if (sideVertices.Contains <XYZ>(
                                    v, comparer))
                            {
                                topFaces.Add(f);
                                ++n;

#if CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
                                // Display face for debugging purposes

                                foreach (EdgeArray ea in f.EdgeLoops)
                                {
                                    IEnumerable <Curve> curves
                                        = ea.Cast <Edge>()
                                          .Select <Edge, Curve>(
                                              x => x.AsCurve());

                                    foreach (Curve curve in curves)
                                    {
                                        //creator.CreateModelCurve( curve.get_Transformed( _t ) ); // 2013
                                        creator.CreateModelCurve(curve.CreateTransformed(_t)); // 2014
                                    }
                                }
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES

                                break;
                            }
                        }
                    }
                }

                Debug.Print(string.Format(
                                "{0} top face{1} found on {2} ({3})",
                                n, Util.PluralSuffix(n),
                                Util.ElementDescription(e)),
                            nWalls++);
            }

#if CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES
            t.Commit();
#endif // CREATE_MODEL_CURVES_FOR_TOP_FACE_EDGES

            string s = string.Format(
                "{0} wall{1} successfully processed",
                nWalls, Util.PluralSuffix(nWalls));

            n = topFaces.Count;

            TaskDialog.Show("Wall Top Faces",
                            string.Format(
                                "{0} with {1} top face{2}.",
                                s, n, Util.PluralSuffix(n)));

            return(Result.Succeeded);
        }