Example #1
0
    public static CSolid ReduceSolid(Solid A)
    {
        CSolid s = new CSolid();

        s.faces    = new List <CFace>();
        s.vertices = new List <CPoint>();

        foreach (Face a in A.faces)
        {
            if (a.isPlanar())
            {
                CFace        ca      = new CFace();
                List <Point> aPoints = a.GetPoints();
                ca.points = new int[aPoints.Count];
                ca.solid  = s;
                for (int i = 0; i < aPoints.Count; ++i)
                {
                    int index = s.vertices.FindIndex(x => x.position == aPoints[i].position);
                    if (index == -1)
                    {
                        s.vertices.Add(new CPoint(aPoints[i]));
                        ca.points[i] = s.vertices.Count - 1;
                    }
                    else
                    {
                        ca.points[i] = index;
                    }
                }
                s.faces.Add(ca);
            }
            else
            {
                List <Point> aPoints = a.GetPoints();

                for (int i = 0; i < aPoints.Count; ++i)
                {
                    int index = s.vertices.FindIndex(x => x.position == aPoints[i].position);
                    if (index == -1)
                    {
                        s.vertices.Add(new CPoint(aPoints[i]));
                    }
                }

                for (int i = 0; i < a.subTriangles.Count; i += 3)
                {
                    CFace ct = new CFace();
                    ct.solid  = s;
                    ct.points = new int[] {
                        s.vertices.FindIndex(x => x.position == a.subTriangles[i]),
                        s.vertices.FindIndex(x => x.position == a.subTriangles[i + 1]),
                        s.vertices.FindIndex(x => x.position == a.subTriangles[i + 2])
                    };
                    s.faces.Add(ct);
                }
            }
        }

        return(s);
    }
Example #2
0
    public static List <List <Vector3> > CrossSection(CSolid B, CFace a)
    {
        Vector3[] bTrans = new Vector3[B.vertices.Count];
        Vector3[] aTrans = new Vector3[a.points.Length];

        for (int i = 0; i < a.points.Length; ++i)
        {
            aTrans[i] = a.solid.vertices[a.points[i]].position;
        }
        for (int i = 0; i < B.vertices.Count; ++i)
        {
            bTrans[i] = B.vertices[i].position;
        }

        aTrans = PolyTransform(aTrans, a);
        bTrans = PolyTransform(bTrans, a);

        List <List <Vector3> > edges = new List <List <Vector3> >();

        float epsilonSquared = 0.00001f;

        foreach (CFace b in B.faces)
        {
            List <Vector3> intersections = new List <Vector3>();
            for (int i = 0; i < b.points.Length; ++i)
            {
                int j  = (i + 1) % b.points.Length;
                int pi = b.points[i];
                int pj = b.points[j];
                if (Mathf.Sign(bTrans[pi].y) != Mathf.Sign(bTrans[pj].y))
                {
                    float t = -bTrans[pi].y / (bTrans[pj].y - bTrans[pi].y);
                    intersections.Add(bTrans[pi] + (bTrans[pj] - bTrans[pi]) * t);
                }
            }
            if (intersections.Count > 1)
            {
                for (int i = intersections.Count - 1; i >= 0; --i)
                {
                    for (int j = 0; j < i; ++j)
                    {
                        if ((intersections[j] - intersections[i]).sqrMagnitude <= epsilonSquared)
                        {
                            intersections.RemoveAt(i);
                            i = Mathf.Min(i, intersections.Count - 1);
                        }
                    }
                }
            }

            if (intersections.Count > 1)
            {
                Vector3 edgeDir = intersections[intersections.Count - 1] - intersections[0];
                intersections.Sort((x, y) => (int)Mathf.Sign(Vector3.Dot(y - x, edgeDir)));
                for (int i = 0; i < intersections.Count / 2; ++i)
                {
                    List <Vector3> edge = new List <Vector3>();
                    edge.Add(intersections[i * 2]); edge.Add(intersections[i * 2 + 1]);
                    edges.Add(edge);
                }
            }
            else if (intersections.Count == 1)
            {
                List <Vector3> edge = new List <Vector3>();
                edge.Add(intersections[0]);
                edges.Add(edge);
            }
        }

        for (int i = edges.Count - 1; i >= 0; --i)
        {
            for (int j = 0; j < edges.Count; ++j)
            {
                if (i == j)
                {
                    continue;
                }
                if ((edges[j][edges[j].Count - 1] - edges[i][0]).sqrMagnitude <= epsilonSquared)
                {
                    for (int k = 1; k < edges[i].Count; ++k)
                    {
                        edges[j].Add(edges[i][k]);
                    }
                    edges[i].Clear();
                    edges.RemoveAt(i);
                    break;
                }
                else if ((edges[j][edges[j].Count - 1] - edges[i][edges[i].Count - 1]).sqrMagnitude <= epsilonSquared)
                {
                    for (int k = edges[i].Count - 2; k >= 0; --k)
                    {
                        edges[j].Add(edges[i][k]);
                    }
                    edges[i].Clear();
                    edges.RemoveAt(i);
                    break;
                }
                else if ((edges[j][0] - edges[i][edges[i].Count - 1]).sqrMagnitude <= epsilonSquared)
                {
                    for (int k = edges[i].Count - 2; k >= 0; --k)
                    {
                        edges[j].Insert(0, edges[i][k]);
                    }
                    edges[i].Clear();
                    edges.RemoveAt(i);
                    break;
                }
                else if ((edges[j][0] - edges[i][0]).sqrMagnitude <= epsilonSquared)
                {
                    for (int k = 1; k < edges[i].Count - 1; ++k)
                    {
                        edges[j].Insert(0, edges[i][k]);
                    }
                    edges[i].Clear();
                    edges.RemoveAt(i);
                    break;
                }
            }
        }

        for (int i = edges.Count - 1; i >= 0; --i)
        {
            if (edges[i].Count < 3)
            {
                edges.RemoveAt(i);
            }
            else if ((edges[i][edges[i].Count - 1] - edges[i][0]).sqrMagnitude <= epsilonSquared)
            {
                edges[i].RemoveAt(edges[i].Count - 1);
            }
        }

        return(edges);
    }
