Example #1
0
        /// <summary>
        /// Creates a Polygon from an array of points.
        /// </summary>
        /// <param name="points"></param>
        /// <param name="shared"></param>
        /// <returns></returns>
        public static Polygon createPolygon(Vector3[] points, System.Object shared = null)
        {
            if (points.Length < 2)
            {
                return null;
            }

            List<IVertex> vertices = new List<IVertex>();
            foreach (Vector3 pos in points)
            {
                vertices.Add(new Vertex(pos));
            }
            Polygon polygon = new Polygon(vertices, shared);

            return polygon;
        }
Example #2
0
        /// <summary>
        /// Extrudes a polygon.
        /// </summary>
        /// <param name="polygon">The polygon to extrude</param>
        /// <param name="distance">Extrusion distance</param>
        /// <param name="normal">Optional normal to extrude along, default is polygon normal</param>
        /// <returns></returns>
        public static List<Polygon> extrudePolygon(Polygon polygon, float distance, Vector3? normal = null)
        {
            normal = normal != null ? normal : polygon.plane.normal;

            Vector3 du = normal.GetValueOrDefault();
            IVertex[] vertices = polygon.vertices;
            List<IVertex> top = new List<IVertex>();
            List<IVertex> bot = new List<IVertex>();
            List<Polygon> polygons = new List<Polygon>();
            Vector3 invNormal = normal.GetValueOrDefault();

            du *= distance;
            invNormal *= -1f;

            for (int i = 0; i < vertices.Length; i++)
            {
                int j = (i + 1) % vertices.Length;
                Vector3 p1 = vertices[i].pos;
                Vector3 p2 = vertices[j].pos;
                Vector3 p3 = p2 + du;
                Vector3 p4 = p1 + du;
                Plane plane = Plane.fromPoints(p1, p2, p3);
                Vertex v1 = new Vertex(p1, plane.normal);
                Vertex v2 = new Vertex(p2, plane.normal);
                Vertex v3 = new Vertex(p3, plane.normal);
                Vertex v4 = new Vertex(p4, plane.normal);
                Polygon poly = new Polygon(new List<IVertex>(new IVertex[] { v1, v2, v3, v4 }), polygon.shared);
                polygons.Add(poly);
                top.Add(new Vertex(p4, normal.GetValueOrDefault()));
                bot.Insert(0, new Vertex(p1, invNormal));
            }

            polygons.Add(new Polygon(top, polygon.shared));
            polygons.Add(new Polygon(bot, polygon.shared));

            return polygons;
        }
Example #3
0
File: CSG.cs Project: icegbq/csg.cs
 /// <summary>
 /// Create CSG from array, does not clone the polygons
 /// </summary>
 /// <param name="polygon"></param>
 /// <returns></returns>
 private static CSG fromPolygons(Polygon[] polygons)
 {
     //TODO: Optimize polygons to share vertices
     CSG csg = new CSG();
     csg.polygons.AddRange(polygons);
     return csg;
 }
Example #4
0
File: CSG.cs Project: icegbq/csg.cs
        /// <summary>
        /// Cube function, Untested but compiles
        /// </summary>
        /// <param name="center">world space center of the cube</param>
        /// <param name="radius">size of the cube created at center</param>
        /// <returns></returns>
        public static CSG cube(Vector3? center, Vector3? radius)
        {
            Vector3 c = center.GetValueOrDefault(Vector3.zero);
            Vector3 r = radius.GetValueOrDefault(Vector3.one);

            //TODO: Test if this works
            Polygon[] polygons = new Polygon[6];
            int[][][] data = new int[][][] {
                new int[][]{new int[]{0, 4, 6, 2}, new int[]{-1, 0, 0}},
                new int[][]{new int[]{1, 3, 7, 5}, new int[]{1, 0, 0}},
                new int[][]{new int[]{0, 1, 5, 4}, new int[]{0, -1, 0}},
                new int[][]{new int[]{2, 6, 7, 3}, new int[]{0, 1, 0}},
                new int[][]{new int[]{0, 2, 3, 1}, new int[]{0, 0, -1}},
                new int[][]{new int[]{4, 5, 7, 6}, new int[]{0, 0, 1}}
            };
            for (int x = 0; x < 6; x++)
            {
                int[][] v = data[x];
                Vector3 normal = new Vector3((float)v[1][0], (float)v[1][1], (float)v[1][2]);

                IVertex[] verts = new IVertex[4];
                for (int i = 0; i < 4; i++)
                {
                    verts[i] = new Vertex(
                        new Vector3(
                            c.x + (r.x * (2 * (((v[0][i] & 1) > 0) ? 1 : 0) - 1)),
                            c.y + (r.y * (2 * (((v[0][i] & 2) > 0) ? 1 : 0) - 1)),
                            c.z + (r.z * (2 * (((v[0][i] & 4) > 0) ? 1 : 0) - 1))),
                            normal
                        );
                }
                polygons[x] = new Polygon(verts);
            }
            return CSG.fromPolygons(polygons);
        }
