コード例 #1
0
        // Note: This method is not optimized! Code is simplified for clarity!
        //          for example: Plane.Distance / Plane.OnSide should be inlined manually and shouldn't use enums, but floating point values directly!
        public PolygonSplitResult PolygonSplit(Plane cuttingPlane, Vector3 translation, ref Polygon inputPolygon, out Polygon outsidePolygon)
        {
            HalfEdge prev		= Edges[inputPolygon.FirstIndex];
            HalfEdge current	= Edges[prev.NextIndex];
            HalfEdge next		= Edges[current.NextIndex];
            HalfEdge last		= next;
            HalfEdge enterEdge	= null;
            HalfEdge exitEdge	= null;

            var prevVertex			= Vertices[prev.VertexIndex];
            var prevDistance		= cuttingPlane.Distance(prevVertex);		// distance to previous vertex
            var prevSide			= Plane.OnSide(prevDistance);				// side of plane of previous vertex

            var currentVertex		= Vertices[current.VertexIndex];
            var currentDistance		= cuttingPlane.Distance(currentVertex);		// distance to current vertex
            var currentSide			= Plane.OnSide(currentDistance);			// side of plane of current vertex

            do
            {
                var nextVertex		= Vertices[next.VertexIndex];
                var nextDistance	= cuttingPlane.Distance(nextVertex);		// distance to next vertex
                var nextSide		= Plane.OnSide(nextDistance);				// side of plane of next vertex

                if (prevSide != currentSide)							// check if edge crossed the plane ...
                {
                    if (currentSide != PlaneSideResult.Intersects)		// prev:inside/outside - current:inside/outside - next:??
                    {
                        if (prevSide != PlaneSideResult.Intersects)		// prev:inside/outside - current:outside        - next:??
                        {
                            // Calculate intersection of edge with plane split the edge into two, inserting the new vertex
                            var newVertex	= Plane.Intersection(prevVertex, currentVertex, prevDistance, currentDistance);
                            var newEdge		= EdgeSplit(current, newVertex);

                            if (prevSide == PlaneSideResult.Inside)		// prev:inside         - current:outside        - next:??
                            {
                                //edge01 exits:
                                //
                                //      outside
                                //         1
                                //         *
                                // ......./........ intersect
                                //       /
                                //      0
                                //      inside

                                exitEdge		= current;
                            } else
                            if (prevSide == PlaneSideResult.Outside)		// prev:outside - current:inside - next:??
                            {
                                //edge01 enters:
                                //
                                //      outside
                                //      0
                                //       \
                                // .......\........ intersect
                                //         *
                                //         1
                                //      inside

                                enterEdge		= current;
                            }

                            prevDistance	= 0;
                            prev			= Edges[prev.NextIndex];
                            prevSide		= PlaneSideResult.Intersects;

                            if (exitEdge != null &&
                                enterEdge != null)
                                break;

                            current			= Edges[prev.NextIndex];
                            currentVertex	= Vertices[current.VertexIndex];

                            next			= Edges[current.NextIndex];
                            nextVertex		= Vertices[next.VertexIndex];
                        }
                    } else												// prev:??                - current:intersects - next:??
                    {
                        if (prevSide == PlaneSideResult.Intersects ||	// prev:intersects        - current:intersects - next:??
                            nextSide == PlaneSideResult.Intersects ||	// prev:??                - current:intersects - next:intersects
                            prevSide == nextSide)						// prev:inside/outde      - current:intersects - next:inside/outde
                        {
                            if (prevSide == PlaneSideResult.Inside ||	// prev:inside            - current:intersects - next:intersects/inside
                                nextSide == PlaneSideResult.Inside)		// prev:intersects/inside - current:intersects - next:inside
                            {
                                //      outside
                                // 0       1
                                // --------*....... intersect
                                //          \
                                //           2
                                //       inside
                                //
                                //      outside
                                //         1      2
                                // ........*------- intersect
                                //        /
                                //       0
                                //      inside
                                //
                                //     outside
                                //        1
                                //........*....... intersect
                                //       / \
                                //      0   2
                                //      inside
                                //

                                prevSide = PlaneSideResult.Inside;
                                enterEdge = exitEdge = null;
                                break;
                            } else
                            if (prevSide == PlaneSideResult.Outside ||		// prev:outside            - current:intersects - next:intersects/outside
                                nextSide == PlaneSideResult.Outside)		// prev:intersects/outside - current:intersects - next:outside
                            {
                                //     outside
                                //          2
                                //         /
                                //..------*....... intersect
                                //  0     1
                                //     inside
                                //
                                //     outside
                                //      0
                                //       \
                                //........*------- intersect
                                //        1      2
                                //     inside
                                //
                                //     outside
                                //      0   2
                                //       \ /
                                //........*....... intersect
                                //        1
                                //     inside
                                //

                                prevSide = PlaneSideResult.Outside;
                                enterEdge = exitEdge = null;
                                break;
                            }
                        } else											// prev:inside/outside - current:intersects - next:inside/outside
                        {
                            if (prevSide == PlaneSideResult.Inside)		// prev:inside         - current:intersects - next:outside
                            {
                                //find exit edge:
                                //
                                //      outside
                                //           2
                                //        1 /
                                // ........*....... intersect
                                //        /
                                //       0
                                //       inside

                                exitEdge = current;
                                if (enterEdge != null)
                                    break;
                            } else										// prev:outside        - current:intersects - next:inside
                            {
                                //find enter edge:
                                //
                                //      outside
                                //       0
                                //        \ 1
                                // ........*....... intersect
                                //          \
                                //           2
                                //       inside

                                enterEdge = current;
                                if (exitEdge != null)
                                    break;
                            }
                        }
                    }
                }

                prev	= current;
                current = next;
                next	= Edges[next.NextIndex];

                prevDistance	= currentDistance;
                currentDistance = nextDistance;
                prevSide		= currentSide;
                currentSide		= nextSide;
                prevVertex		= currentVertex;
                currentVertex	= nextVertex;
            } while (next != last);

            // We should never have only one edge crossing the plane ..
            Debug.Assert((enterEdge == null) == (exitEdge == null));

            // Check if we have an edge that exits and an edge that enters the plane and split the polygon into two if we do
            if (enterEdge != null && exitEdge != null)
            {
                //enter   .
                //        .
                //  =====>*----->
                //        .
                //
                //outside . inside
                //        .
                //  <-----*<=====
                //        .
                //        .  exit

                outsidePolygon = new Polygon();
                var outsidePolygonIndex = (short)this.Polygons.Count;
                this.Polygons.Add(outsidePolygon);

                var outsideEdge			= new HalfEdge();
                var outsideEdgeIndex	= (short)Edges.Count;

                var insideEdge			= new HalfEdge();
                var insideEdgeIndex		= (short)(outsideEdgeIndex + 1);

                outsideEdge.TwinIndex		= insideEdgeIndex;
                insideEdge.TwinIndex		= outsideEdgeIndex;

                //insideEdge.PolygonIndex	= inputPolygonIndex;// index does not change
                outsideEdge.PolygonIndex	= outsidePolygonIndex;

                outsideEdge.VertexIndex		= exitEdge.VertexIndex;
                insideEdge.VertexIndex		= enterEdge.VertexIndex;

                outsideEdge.NextIndex		= exitEdge.NextIndex;
                insideEdge.NextIndex		= enterEdge.NextIndex;

                exitEdge.NextIndex			= insideEdgeIndex;
                enterEdge.NextIndex			= outsideEdgeIndex;

                outsidePolygon.FirstIndex	= outsideEdgeIndex;
                inputPolygon.FirstIndex		= insideEdgeIndex;

                outsidePolygon.Visible		= inputPolygon.Visible;
                outsidePolygon.Category		= inputPolygon.Category;
                outsidePolygon.PlaneIndex	= inputPolygon.PlaneIndex;

                Edges.Add(outsideEdge);
                Edges.Add(insideEdge);

                // calculate the bounds of the polygons
                outsidePolygon.Bounds.Clear();
                var first = Edges[outsidePolygon.FirstIndex];
                var iterator = first;
                do
                {
                    outsidePolygon.Bounds.Add(Vertices[iterator.VertexIndex]);
                    iterator.PolygonIndex = outsidePolygonIndex;
                    iterator = Edges[iterator.NextIndex];
                } while (iterator != first);

                inputPolygon.Bounds.Clear();
                first = Edges[inputPolygon.FirstIndex];
                iterator = first;
                do
                {
                    inputPolygon.Bounds.Add(Vertices[iterator.VertexIndex]);
                    iterator = Edges[iterator.NextIndex];
                } while (iterator != first);

                return PolygonSplitResult.Split;
            } else
            {
                outsidePolygon = null;
                switch (prevSide)
                {
                    case PlaneSideResult.Inside:	return PolygonSplitResult.CompletelyInside;
                    case PlaneSideResult.Outside:	return PolygonSplitResult.CompletelyOutside;
                    default:
                    case PlaneSideResult.Intersects:
                    {
                        var polygonPlane = Planes[inputPolygon.PlaneIndex];
                        var result = Vector3.Dot(polygonPlane.Normal, cuttingPlane.Normal);
                        if (result > 0)
                            return PolygonSplitResult.PlaneAligned;
                        else
                            return PolygonSplitResult.PlaneOppositeAligned;
                    }
                }
            }
        }
