public static Polyline[] IntersectTwoPlates(Polyline plateA0, Polyline plateA1, Polyline plateB0, Polyline plateB1)
        {
            double extend = 0;

            var pA0B0 = PolylinePlane(plateA0, plateB0);
            var pA0B1 = PolylinePlane(plateA0, plateB1);
            var pA1B0 = PolylinePlane(plateA1, plateB0);
            var pA1B1 = PolylinePlane(plateA1, plateB1);

            if (pA0B0[0] != Point3d.Unset && pA0B0[1] != Point3d.Unset && pA0B1[0] != Point3d.Unset && pA0B1[1] != Point3d.Unset &&
                pA1B0[0] != Point3d.Unset && pA1B0[1] != Point3d.Unset && pA1B1[0] != Point3d.Unset && pA1B1[1] != Point3d.Unset
                )
            {
                Point3d pA0B0Mid = PointUtil.AveragePoint(pA0B0);
                Point3d pA0B1Mid = PointUtil.AveragePoint(pA0B1);
                Point3d pA1B0Mid = PointUtil.AveragePoint(pA1B0);
                Point3d pA1B1Mid = PointUtil.AveragePoint(pA1B1);

                Vector3d v0 = (pA0B0[0] - pA0B0[1]).UnitVector() * extend;
                Vector3d v1 = (pA0B1[0] - pA0B1[1]).UnitVector() * extend;
                Vector3d v2 = (pA1B0[0] - pA1B0[1]).UnitVector() * extend;
                Vector3d v3 = (pA1B1[0] - pA1B1[1]).UnitVector() * extend;

                Polyline u0 = new Polyline(new Point3d[] { pA0B0[0], pA0B0Mid - v0, pA0B1Mid - v1, pA0B1[0] });
                Polyline u1 = new Polyline(new Point3d[] { pA1B0[0], pA1B0Mid - v2, pA1B1Mid - v3, pA1B1[0] });

                Polyline u2 = new Polyline(new Point3d[] { pA0B0[1], pA0B0Mid + v0, pA1B0Mid + v2, pA1B0[1] });
                Polyline u3 = new Polyline(new Point3d[] { pA0B1[1], pA0B1Mid + v1, pA1B1Mid + v3, pA1B1[1] });

                return(new Polyline[] { u0, u1, u2, u3 });
            }


            return(new Polyline[0]);
        }
        public static Polyline[] InterpolatePolylines(Polyline from, Polyline to, int Steps, bool includeEnds = true)
        {
            if (from.Count == to.Count)
            {
                Polyline[] interpolatedPolylines = new Polyline[Steps + (Convert.ToInt32(includeEnds) * 2)];

                for (int i = 0; i < Steps + (Convert.ToInt32(includeEnds) * 2); i++)
                {
                    interpolatedPolylines[i] = new Polyline();
                }


                System.Collections.Generic.IEnumerator <Point3d> enum0 = from.GetEnumerator();
                System.Collections.Generic.IEnumerator <Point3d> enum1 = to.GetEnumerator();



                while (enum0.MoveNext())
                {
                    Point3d[] pt = PointUtil.InterpolatePoints(enum0.Current, enum1.Current, Steps, includeEnds);

                    for (int i = 0; i < Steps + (Convert.ToInt32(includeEnds) * 2); i++)
                    {
                        interpolatedPolylines[i].Add(pt[i]);
                    }

                    enum1.MoveNext();
                }

                return(interpolatedPolylines);
            }

            return(null);
        }
        public static Polyline DovetailPolylineShifted(Point3d[] pts, int d)
        {
            Point3d[] interA  = PointUtil.InterpolatePoints(pts[0], pts[1], d);
            Point3d[] interA_ = PointUtil.InterpolatePoints(pts[2], pts[3], d);



            Point3d[] interB;
            Point3d[] interB_;

            if (d % 2 == 1)
            {
                interB  = PointUtil.InterpolatePoints(pts[5], pts[4], d);
                interB_ = PointUtil.InterpolatePoints(pts[7], pts[6], d);
            }
            else
            {
                interB_ = PointUtil.InterpolatePoints(pts[5], pts[4], d);
                interB  = PointUtil.InterpolatePoints(pts[7], pts[6], d);
            }



            Polyline poly = new Polyline();
            Polyline temp = new Polyline();

            for (int j = 0; j < interA.Length - 1; j++)
            {
                if (j % 2 == 0)
                {
                    poly.Add(interA[j]);
                    poly.Add(interA[j + 1]);
                    temp.Add(interB[j]);
                    temp.Add(interB[j + 1]);
                }
                else
                {
                    poly.Add(interA_[j]);
                    poly.Add(interA_[j + 1]);
                    temp.Add(interB_[j]);
                    temp.Add(interB_[j + 1]);
                }
            }

            poly.AddRange(temp);
            poly.Close();
            return(poly);
        }
        public static Polyline DovetailPolyline(Line lineA, Line lineB, Line lineA_, Line lineB_, int d)
        {
            Point3d[] interA  = PointUtil.InterpolatePoints(lineA.From, lineB.From, d);
            Point3d[] interA_ = PointUtil.InterpolatePoints(lineA_.From, lineB_.From, d);



            Point3d[] interB;
            Point3d[] interB_;

            if (d % 2 == 1)
            {
                interB  = PointUtil.InterpolatePoints(lineB.To, lineA.To, d);
                interB_ = PointUtil.InterpolatePoints(lineB_.To, lineA_.To, d);
            }
            else
            {
                interB_ = PointUtil.InterpolatePoints(lineB.To, lineA.To, d);
                interB  = PointUtil.InterpolatePoints(lineB_.To, lineA_.To, d);
            }



            Polyline poly = new Polyline();
            Polyline temp = new Polyline();

            for (int j = 0; j < interA.Length - 1; j++)
            {
                if (j % 2 == 0)
                {
                    poly.Add(interA[j]);
                    poly.Add(interA[j + 1]);
                    temp.Add(interB[j]);
                    temp.Add(interB[j + 1]);
                }
                else
                {
                    poly.Add(interA_[j]);
                    poly.Add(interA_[j + 1]);
                    temp.Add(interB_[j]);
                    temp.Add(interB_[j + 1]);
                }
            }

            poly.AddRange(temp);
            poly.Close();
            return(poly);
        }
        /// <summary>
        /// Move two planes by z axis and output one that is closer to target point
        /// </summary>
        /// <param name="polyline"></param>
        /// <param name="point"></param>
        /// <param name="dist"></param>
        /// <returns></returns>
        public static Plane MovePolylinePlaneToPoint(this Polyline polyline, Point3d point, double dist)
        {
            Plane planeA = polyline.plane();

            planeA.Translate(planeA.ZAxis * dist);

            Plane planeB = polyline.plane();

            planeB.Translate(planeB.ZAxis * -dist);

            double dA = PointUtil.FastDistance(point, planeA.Origin);
            double dB = PointUtil.FastDistance(point, planeB.Origin);

            if (dA > dB)
            {
                return(planeB);
            }

            return(planeA);
        }
        public static List <Polyline> InterpolateTwoLines(Line l0, Line l1, int n = 1)
        {
            List <Polyline> squares = new List <Polyline>();

            if (n > 0)
            {
                Point3d[] interpolatePt0 = PointUtil.InterpolatePoints(l0.From, l0.To, n); //bottom interpolation
                Point3d[] interpolatePt1 = PointUtil.InterpolatePoints(l1.From, l1.To, n); //top inerpolation

                for (int i = 0; i < n + 1; i++)
                {
                    Polyline polyline = new Polyline(new[] {
                        interpolatePt0[i],
                        interpolatePt0[i + 1],
                        interpolatePt1[i + 1],
                        interpolatePt1[i],
                        interpolatePt0[i]
                    });
                    squares.Add(polyline);
                }

                return(squares);
            }
            else
            {
                squares.Add(new Polyline(new[] {
                    l0.From,
                    l0.To,
                    l1.To,
                    l1.From,
                    l0.From
                }));
            }

            return(squares);
        }