Exemple #1
0
        public List <MeshPart> PolySeparate()
        {
            List <Tuple <HashSet <int>, HashSet <Vector3>, List <int> > > list = new List <Tuple <HashSet <int>, HashSet <Vector3>, List <int> > >();

            AssertMatchingCounts();

            // create index groups
            for (int i = 0; i < indices.Count; i += 3)
            {
                int     i0 = indices[i], i1 = indices[i + 1], i2 = indices[i + 2];
                Vector3 v0 = vertices[i0], v1 = vertices[i1], v2 = vertices[i2];
                AddIndices(list, vertices, v0, v1, v2, i0, i1, i2, false, false, false);
            }

            return(list.ConvertAll(set => {
                MeshPart part = new MeshPart(side);

                foreach (int ind in set.Item3)
                {
                    if (part.indexMap.ContainsKey(ind))
                    {
                        part.indices.Add(part.indexMap[ind]);
                    }
                    else
                    {
                        part.indexMap.Add(ind, part.vertices.Count);
                        part.indices.Add(part.vertices.Count);
                        part.vertices.Add(vertices[ind]);
                        if (uvs.Count > 0)
                        {
                            part.uvs.Add(uvs[ind]);
                        }
                        if (normals.Count > 0)
                        {
                            part.normals.Add(normals[ind]);
                        }
                    }
                }

                return part;
            }));
        }
Exemple #2
0
        public static CutResult Run(
            GameObject target,
            CuttingTemplate template
            )
        {
            Mesh          mesh = target.GetComponent <MeshFilter>().mesh;
            MeshPart      pos = new MeshPart(true), neg = new MeshPart(false);
            RingGenerator intersection_ring = new RingGenerator();

            Vector3[] vertices              = mesh.vertices;
            Vector3[] normals               = mesh.normals;
            int[]     triangles             = mesh.triangles;

            bool addNormals = normals.Length > 0;

            // Debug.Log(vertices.Length + " verts, " + triangles.Length / 3 + " tris, " + template.points.Count + "tpl. points");

            // divide mesh in half by vertices
            int i = 0;

            foreach (Vector3 vertex in vertices)
            {
                if (template.IsAbove(vertex))
                {
                    pos.indexMap.Add(i, pos.vertices.Count);
                    pos.vertices.Add(vertex);
                    if (addNormals)
                    {
                        pos.normals.Add(normals[i]);
                    }
                }
                else
                {
                    neg.indexMap.Add(i, neg.vertices.Count);
                    neg.vertices.Add(vertex);
                    if (addNormals)
                    {
                        neg.normals.Add(normals[i]);
                    }
                }
                i++;
            }

            // RingGen's are associated to first template point
            //   these define the rings used for generating strip-wise inner geometry
            // SortedDictionary are for connecting edges of strip-wise inner geometry
            //   Sorted by signed distance to template plane, so they get connected in the right order
            Dictionary <Vector3, Tuple <SortedDictionary <float, Vector3>, RingGen> > point_data = new Dictionary <Vector3, Tuple <SortedDictionary <float, Vector3>, RingGen> >();

            foreach (Vector3 point in template.points)
            {
                point_data.Add(point, new Tuple <SortedDictionary <float, Vector3>, RingGen>(new SortedDictionary <float, Vector3>(), new RingGen()));
            }

            IvSaver ivSaver = new IvSaver();

            // put triangles in correct mesh
            for (i = 0; i < triangles.Length; i += 3)
            {
                // find orignal indices
                int i_a = triangles[i],
                    i_b = triangles[i + 1],
                    i_c = triangles[i + 2];

                // find original verticies
                Vector3 a = vertices[i_a],
                        b = vertices[i_b],
                        c = vertices[i_c];

                // seperation check
                if (!ProcessTriangle(template, a, b, c, point_data, pos, neg, intersection_ring, ivSaver, addNormals))
                {
                    if (template.IsAbove(a))
                    {
                        // triangle above plane
                        pos.indices.Add(pos.indexMap[i_a]);
                        pos.indices.Add(pos.indexMap[i_b]);
                        pos.indices.Add(pos.indexMap[i_c]);
                    }
                    else
                    {
                        // triangle below plane
                        neg.indices.Add(neg.indexMap[i_a]);
                        neg.indices.Add(neg.indexMap[i_b]);
                        neg.indices.Add(neg.indexMap[i_c]);
                    }
                }
            }

            // Generate strip (inner) geometry
            SortedDictionary <float, Vector3> next_dist_map = point_data[template.points[template.isClosed ? 0 : template.points.Count - 1]].Item1;
            Vector3 next_point = template.isClosed ? template.points.First() : template.points.Last();

            for (i = template.points.Count - (template.isClosed ? 1 : 2); i >= 0; i--)
            {
                SortedDictionary <float, Vector3> dist_map = point_data[template.points[i]].Item1;
                Vector3 point = template.points[i];
                //Debugging.LogLine(template.points[i-1],template.normal);
                //Debugging.LogLine(template.points[i],template.normal);
                //Debugging.LogList(point_data[template.points[i-1]].Item1.Keys);
                //Debugging.LogList(point_data[template.points[i]].Item1.Keys);
                RingGen rg = point_data[template.points[i]].Item2;
                // Debug.Log("points: "+point+" -> "+next_point);
                //rg.MyDebugLog();
                rg.TemplateJoin(template, dist_map);
                rg.TemplateJoin(template, next_dist_map);
                //rg.MyDebugLog();
                foreach (Ring ring in rg.GetRings(false, false))
                {
                    //Debugging.DebugRing(ring.verts);
                    Vector3 normal = Vector3.Cross(template.normal, next_point - point);
                    GenerateRingMesh(ring.verts, pos, normal, true, null, addNormals);
                    //TmpGen(ring.verts,pos,normal);
                    GenerateRingMesh(ring.verts, neg, normal, false, null, addNormals);
                    //TmpGen(ring.verts,neg,normal,true);
                }
                // Debug.Log("---------------------------");
                next_dist_map = dist_map;
                next_point    = point;
            }

            // Debug.Log("template: "+template);

            return(new CutResult(target, Vector3.zero, intersection_ring.GetRings(false, false), pos, neg));
        }
Exemple #3
0
        public List <MeshPart> PartialPolySeparate(
            CuttingPlane plane,
            HashSet <Vector3> allow_cut
            )
        {
            //Debug.Log("allow_cut");
            //foreach (Vector3 v in allow_cut) Debug.Log(VecStr(v));
            //Debug.Log("missing");

            List <Tuple <HashSet <int>, HashSet <Vector3>, List <int> > > list = new List <Tuple <HashSet <int>, HashSet <Vector3>, List <int> > >();

            AssertMatchingCounts();

            // create index groups
            for (int i = 0; i < indices.Count; i += 3)
            {
                int     i0 = indices[i], i1 = indices[i + 1], i2 = indices[i + 2];
                Vector3 v0 = vertices[i0], v1 = vertices[i1], v2 = vertices[i2];
                bool    ci0 = allow_cut.Contains(v0),
                        ci1 = allow_cut.Contains(v1),
                        ci2 = allow_cut.Contains(v2);
                AddIndices(list, vertices, v0, v1, v2, i0, i1, i2, ci0, ci1, ci2);
            }

            return(list.ConvertAll(set => {
                MeshPart part = new MeshPart(false);

                int doSwap = 0, doStay = 0; // temporary solution (?)

                foreach (int ind in set.Item3)
                {
                    Vector3 point = vertices[ind];
                    if (!allow_cut.Contains(point))
                    {
                        if (plane.IsAbove(point))
                        {
                            doSwap++;
                        }
                        else
                        {
                            doStay++;
                        }
                    }
                    ;
                    if (part.indexMap.ContainsKey(ind))
                    {
                        part.indices.Add(part.indexMap[ind]);
                    }
                    else
                    {
                        part.indexMap.Add(ind, part.vertices.Count);
                        part.indices.Add(part.vertices.Count);
                        part.vertices.Add(point);
                        if (uvs.Count > 0)
                        {
                            part.uvs.Add(uvs[ind]);
                        }
                    }
                }

                if (doSwap > doStay)
                {
                    part.SwapSide();
                }

                part.AssertMatchingCounts();

                return part;
            }));
        }
