Exemple #1
0
        /// <summary>
        /// Converts a CSG polygon to a poly2tri polygon (including holes)
        /// </summary>
        /// <param name="polygon">the polygon to convert</param>
        /// <returns>a CSG polygon to a poly2tri polygon (including holes)</returns>
        ///
        private static Poly2Tri.Polygon fromCSGPolygon(Polygon polygon)
        {
            // convert polygon
            List <Poly2Tri.PolygonPoint> points = new List <Poly2Tri.PolygonPoint>();

            foreach (Vertex v in polygon.vertices)
            {
                Poly2Tri.PolygonPoint vp = new Poly2Tri.PolygonPoint(v.pos.x(), v.pos.y(), v.pos.z());
                points.Add(vp);
            }

            Poly2Tri.Polygon result = new Poly2Tri.Polygon(points);

            // convert holes
            List <Polygon> holesOfPresult = polygon.getStorage().getValue <List <Polygon> >(Edge.KEY_POLYGON_HOLES);

            if (holesOfPresult != null)
            {
                List <Polygon> holesOfP = holesOfPresult;

                holesOfP.ForEach(hP => result.addHole(fromCSGPolygon(hP)));
            }

            return(result);
        }
Exemple #2
0
        /// <summary>
        /// Combines two polygons into one CSG object. Polygons p1 and p2 are treated as top and
        /// bottom of a tube segment with p1 and p2 as the profile. <b>Note:</b> both polygons must have the
        /// same number of vertices. This method does not guarantee intersection-free CSGs. It is in the
        /// responsibility of the caller to ensure that the orientation of p1 and p2 allow for
        /// intersection-free combination of both.
        /// </summary>
        /// <param name="p1">first polygon</param>
        /// <param name="p2">second polygon</param>
        /// <param name="bottom">defines whether to close the bottom of the tube</param>
        /// <param name="top">defines whether to close the top of the tube</param>
        /// <returns>List of polygons</returns>
        ///
        public static List <Polygon> combine(Polygon p1, Polygon p2, bool bottom, bool top)
        {
            List <Polygon> newPolygons = new List <Polygon>();

            if (p1.vertices.Count != p2.vertices.Count)
            {
                throw new Exception("Polygons must have the same number of vertices");
            }

            int numVertices = p1.vertices.Count;

            if (bottom)
            {
                newPolygons.Add(p1.flipped());
            }

            for (int i = 0; i < numVertices; i++)
            {
                int nexti = (i + 1) % numVertices;

                IVector3d bottomV1 = p1.vertices[i].pos;
                IVector3d topV1    = p2.vertices[i].pos;
                IVector3d bottomV2 = p1.vertices[nexti].pos;
                IVector3d topV2    = p2.vertices[nexti].pos;

                List <IVector3d> pPoints;

                pPoints = new List <IVector3d> {
                    bottomV2, topV2, topV1
                };
                newPolygons.Add(Polygon.fromPoints(pPoints, p1.getStorage()));
                pPoints = new List <IVector3d> {
                    bottomV2, topV1, bottomV1
                };
                newPolygons.Add(Polygon.fromPoints(pPoints, p1.getStorage()));
            }

            if (top)
            {
                newPolygons.Add(p2);
            }

            return(newPolygons);
        }
Exemple #3
0
        public static List <Polygon> concaveToConvex(Polygon concave)
        {
            List <Polygon> result = new List <Polygon>();

            IVector3d normal = concave.vertices[0].normal.clone();

            bool cw = !Extrude.isCCW(concave);

            Poly2Tri.Polygon p = fromCSGPolygon(concave);

            Poly2Tri.Poly2Tri.triangulate(p);

            List <Poly2Tri.DelaunayTriangle> triangles = p.getTriangles();

            List <Vertex> triPoints = new List <Vertex>();

            foreach (Poly2Tri.DelaunayTriangle t in triangles)
            {
                int counter = 0;
                foreach (Poly2Tri.TriangulationPoint tp in t.points)
                {
                    triPoints.Add(new Vertex(
                                      Vector3d.xyz(tp.getX(), tp.getY(), tp.getZ()),
                                      normal));

                    if (counter == 2)
                    {
                        if (!cw)
                        {
                            triPoints.Reverse();
                        }
                        Polygon poly =
                            new Polygon(
                                triPoints, concave.getStorage());
                        result.Add(poly);
                        counter   = 0;
                        triPoints = new List <Vertex>();
                    }
                    else
                    {
                        counter++;
                    }
                }
            }

            return(result);
        }
Exemple #4
0
        private static CSG extrude(IVector3d dir, Polygon polygon1)
        {
            List <Polygon> newPolygons = new List <Polygon>();

            if (dir.z() < 0)
            {
                throw new ArgumentException("z < 0 currently not supported for extrude: " + dir);
            }

            newPolygons.AddRange(PolygonUtil.concaveToConvex(polygon1));
            Polygon polygon2 = polygon1.translated(dir);

            int numvertices = polygon1.vertices.Count;

            for (int i = 0; i < numvertices; i++)
            {
                int nexti = (i + 1) % numvertices;

                IVector3d bottomV1 = polygon1.vertices[i].pos;
                IVector3d topV1    = polygon2.vertices[i].pos;
                IVector3d bottomV2 = polygon1.vertices[nexti].pos;
                IVector3d topV2    = polygon2.vertices[nexti].pos;

                List <IVector3d> pPoints = new List <IVector3d> {
                    bottomV2, topV2, topV1, bottomV1
                };

                newPolygons.Add(Polygon.fromPoints(pPoints, polygon1.getStorage()));
            }

            polygon2 = polygon2.flipped();
            List <Polygon> topPolygons = PolygonUtil.concaveToConvex(polygon2);

            newPolygons.AddRange(topPolygons);

            return(CSG.fromPolygons(newPolygons));
        }