コード例 #2
0
ファイル: ObjLoader.cs プロジェクト: glocklueng/cnc_machine
        static float DistanceToCylinder(Vector3 cy1, Vector3 cy2, Vector3 point)
        {
            float distance = 0;

            if ((cy1 - cy2).Length < 0.0001)
            {
                return (cy1 - point).Length;
            }

            Plane p = new Plane();
            p.normal = cy1 - cy2;
            p.normal.Normalize();
            p.point = cy2;

            float d1 = p.Distance(point);

            p.normal = -p.normal;
            p.point = cy1;
            float d2 = p.Distance(point);

            if (float.IsNaN(d2) || float.IsNaN(d1))
            {
            }

            if (Math.Sign(d1) == Math.Sign(d2))
            {
                // Inside Endpoints
                Vector3 pt = point - p.normal * d2;
                distance = (pt - p.point).Length;
            }
            else
            {
                distance = (float)Math.Min((point - cy1).Length, (point - cy2).Length);
            }

            return distance;
        }
コード例 #3
0
ファイル: ObjLoader.cs プロジェクト: glocklueng/cnc_machine
            public Intersect CalculateIntersect(Vector3 location, Vector3 direction)
            {
                Intersect i = new Intersect();

                i.intersectPoint = new Vector3(0, 0, 0);
                i.intersects = false;

                Plane plane = new Plane(this);

                float distance = plane.Distance(location, direction);
                //Console.WriteLine("Distance = {0}", distance);

                i.distance = distance;
                i.intersectPoint = distance * direction + location;
                if (distance < 0)
                {
                    i.intersects = false;
                }
                else
                {
                    i.intersects = ObjLoader.IsPointInPolygon(this, i.intersectPoint);
                }

                return i;
            }