Exemple #4
0
 public CutObj(MeshPart part, CutResult res, bool isPolySeperated) : base(part, res, isPolySeperated)
 {
 }
Exemple #5
0
        private static bool ProcessTriangle(
            CuttingTemplate template,
            Vector3 a, Vector3 b, Vector3 c,
            Dictionary <Vector3, Tuple <SortedDictionary <float, Vector3>, RingGen> > point_data,
            MeshPart pos, MeshPart neg,
            RingGenerator intersection_ring,
            IvSaver ivSaver,
            bool addNormals
            )
        {
            List <Vector3> points    = template.points;
            Vector3        normal    = template.normal;
            RingGenerator  tri_rings = new RingGenerator();
            Vector3        tri_nor   = -Vector3.Cross(c - a, c - b).normalized;

            if (tri_nor == Vector3.zero)
            {
                // Debug.LogWarning("zero area tri");
                return(true);
            }
            bool    partToUse = Vector3.Dot(tri_nor, normal) > 0;
            bool    ring_dir  = partToUse;
            MUPlane tri_plane = new MUPlane(tri_nor, a);
            Vector3 ab_nor    = Vector3.Cross(tri_nor, (b - a).normalized), // vector perpendicular to edge and pointing away from triangle
                    bc_nor    = Vector3.Cross(tri_nor, (c - b).normalized),
                    ca_nor    = Vector3.Cross(tri_nor, (a - c).normalized);

        #if EPSILON_TEST
            if (Math.Abs(Vector3.Dot(tri_nor, normal)) < 0.01f)
            {
                Debug.LogWarning("epsilon ignore");
                return(false);
            }
        #endif
            // Debug.Log("tri verts: "+a+" "+b+" "+c);
            // Debug.Log((b-a).magnitude+" "+(c-b).magnitude+" "+(a-c).magnitude);
            // Debug.Log("edge norms: "+ab_nor+" "+bc_nor+" "+ca_nor);
            Dictionary <float, Vector3> map_ab = new Dictionary <float, Vector3>(), // distance (from first vertex in edge) -> vertex in edge
                                        map_bc = new Dictionary <float, Vector3>(), // used for sorting... TODO: change to SortedDictionary
                                        map_ca = new Dictionary <float, Vector3>();
            HashSet <Vector3> exiting_ivs      = new HashSet <Vector3>();
            MUPlane           ab = new MUPlane(ab_nor, a), // planes passing through edges, perpendicular to triangle
                              bc = new MUPlane(bc_nor, b),
                              ca = new MUPlane(ca_nor, c);
            // Debug.Log("tri: "+tri_plane+" "+normal);
            //Debugging.DebugRing(points);
            Vector3 opi, old_point;
            bool    oaab, oabc, oaca;
            SortedDictionary <float, Vector3> dist_map_old;
            RingGen strip_rings;
            if (template.isClosed)
            {
                opi          = tri_plane.DirectionalProject(points.Last(), normal);
                old_point    = points.Last();
                oaab         = ab.IsAbove(opi);
                oabc         = bc.IsAbove(opi);
                oaca         = ca.IsAbove(opi);
                dist_map_old = point_data[points.Last()].Item1;
                strip_rings  = point_data[points.Last()].Item2;
            }
            else
            {
                opi          = tri_plane.DirectionalProject(points.First(), normal);
                old_point    = points.First();
                oaab         = ab.IsAbove(opi);
                oabc         = bc.IsAbove(opi);
                oaca         = ca.IsAbove(opi);
                dist_map_old = point_data[points.First()].Item1;
                strip_rings  = point_data[points.First()].Item2;
            }
            bool oldInside = !(oaab || oabc || oaca);
            for (int i = template.isClosed ? 0 : 1; i < points.Count; i++)
            {
                Vector3 cur_point = points[i];
                SortedDictionary <float, Vector3> dist_map = point_data[cur_point].Item1;
                Vector3 pi = tri_plane.DirectionalProject(cur_point, normal);
                // Debug.Log(opi+" => "+pi);
                bool aab    = ab.IsAbove(pi), // above means outside edge
                     abc    = bc.IsAbove(pi),
                     aca    = ca.IsAbove(pi);
                bool inside = !(aab || abc || aca);
                // Debug.Log(aab+" "+abc+" "+aca+" | "+oaab+" "+oabc+" "+oaca);
                if (inside != oldInside)
                {
                    // Debug.Log("EDGE PAIR: "+a+" "+b+" "+c+" pi-opi: "+pi+" "+opi+" hc: "+pi.GetHashCode()+" "+opi.GetHashCode());
                    // add edge pair
                    MUPlane edge_plane;
                    Dictionary <float, Vector3> map;
                    Vector3 ep1, ep2, iv;
                    if (inside)
                    {
                        if (oaab)
                        {
                            edge_plane = ab; map = map_ab; ep1 = a; ep2 = b;
                            iv         = ivSaver.Intersect(edge_plane, ep1, ep2, opi, pi, old_point, cur_point);
                            if (Vector3.Dot(ep1 - iv, ep2 - iv) < 0)
                            {
                                goto connect;
                            }
                        }
                        if (oabc)
                        {
                            edge_plane = bc; map = map_bc; ep1 = b; ep2 = c;
                            iv         = ivSaver.Intersect(edge_plane, ep1, ep2, opi, pi, old_point, cur_point);
                            if (Vector3.Dot(ep1 - iv, ep2 - iv) < 0)
                            {
                                goto connect;
                            }
                        }
                        if (oaca)
                        {
                            edge_plane = ca; map = map_ca; ep1 = c; ep2 = a;
                            iv         = ivSaver.Intersect(edge_plane, ep1, ep2, opi, pi, old_point, cur_point);
                            if (Vector3.Dot(ep1 - iv, ep2 - iv) < 0)
                            {
                                goto connect;
                            }
                        }
                        throw MeshUtilsException.Internal("Point on neither side of triangle");
connect:
                        // Debug.Log("EDGE PAIR: "+iv+" "+pi+" hc: "+iv.GetHashCode()+" "+pi.GetHashCode());
                        float dist_key = template.plane.SignedDistance(pi);
                        if (!dist_map.ContainsKey(dist_key))
                        {
                            dist_map.Add(dist_key, pi);
                        }
                        map.Add((ep1 - iv).magnitude, iv);
                        strip_rings.AddConnected(ring_dir?iv:pi, ring_dir?pi:iv);
                        intersection_ring.AddConnected(ring_dir?iv:pi, ring_dir?pi:iv);
                        tri_rings.AddConnected(iv, pi);
                    }
                    else
                    {
                        // Debug.Log(a+" "+b+" "+c+" "+template_plane);
                        // Debug.Log(pa+" "+pb+" "+pc+" "+points[i-1]+" "+points[i]);
                        if (aab)
                        {
                            edge_plane = ab; map = map_ab; ep1 = a; ep2 = b;
                            iv         = ivSaver.Intersect(edge_plane, ep1, ep2, opi, pi, old_point, cur_point);
                            if (Vector3.Dot(ep1 - iv, ep2 - iv) < 0)
                            {
                                goto connect;
                            }
                        }
                        if (abc)
                        {
                            edge_plane = bc; map = map_bc; ep1 = b; ep2 = c;
                            iv         = ivSaver.Intersect(edge_plane, ep1, ep2, opi, pi, old_point, cur_point);
                            if (Vector3.Dot(ep1 - iv, ep2 - iv) < 0)
                            {
                                goto connect;
                            }
                        }
                        if (aca)
                        {
                            edge_plane = ca; map = map_ca; ep1 = c; ep2 = a;
                            iv         = ivSaver.Intersect(edge_plane, ep1, ep2, opi, pi, old_point, cur_point);
                            if (Vector3.Dot(ep1 - iv, ep2 - iv) < 0)
                            {
                                goto connect;
                            }
                        }
                        throw MeshUtilsException.Internal("Point on neither side of triangle");
connect:
                        // Debug.Log("EDGE PAIR: "+iv+" "+opi+" hc: "+iv.GetHashCode()+" "+opi.GetHashCode());
                        float dist_key = template.plane.SignedDistance(opi);
                        if (!dist_map_old.ContainsKey(dist_key))
                        {
                            dist_map_old.Add(dist_key, opi);
                        }
                        map.Add((ep1 - iv).magnitude, iv);
                        strip_rings.AddConnected(ring_dir?opi:iv, ring_dir?iv:opi);
                        intersection_ring.AddConnected(ring_dir?opi:iv, ring_dir?iv:opi);
                        tri_rings.AddConnected(opi, iv);
                        exiting_ivs.Add(iv);
                    }
                }
                else if (inside)
                {
                    // add inner pair
                    // Debug.Log("INNER PAIR: "+a+" "+b+" "+c+" pi-opi: "+pi+" "+opi+" hc: "+pi.GetHashCode()+" "+opi.GetHashCode());
                    // Debug.Log("INNER PAIR: "+pi+" "+opi+" hc: "+pi.GetHashCode()+" "+opi.GetHashCode());
                    strip_rings.AddConnected(ring_dir?opi:pi, ring_dir?pi:opi);
                    intersection_ring.AddConnected(ring_dir?opi:pi, ring_dir?pi:opi);
                    tri_rings.AddConnected(opi, pi);
                    float dist_key = template.plane.SignedDistance(pi);
                    if (!dist_map.ContainsKey(dist_key))
                    {
                        dist_map.Add(dist_key, pi);
                    }
                    dist_key = template.plane.SignedDistance(opi);
                    if (!dist_map_old.ContainsKey(dist_key))
                    {
                        dist_map_old.Add(dist_key, opi);
                    }
                }
                else
                {
                    // add outer pair
                    if ( // test to check if edge does not cross triangle
                        (aab && oaab) ||
                        (abc && oabc) ||
                        (aca && oaca)
                        )
                    {
                        goto continue_for;
                    }
                    // crosses triangle
                    if (!aab && !oaab)   // not ab
                    {
                        Vector3 iv0 = ivSaver.Intersect(bc, b, c, opi, pi, old_point, cur_point),
                                iv1 = ivSaver.Intersect(ca, c, a, opi, pi, old_point, cur_point);
                        if (
                            Vector3.Dot(b - iv0, c - iv0) > 0 ||
                            Vector3.Dot(c - iv1, a - iv1) > 0
                            )
                        {
                            goto continue_for;
                        }
                        // Debug.Log("OUTER PAIR: "+iv0+" "+iv1+" hc: "+iv0.GetHashCode()+" "+iv1.GetHashCode());
                        map_bc.Add((b - iv0).magnitude, iv0);
                        map_ca.Add((c - iv1).magnitude, iv1);
                        bool iv0_first = (iv0 - opi).magnitude < (iv1 - opi).magnitude;
                        exiting_ivs.Add(iv0_first?iv1:iv0);
                        tri_rings.AddConnected(iv0_first?iv0:iv1, iv0_first?iv1:iv0);
                        strip_rings.AddConnected((!ring_dir ^ iv0_first)?iv0:iv1, (!ring_dir ^ iv0_first)?iv1:iv0);
                        intersection_ring.AddConnected((!ring_dir ^ iv0_first)?iv0:iv1, (!ring_dir ^ iv0_first)?iv1:iv0);
                    }
                    else if (!abc && !oabc)     // not bc
                    {
                        Vector3 iv0 = ivSaver.Intersect(ca, c, a, opi, pi, old_point, cur_point),
                                iv1 = ivSaver.Intersect(ab, a, b, opi, pi, old_point, cur_point);
                        if (
                            Vector3.Dot(c - iv0, a - iv0) > 0 ||
                            Vector3.Dot(a - iv1, b - iv1) > 0
                            )
                        {
                            goto continue_for;
                        }
                        // Debug.Log("OUTER PAIR: "+iv0+" "+iv1+" hc: "+iv0.GetHashCode()+" "+iv1.GetHashCode());
                        map_ca.Add((c - iv0).magnitude, iv0);
                        map_ab.Add((a - iv1).magnitude, iv1);
                        bool iv0_first = (iv0 - opi).magnitude < (iv1 - opi).magnitude;
                        exiting_ivs.Add(iv0_first?iv1:iv0);
                        tri_rings.AddConnected(iv0_first?iv0:iv1, iv0_first?iv1:iv0);
                        strip_rings.AddConnected((!ring_dir ^ iv0_first)?iv0:iv1, (!ring_dir ^ iv0_first)?iv1:iv0);
                        intersection_ring.AddConnected((!ring_dir ^ iv0_first)?iv0:iv1, (!ring_dir ^ iv0_first)?iv1:iv0);
                    }
                    else if (!aca && !oaca)     // not ca
                    {
                        Vector3 iv0 = ivSaver.Intersect(ab, a, b, opi, pi, old_point, cur_point),
                                iv1 = ivSaver.Intersect(bc, b, c, opi, pi, old_point, cur_point);
                        if (
                            Vector3.Dot(a - iv0, b - iv0) > 0 ||
                            Vector3.Dot(b - iv1, c - iv1) > 0
                            )
                        {
                            goto continue_for;
                        }
                        // Debug.Log("OUTER PAIR: "+iv0+" "+iv1+" hc: "+iv0.GetHashCode()+" "+iv1.GetHashCode());
                        map_ab.Add((a - iv0).magnitude, iv0);
                        map_bc.Add((b - iv1).magnitude, iv1);
                        bool iv0_first = (iv0 - opi).magnitude < (iv1 - opi).magnitude;
                        exiting_ivs.Add(iv0_first?iv1:iv0);
                        tri_rings.AddConnected(iv0_first?iv0:iv1, iv0_first?iv1:iv0);
                        strip_rings.AddConnected((!ring_dir ^ iv0_first)?iv0:iv1, (!ring_dir ^ iv0_first)?iv1:iv0);
                        intersection_ring.AddConnected((!ring_dir ^ iv0_first)?iv0:iv1, (!ring_dir ^ iv0_first)?iv1:iv0);
                    }
                    else     // opposite sides
                    {
                        MUPlane edge_plane, edge_plane1;
                        Dictionary <float, Vector3> map, map1;
                        Vector3 iv, iv1; // iv is entry, must be one side; iv1 is exit, can be either two other sides
                        float   iv_mag, iv1_mag;
                        bool    swap_ring_dir = false;

                        if (aab && !abc && !aca || oaab && !oabc && !oaca)
                        {
                            // Debug.Log("1 swap "+oaab);
                            if (oaab)
                            {
                                swap_ring_dir = true;
                            }
                            edge_plane = ab;
                            map        = map_ab;
                            iv         = ivSaver.Intersect(ab, a, b, opi, pi, old_point, cur_point);
                            iv_mag     = (a - iv).magnitude;
                            if (Vector3.Dot(a - iv, b - iv) > 0)
                            {
                                goto continue_for;
                            }
                            iv1 = ivSaver.Intersect(bc, b, c, opi, pi, old_point, cur_point);
                            if (Vector3.Dot(b - iv1, c - iv1) > 0)
                            {
                                iv1         = ivSaver.Intersect(ca, c, a, opi, pi, old_point, cur_point);
                                iv1_mag     = (c - iv1).magnitude;
                                edge_plane1 = ca;
                                map1        = map_ca;
                            }
                            else
                            {
                                iv1_mag     = (b - iv1).magnitude;
                                edge_plane1 = bc;
                                map1        = map_bc;
                            }
                            goto connect_opposite;
                        }
                        else if (!aab && abc && !aca || !oaab && oabc && !oaca)
                        {
                            // Debug.Log("2 swap "+oabc);
                            if (oabc)
                            {
                                swap_ring_dir = true;
                            }
                            edge_plane = bc;
                            map        = map_bc;
                            iv         = ivSaver.Intersect(bc, b, c, opi, pi, old_point, cur_point);
                            iv_mag     = (b - iv).magnitude;
                            if (Vector3.Dot(b - iv, c - iv) > 0)
                            {
                                goto continue_for;
                            }
                            iv1 = ivSaver.Intersect(ca, c, a, opi, pi, old_point, cur_point);
                            if (Vector3.Dot(c - iv1, a - iv1) > 0)
                            {
                                iv1         = ivSaver.Intersect(ab, a, b, opi, pi, old_point, cur_point);
                                iv1_mag     = (a - iv1).magnitude;
                                edge_plane1 = ab;
                                map1        = map_ab;
                            }
                            else
                            {
                                iv1_mag     = (c - iv1).magnitude;
                                edge_plane1 = ca;
                                map1        = map_ca;
                            }
                            goto connect_opposite;
                        }
                        else if (!aab && !abc && aca || !oaab && !oabc && oaca)
                        {
                            // Debug.Log("3 swap "+oaca);
                            if (oaca)
                            {
                                swap_ring_dir = true;
                            }
                            edge_plane = ca;
                            map        = map_ca;
                            iv         = ivSaver.Intersect(ca, c, a, opi, pi, old_point, cur_point);
                            iv_mag     = (c - iv).magnitude;
                            if (Vector3.Dot(c - iv, a - iv) > 0)
                            {
                                goto continue_for;
                            }
                            iv1 = ivSaver.Intersect(ab, a, b, opi, pi, old_point, cur_point);
                            if (Vector3.Dot(a - iv1, b - iv1) > 0)
                            {
                                iv1         = ivSaver.Intersect(bc, b, c, opi, pi, old_point, cur_point);
                                iv1_mag     = (b - iv1).magnitude;
                                edge_plane1 = bc;
                                map1        = map_bc;
                            }
                            else
                            {
                                iv1_mag     = (a - iv1).magnitude;
                                edge_plane1 = ab;
                                map1        = map_ab;
                            }
                            goto connect_opposite;
                        }

                        throw MeshUtilsException.Internal("Case exhaustion failed");
connect_opposite:
                        // Debug.Log("CROSS PAIR: "+iv+" "+iv1+" hc: "+iv.GetHashCode()+" "+iv1.GetHashCode());
                        // Debug.Log("yay "+opi+" "+pi+" "+a+" "+b+" "+c+" "+aab+" "+abc+" "+aca+" "+oaab+" "+oabc+" "+oaca);
                        map.Add(iv_mag, iv);
                        map1.Add(iv1_mag, iv1);
                        exiting_ivs.Add(swap_ring_dir?iv1:iv);
                        // Debug.Log("exiting is "+(swap_ring_dir?iv1:iv));
                        strip_rings.AddConnected((!ring_dir ^ swap_ring_dir)?iv:iv1, (!ring_dir ^ swap_ring_dir)?iv1:iv);
                        intersection_ring.AddConnected((!ring_dir ^ swap_ring_dir)?iv:iv1, (!ring_dir ^ swap_ring_dir)?iv1:iv);
                        tri_rings.AddConnected(swap_ring_dir?iv:iv1, swap_ring_dir?iv1:iv);
                    }
                }
continue_for:
                old_point    = cur_point;
                oldInside    = inside;
                oaab         = aab;
                oabc         = abc;
                oaca         = aca;
                opi          = pi;
                dist_map_old = dist_map;
                strip_rings  = point_data[points[i]].Item2;
            }
            if (tri_rings.HasComplete())
            {
            #if !HANDLE_CLOSED
                throw MeshUtilsException.Internal("Template closed and within triangle not handled");
            #else
                // Debug.Log("inside");
                if (tri_rings.HasPartials())
                {
                    throw MeshUtilsException.Internal("Unexpected condition");
                }
                List <Ring> ring = tri_rings.GetRings(false, false);
                if (ring.Count != 1)
                {
                    throw MeshUtilsException.Internal("Multiple rings in single triangle");
                }
                Debugging.DebugRing(ring[0].verts);
                GenerateRingMesh(ring[0].verts, partToUse?neg:pos, tri_nor, true, null, addNormals);

                var r0 = new Ring(new List <Vector3>()
                {
                    a, b, c
                });
                var r1 = ring[0];

                r1.verts.Reverse();

                // join indices
                int i0 = 0, i1 = 0;
                r0.RingDist(r1, ref i0, ref i1);

                // the inner ring should have the opposite direction
                // join by inserting r1 at i0 in r0
                List <Vector3> res = new List <Vector3>();
                res.AddRange(r0.verts.GetRange(0, i0 + 1));               // r0 from start to split
                res.AddRange(r1.verts.GetRange(i1, r1.verts.Count - i1)); // r1 from split to end
                res.AddRange(r1.verts.GetRange(0, i1 + 1));               // r1 from start to split
                res.AddRange(r0.verts.GetRange(i0, r0.verts.Count - i0)); // r0 from split to end

                // Debugging.DebugRing(res);

                GenerateRingMesh(res, partToUse?pos:neg, tri_nor, true, null, addNormals);
                return(true);
            #endif
            }
            if (!tri_rings.HasPartials())
            {
                return(false);
            }
            // Debugging.DebugRing(points.ConvertAll(p=>tri_plane.DirectionalProject(p,normal)));
            // Debug.Log("tri verts:"+a+" "+b+" "+c);
            // tri_rings.MyDebugLog();
            // Debug.Log("connecting ivs...");
            RingGenerator inv_tri_rings = tri_rings.Duplicate();                                // seperate rings needed for other MeshPart
            ConnectIVs(exiting_ivs, a, b, c, map_ab, map_ca, map_bc, tri_rings, inv_tri_rings); // connect edges around in triangle rings
            ConnectIVs(exiting_ivs, b, c, a, map_bc, map_ab, map_ca, tri_rings, inv_tri_rings); // one call per edge
            ConnectIVs(exiting_ivs, c, a, b, map_ca, map_bc, map_ab, tri_rings, inv_tri_rings);
            // Debug.Log("gen:");
            //tri_rings.MyDebugLog();
            foreach (var ring in tri_rings.GetRings(false, false))
            {
                // Debugging.DebugRing(ring.verts);
                GenerateRingMesh(ring.verts, partToUse?neg:pos, tri_nor, true, null, addNormals);
            }
            // Debug.Log("gen inv:");
            //inv_tri_rings.MyDebugLog();
            foreach (var ring in inv_tri_rings.GetRings(false, false))
            {
                //Debugging.DebugRing(ring.verts);
                ring.verts.Reverse();
                GenerateRingMesh(ring.verts, partToUse?pos:neg, tri_nor, true, null, addNormals);
            }
            //Debug.Log("--------------- END PROCESS TRIANGLE");
            return(true);
        }