Exemple #5
0
        private static List <Polygon> extrude(IVector3d dir, Polygon polygon1, bool top, bool bottom)
        {
            List <Polygon> newPolygons = new List <Polygon>();


            if (bottom)
            {
                newPolygons.AddRange(PolygonUtil.concaveToConvex(polygon1));
            }

            Polygon polygon2 = polygon1.translated(dir);

            Transform rot = Transform.unity();

            IVector3d a = polygon2.getPlane().getNormal().normalized();
            IVector3d b = dir.normalized();

            IVector3d c = a.crossed(b);

            double l = c.magnitude(); // sine of angle

            if (l > 1e-9)
            {
                IVector3d axis  = c.times(1.0 / l);
                double    angle = a.angle(b);

                double sx = 0;
                double sy = 0;
                double sz = 0;

                int n = polygon2.vertices.Count;

                foreach (Vertex v in polygon2.vertices)
                {
                    sx += v.pos.x();
                    sy += v.pos.y();
                    sz += v.pos.z();
                }

                IVector3d center = Vector3d.xyz(sx / n, sy / n, sz / n);

                rot = rot.rot(center, axis, angle * Math.PI / 180.0);

                foreach (Vertex v in polygon2.vertices)
                {
                    v.pos = rot.transform(v.pos);
                }
            }

            int numvertices = polygon1.vertices.Count;

            for (int i = 0; i < numvertices; i++)
            {
                int nexti = (i + 1) % numvertices;

                IVector3d bottomV1 = polygon1.vertices[i].pos;
                IVector3d topV1    = polygon2.vertices[i].pos;
                IVector3d bottomV2 = polygon1.vertices[nexti].pos;
                IVector3d topV2    = polygon2.vertices[nexti].pos;

                List <IVector3d> pPoints = new List <IVector3d> {
                    bottomV2, topV2, topV1, bottomV1
                };

                newPolygons.Add(Polygon.fromPoints(pPoints, polygon1.getStorage()));
            }

            polygon2 = polygon2.flipped();
            List <Polygon> topPolygons = PolygonUtil.concaveToConvex(polygon2);

            if (top)
            {
                newPolygons.AddRange(topPolygons);
            }

            return(newPolygons);
        }
Exemple #6
0
        /// <summary>
        /// Splits a <see cref="Polygon"/> by this plane if needed. After that it puts the
        /// polygons or the polygon fragments in the appropriate lists
        /// (<c>front</c>, <c>back</c>). Coplanar polygons go into either
        /// <c>coplanarFront</c>, <c>coplanarBack</c> depending on their
        /// orientation with respect to this plane. Polygons in front or back of this
        /// plane go into either <c>front</c> or <c>back</c>.
        /// </summary>
        /// <param name="polygon">polygon to split</param>
        /// <param name="coplanarFront">"coplanar front" polygons</param>
        /// <param name="coplanarBack">"coplanar back" polygons</param>
        /// <param name="front">front polygons</param>
        /// <param name="back">back polgons</param>
        ///
        public void splitPolygon(
            Polygon polygon,
            List <Polygon> coplanarFront,
            List <Polygon> coplanarBack,
            List <Polygon> front,
            List <Polygon> back)
        {
            const int COPLANAR = 0;
            const int FRONT    = 1;
            const int BACK     = 2;
            const int SPANNING = 3; // == some in the FRONT + some in the BACK

            // Classify each point as well as the entire polygon into one of the
            // above four classes.
            int        polygonType = 0;
            List <int> types       = new List <int>(polygon.vertices.Count);

            for (int i = 0; i < polygon.vertices.Count; i++)
            {
                double t    = this.normal.dot(polygon.vertices[i].pos) - this.dist;
                int    type = (t < -Plane.EPSILON) ? BACK : (t > Plane.EPSILON) ? FRONT : COPLANAR;
                polygonType |= type;
                types.Add(type);
            }

            //System.out.println("> switching");
            // Put the polygon in the correct list, splitting it when necessary.
            switch (polygonType)
            {
            case COPLANAR:
                //System.out.println(" -> coplanar");
                (this.normal.dot(polygon._csg_plane.normal) > 0 ? coplanarFront : coplanarBack).Add(polygon);
                break;

            case FRONT:
                //System.out.println(" -> front");
                front.Add(polygon);
                break;

            case BACK:
                //System.out.println(" -> back");
                back.Add(polygon);
                break;

            case SPANNING:
                //System.out.println(" -> spanning");
                List <Vertex> f = new List <Vertex>();
                List <Vertex> b = new List <Vertex>();
                for (int i = 0; i < polygon.vertices.Count; i++)
                {
                    int    j  = (i + 1) % polygon.vertices.Count;
                    int    ti = types[i];
                    int    tj = types[j];
                    Vertex vi = polygon.vertices[i];
                    Vertex vj = polygon.vertices[j];
                    if (ti != BACK)
                    {
                        f.Add(vi);
                    }
                    if (ti != FRONT)
                    {
                        b.Add(ti != BACK ? vi.clone() : vi);
                    }
                    if ((ti | tj) == SPANNING)
                    {
                        double t = (this.dist - this.normal.dot(vi.pos))
                                   / this.normal.dot(vj.pos.minus(vi.pos));
                        Vertex v = vi.interpolate(vj, t);
                        f.Add(v);
                        b.Add(v.clone());
                    }
                }
                if (f.Count >= 3)
                {
                    front.Add(new Polygon(f, polygon.getStorage()));
                }
                if (b.Count >= 3)
                {
                    back.Add(new Polygon(b, polygon.getStorage()));
                }
                break;
            }
        }