コード例 #4
0
ファイル: ObjLoader.cs プロジェクト: glocklueng/cnc_machine
            /// <summary>
            /// Trim interior loops from the line
            /// </summary>
            public void Clean(Vector3 normal)
            {
                List<int> remove = new List<int>();
                for (int i = 0; i < indices.Count(); i++)
                {
                    Vector3 v1 = GetVertex(i);
                    Vector3 v2 = GetVertex((i + 1) % indices.Count());
                    for (int j = 2; j < indices.Count() - 1; j++)
                    {
                        int j1 = (j + i) % indices.Count();
                        int j2 = (j + i + 1) % indices.Count();
                        Vector3 v3 = GetVertex(j1);
                        Vector3 v4 = GetVertex(j2);

                        Vector3 n1 = v2 - v1;
                        Vector3 n2 = v4 - v3;
                        n1.Normalize();
                        n2.Normalize();

                        if ((n1 - n2).Length < 0.0001f)
                        {
                            // No crossing, same direction
                            continue;
                        }

                        Vector3 perp = Vector3.Cross(normal, n2);
                        Plane p = new Plane ();

                        //GL.Begin(BeginMode.Lines);
                        //GL.Vertex3(v4);
                        //GL.Vertex3(v4 + perp * 100);
                        //GL.End();
                        p.normal = perp;
                        p.point = v3;

                        float distance = p.Distance(v1, n1);
                        if (distance > 0 && distance < (v2 - v1).Length && (Vector3.Dot(perp, n1) < 0))//!float.IsInfinity(distance))
                        {
                            Vector3 point = n1 * distance + v1;
                            if (DistanceToCylinder (v3, v4, point) < 0.01f)
                            {
                                for (int k = 0; k < j; k++)
                                {
                                    int removeIndex = (i + 1) % indices.Count();
                                    indices.RemoveAt(removeIndex);
                                }
                                vertices.Add(point);
                                indices.Insert(i + 1, vertices.Count() - 1);
                                //GL.PointSize(15);
                                //GL.Color3(Color.Turquoise);
                                //GL.Begin(BeginMode.Points);
                                //GL.Vertex3(point);
                                //
                                //GL.End();
                                //GL.PointSize(1);
                                i = i - 1;
                                continue;
                            }
                        }
                    }
                }
                LineLoop n = new LineLoop(this);
                this.indices = n.indices;
                this.vertices = n.vertices;
            }