Example #5
0
        /// <summary>
        /// Split `polygon` by this plane if needed, then put the polygon or polygon
        /// fragments in the appropriate lists. Coplanar polygons go into either
        /// `coplanarFront` or `coplanarBack` depending on their orientation with
        /// respect to this plane. Polygons in front or in back of this plane go into
        /// either `front` or `back`
        /// </summary>
        /// <param name="polygon"></param>
        /// <param name="coplanarFront"></param>
        /// <param name="coplanarBack"></param>
        /// <param name="front"></param>
        /// <param name="back"></param>
        public void splitPolygon(Polygon polygon,
                                 ref List <Polygon> coplanarFront,
                                 ref List <Polygon> coplanarBack,
                                 ref List <Polygon> front,
                                 ref List <Polygon> back)
        {
            //Debug.Log("splitPolygon: " + polygon.vertices[0].pos + ", " + polygon.vertices[1].pos + ", " + polygon.vertices[2].pos);

            IVertex[]  vertices    = polygon.vertices;
            int        polygonType = 0;
            List <int> types       = new List <int>();
            int        type;
            float      t;
            int        i;

            for (i = 0; i < vertices.Length; i++)
            {
                t = Vector3.Dot(this.normal, vertices[i].pos) - this.w;
                if (t < -Plane.EPSILON)
                {
                    type = BACK;
                }
                else if (t > Plane.EPSILON)
                {
                    type = FRONT;
                }
                else
                {
                    type = COPLANAR;
                }
                polygonType |= type;
                types.Add(type);
            }

            // Put the polygon in the correct list, splitting it when necessary.
            switch (polygonType)
            {
            case COPLANAR:
                if (Vector3.Dot(this.normal, polygon.plane.normal) > 0)
                {
                    coplanarFront.Add(polygon);
                }
                else
                {
                    coplanarBack.Add(polygon);
                }
                break;

            case FRONT:
                front.Add(polygon);
                break;

            case BACK:
                back.Add(polygon);
                break;

            default:
            case SPANNING:
                if (polygonType != SPANNING)
                {
                    Debug.Log("Defaulting to spanning");
                }

                List <IVertex> f = new List <IVertex>();
                List <IVertex> b = new List <IVertex>();
                for (i = 0; i < vertices.Length; i++)
                {
                    int     j  = (i + 1) % vertices.Length;
                    int     ti = types[i];
                    int     tj = types[j];
                    IVertex vi = vertices[i];
                    IVertex vj = vertices[j];
                    if (ti != BACK)
                    {
                        f.Add(vi);
                    }
                    if (ti != FRONT)
                    {
                        b.Add(ti != BACK ? vi.clone() : vi);
                    }
                    if ((ti | tj) == SPANNING)
                    {
                        t = (this.w - Vector3.Dot(this.normal, vi.pos)) /
                            Vector3.Dot(this.normal, vj.pos - vi.pos);
                        IVertex v = vi.interpolate(vj, t);
                        f.Add(v);
                        b.Add(v.clone());
                    }
                }
                if (f.Count >= 3)
                {
                    front.Add(new Polygon(f, polygon.shared));
                }
                if (b.Count >= 3)
                {
                    back.Add(new Polygon(b, polygon.shared));
                }
                break;
            }
        }
