Пример #1
0
        //public void CreateModelLine( XYZ p, XYZ q )
        //{
        //  if( p.IsAlmostEqualTo( q ) )
        //  {
        //    throw new ArgumentException(
        //      "Expected two different points." );
        //  }
        //  Line line = Line.CreateBound( p, q );
        //  if( null == line )
        //  {
        //    throw new Exception(
        //      "Geometry line creation failed." );
        //  }
        //  _credoc.NewModelCurve( line,
        //    NewSketchPlanePassLine( line ) );
        //}

        /// <summary>
        /// Return a new sketch plane containing the given curve.
        /// Update, later: please note that the Revit API provides
        /// an overload of the NewPlane method taking a CurveArray
        /// argument, which could presumably be used instead.
        /// </summary>
        SketchPlane NewSketchPlaneContainCurve(
            Curve curve)
        {
            XYZ p      = curve.GetEndPoint(0);
            XYZ normal = GetCurveNormal(curve);

            //Plane plane = _creapp.NewPlane( normal, p ); // 2016
            Plane plane = Plane.CreateByNormalAndOrigin(normal, p); // 2017

#if DEBUG
            if (!(curve is Line))
            {
                //CurveArray a = _creapp.NewCurveArray();
                //a.Append( curve );
                //Plane plane2 = _creapp.NewPlane( a ); // 2016

                List <Curve> a = new List <Curve>(1);
                a.Add(curve);
                CurveLoop b      = CurveLoop.Create(a);
                Plane     plane2 = b.GetPlane(); // 2017


                Debug.Assert(Util.IsParallel(plane2.Normal,
                                             plane.Normal), "expected equal planes");

                Debug.Assert(Util.IsZero(plane2.SignedDistanceTo(
                                             plane.Origin)), "expected equal planes");
            }
#endif // DEBUG

            //return _credoc.NewSketchPlane( plane ); // 2013

            return(SketchPlane.Create(_doc, plane)); // 2014
        }
Пример #2
0
        /// <summary>
        /// Project given 3D XYZ point onto plane.
        /// </summary>
        public static XYZ ProjectOnto(
            this Plane plane,
            XYZ p)
        {
            double d = plane.SignedDistanceTo(p);

            XYZ q = p + d * plane.Normal;

            Debug.Assert(
                Util.IsZero(plane.SignedDistanceTo(q)),
                "expected point on plane to have zero distance to plane");

            return(q);
        }
        Transform GetTransformToZ(XYZ v)
        {
            Transform t;

            double a = XYZ.BasisZ.AngleTo(v);

            if (Util.IsZero(a))
            {
                t = Transform.Identity;
            }
            else
            {
                XYZ axis = Util.IsEqual(a, Math.PI)
          ? XYZ.BasisX
          : v.CrossProduct(XYZ.BasisZ);

                //t = Transform.get_Rotation( XYZ.Zero, axis, a ); // 2013
                t = Transform.CreateRotation(axis, a); // 2014
            }
            return(t);
        }
