Beispiel #1
0
        public static void GenIntersection(
            CuttingPlane plane,
            Vector3 a, Vector3 b, Vector3 c,
            RingGenerator rings
            )
        {
            // find intersection vertices
            Vector3 e = plane.Intersection(a, c, Vector2.zero, Vector2.zero, 0).Item1,
                    d = plane.Intersection(b, c, Vector2.zero, Vector2.zero, 0).Item1;

            // 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();
            }

            // 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;

            // add connected pair in ring generator
            rings.AddConnected(dir?e:d, dir?d:e);
        }
Beispiel #2
0
        public RingGenerator Duplicate()
        {
            RingGenerator gen = new RingGenerator();

            gen.complete = complete.ConvertAll(r => r.ConvertAll(v => v));
            gen.partials = partials.ConvertAll(r => r.ConvertAll(v => v));
            return(gen);
        }
Beispiel #3
0
        // ----------------------------
        // Complete rings in triangle
        // ----------------------------
        private static void ConnectIVs(
            HashSet <Vector3> exiting_ivs,
            Vector3 ep1, Vector3 ep2, Vector3 oep,
            Dictionary <float, Vector3> map,
            Dictionary <float, Vector3> prev_map,
            Dictionary <float, Vector3> next_map,
            RingGenerator rings, RingGenerator rings2
            )
        {
            if (map.Count == 0)
            {
                return;
            }
            List <float> keyList = new List <float>(map.Keys);

            keyList.Sort();
            int oneIfFirstIsEntry = 0;

            // Debugging.LogList(keyList);
            // check first is exit or entry
            // connect in relevant ring generator
            if (!exiting_ivs.Contains(map[keyList[0]]))
            {
                // Debug.Log("First is entry");
                // connect first edge point to first entry
                rings.AddConnected(ep1, map[keyList[0]]);
                oneIfFirstIsEntry = 1;
                // if previous are empty, connect around
                if (prev_map.Count == 0)
                {
                    rings.AddConnected(oep, ep1);
                }
            }
            else
            {
                // Debug.Log("First is exit");
                rings2.AddConnected(map[keyList[0]], ep1);
                if (prev_map.Count == 0)
                {
                    rings2.AddConnected(ep1, oep);
                }
            }
            // connect inner
            int i;

            for (i = 1; i < keyList.Count; i++)
            {
                // Debug.Log(map[keyList[i-1]]+" "+map[keyList[i]]);
                if (i % 2 != oneIfFirstIsEntry)
                {
                    rings.AddConnected(map[keyList[i - 1]], map[keyList[i]]);
                }
                else
                {
                    rings2.AddConnected(map[keyList[i]], map[keyList[i - 1]]);
                }
            }
            // check exit or entrance
            // connect to edge point in relevant ring generator
            i = keyList.Count - 1;
            if (exiting_ivs.Contains(map[keyList[i]]))
            {
                //Debug.Log("last was exit");
                rings.AddConnected(map[keyList[i]], ep2);
                if (next_map.Count == 0 && prev_map.Count == 0)
                {
                    rings.AddConnected(ep2, oep);
                }
            }
            else
            {
                // Debug.Log("last was entry");
                rings2.AddConnected(ep2, map[keyList[i]]);
                if (next_map.Count == 0 && prev_map.Count == 0)
                {
                    rings2.AddConnected(oep, ep2);
                }
            }
        }
Beispiel #4
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));
        }
Beispiel #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);
        }
Beispiel #6
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));
        }
Beispiel #7
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));
        }
Beispiel #8
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);
        }
Beispiel #9
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));
        }