Exemple #6
0
        public static void GenerateRingMesh(
            List <Vector3> ring, MeshPart part, Vector3 normal, bool side, Vector2?innerUV, bool addNormals = false
            )
        {
            bool addUVs = innerUV != null;

            // List<List<Vector3>> reduceHist = new List<List<Vector3>>();
            // reduceHist.Add(ring);

            int indStart = part.vertices.Count;

            part.vertices.AddRange(ring);
            if (addUVs || addNormals)
            {
                foreach (var _ in ring)
                {
                    if (addUVs)
                    {
                        part.uvs.Add(innerUV.Value);
                    }
                    if (addNormals)
                    {
                        part.normals.Add(side ? -normal : normal);
                    }
                }
            }

            List <Tuple <Vector3, int> > set = ring.ConvertAll(v => new Tuple <Vector3, int>(v, indStart++));

            int  i = -1, lsc = set.Count;
            bool didInf = false;

            while (set.Count > 1)
            {
                i++;
                if (i >= set.Count)
                {
                    if (lsc == set.Count)
                    {
                        if (didInf)
                        {
                            // Debug.LogError("ear clipping failed");
                            // DebugRings(reduceHist);
                            // Debug.Log("normal "+(normal*1000));
                            // DebugRing(set.ConvertAll(s=>s.Item1));
                            throw MeshUtilsException.Internal("Ear clipping failed");
                        }
                        didInf = true;
                    }
                    else
                    {
                        didInf = false;
                    }
                    lsc = set.Count;
                }
                i %= set.Count;

                Tuple <Vector3, int> vi0 = set[i],
                                     vi1 = set[(i + 1) % set.Count],
                                     vi2 = set[(i + 2) % set.Count];
                Vector3 d1 = vi1.Item1 - vi0.Item1; // i0 -> i1
                Vector3 d2 = vi2.Item1 - vi0.Item1; // i0 -> i2

                // we assume points do not lie in a line (see SimplifyRing)
                // if they do however, it's just a waste of vertices

                // check convex ear
                float conv = Vector3.Dot(Vector3.Cross(d1.normalized, d2.normalized), normal);
                if (conv > 0)
                {
                    continue;
                }

                // check that there are no other vertices inside this triangle
                if (set.Exists(v => {
                    // note: we must compare the vectors, otherwise coinciding vectors do not
                    // register as being the same
                    if (v.Item1 == vi0.Item1 || v.Item1 == vi1.Item1 || v.Item1 == vi2.Item1)
                    {
                        return(false);
                    }
                    return(VectorUtil.CheckIsInside(d1, d2, v.Item1 - vi0.Item1));
                }))
                {
                    continue;
                }

                // generate indices
                if (side)
                {
                    part.indices.Add(vi0.Item2);
                    part.indices.Add(vi1.Item2);
                    part.indices.Add(vi2.Item2);
                }
                else
                {
                    part.indices.Add(vi0.Item2);
                    part.indices.Add(vi2.Item2);
                    part.indices.Add(vi1.Item2);
                }

                // eliminate vertex
                set.RemoveAt((++i) % set.Count);
                i++;

                // reduceHist.Add(set.ConvertAll(s=>s.Item1));
            }
        }