Пример #4
0
        /// <summary>
        /// Determine the plane that a given curve resides in and return its normal vector.
        /// Ask the curve for its start and end points and some point in the middle.
        /// The latter can be obtained by asking the curve for its parameter range and
        /// evaluating it in the middle, or by tessellation. In case of tessellation,
        /// you could iterate through the tessellation points and use each one together
        /// with the start and end points to try and determine a valid plane.
        /// Once one is found, you can add debug assertions to ensure that the other
        /// tessellation points (if there are any more) are in the same plane.
        /// In the case of the line, the tessellation only returns two points.
        /// I once heard that that is the only element that can do that, all
        /// non-linear curves return at least three. So you could use this property
        /// to determine that a line is a line (and add an assertion as well, if you like).
        /// Update, later: please note that the Revit API provides an overload of the
        /// NewPlane method taking a CurveArray argument.
        /// </summary>
        XYZ GetCurveNormal(Curve curve)
        {
            IList <XYZ> pts = curve.Tessellate();
            int         n   = pts.Count;

            Debug.Assert(1 < n,
                         "expected at least two points "
                         + "from curve tessellation");

            XYZ p = pts[0];
            XYZ q = pts[n - 1];
            XYZ v = q - p;
            XYZ w, normal = null;

            if (2 == n)
            {
                Debug.Assert(curve is Line,
                             "expected non-line element to have "
                             + "more than two tessellation points");

                // For non-vertical lines, use Z axis to
                // span the plane, otherwise Y axis:

                double dxy = Math.Abs(v.X) + Math.Abs(v.Y);

                w = (dxy > Util.TolPointOnPlane)
          ? XYZ.BasisZ
          : XYZ.BasisY;

                normal = v.CrossProduct(w).Normalize();
            }
            else
            {
                int i = 0;
                while (++i < n - 1)
                {
                    w      = pts[i] - p;
                    normal = v.CrossProduct(w);
                    if (!normal.IsZeroLength())
                    {
                        normal = normal.Normalize();
                        break;
                    }
                }

#if DEBUG
                {
                    XYZ normal2;
                    while (++i < n - 1)
                    {
                        w       = pts[i] - p;
                        normal2 = v.CrossProduct(w);
                        Debug.Assert(normal2.IsZeroLength() ||
                                     Util.IsZero(normal2.AngleTo(normal)),
                                     "expected all points of curve to "
                                     + "lie in same plane");
                    }
                }
#endif // DEBUG
            }
            return(normal);
        }
        /*
         * /// <summary>
         * /// Return the average of a list of values.
         * /// Prerequisite: the underlying class T must supply
         * /// operator*(double) and operator+(const T &).
         * /// </summary>
         * T Average<T>( List<T> a )
         * {
         * T result;
         * bool first = true;
         * foreach( T x in a )
         * {
         *  if( first )
         *  {
         *    result = x;
         *  }
         *  else
         *  {
         *    result += x;
         *  }
         * }
         * return result * ( 1.0 / a.Count );
         * }
         *
         * XYZ Sum( List<XYZ> a )
         * {
         * XYZ sum = XYZ.Zero;
         * foreach( XYZ x in a )
         * {
         *  sum += x;
         * }
         * return sum;
         * }
         *
         * XYZ Average( List<XYZ> a )
         * {
         * return Sum( a ) * (1.0 / a.Count);
         * }
         *
         * XYZ TriangleCenter( List<XYZ> pts )
         * {
         * Debug.Assert( 3 == pts.Count, "expected three points in triangle" );
         * return Average( pts );
         * }
         */

        /// <summary>
        /// Return the plane properties of a given polygon,
        /// i.e. the plane normal, area, and its distance
        /// from the origin. Cf. also GetSignedPolygonArea.
        /// </summary>
        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);
        }
Пример #6
0
        /// <summary>
        /// Determine the elevation boundary profile
        /// polygons of the exterior vertical planar
        /// face of the given wall solid.
        /// </summary>
        /// <param name="polygons">Return polygonal boundary
        /// loops of exterior vertical planar face, i.e.
        /// profile of wall elevation incl. holes</param>
        /// <param name="solid">Input solid</param>
        /// <param name="w">Vector pointing along
        /// wall centre line</param>
        /// <param name="w">Vector pointing towards
        /// exterior wall face</param>
        /// <returns>False if no exterior vertical
        /// planar face was found, else true</returns>
        static bool GetProfile(
            List <List <XYZ> > polygons,
            Solid solid,
            XYZ v,
            XYZ w)
        {
            double     d, dmax = 0;
            PlanarFace outermost = null;
            FaceArray  faces     = solid.Faces;

            foreach (Face f in faces)
            {
                PlanarFace pf = f as PlanarFace;
                if (null != pf &&
                    Util.IsVertical(pf) &&
                    Util.IsZero(v.DotProduct(pf.FaceNormal)))
                {
                    d = pf.Origin.DotProduct(w);
                    if ((null == outermost) ||
                        (dmax < d))
                    {
                        outermost = pf;
                        dmax      = d;
                    }
                }
            }

            if (null != outermost)
            {
                XYZ            voffset = _offset * w;
                XYZ            p, q = XYZ.Zero;
                bool           first;
                int            i, n;
                EdgeArrayArray loops = outermost.EdgeLoops;
                foreach (EdgeArray loop in loops)
                {
                    List <XYZ> vertices = new List <XYZ>();
                    first = true;
                    foreach (Edge e in loop)
                    {
                        IList <XYZ> points = e.Tessellate();
                        p = points[0];
                        if (!first)
                        {
                            Debug.Assert(p.IsAlmostEqualTo(q),
                                         "expected subsequent start point"
                                         + " to equal previous end point");
                        }
                        n = points.Count;
                        q = points[n - 1];
                        for (i = 0; i < n - 1; ++i)
                        {
                            XYZ a = points[i];
                            a += voffset;
                            vertices.Add(a);
                        }
                    }
                    q += voffset;
                    Debug.Assert(q.IsAlmostEqualTo(vertices[0]),
                                 "expected last end point to equal"
                                 + " first start point");
                    polygons.Add(vertices);
                }
            }
            return(null != outermost);
        }