Example #3
0
    public static Solid Clip(Solid A, Solid B, ClipMode mode)
    {
        List <CFace> Ai, Ax, Ao, Bi, Bx, Bo;
        CSolid       Ac = ReduceSolid(A);
        CSolid       Bc = ReduceSolid(B);

        //Divvy(Ac, Bc, out Ai, out Ax, out Ao);
        //Divvy(Bc, Ac, out Bi, out Bx, out Bo);
        Ai = new List <CFace>();
        Ao = new List <CFace>();
        Bi = new List <CFace>();
        Bo = new List <CFace>();


        foreach (CFace a in Ac.faces)
        {
            Vector3[] p = PolyTransform(a.GetVerts(), a);
            List <List <Vector3> > cross = CrossSection(Bc, a);
            foreach (List <Vector3> ql in cross)
            {
                Vector3[]        q = ql.ToArray();
                List <Vector3[]> pi, po;
                Clip2D(p, q, out pi, out po);
                foreach (Vector3[] poly in pi)
                {
                    Ai.Add(Ac.MapFace(DePolyTransform(poly, a)));
                }
                foreach (Vector3[] poly in po)
                {
                    Ao.Add(Ac.MapFace(DePolyTransform(poly, a)));
                }
            }
            if (cross.Count == 0)
            {
                if (B.ContainsPoint(Ac.vertices[a.points[0]].position))
                {
                    Ai.Add(a);
                }
                else
                {
                    Ao.Add(a);
                }
            }
        }

        foreach (CFace b in Bc.faces)
        {
            Vector3[] p = PolyTransform(b.GetVerts(), b);
            List <List <Vector3> > cross = CrossSection(Ac, b);
            foreach (List <Vector3> ql in cross)
            {
                Vector3[]        q = ql.ToArray();
                List <Vector3[]> pi, po;
                Clip2D(p, q, out pi, out po);
                foreach (Vector3[] poly in pi)
                {
                    Bi.Add(Bc.MapFace(DePolyTransform(poly, b)));
                }
                foreach (Vector3[] poly in po)
                {
                    Bo.Add(Bc.MapFace(DePolyTransform(poly, b)));
                }
            }
            if (cross.Count == 0)
            {
                if (A.ContainsPoint(Bc.vertices[b.points[0]].position))
                {
                    Bi.Add(b);
                }
                else
                {
                    Bo.Add(b);
                }
            }
        }


        //Set up merged CSolid
        CSolid Cc;

        Cc.vertices = new List <CPoint>();
        Cc.faces    = new List <CFace>();
        int ACount = Ac.vertices.Count;

        Cc.vertices.AddRange(Ac.vertices);
        Cc.vertices.AddRange(Bc.vertices);

        //find points that are probably the same
        int[] map     = new int[Cc.vertices.Count];
        float epsilon = 0.005f;

        for (int i = 0; i < Cc.vertices.Count; ++i)
        {
            map[i] = -1;
        }
        for (int i = Cc.vertices.Count - 1; i >= 0; --i)
        {
            for (int j = 0; j <= i; ++j)
            {
                if (Vector3.Distance(Cc.vertices[i].position, Cc.vertices[j].position) < epsilon)
                {
                    if (Cc.vertices[i].id != -1)
                    {
                        Cc.vertices[j].SetId(Cc.vertices[i].id);
                    }
                    map[i] = j;
                    break;
                }
            }
        }

        //Add verts to merged CSolid
        if (mode == ClipMode.Subtract)
        {
            foreach (CFace f in Ao)
            {
                for (int i = 0; i < f.points.Length; ++i)
                {
                    f.points[i] = map[f.points[i]];
                }
            }
            Cc.faces.AddRange(Ao);
            foreach (CFace f in Bi)
            {
                for (int i = 0; i < f.points.Length; ++i)
                {
                    f.points[i] = map[f.points[i] + ACount];
                }
            }
            Cc.faces.AddRange(Bi);
        }
        else if (mode == ClipMode.Add)
        {
            //Merge A and B into C, using faces Ao, Bi, adding to point indices of Bi respectively (TODO)
        }
        else if (mode == ClipMode.Intersect)
        {
            //Merge A and B into C, using faces Ai, Bi, adding to point indices of Bi respectively (TODO)
        }

        //Find used vertices
        bool[] used = new bool[Cc.vertices.Count];
        foreach (CFace f in Cc.faces)
        {
            foreach (int i in f.points)
            {
                used[i] = true;
            }
        }

        //Map duplicate points, create new points, delete unused points
        Point[] points = new Point[Cc.vertices.Count];                                    //Sparse Array
        Dictionary <int, Edge>[] edgeTo = new Dictionary <int, Edge> [Cc.vertices.Count]; //Sparse grid
        for (int i = 0; i < Cc.vertices.Count; ++i)
        {
            if (used[i])
            {
                if (map[i] == i)
                {
                    points[i] = Cc.vertices[i].id == -1 ? new Point(Cc.vertices[i].position) : DCGBase.all[Cc.vertices[i].id] as Point;
                    Cc.vertices[i].SetId(points[i].elementID);
                    edgeTo[i] = new Dictionary <int, Edge>();
                }
            }
            else
            {
                if (Cc.vertices[i].id != -1)
                {
                    DCGBase.all[Cc.vertices[i].id].Remove();
                }
            }
        }

        //Nuke A and B
        foreach (Point p in A.getPoints())
        {
            for (int i = p.edges.Count - 1; i >= 0; --i)
            {
                p.edges[i].Remove();
            }
        }

        foreach (Point p in B.getPoints())
        {
            for (int i = p.edges.Count - 1; i >= 0; --i)
            {
                p.edges[i].Remove();
            }
        }

        //Create new edges/faces in DCG
        Face[] faces = new Face[Cc.faces.Count];
        for (int i = 0; i < Cc.faces.Count; ++i)
        {
            CFace  f     = Cc.faces[i];
            Edge[] edges = new Edge[f.points.Length];

            Debug.Log(f.points.Length);
            for (int j = 0; j < f.points.Length; ++j)
            {
                int  k   = (j + 1) % f.points.Length;
                int  pk  = f.points[k];
                int  pj  = f.points[j];
                bool kcj = edgeTo[pk].ContainsKey(pj);
                bool jck = edgeTo[pj].ContainsKey(pk);
                if (jck)
                {
                    edges[j] = edgeTo[pj][pk];
                    if (!kcj)
                    {
                        edgeTo[pk].Add(pj, edges[j]);
                    }
                }
                else if (kcj)
                {
                    edges[j] = edgeTo[pk][pj];
                    if (!jck)
                    {
                        edgeTo[pj].Add(pk, edges[j]);
                    }
                }
                else
                {
                    edges[j] = new Edge(points[pj], points[pk]);
                    //if (!jck)
                    edgeTo[pj].Add(pk, edges[j]);
                    //if (!kcj)
                    edgeTo[pk].Add(pj, edges[j]);
                }
                //Debug.DrawLine(edges[j].points[0].position, edges[j].points[1].position, new Color(Random.value, Random.value, Random.value), 1000, false);
            }
            //Debug.Log(edges.Length);
            faces[i] = new Face(new List <Edge>(edges));
        }

        //Create new solid from C
        return(new Solid(new List <Face>(faces)));
        //return new Solid();

        //TODO eventually, if we have time:
        //Relate generated Faces and Edges to existing Faces and Edges, in order to reduce new objects being created or to copy materials/etc.
    }