Exemple #7
0
 public FriendlyCutObj(MeshPart part, CutResult result, bool isPolySeperated)
 {
     this.part            = part;
     this.cutResult       = result;
     this.isPolySeperated = isPolySeperated;
 }
Exemple #8
0
 // -----------------------------------------------------
 // Generate triangle mesh within possibly concave ring
 // -----------------------------------------------------
 public static void GenerateRingMesh(
     Ring ring, MeshPart part, Vector3 normal, Vector2?innerUV, bool addNormals = false
     )
 {
     GenerateRingMesh(ring.verts, part, normal, innerUV, addNormals);
 }
Exemple #9
0
 public static void GenerateRingMesh(
     List <Vector3> ring, MeshPart part, Vector3 normal, Vector2?innerUV, bool addNormals = false
     )
 {
     GenerateRingMesh(ring, part, normal, part.side, innerUV, addNormals);
 }
Exemple #10
0
        public static CutResult Run(
            GameObject target,
            CuttingPlane plane,
            CutParams param
            )
        {
            CuttingPlane cutting_plane = plane.ToLocalSpace(target.transform);

            Mesh          mesh = target.GetComponent <MeshFilter>().mesh;
            MeshPart      pos = new MeshPart(true), neg = new MeshPart(false);
            RingGenerator rings = new RingGenerator();

            //DateTime start = DateTime.Now;

            Vector2[] uvs       = mesh.uv;
            Vector3[] vertices  = mesh.vertices;
            Vector3[] normals   = mesh.normals;
            int[]     triangles = mesh.triangles;

            bool addUVs     = uvs.Length > 0 && param.innerTextureCoord != null,
                 addNormals = normals.Length > 0;

            // divide mesh in half by vertices
            int i = 0;

            foreach (Vector3 vertex in vertices)
            {
                if (cutting_plane.IsAbove(vertex))
                {
                    pos.indexMap.Add(i, pos.vertices.Count);
                    pos.vertices.Add(vertex);
                    if (addUVs)
                    {
                        pos.uvs.Add(uvs[i]);
                    }
                    if (addNormals)
                    {
                        pos.normals.Add(normals[i]);
                    }
                }
                else
                {
                    neg.indexMap.Add(i, neg.vertices.Count);
                    neg.vertices.Add(vertex);
                    if (addUVs)
                    {
                        neg.uvs.Add(uvs[i]);
                    }
                    if (addNormals)
                    {
                        neg.normals.Add(normals[i]);
                    }
                }
                i++;
            }

            //Debug.Log((DateTime.Now-start).TotalMilliseconds+" elapsed (1)");
            //start = DateTime.Now;

            // if either vertex list is empty the knife plane didn't collide
            if (pos.vertices.Count == 0 || neg.vertices.Count == 0)
            {
                if (!param.allowSingleResult)
                {
                    return(null);
                }
            }

            // put triangles in correct mesh
            for (i = 0; i < triangles.Length; i += 3)
            {
                // find orignal indices
                int i_a = triangles[i],
                    i_b = triangles[i + 1],
                    i_c = triangles[i + 2];

                // find original verticies
                Vector3 a = vertices[i_a],
                        b = vertices[i_b],
                        c = vertices[i_c];

                // find original uvs
                Vector2 txa, txb, txc;
                if (addUVs)
                {
                    txa = uvs[i_a];
                    txb = uvs[i_b];
                    txc = uvs[i_c];
                }
                else
                {
                    txa = txb = txc = Vector3.zero;
                }

                // find original normals
                Vector3 na, nb, nc;
                if (addNormals)
                {
                    na = normals[i_a];
                    nb = normals[i_b];
                    nc = normals[i_c];
                }
                else
                {
                    na = nb = nc = Vector3.zero;
                }

                // seperation check
                bool aAbove = cutting_plane.IsAbove(a),
                     bAbove = cutting_plane.IsAbove(b),
                     cAbove = cutting_plane.IsAbove(c);

                if (aAbove && bAbove && cAbove)
                {
                    // triangle above plane
                    pos.indices.Add(pos.indexMap[i_a]);
                    pos.indices.Add(pos.indexMap[i_b]);
                    pos.indices.Add(pos.indexMap[i_c]);
                }
                else if (!aAbove && !bAbove && !cAbove)
                {
                    // triangle below plane
                    neg.indices.Add(neg.indexMap[i_a]);
                    neg.indices.Add(neg.indexMap[i_b]);
                    neg.indices.Add(neg.indexMap[i_c]);
                }
                else
                {
                    // triangle crosses plane
                    // call Util.GenTriangles
                    if (aAbove == bAbove)
                    {
                        // a, b, c
                        GenTriangles(
                            cutting_plane,
                            aAbove ? pos : neg,
                            !aAbove ? pos : neg,
                            a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c,
                            rings,
                            addUVs,
                            addNormals
                            );
                    }
                    else if (aAbove == cAbove)
                    {
                        // c, a, b
                        GenTriangles(
                            cutting_plane,
                            aAbove ? pos : neg,
                            !aAbove ? pos : neg,
                            c, a, b, txc, txa, txb, na, nb, nc, i_c, i_a, i_b,
                            rings,
                            addUVs,
                            addNormals
                            );
                    }
                    else if (bAbove == cAbove)
                    {
                        // b, c, a (use bAbove)
                        GenTriangles(
                            cutting_plane,
                            bAbove ? pos : neg,
                            !bAbove ? pos : neg,
                            b, c, a, txb, txc, txa, na, nb, nc, i_b, i_c, i_a,
                            rings,
                            addUVs,
                            addNormals
                            );
                    }
                }
            }

            //Debug.Log((DateTime.Now-start).TotalMilliseconds+" elapsed (2)");
            //start = DateTime.Now;

            List <Ring> ringOut = rings.GetRings(param.selfConnectRings, param.ignorePartialRings);

            List <Ring> analysis = param.hiearchyAnalysis ? Hierarchy.Analyse(ringOut, cutting_plane.normal) : ringOut;

            Vector2?innerUV = addUVs ? param.innerTextureCoord : null;

            // generate seperation meshing
            foreach (var ring in analysis)
            {
                GenerateRingMesh(ring, pos, cutting_plane.normal, innerUV, addNormals);
                GenerateRingMesh(ring, neg, cutting_plane.normal, innerUV, addNormals);
            }

            //Debug.Log((DateTime.Now-start).TotalMilliseconds+" elapsed (3)");
            //start = DateTime.Now;

            return(new CutResult(target, cutting_plane.ToWorldSpace().normal, ringOut, pos, neg));
        }