コード例 #5
0
ファイル: ObjLoader.cs プロジェクト: glocklueng/cnc_machine
        private PolyLine TrianglePlaneIntersect(Face f, Plane p)
        {
            PolyLine polyLine = new PolyLine();

            float epsilon = 0.01f; // TODO: Auto compute based on scale
            float epsilon_unit = 0.00001f; // Unit size epsilon value
            Vector3 f_normal = f.Normal;
            f_normal.Normalize();
            p.normal.Normalize();

            if ((f_normal - p.normal).Length < epsilon_unit || (f_normal + p.normal).Length < epsilon_unit)
            {
                // No intersection
            }
            else
            {
                Vector3 expected_direction = Vector3.Cross(f.Normal, p.normal);

                // Assume we're dealing with triangles only
                int verts = f.vertices.Count();
                if (verts != 3)
                {
                    throw new Exception("The number of vertices is not 3!");
                }

                float[] d = new float[3];
                for (int i = 0; i < 3; i++)
                {
                    d[i] = p.Distance(f.vertices[i]);
                }

                for (int i = 0; i < 3; i++)
                {
                    // Is the line on the plane?
                    if (Math.Abs(d[i]) < epsilon && Math.Abs(d[(i + 1) % 3]) < epsilon)
                    {
                        polyLine.points.Add(f.vertices[i]);
                        polyLine.points.Add(f.vertices[(i + 1) % 3]);
                        break;
                    }
                }

                if (polyLine.points.Count() == 0)
                {
                    // Line not on a plain: might have an intersection with a point and the opposite line
                    for (int i = 0; i < 3; i++)
                    {
                        float d1 = d[i];
                        float d2 = d[(i + 1) % 3];
                        float d3 = d[(i + 2) % 3];
                        if (Math.Abs(d[i]) < epsilon && Math.Sign(d2) != Math.Sign(d3))
                        {
                            d2 = Math.Abs(d2);
                            d3 = Math.Abs(d3);

                            // One negative, one positive
                            float total = d2 + d3;
                            Vector3 result = (f.vertices[(i + 1) % 3] * d3 + f.vertices[(i + 2) % 3] * d2) / total;
                            polyLine.points.Add(f.vertices[i]);
                            polyLine.points.Add(result);
                            break;
                        }
                    }
                    if (polyLine.points.Count() == 0)
                    {
                        // No edge in plane and no point + line intersect: maybe two lines intersect?
                        for (int i = 0; i < 3; i++)
                        {
                            // Intersection with an edge
                            if (Math.Sign(d[i]) != Math.Sign(d[(i + 1) % 3]))
                            {
                                float d1 = Math.Abs(d[i]);
                                float d2 = Math.Abs(d[(i + 1) % 3]);
                                float total = d1 + d2;
                                Vector3  result = (f.vertices[i] * d2 + f.vertices[(i + 1) % 3] * d1) / total;
                                polyLine.points.Add(result);
                                if (polyLine.points.Count() == 2)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                if (polyLine.points.Count() >= 2)
                {
                    //DrawCone1(polyLine.points[0], polyLine.points[1]);
                    Vector3 direction = polyLine.points[1] - polyLine.points[0];
                    if (Vector3.Dot(direction, expected_direction) < 0)
                    {
                        PolyLine reversed = new PolyLine();
                        reversed.points.Add(polyLine.points[1]);
                        reversed.points.Add(polyLine.points[0]);
                        polyLine = reversed;
                    }
                //
                //
                //    Color[] colors = new Color[] { Color.DarkRed, Color.LightGreen, Color.DarkBlue };
                //    int i = 0;
                //    GL.Begin(BeginMode.LineLoop);
                //    foreach (Vector3 v in polyLine.points)
                //    {
                //        GL.Color3(colors[i++]);
                //        GL.Vertex3(v);
                //
                //    }
                //    GL.End();
                //
                //    GL.PointSize(10);
                //    GL.Color3(Color.Orange);
                //    GL.Begin(BeginMode.Points);
                //    foreach (Vector3 v in polyLine.points)
                //    {
                //        GL.Vertex3(v);
                //    }
                //    GL.End();
                //    GL.PointSize(1);
                }
            }
            return polyLine;
        }