Example #6
0
        /// <summary>
        /// Split `polygon` by this plane if needed, then put the polygon or polygon
        /// fragments in the appropriate lists. Coplanar polygons go into either
        /// `coplanarFront` or `coplanarBack` depending on their orientation with
        /// respect to this plane. Polygons in front or in back of this plane go into
        /// either `front` or `back`
        /// </summary>
        /// <param name="polygon"></param>
        /// <param name="coplanarFront"></param>
        /// <param name="coplanarBack"></param>
        /// <param name="front"></param>
        /// <param name="back"></param>
        public void splitPolygon(Polygon polygon,
                                 ref List<Polygon> coplanarFront,
                                 ref List<Polygon> coplanarBack,
                                 ref List<Polygon> front,
                                 ref List<Polygon> back)
        {
            //Debug.Log("splitPolygon: " + polygon.vertices[0].pos + ", " + polygon.vertices[1].pos + ", " + polygon.vertices[2].pos);

            IVertex[] vertices = polygon.vertices;
            int polygonType = 0;
            List<int> types = new List<int>();
            int type;
            float t;
            int i;

            for (i = 0; i < vertices.Length; i++)
            {
                t = Vector3.Dot(this.normal, vertices[i].pos) - this.w;
                if (t < -Plane.EPSILON) { type = BACK; } else if (t > Plane.EPSILON) { type = FRONT; } else { type = COPLANAR; }
                polygonType |= type;
                types.Add(type);
            }

            // Put the polygon in the correct list, splitting it when necessary.
            switch (polygonType)
            {
                case COPLANAR:
                    if (Vector3.Dot(this.normal, polygon.plane.normal) > 0)
                    {
                        coplanarFront.Add(polygon);
                    }
                    else
                    {
                        coplanarBack.Add(polygon);
                    }
                    break;
                case FRONT:
                    front.Add(polygon);
                    break;
                case BACK:
                    back.Add(polygon);
                    break;
                default:
                case SPANNING:
                    if (polygonType != SPANNING)
                        Debug.Log("Defaulting to spanning");

                    List<IVertex> f = new List<IVertex>();
                    List<IVertex> b = new List<IVertex>();
                    for (i = 0; i < vertices.Length; i++)
                    {
                        int j = (i + 1) % vertices.Length;
                        int ti = types[i];
                        int tj = types[j];
                        IVertex vi = vertices[i];
                        IVertex vj = vertices[j];
                        if (ti != BACK) f.Add(vi);
                        if (ti != FRONT) b.Add(ti != BACK ? vi.clone() : vi);
                        if ((ti | tj) == SPANNING)
                        {
                            t = (this.w - Vector3.Dot(this.normal, vi.pos)) /
                                 Vector3.Dot(this.normal, vj.pos - vi.pos);
                            IVertex v = vi.interpolate(vj, t);
                            f.Add(v);
                            b.Add(v.clone());
                        }
                    }
                    if (f.Count >= 3) front.Add(new Polygon(f, polygon.shared));
                    if (b.Count >= 3) back.Add(new Polygon(b, polygon.shared));
                    break;
            }
        }
Example #7
0
        public Mesh toMesh()
        {
            List <Polygon> trisFromPolygons = new List <Polygon>();

            // triangulate polygons
            for (int i = this.polygons.Count - 1; i >= 0; i--)
            {
                if (this.polygons[i].vertices.Length > 3)
                {
                    //Debug.Log("!!! Poly to Tri (order): " + this.polygons[i].vertices.Length);
                    for (int vi = 1; vi < this.polygons[i].vertices.Length - 1; vi++)
                    {
                        IVertex[] tri = new IVertex[] {
                            this.polygons[i].vertices[0],
                            this.polygons[i].vertices[vi],
                            this.polygons[i].vertices[vi + 1]
                        };
                        trisFromPolygons.Add(new Polygon(tri));
                    }
                    // the original polygon is replaced by a set of triangles
                    this.polygons.RemoveAt(i);
                }
            }
            this.polygons.AddRange(trisFromPolygons);

            // TODO: Simplify mesh - the boolean CSG algorithm leaves lots of coplanar
            //       polygons that share an edge that could be simplified.

            // At this point, we have a soup of triangles without regard for shared vertices.
            // We index these to combine any vertices with identical positions & normals
            // (and maybe later UVs & vertex colors)

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

            int[] tris = new int[this.polygons.Count * 3];
            for (int pi = 0; pi < this.polygons.Count; pi++)
            {
                Polygon tri = this.polygons[pi];

                if (tri.vertices.Length > 3)
                {
                    Debug.LogError("Polygon should be a triangle, but isn't !!");
                }

                for (int vi = 0; vi < 3; vi++)
                {
                    Vertex vertex = tri.vertices[vi] as Vertex;
                    bool   equivalentVertexAlreadyInList = false;
                    for (int i = 0; i < vertices.Count; i++)
                    {
                        if (vertices[i].pos.ApproximatelyEqual(vertex.pos) &&
                            vertices[i].normal.ApproximatelyEqual(vertex.normal))
                        {
                            equivalentVertexAlreadyInList = true;
                            vertex.index = vertices[i].index;
                        }
                    }
                    if (!equivalentVertexAlreadyInList)
                    {
                        vertices.Add(vertex);
                        vertex.index = vertices.Count - 1;
                    }
                    tris[(pi * 3) + vi] = vertex.index;
                }
                //Debug.Log(string.Format("Added tri {0},{1},{2}: {3},{4},{5}", pi, pi+1, pi+2, tris[pi], tris[pi+1], tris[pi+2]));
            }

            Vector3[] verts   = new Vector3[this.polygons.Count * 3];
            Vector3[] normals = new Vector3[this.polygons.Count * 3];
            Mesh      m       = new Mesh();

            for (int i = 0; i < vertices.Count; i++)
            {
                verts[i]   = vertices[i].pos;
                normals[i] = vertices[i].normal;
            }
            m.vertices  = verts;
            m.normals   = normals;
            m.triangles = tris;
            //m.RecalculateBounds();
            //m.RecalculateNormals();
            //m.Optimize();

            //Debug.Log("toMesh verts, normals, tris: " + m.vertices.Length + ", " +m.normals.Length+", "+m.triangles.Length);

            return(m);
        }