Exemple #11
0
        public static CutResult Run(
            GameObject target,
            CuttingPlane plane,
            CutParams param
            )
        {
            CuttingPlane cutting_plane = plane.ToLocalSpace(target.transform);

            Mesh          mesh = target.GetComponent <MeshFilter>().mesh;
            MeshPart      pos = new MeshPart(true), neg = new MeshPart(false);
            RingGenerator pos_rings = new RingGenerator(), neg_rings = new RingGenerator();

            Vector2[] uvs       = mesh.uv;
            Vector3[] vertices  = mesh.vertices;
            Vector3[] normals   = mesh.normals;
            int[]     triangles = mesh.triangles;

            bool addUVs     = uvs.Length > 0 && param.innerTextureCoord != null,
                 addNormals = normals.Length > 0;

            // removed indices
            HashSet <int> removed = new HashSet <int>();

            // divide mesh in half by vertices
            int i = -1;

            foreach (Vector3 vertex in vertices)
            {
                i++;
                float dist = cutting_plane.Distance(vertex);
                if (dist < param.seperationDistance)
                {
                    removed.Add(i);
                    continue;
                }
                if (cutting_plane.IsAbove(vertex))
                {
                    pos.indexMap.Add(i, pos.vertices.Count);
                    pos.vertices.Add(vertex);
                    if (addUVs)
                    {
                        pos.uvs.Add(uvs[i]);
                    }
                    if (addNormals)
                    {
                        pos.normals.Add(normals[i]);
                    }
                }
                else
                {
                    neg.indexMap.Add(i, neg.vertices.Count);
                    neg.vertices.Add(vertex);
                    if (addUVs)
                    {
                        neg.uvs.Add(uvs[i]);
                    }
                    if (addNormals)
                    {
                        pos.normals.Add(normals[i]);
                    }
                }
            }

            // if either vertex list is empty and no vertices were removed, the knife plane didn't collide
            if (pos.vertices.Count == 0 || neg.vertices.Count == 0)
            {
                if (!param.allowSingleResult)
                {
                    return(null);
                }
            }

            // put triangles in correct mesh
            for (i = 0; i < triangles.Length; i += 3)
            {
                // find orignal indices
                int i_a = triangles[i],
                    i_b = triangles[i + 1],
                    i_c = triangles[i + 2];

                // find if these were removed in cut
                bool r_a = removed.Contains(i_a),
                     r_b = removed.Contains(i_b),
                     r_c = removed.Contains(i_c);

                // if all are removed, ignore triangle
                if (r_a && r_b && r_c)
                {
                    continue;
                }

                // find original verticies
                Vector3 a = vertices[i_a],
                        b = vertices[i_b],
                        c = vertices[i_c];

                Vector2 txa, txb, txc;

                // find original uvs
                if (uvs.Length > 0)
                {
                    txa = uvs[i_a];
                    txb = uvs[i_b];
                    txc = uvs[i_c];
                }
                else
                {
                    txa = txb = txc = Vector2.zero;
                }

                // find original normals
                Vector3 na, nb, nc;
                if (addNormals)
                {
                    na = normals[i_a];
                    nb = normals[i_b];
                    nc = normals[i_c];
                }
                else
                {
                    na = nb = nc = Vector3.zero;
                }

                // seperation check
                bool aAbove = cutting_plane.IsAbove(a),
                     bAbove = cutting_plane.IsAbove(b),
                     cAbove = cutting_plane.IsAbove(c);

                if (!r_a && !r_b && !r_c)
                {
                    // all available
                    if (aAbove && bAbove && cAbove)
                    {
                        // triangle above plane
                        pos.indices.Add(pos.indexMap[i_a]);
                        pos.indices.Add(pos.indexMap[i_b]);
                        pos.indices.Add(pos.indexMap[i_c]);
                    }
                    else if (!aAbove && !bAbove && !cAbove)
                    {
                        // triangle below plane
                        neg.indices.Add(neg.indexMap[i_a]);
                        neg.indices.Add(neg.indexMap[i_b]);
                        neg.indices.Add(neg.indexMap[i_c]);
                    }
                    else
                    {
                        // triangle crosses plane
                        if (aAbove == bAbove)
                        {
                            // a, b, c
                            GenTwoTriangles(
                                cutting_plane,
                                aAbove ? pos : neg,
                                a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c,
                                aAbove ? pos_rings : neg_rings,
                                addUVs,
                                addNormals,
                                -param.seperationDistance
                                );
                            GenTriangle(
                                cutting_plane,
                                cAbove ? pos : neg,
                                c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b,
                                cAbove ? pos_rings : neg_rings,
                                addUVs,
                                addNormals,
                                param.seperationDistance
                                );
                        }
                        else if (aAbove == cAbove)
                        {
                            // c, a, b
                            GenTwoTriangles(
                                cutting_plane,
                                aAbove ? pos : neg,
                                c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b,
                                aAbove ? pos_rings : neg_rings,
                                addUVs,
                                addNormals,
                                -param.seperationDistance
                                );
                            GenTriangle(
                                cutting_plane,
                                bAbove ? pos : neg,
                                b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a,
                                bAbove ? pos_rings : neg_rings,
                                addUVs,
                                addNormals,
                                param.seperationDistance
                                );
                        }
                        else if (bAbove == cAbove)
                        {
                            // b, c, a
                            GenTwoTriangles(
                                cutting_plane,
                                bAbove ? pos : neg,
                                b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a,
                                bAbove ? pos_rings : neg_rings,
                                addUVs,
                                addNormals,
                                -param.seperationDistance
                                );
                            GenTriangle(
                                cutting_plane,
                                aAbove ? pos : neg,
                                a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c,
                                aAbove ? pos_rings : neg_rings,
                                addUVs,
                                addNormals,
                                param.seperationDistance
                                );
                        }
                    }
                }
                else if (!r_a && !r_b)
                {
                    // a and b available
                    if (aAbove != bAbove)
                    {
                        GenTriangle(
                            cutting_plane,
                            aAbove ? pos : neg,
                            a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c,
                            aAbove ? pos_rings : neg_rings,
                            addUVs,
                            addNormals,
                            param.seperationDistance
                            );
                        GenTriangle(
                            cutting_plane,
                            bAbove ? pos : neg,
                            b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a,
                            bAbove ? pos_rings : neg_rings,
                            addUVs,
                            addNormals,
                            param.seperationDistance
                            );
                    }
                    else
                    {
                        GenTwoTriangles(
                            cutting_plane,
                            aAbove ? pos : neg,
                            a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c,
                            aAbove ? pos_rings : neg_rings,
                            addUVs,
                            addNormals,
                            -param.seperationDistance
                            );
                    }
                }
                else if (!r_a && !r_c)
                {
                    // a and c available
                    if (aAbove != cAbove)
                    {
                        GenTriangle(
                            cutting_plane,
                            aAbove ? pos : neg,
                            a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c,
                            aAbove ? pos_rings : neg_rings,
                            addUVs,
                            addNormals,
                            param.seperationDistance
                            );
                        GenTriangle(
                            cutting_plane,
                            cAbove ? pos : neg,
                            c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b,
                            cAbove ? pos_rings : neg_rings,
                            addUVs,
                            addNormals,
                            param.seperationDistance
                            );
                    }
                    else
                    {
                        GenTwoTriangles(
                            cutting_plane,
                            aAbove ? pos : neg,
                            c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b,
                            aAbove ? pos_rings : neg_rings,
                            addUVs,
                            addNormals,
                            -param.seperationDistance
                            );
                    }
                }
                else if (!r_b && !r_c)
                {
                    // b and c available
                    if (bAbove != cAbove)
                    {
                        GenTriangle(
                            cutting_plane,
                            bAbove ? pos : neg,
                            b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a,
                            bAbove ? pos_rings : neg_rings,
                            addUVs,
                            addNormals,
                            param.seperationDistance
                            );
                        GenTriangle(
                            cutting_plane,
                            cAbove ? pos : neg,
                            c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b,
                            cAbove ? pos_rings : neg_rings,
                            addUVs,
                            addNormals,
                            param.seperationDistance
                            );
                    }
                    else
                    {
                        GenTwoTriangles(
                            cutting_plane,
                            bAbove ? pos : neg,
                            b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a,
                            bAbove ? pos_rings : neg_rings,
                            addUVs,
                            addNormals,
                            -param.seperationDistance
                            );
                    }
                }
                else if (!r_a)
                {
                    // a available
                    GenTriangle(
                        cutting_plane,
                        aAbove ? pos : neg,
                        a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c,
                        aAbove ? pos_rings : neg_rings,
                        addUVs,
                        addNormals,
                        param.seperationDistance
                        );
                }
                else if (!r_b)
                {
                    // b available
                    GenTriangle(
                        cutting_plane,
                        bAbove ? pos : neg,
                        b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a,
                        bAbove ? pos_rings : neg_rings,
                        addUVs,
                        addNormals,
                        param.seperationDistance
                        );
                }
                else
                {
                    // c available
                    GenTriangle(
                        cutting_plane,
                        cAbove ? pos : neg,
                        c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b,
                        cAbove ? pos_rings : neg_rings,
                        addUVs,
                        addNormals,
                        param.seperationDistance
                        );
                }
            }

            List <Ring> pos_ring_res = pos_rings.GetRings(param.selfConnectRings, param.ignorePartialRings);
            List <Ring> neg_ring_res = neg_rings.GetRings(param.selfConnectRings, param.ignorePartialRings);

            List <Ring> pos_analysis = param.hiearchyAnalysis ? Hierarchy.Analyse(pos_ring_res, cutting_plane.normal) : pos_ring_res;
            List <Ring> neg_analysis = param.hiearchyAnalysis ? Hierarchy.Analyse(neg_ring_res, cutting_plane.normal) : neg_ring_res;

            Vector2?innerUV = addUVs ? param.innerTextureCoord : null;

            // generate seperation meshing
            foreach (var ring in pos_analysis)
            {
                GenerateRingMesh(ring, pos, cutting_plane.normal, innerUV);
            }
            foreach (var ring in neg_analysis)
            {
                GenerateRingMesh(ring, neg, cutting_plane.normal, innerUV);
            }

            List <MeshPart> resParts = new List <MeshPart>();

            if (pos.vertices.Count > 0)
            {
                resParts.Add(pos);
            }
            if (neg.vertices.Count > 0)
            {
                resParts.Add(neg);
            }

            if (resParts.Count < 2 && !param.allowSingleResult)
            {
                return(null);
            }

            return(new CutResult(target, resParts, cutting_plane.ToWorldSpace().normal, new List <Ring>(), false));
        }
Exemple #12
0
        public static void GenPartialTriangles(
            CuttingPlane plane,
            MeshPart part,
            Vector3 a, Vector3 b, Vector3 c,
            Vector2 txa, Vector2 txb, Vector2 txc,
            int i_a, int i_b, int i_c,
            HashSet <Vector3> allow_cut,
            bool addUVs
            )
        {
            // find intersection vertices / uvs
            var es = plane.Intersection(a, c, txa, txc, 0);
            var ds = plane.Intersection(b, c, txb, txc, 0);

            Vector3 e = es.Item1, d = ds.Item1;
            Vector2 txe = es.Item2, txd = ds.Item2;

            // if e == d, the three vertices lie in a line,
            //   and thus do not make up a triangle
            if (e == d)
            {
                return;

                // not sure if this is nescessary
                throw MeshUtilsException.ZeroAreaTriangle();
            }

            if (
                !allow_cut.Contains(e) &&
                !allow_cut.Contains(d)
                )
            {
                // triangle must not be cut
                part.indices.Add(part.indexMap[i_a]);
                part.indices.Add(part.indexMap[i_b]);
                part.indices.Add(part.indexMap[i_c]);
                return;
            }

            // new indices
            int i0 = part.vertices.Count, i1 = part.vertices.Count + 2;

            // add new vertices and uvs
            part.vertices.Add(d);
            part.vertices.Add(e);
            part.vertices.Add(d);
            part.vertices.Add(e);
            if (addUVs)
            {
                part.uvs.Add(txd);
                part.uvs.Add(txe);
                part.uvs.Add(txd);
                part.uvs.Add(txe);
            }

            // generate triangles ...

            // add a,d,e
            part.indices.Add(part.indexMap[i_a]);
            part.indices.Add(i0);
            part.indices.Add(i0 + 1);
            // add a,b,d
            part.indices.Add(part.indexMap[i_a]);
            part.indices.Add(part.indexMap[i_b]);
            part.indices.Add(i0);
            // add e,d,c
            part.indices.Add(i1 + 1);
            part.indices.Add(i1);
            part.indices.Add(part.indexMap[i_c]);
        }
Exemple #13
0
        // ------------------------------------------------------------
        // Generate single triangle for an intersecting triangle a,b,c
        // It is assumed that a is on the positive half plane
        // ------------------------------------------------------------
        public static void GenTriangle(
            CuttingPlane plane,
            MeshPart pos,
            Vector3 a, Vector3 b, Vector3 c,
            Vector2 txa, Vector2 txb, Vector2 txc,
            Vector3 na, Vector3 nb, Vector3 nc,
            int i_a, int i_b, int i_c,
            RingGenerator rings,
            bool addUVs,
            bool addNormals,
            float shift
            )
        {
            // find intersection vertices / uvs
            var es = plane.Intersection(c, a, txa, txc, nc, na, shift);
            var ds = plane.Intersection(b, a, txb, txc, nb, na, shift);

            Vector3 e = es.Item1, d = ds.Item1;
            Vector2 txe = es.Item2, txd = ds.Item2;
            Vector3 ne = es.Item3, nd = ds.Item3;

            // if e == d, the three vertices lie in a line,
            //   and thus do not make up a triangle
            if (e == d)
            {
                return;

                // not sure if this is nescessary
                throw MeshUtilsException.ZeroAreaTriangle();
            }

            // new indices
            int i0 = pos.vertices.Count;

            // add connected pair in ring generator

            // find proper direction for ring
            Vector3 tri_nor = Vector3.Cross(c - a, c - b);
            bool    dir     = Vector3.Dot(e - d, Vector3.Cross(plane.normal, tri_nor)) > 0;

            rings.AddConnected(dir?e:d, dir?d:e);

            // add new vertices and uvs
            pos.vertices.Add(d);
            pos.vertices.Add(e);
            if (addUVs)
            {
                pos.uvs.Add(txd);
                pos.uvs.Add(txe);
            }
            if (addNormals)
            {
                pos.normals.Add(nd);
                pos.normals.Add(ne);
            }

            // add a,d,e to positive indicies
            pos.indices.Add(pos.indexMap[i_a]);
            pos.indices.Add(i0);
            pos.indices.Add(i0 + 1);
        }
Exemple #14
0
        public static CutResult Run(
            GameObject target,
            CuttingPlane plane,
            CutParams param
            )
        {
            CuttingPlane cutting_plane = plane.ToLocalSpace(target.transform);
            Mesh         mesh          = target.GetComponent <MeshFilter>().mesh;

            MeshPart part = new MeshPart(false);

            Vector2[] uvs       = mesh.uv;
            Vector3[] vertices  = mesh.vertices;
            int[]     triangles = mesh.triangles;

            //
            // First we find the rings that are eligable for cutting
            //

            RingGenerator rings = new RingGenerator();

            int i;

            for (i = 0; i < triangles.Length; i += 3)
            {
                // find orignal indices
                int i_a = triangles[i],
                    i_b = triangles[i + 1],
                    i_c = triangles[i + 2];

                // find original verticies
                Vector3 a = vertices[i_a],
                        b = vertices[i_b],
                        c = vertices[i_c];

                // seperation check
                bool aAbove = cutting_plane.IsAbove(a),
                     bAbove = cutting_plane.IsAbove(b),
                     cAbove = cutting_plane.IsAbove(c);

                if (aAbove == bAbove && aAbove == cAbove)
                {
                    continue;
                }

                if (aAbove == bAbove)
                {
                    // a, b, c
                    GenIntersection(
                        cutting_plane,
                        a, b, c,
                        rings
                        );
                }
                else if (aAbove == cAbove)
                {
                    // c, a, b
                    GenIntersection(
                        cutting_plane,
                        c, a, b,
                        rings
                        );
                }
                else if (bAbove == cAbove)
                {
                    // b, c, a
                    GenIntersection(
                        cutting_plane,
                        b, c, a,
                        rings
                        );
                }
            }

            Vector3 point = target.transform.InverseTransformPoint(param.originPoint);

            List <Ring> resulting_rings = new List <Ring>();

            foreach (Ring ring in rings.GetRings(param.selfConnectRings, param.ignorePartialRings))
            {
                Vector3 vec = ring.FurthestVectorToRingPerimeter(point);
                vec = target.transform.TransformVector(vec);
                // Debug.DrawRay(param.originPoint,vec,Color.blue,10);
                float mag = vec.magnitude;
                Debug.Log(mag);
                if (mag < param.maxCutDistance)
                {
                    resulting_rings.Add(ring);
                }
            }

            if (resulting_rings.Count == 0)
            {
                return(null);
            }

            // Debug.Log(resulting_rings.Count);

            HashSet <Vector3> allow_cut = new HashSet <Vector3>();

            foreach (Ring ring in resulting_rings)
            {
                foreach (Vector3 v in ring.verts)
                {
                    allow_cut.Add(v);
                }
            }

            //
            // Start of cutting
            //

            bool addUVs = uvs.Length > 0 && param.innerTextureCoord != null;

            // transfer vertices into MeshPart
            i = 0;
            foreach (Vector3 vertex in vertices)
            {
                part.indexMap.Add(i, part.vertices.Count);
                part.vertices.Add(vertex);
                if (addUVs)
                {
                    part.uvs.Add(uvs[i]);
                }
                i++;
            }

            // process triangles
            for (i = 0; i < triangles.Length; i += 3)
            {
                // find orignal indices
                int i_a = triangles[i],
                    i_b = triangles[i + 1],
                    i_c = triangles[i + 2];

                // find original verticies
                Vector3 a = vertices[i_a],
                        b = vertices[i_b],
                        c = vertices[i_c];

                Vector2 txa, txb, txc;

                // find original uvs
                if (uvs.Length > 0)
                {
                    txa = uvs[i_a];
                    txb = uvs[i_b];
                    txc = uvs[i_c];
                }
                else
                {
                    txa = txb = txc = Vector2.zero;
                }

                // seperation check
                bool aAbove = cutting_plane.IsAbove(a),
                     bAbove = cutting_plane.IsAbove(b),
                     cAbove = cutting_plane.IsAbove(c);

                if (aAbove == bAbove && aAbove == cAbove)
                {
                    // triangle on one side of plane
                    part.indices.Add(part.indexMap[i_a]);
                    part.indices.Add(part.indexMap[i_b]);
                    part.indices.Add(part.indexMap[i_c]);
                }
                else
                {
                    // triangle crosses plane
                    if (aAbove == bAbove)
                    {
                        // a, b, c
                        GenPartialTriangles(
                            cutting_plane,
                            part,
                            a, b, c, txa, txb, txc, i_a, i_b, i_c,
                            allow_cut,
                            addUVs
                            );
                    }
                    else if (aAbove == cAbove)
                    {
                        // c, a, b
                        GenPartialTriangles(
                            cutting_plane,
                            part,
                            c, a, b, txc, txa, txb, i_c, i_a, i_b,
                            allow_cut,
                            addUVs
                            );
                    }
                    else if (bAbove == cAbove)
                    {
                        // b, c, a
                        GenPartialTriangles(
                            cutting_plane,
                            part,
                            b, c, a, txb, txc, txa, i_b, i_c, i_a,
                            allow_cut,
                            addUVs
                            );
                    }
                }
            }

            List <Ring> analysis = param.hiearchyAnalysis ? Hierarchy.Analyse(resulting_rings, cutting_plane.normal) : resulting_rings;

            List <MeshPart> parts = part.PartialPolySeparate(cutting_plane, allow_cut);

            if (parts.Count < 2 && !param.allowSingleResult)
            {
                return(null);
            }

            // generate seperation meshing
            if (parts.Count > 0)
            {
                foreach (var ring in analysis)
                {
                    foreach (var resPart in parts)
                    {
                        GenerateRingMesh(ring, resPart, cutting_plane.normal, param.innerTextureCoord);
                    }
                }
            }

            return(new CutResult(target, parts, cutting_plane.ToWorldSpace().normal, resulting_rings, true));
        }