Exemplo n.º 1
0
        private static void AddPoint([CanBeNull] Matrix3x2?transform, Vector2 point, List <ContourVertex> vertices)
        {
            ContourVertex vertex;

            if (transform != null)
            {
                var pt = Matrix3x2.Transform(transform.Value, point);
                vertex = new ContourVertex {
                    Position = new Vec3 {
                        X = pt.X,
                        Y = pt.Y,
                        Z = StandardZ
                    }
                };
            }
            else
            {
                vertex = new ContourVertex {
                    Position = new Vec3 {
                        X = point.X,
                        Y = point.Y,
                        Z = StandardZ
                    }
                };
            }

            vertices.Add(vertex);
        }
        public List <VertexPositionColor> GetTesselationVertices(Color color)
        {
            var fakeSector = new CubeSector(CubeSector.CubeSectorFace.FRONT, 0, 0, 8);
            List <List <ContourVertex> > contours = new List <List <ContourVertex> >();

            foreach (var inner in inners)
            {
                var innerContour = inner.Skip(1).Select(x => Vector2DToContourVertex(x, true)).ToList(); // skip 1 since our loops end in a duplicate
                if (innerContour.Count == 3)
                {
                    // TODO: the tesselator just doesn't like triangles!? seriously??
                    var avg01 = new ContourVertex()
                    {
                        Position = new Vec3()
                        {
                            X = innerContour[0].Position.X / 2 + innerContour[1].Position.X / 2, Y = innerContour[0].Position.Y / 2 + innerContour[1].Position.Y / 2, Z = 0
                        }, Data = innerContour[0].Data
                    };
                    innerContour.Insert(1, avg01);
                }
                contours.Add(innerContour);
            }
            foreach (var outer in outers)
            {
                var outerContours = new List <List <ContourVertex> >()
                {
                    outer.Skip(1).Select(y => Vector2DToContourVertex(y)).ToList()
                };                                                                                                                      // skip 1 since our loops end in a duplicate
                contours.AddRange(outerContours);
            }
            var vertices = OSMPolygonBufferGenerator.Tesselate(contours, color);

            return(vertices);
        }
Exemplo n.º 3
0
        void tessPoly(PointF[] source, Color polyColor, float alpha)
        {
            // Now we need to check for polyfill, and triangulate the polygon if needed.
            //if (enableFilledPolys)
            {
                var tess = new Tess();

                ContourVertex[] contour = new ContourVertex[source.Length];
                for (int pt = 0; pt < contour.Length; pt++)
                {
                    contour[pt].Position = new Vec3 {
                        X = source[pt].X, Y = source[pt].Y, Z = 0
                    };
                }
                tess.AddContour(contour, ContourOrientation.Clockwise);                 // keep our orientation to allow holes to be handled.

                // Triangulate.
                tess.Tessellate(WindingRule.NonZero, ElementType.Polygons, 3);                 // We don't have any hole polygons here.

                // Iterate triangles and create output geometry
                for (int i = 0; i < tess.ElementCount; i++)
                {
                    PointF[] tempPoly = new PointF[3];                     // 3 points.
                    tempPoly[0] = new PointF((float)tess.Vertices[tess.Elements[i * 3]].Position.X, (float)tess.Vertices[tess.Elements[i * 3]].Position.Y);
                    tempPoly[1] = new PointF((float)tess.Vertices[tess.Elements[(i * 3) + 1]].Position.X, (float)tess.Vertices[tess.Elements[(i * 3) + 1]].Position.Y);
                    tempPoly[2] = new PointF((float)tess.Vertices[tess.Elements[(i * 3) + 2]].Position.X, (float)tess.Vertices[tess.Elements[(i * 3) + 2]].Position.Y);

                    tessPolyList.Add(new ovp_Poly(clockwiseOrder(tempPoly).ToArray(), polyColor, alpha));
                }
            }
        }
Exemplo n.º 4
0
        protected virtual int[] GetTriangleIndices()
        {
            if (tess == null)
            {
                tess = new Tess();
            }

            var contour = new ContourVertex[Vertices.Count];

            for (var i = 0; i < contour.Length; i++)
            {
                var vertex = Vertices[i];
                contour[i].Position = new Vec3 {
                    X = vertex.X, Y = vertex.Y
                };
            }

            tess.AddContour(contour, ContourOrientation.Clockwise);
            tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3);

            var indices = new int[tess.Elements.Length];

            for (var i = 0; i < indices.Length; i++)
            {
                var position = tess.Vertices[tess.Elements[i]].Position;
                indices[i] = Vertices.IndexOf(new Vector2(position.X, position.Y));
            }

            return(indices);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Gets a triangulation, where the Indices are related to the Points
        /// </summary>
        /// <param name="Indices">Indices</param>
        /// <param name="Points">List ofPoints</param>
        public void TriAngulation(List <IndexType> Indices, List <xyf> Points)
        {
            Tess Tess = new Tess();

            Tess.UsePooling = true;

            for (int i = 0; i < Count; i++)
            {
                ContourVertex[] CV = new ContourVertex[this[i].Count];
                for (int j = 0; j < this[i].Count; j++)
                {
                    CV[j] = new ContourVertex();

                    CV[j].Position.X = (float)this[i][j].X;
                    CV[j].Position.Y = (float)this[i][j].Y;
                }
                Tess.AddContour(CV);
            }
            Tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3);
            Indices.Clear();
            for (int i = 0; i < Tess.Elements.Length; i++)
            {
                Indices.Add((IndexType)(Tess.Elements[i]));
            }

            for (int i = 0; i < Tess.Vertices.Length; i++)
            {
                Points.Add(new xyf(Tess.Vertices[i].Position.X, Tess.Vertices[i].Position.Y));
            }
        }
Exemplo n.º 6
0
        internal List <List <ContourVertex> > ToContours()
        {
            List <List <ContourVertex> > contours = new List <List <ContourVertex> >();
            List <GraphNode>             starts   = nodes.Where(x => x.prevConnections.Count == 0 && x.nextConnections.Count == 1).ToList();
            HashSet <GraphNode>          visited  = new HashSet <GraphNode>();

            foreach (var start in starts)
            {
                List <ContourVertex> contour = new List <ContourVertex>();
                GraphNode            next    = start;
                GraphNode            prev    = null;
                while (next != null)
                {
                    ContourVertex vertex = new ContourVertex();
                    vertex.Position = new Vec3 {
                        X = (float)next.pos.X, Y = (float)next.pos.Y, Z = 0
                    };
                    contour.Add(vertex);
                    visited.Add(next);
                    GraphNode nextnext = GetNext(prev, next);
                    prev = next;
                    next = nextnext;
                }
                if (contour.Count > 0)
                {
                    contours.Add(contour);
                }
            }
            // now find the loops
            foreach (var node in nodes)
            {
                List <ContourVertex> contour = new List <ContourVertex>();
                GraphNode            next    = node;
                GraphNode            prev    = null;
                while (!visited.Contains(next))
                {
                    ContourVertex vertex = new ContourVertex();
                    vertex.Data     = next.isHole; // TODO: get rid of this
                    vertex.Position = new Vec3 {
                        X = (float)next.pos.X, Y = (float)next.pos.Y, Z = 0
                    };
                    contour.Add(vertex);
                    visited.Add(next);
                    GraphNode nextnext = GetNext(prev, next);
                    if (nextnext == null)
                    {
                        break;
                    }
                    prev = next;
                    next = nextnext;
                }
                if (contour.Count > 0)
                {
                    contour.Add(contour[0]); // close it?
                    contours.Add(contour);
                }
            }
            return(contours);
        }
        public static void GenerateFillMesh(ShapeData shape, MeshBuilder meshBuilder)
        {
            Profiler.BeginSample("GenerateFillMesh");
            if (shape.GetVertexInfoList().Count < 3)
            {
                return;
            }

            Matrix4x4 m = Matrix4x4.TRS(Vector3.zero, Quaternion.LookRotation(shape.FillNormal), Vector3.one).inverse;

            // tesselation
            ContourVertex[] contour = new ContourVertex[shape.GetVertexInfoList().Count - 2 - (shape.IsStrokeClosed ? 1 : 0)];             // ignore first and last point

            for (int i = 0; i < contour.Length; i++)
            {
                Vector3 p = m.MultiplyPoint(shape.GetVertexInfoList()[i + 1].position);

                var pos = new Vec3();
                pos.X = p.x;
                pos.Y = p.y;
                pos.Z = 0;

                var v = new ContourVertex();
                v.Position = pos;
                v.Data     = shape.GetVertexInfoList()[i + 1].position;
                contour[i] = v;
            }

            if (tesselator == null)
            {
                tesselator = new Tess();
                //tesselator.UsePooling = true;
            }
            tesselator.AddContour(contour, ContourOrientation.CounterClockwise);
            tesselator.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3, delegate(Vec3 position, object[] data, float[] weights)
            {
                return((Vector3)data[0] * weights[0] + (Vector3)data[1] * weights[1] + (Vector3)data[2] * weights[2] + (Vector3)data[3] * weights[3]);
            });


            meshBuilder.currentSubmesh = 0;
            for (int i = 0; i < tesselator.ElementCount; i++)
            {
                meshBuilder.AddTriangle(
                    meshBuilder.currentVertCount + tesselator.Elements[i * 3 + 0],
                    meshBuilder.currentVertCount + tesselator.Elements[i * 3 + 1],
                    meshBuilder.currentVertCount + tesselator.Elements[i * 3 + 2]);
            }

            for (int i = 0; i < tesselator.Vertices.Length; i++)
            {
                meshBuilder.AddVert();
                meshBuilder.SetCurrentPosition((Vector3)tesselator.Vertices[i].Data);
                meshBuilder.SetCurrentColor(shape.FillColor);
                meshBuilder.SetCurrentUV0((Vector2)(Vector3)tesselator.Vertices[i].Data);
            }

            Profiler.EndSample();
        }
Exemplo n.º 8
0
        internal void Tessellate(TessellatorPool tessellators)
        {
            if (Indices == null)
            {
                if (actualPositions.Length == 4)
                {
                    Indices = SpriteIndices;
                    return;
                }
                var pos         = new ContourVertex[actualPositions.Length];
                var tessellator = tessellators.GetTessellatorAvailable();
                try
                {
                    for (int i = 0; i < actualPositions.Length; i++)
                    {
                        pos[i] = actualPositions[i].GetContourVertex();
                    }

                    tessellator.AddContour(pos, ContourOrientation.Clockwise);
                    tessellator.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3);
                    Indices = new short[tessellator.Elements.Length];
                    Span <short> indexConversionTable = stackalloc short[actualPositions.Length];
                    indexConversionTable.Fill(-1);
                    if (tessellator.VertexCount != actualPositions.Length)                      //Detecting addition or deletion of points
                    {
                        throw new ArithmeticException("The shapes may be intersecting.");
                    }
                    else
                    {
                        for (var i = 0; i < tessellator.Elements.Length; i++)
                        {
                            int   index = tessellator.Elements[i];
                            short conv  = indexConversionTable[index];
                            if (conv == -1)
                            {
                                var   position = tessellator.Vertices[index].Position.GetVector();
                                short q        = (short)Array.FindIndex(actualPositions, a => a.Position == position);
                                if (q == -1)
                                {
                                    throw new KeyNotFoundException("No matching value was found.");
                                }
                                indexConversionTable[index] = Indices[i] = q;
                            }
                            else
                            {
                                Indices[i] = conv;
                            }
                        }
                    }
                }
                finally
                {
                    tessellators.ReturnTessellator(tessellator);
                }
            }
        }
        /// <summary>
        /// Gets the contour vertex.
        /// </summary>
        /// <param name="vertexPositionColorTexture">The vertex position color texture.</param>
        /// <returns></returns>
        public static ContourVertex GetContourVertex(this VertexPositionColorTexture vertexPositionColorTexture)
        {
            var g = new ContourVertex();

            g.Position = new Vec3()
            {
                X = vertexPositionColorTexture.Position.X, Y = vertexPositionColorTexture.Position.Y, Z = vertexPositionColorTexture.Position.Z
            };
            return(g);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Adds a closed contour to be tessellated.
        /// </summary>
        /// <param name="vertices"> Vertices of the contour. </param>
        /// <param name="forceOrientation">
        /// Orientation of the contour.
        /// <see cref="ContourOrientation.Original"/> keeps the orientation of the input vertices.
        /// <see cref="ContourOrientation.Clockwise"/> and <see cref="ContourOrientation.CounterClockwise"/>
        /// force the vertices to have a specified orientation.
        /// </param>
        public void AddContour(IList <Vector3> vertices, ContourOrientation forceOrientation = ContourOrientation.Original)
        {
            var contour = new ContourVertex[vertices.Count];

            for (int i = 0; i < vertices.Count; i++)
            {
                Vector3 vertex = vertices[i];
                contour[i].Position = new Vec3(vertex.x, vertex.y, vertex.z);
            }
            tess.AddContour(contour, forceOrientation);
        }
Exemplo n.º 11
0
        private void RefreshAsset(string name)
        {
            var asset = _data.GetAsset(name);

            _sw.Reset();

            foreach (var poly in asset.Polygons)
            {
                var v = new ContourVertex[poly.Count];
                for (int i = 0; i < poly.Count; i++)
                {
                    v[i].Position = new Vec3 {
                        X = poly[i].X, Y = poly[i].Y
                    };
                    v[i].Data = poly[i].Color;
                }
                _sw.Start();
                _tess.AddContour(v, poly.Orientation);
                _sw.Stop();
            }

            _sw.Start();
            _tess.Tessellate(_windingRule, ElementType.Polygons, _polySize, VertexCombine);
            _sw.Stop();

            var output = new PolygonSet();

            for (int i = 0; i < _tess.ElementCount; i++)
            {
                var poly = new Polygon();
                for (int j = 0; j < _polySize; j++)
                {
                    int index = _tess.Elements[i * _polySize + j];
                    if (index == -1)
                    {
                        continue;
                    }
                    var v = new PolygonPoint {
                        X     = _tess.Vertices[index].Position.X,
                        Y     = _tess.Vertices[index].Position.Y,
                        Color = (Color)_tess.Vertices[index].Data
                    };
                    poly.Add(v);
                }
                output.Add(poly);
            }

            statusMain.Text = string.Format("{0:F3} ms - {1} polygons (of {2} vertices) {3}", _sw.Elapsed.TotalMilliseconds, _tess.ElementCount, _polySize, _polySize == 3 ? "... triangles" : "");

            _canvas.Input  = asset.Polygons;
            _canvas.Output = output;
            _canvas.Invalidate();
        }
Exemplo n.º 12
0
        List <PointF[]> checkPoly(PointF[] poly)
        {
            List <PointF[]> output = new List <PointF[]>();

            PointF[] source = poly.ToArray();

            if ((poly[0].X != poly[poly.Length - 1].X) && (poly[0].Y != poly[poly.Length - 1].Y))
            {
                PointF[] tempPoly = new PointF[poly.Length + 1];
                for (int pt = 0; pt < poly.Length; pt++)
                {
                    tempPoly[pt] = new PointF(poly[pt].X, poly[pt].Y);
                }
                tempPoly[tempPoly.Length - 1] = new PointF(tempPoly[0].X, tempPoly[0].Y);
                source = tempPoly.ToArray();
            }

            // Now we need to check for polyfill, and triangulate the polygon if needed.
            if (enableFilledPolys)
            {
                var tess = new Tess();

                ContourVertex[] contour = new ContourVertex[source.Length];
                for (int pt = 0; pt < contour.Length; pt++)
                {
                    contour[pt].Position = new Vec3 {
                        X = source[pt].X, Y = source[pt].Y, Z = 0
                    };
                }
                tess.AddContour(contour, ContourOrientation.Clockwise);                 // keep our orientation to allow holes to be handled.

                // Triangulate.
                tess.Tessellate(WindingRule.Positive, ElementType.Polygons, 3);                 // We don't have any hole polygons here.

                // Iterate triangles and create output geometry
                for (int i = 0; i < tess.ElementCount; i++)
                {
                    PointF[] tempPoly = new PointF[3];                     // 3 points.
                    tempPoly[0] = new PointF((float)tess.Vertices[tess.Elements[i * 3]].Position.X, (float)tess.Vertices[tess.Elements[i * 3]].Position.Y);
                    tempPoly[1] = new PointF((float)tess.Vertices[tess.Elements[(i * 3) + 1]].Position.X, (float)tess.Vertices[tess.Elements[(i * 3) + 1]].Position.Y);
                    tempPoly[2] = new PointF((float)tess.Vertices[tess.Elements[(i * 3) + 2]].Position.X, (float)tess.Vertices[tess.Elements[(i * 3) + 2]].Position.Y);

                    output.Add(clockwiseOrder(tempPoly).ToArray());
                }
            }
            else
            {
                output.Add(source.ToArray());
            }

            return(output);
        }
        public static void GenerateShadowMesh(Mesh mesh, Vector3[] shapePath)
        {
            Color          meshInteriorColor = new Color(0, 0, 0, 1);
            List <Vector3> vertices          = new List <Vector3>();
            List <int>     triangles         = new List <int>();
            List <Vector4> tangents          = new List <Vector4>();

            // Create interior geometry
            int pointCount = shapePath.Length;
            var inputs     = new ContourVertex[pointCount];

            for (int i = 0; i < pointCount; ++i)
            {
                inputs[i] = new ContourVertex()
                {
                    Position = new Vec3()
                    {
                        X = shapePath[i].x, Y = shapePath[i].y
                    }, Data = meshInteriorColor
                }
            }
            ;

            Tess tessI = new Tess();

            tessI.AddContour(inputs, ContourOrientation.Original);
            tessI.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3, InterpCustomVertexData);

            var indicesI  = tessI.Elements.Select(i => i).ToArray();
            var verticesI = tessI.Vertices.Select(v => new Vector3(v.Position.X, v.Position.Y, 0)).ToArray();

            vertices.AddRange(verticesI);
            triangles.AddRange(indicesI);

            InitializeTangents(vertices.Count, tangents);

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

            PopulateEdgeArray(vertices, triangles, edges);
            SortEdges(edges);
            CreateShadowTriangles(vertices, triangles, tangents, edges);

            Vector3[] finalVertices  = vertices.ToArray();
            int[]     finalTriangles = triangles.ToArray();
            Vector4[] finalTangents  = tangents.ToArray();

            mesh.Clear();
            mesh.vertices  = finalVertices;
            mesh.triangles = finalTriangles;
            mesh.tangents  = finalTangents;
        }
    }
Exemplo n.º 14
0
        /// <summary>
        /// trs vertices to eliminate Z and eleminate duplicates
        /// </summary>
        ContourVertex[] make2DSegment(CGVolume vol, int index)
        {
            Matrix4x4 m   = getMat(vol, index, false);
            int       idx = vol.GetSegmentIndex(index);

            ContourVertex[] res = new ContourVertex[vol.CrossSize];
            for (int i = 0; i < vol.CrossSize; i++)
            {
                res[i] = m.MultiplyPoint(vol.Vertex[idx + i]).ContourVertex();
            }

            return(res);
        }
Exemplo n.º 15
0
 public static void ToTess(PolygonSet pset, Tess tess)
 {
     foreach (var poly in pset)
     {
         var v = new ContourVertex[poly.Count];
         for (int i = 0; i < poly.Count; i++)
         {
             v[i].Position = new Vec3(poly[i].X, poly[i].Y, poly[i].Z);
             v[i].Data     = poly[i].Color;
         }
         tess.AddContour(v, poly.Orientation);
     }
 }
Exemplo n.º 16
0
        private static void BuildGeometryFromClipPaths(VectorUtils.Geometry geom, List <List <IntPoint> > paths, List <Vector2> outVerts, List <UInt16> outInds, ref UInt16 maxIndex)
        {
            var vertices    = new List <Vector2>(100);
            var indices     = new List <UInt16>(vertices.Capacity * 3);
            var vertexIndex = new Dictionary <IntPoint, UInt16>();

            foreach (var path in paths)
            {
                if (path.Count == 3)
                {
                    // Triangle case, no need to tessellate
                    foreach (var pt in path)
                    {
                        StoreClipVertex(vertexIndex, vertices, indices, pt, ref maxIndex);
                    }
                }
                else if (path.Count > 3)
                {
                    // Generic polygon case, we need to tessellate first
                    var tess    = new Tess();
                    var contour = new ContourVertex[path.Count];
                    for (int i = 0; i < path.Count; ++i)
                    {
                        contour[i] = new ContourVertex()
                        {
                            Position = new Vec3()
                            {
                                X = path[i].X, Y = path[i].Y, Z = 0.0f
                            }
                        }
                    }
                    ;
                    tess.AddContour(contour, ContourOrientation.Original);

                    var windingRule = WindingRule.NonZero;
                    tess.Tessellate(windingRule, ElementType.Polygons, 3);

                    foreach (var e in tess.Elements)
                    {
                        var v  = tess.Vertices[e];
                        var pt = new IntPoint(v.Position.X, v.Position.Y);
                        StoreClipVertex(vertexIndex, vertices, indices, pt, ref maxIndex);
                    }
                }
            }

            var invMatrix = geom.WorldTransform.Inverse();

            outVerts.AddRange(vertices.Select(v => invMatrix * v));
            outInds.AddRange(indices);
        }
Exemplo n.º 17
0
        internal static ContourVertex[] ToContourVertexArray(this Polygon poly)
        {
            var contour = new List <ContourVertex>();

            foreach (var vert in poly.Vertices)
            {
                var cv = new ContourVertex();
                cv.Position = new Vec3 {
                    X = vert.X, Y = vert.Y, Z = vert.Z
                };
                contour.Add(cv);
            }
            return(contour.ToArray());
        }
Exemplo n.º 18
0
        public static UnityEngine.Mesh BuildMesh(List <Vector2[]> contours)
        {
            Tess tesselation = new Tess();

            foreach (Vector2[] contour in contours)
            {
                if (contour == null)
                {
                    continue;
                }

                int             pathLength = contour.Length;
                ContourVertex[] path       = new ContourVertex[pathLength];
                for (int j = 0; j < pathLength; j++)
                {
                    Vector2 position = contour[j];
                    path[j].Position = new Vec3 {
                        X = position.x, Y = position.y, Z = 0f
                    };
                }
                tesselation.AddContour(path);
            }

            tesselation.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3);

            UnityEngine.Mesh mesh = new UnityEngine.Mesh();
            int meshVertexCount   = tesselation.Vertices.Length;

            Vector3[] vertices = new Vector3[meshVertexCount];

            for (int i = 0; i < meshVertexCount; i++)
            {
                vertices[i] = new Vector3(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y, 0f);
            }

            int numTriangles = tesselation.ElementCount;

            int[] triangles = new int[numTriangles * 3];
            for (int i = 0; i < numTriangles; i++)
            {
                triangles[i * 3]     = tesselation.Elements[i * 3];
                triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1];
                triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2];
            }

            mesh.vertices  = vertices;
            mesh.triangles = triangles;

            return(mesh);
        }
Exemplo n.º 19
0
        private void AddContour(Tess tess, Polygon p, bool reversed = false)
        {
            var numPoints = p.Vertices.Count;
            var contour   = new ContourVertex[numPoints];

            for (var i = 0; i < numPoints; i++)
            {
                var v = p.Vertices[i];
                contour[i].Position = new Vec3 {
                    X = v.X, Y = v.Y, Z = v.Z
                };
            }
            tess.AddContour(contour, reversed ? ContourOrientation.Clockwise : ContourOrientation.CounterClockwise);
        }
Exemplo n.º 20
0
        internal static ContourVertex[] ToContourVertexArray(this List <Vector3> pts)
        {
            var contour = new ContourVertex[pts.Count];

            for (var i = 0; i < contour.Length; i++)
            {
                var v = pts[i];
                contour[i]          = new ContourVertex();
                contour[i].Position = new Vec3 {
                    X = v.X, Y = v.Y, Z = v.Z
                };
            }
            return(contour);
        }
Exemplo n.º 21
0
        internal ContourVertex[] ToContourVertexArray()
        {
            var contour = new ContourVertex[this.Vertices.Length];

            for (var i = 0; i < this.Vertices.Length; i++)
            {
                var v = this.Vertices[i];
                contour[i]          = new ContourVertex();
                contour[i].Position = new Vec3 {
                    X = v.Position.X, Y = v.Position.Y, Z = v.Position.Z
                };
            }
            return(contour);
        }
Exemplo n.º 22
0
        /// <summary>
        /// Convert Loop to an array of ContourVertex.
        /// </summary>
        /// <param name="loop"></param>
        /// <param name="face"></param>
        internal static ContourVertex[] ToContourVertexArray(this Loop loop, Face face)
        {
            var contour = new List <ContourVertex>();

            foreach (var edge in loop.Edges)
            {
                var cv = new ContourVertex();
                cv.Position = new Vec3 {
                    X = edge.Vertex.Point.X, Y = edge.Vertex.Point.Y, Z = edge.Vertex.Point.Z
                };
                contour.Add(cv);
            }
            return(contour.ToArray());
        }
Exemplo n.º 23
0
        internal static void AddContour(Tess tess, Polygon p)
        {
            var numPoints = p.Vertices.Length;
            var contour   = new ContourVertex[numPoints];

            for (var i = 0; i < numPoints; i++)
            {
                var v = p.Vertices[i];
                contour[i].Position = new Vec3 {
                    X = v.X, Y = v.Y, Z = v.Z
                };
            }

            tess.AddContour(contour);
        }
        public List <PointF[]> Triangulate(PolyTree solution)
        {
            List <PointF[]> list = new List <PointF[]>();
            Tess            tess = new Tess();

            tess.NoEmptyPolygons = true;
            Func <IntPoint, ContourVertex> selector = delegate(IntPoint p)
            {
                ContourVertex result = default(ContourVertex);
                result.Position = new Vec3
                {
                    X = (float)p.X,
                    Y = (float)p.Y,
                    Z = 0f
                };
                return(result);
            };

            for (PolyNode polyNode = solution.GetFirst(); polyNode != null; polyNode = polyNode.GetNext())
            {
                if (!polyNode.IsOpen)
                {
                    ContourVertex[] vertices = polyNode.Contour.Select(selector).ToArray();
                    tess.AddContour(vertices);
                }
            }
            tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3);
            int elementCount = tess.ElementCount;

            for (int i = 0; i < elementCount; i++)
            {
                Vec3          position  = tess.Vertices[tess.Elements[i * 3 + 0]].Position;
                Vec3          position2 = tess.Vertices[tess.Elements[i * 3 + 1]].Position;
                Vec3          position3 = tess.Vertices[tess.Elements[i * 3 + 2]].Position;
                List <PointF> list2     = new List <PointF>
                {
                    new PointF(position.X, position.Y),
                    new PointF(position2.X, position2.Y),
                    new PointF(position3.X, position3.Y)
                };
                if (Math.Cross(list2[0], list2[1], list2[2]) > 0f)
                {
                    list2.Reverse();
                }
                list.Add(list2.ToArray());
            }
            return(list);
        }
Exemplo n.º 25
0
        private static ContourVertex[] ToContourVertices(this List <Csg.Vertex> vertices)
        {
            var result = new ContourVertex[vertices.Count];

            for (var i = 0; i < vertices.Count; i++)
            {
                result[i] = new ContourVertex()
                {
                    Position = new Vec3()
                    {
                        X = vertices[i].Pos.X, Y = vertices[i].Pos.Y, Z = vertices[i].Pos.Z
                    }, Data = vertices[i].Tex
                };
            }
            return(result);
        }
Exemplo n.º 26
0
 public void AddVertex(Vec3 v, ref ContourVertex contourVertex)
 {
     if (_vertices.Contains(v))
     {
         contourVertex = _vertices[v];
     }
     else
     {
         _vertices.Add(v, ref contourVertex);
         _minX = Math.Min(_minX, v.X);
         _minY = Math.Min(_minY, v.Y);
         _minZ = Math.Min(_minZ, v.Z);
         _maxX = Math.Max(_maxX, v.X);
         _maxY = Math.Max(_maxY, v.Y);
         _maxZ = Math.Max(_maxZ, v.Z);
     }
 }
Exemplo n.º 27
0
        /// <summary>
        /// Convert Loop to an array of ContourVertex.
        /// </summary>
        /// <param name="loop"></param>
        /// <param name="transform">An optional transform to apply to the contour.</param>
        internal static ContourVertex[] ToContourVertexArray(this Loop loop, Transform transform = null)
        {
            var contour = new ContourVertex[loop.Edges.Count];

            for (var i = 0; i < loop.Edges.Count; i++)
            {
                var edge = loop.Edges[i];
                var p    = transform == null ? edge.Vertex.Point : transform.OfPoint(edge.Vertex.Point);
                var cv   = new ContourVertex
                {
                    Position = new Vec3 {
                        X = p.X, Y = p.Y, Z = p.Z
                    }
                };
                contour[i] = cv;
            }
            return(contour);
        }
        public static void GetFalloffShape(Vector3[] shapePath, ref List <Vector2> extrusionDir)
        {
            int pointCount = shapePath.Length;
            var inputs     = new ContourVertex[pointCount];

            for (int i = 0; i < pointCount; ++i)
            {
                inputs[i] = new ContourVertex()
                {
                    Position = new Vec3()
                    {
                        X = shapePath[i].x, Y = shapePath[i].y
                    }, Data = null
                }
            }
            ;

            GetFalloffExtrusion(inputs, pointCount, ref extrusionDir);
        }
Exemplo n.º 29
0
        private static void AddPoints([CanBeNull] Matrix3x2?transform, [NotNull] Vector2[] points, List <ContourVertex> vertices)
        {
            if (points.Length < 2)
            {
                return;
            }

            // Don't add the first point.
            var verts = new ContourVertex[points.Length - 1];

            if (transform != null)
            {
                for (var i = 1; i < points.Length; ++i)
                {
                    var pt = Matrix3x2.Transform(transform.Value, points[i]);

                    verts[i - 1] = new ContourVertex {
                        Position = new Vec3 {
                            X = pt.X,
                            Y = pt.Y,
                            Z = StandardZ
                        }
                    };
                }
            }
            else
            {
                for (var i = 1; i < points.Length; ++i)
                {
                    var pt = points[i];

                    verts[i - 1] = new ContourVertex {
                        Position = new Vec3 {
                            X = pt.X,
                            Y = pt.Y,
                            Z = StandardZ
                        }
                    };
                }
            }

            vertices.AddRange(verts);
        }
Exemplo n.º 30
0
        public static List <Vector2> GetFeatheredShape(Vector3[] shapePath, float feathering)
        {
            int pointCount = shapePath.Length;
            var inputs     = new ContourVertex[pointCount];

            for (int i = 0; i < pointCount; ++i)
            {
                inputs[i] = new ContourVertex()
                {
                    Position = new Vec3()
                    {
                        X = shapePath[i].x, Y = shapePath[i].y
                    }, Data = null
                }
            }
            ;

            var feathered = UpdateFeatheredShapeLightMesh(inputs, pointCount, feathering);

            return(feathered);
        }
Exemplo n.º 31
0
        /* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
        * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
        * a place to insert the new vertex in the global vertex list.  We insert
        * the new vertex *before* vNext so that algorithms which walk the vertex
        * list will not see the newly created vertices.
        */
        private static void MakeVertex(ContourVertex newVertex, HalfEdge eOrig, ContourVertex vNext)
        {
            HalfEdge e;
            ContourVertex vPrev;
            ContourVertex vNew = newVertex;

            /* insert in circular doubly-linked list before vNext */
            vPrev = vNext.prevVertex;
            vNew.prevVertex = vPrev;
            vPrev.nextVertex = vNew;
            vNew.nextVertex = vNext;
            vNext.prevVertex = vNew;

            vNew.edgeThisIsOriginOf = eOrig;
            vNew.clientIndex = 0;
            /* leave coords, s, t undefined */

            /* fix other edges on this vertex loop */
            e = eOrig;
            do
            {
                e.originVertex = vNew;
                e = e.nextEdgeCCWAroundOrigin;
            } while (e != eOrig);
        }
Exemplo n.º 32
0
        // __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
        // The loop consists of the two new half-edges.
        public HalfEdge MakeEdge()
        {
            var newVertex1 = new ContourVertex();
            var newVertex2 = new ContourVertex();
            var newFace = new Face();
            HalfEdge e;

            e = MakeEdge(halfEdgeHead);

            MakeVertex(newVertex1, e, vertexHead);
            MakeVertex(newVertex2, e.otherHalfOfThisEdge, vertexHead);
            MakeFace(newFace, e, faceHead);
            return e;
        }
Exemplo n.º 33
0
        static void ConnectLeftDegenerate(Tesselator tess, ActiveRegion regUp, ContourVertex vEvent)
        /*
         * The currentSweepVertex vertex lies exactly on an already-processed edge or vertex.
         * Adding the new vertex involves splicing it into the already-processed
         * part of the mesh.
         */
        {
            HalfEdge e, eTopLeft, eTopRight, eLast;
            ActiveRegion reg;
            e = regUp.upperHalfEdge;
            if (e.originVertex.VertEq(vEvent))
            {
                /* e.Org is an unprocessed vertex - just combine them, and wait
                 * for e.Org to be pulled from the queue
                 */
                SpliceMergeVertices(tess, e, vEvent.edgeThisIsOriginOf);
                return;
            }

            if (!e.directionVertex.VertEq(vEvent))
            {
                /* General case -- splice vEvent into edge e which passes through it */
                Mesh.meshSplitEdge(e.otherHalfOfThisEdge);
                if (regUp.fixUpperEdge)
                {
                    /* This edge was fixable -- delete unused portion of original edge */
                    Mesh.DeleteHalfEdge(e.nextEdgeCCWAroundOrigin);
                    regUp.fixUpperEdge = false;
                }
                Mesh.meshSplice(vEvent.edgeThisIsOriginOf, e);
                SweepEvent(tess, vEvent); /* recurse */
                return;
            }

            /* vEvent coincides with e.Dst, which has already been processed.
             * Splice in the additional right-going edges.
             */
            regUp = TopRightRegion(regUp);
            reg = RegionBelow(regUp);
            eTopRight = reg.upperHalfEdge.otherHalfOfThisEdge;
            eTopLeft = eLast = eTopRight.nextEdgeCCWAroundOrigin;
            if (reg.fixUpperEdge)
            {
                /* Here e.Dst has only a single fixable edge going right.
                 * We can delete it since now we have some real right-going edges.
                 */
                if (eTopLeft == eTopRight)
                {
                    throw new Exception();   /* there are some left edges too */
                }
                DeleteRegion(reg);
                Mesh.DeleteHalfEdge(eTopRight);
                eTopRight = eTopLeft.Oprev;
            }
            Mesh.meshSplice(vEvent.edgeThisIsOriginOf, eTopRight);
            if (!eTopLeft.EdgeGoesLeft())
            {
                /* e.Dst had no left-going edges -- indicate this to AddRightEdges() */
                eTopLeft = null;
            }
            AddRightEdges(tess, regUp, eTopRight.nextEdgeCCWAroundOrigin, eLast, eTopLeft, true);
        }
Exemplo n.º 34
0
        /* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
        * eNew == eOrg.Lnext, and eNew.Dst is a newly created vertex.
        * eOrg and eNew will have the same left face.
        */
        private static HalfEdge meshAddEdgeVertex(HalfEdge eOrg)
        {
            HalfEdge eNewSym;
            HalfEdge eNew = MakeEdge(eOrg);

            eNewSym = eNew.otherHalfOfThisEdge;

            /* Connect the new edge appropriately */
            Splice(eNew, eOrg.nextEdgeCCWAroundLeftFace);

            /* Set the vertex and face information */
            eNew.originVertex = eOrg.directionVertex;
            {
                var newVertex = new ContourVertex();

                MakeVertex(newVertex, eNewSym, eNew.originVertex);
            }
            eNew.leftFace = eNewSym.leftFace = eOrg.leftFace;

            return eNew;
        }
Exemplo n.º 35
0
        /*
         * We've computed a new intersection point, now we need a "data" pointer
         * from the user so that we can refer to this new vertex in the
         * rendering callbacks.
         */
        private static void GetIntersectData(Tesselator tess, ContourVertex isect,
                                             ContourVertex orgUp, ContourVertex dstUp,
                                             ContourVertex orgLo, ContourVertex dstLo)
        {
            var data4 = new int[4];
            var weights4 = new double[4];

            data4[0] = orgUp.clientIndex;
            data4[1] = dstUp.clientIndex;
            data4[2] = orgLo.clientIndex;
            data4[3] = dstLo.clientIndex;

            isect.coords[0] = isect.coords[1] = isect.coords[2] = 0;
            VertexWeights(isect, orgUp, dstUp, out weights4[0], out weights4[1]);
            VertexWeights(isect, orgLo, dstLo, out weights4[2], out weights4[3]);

            CallCombine(tess, isect, data4, weights4, true);
        }
Exemplo n.º 36
0
 static void CallCombine(Tesselator tess, ContourVertex intersectionVertex, int[] vertexIndexArray, double[] vertexWeights, bool needed)
 {
     /* Copy coord data in case the callback changes it. */
     double c0 = intersectionVertex.C_0;
     double c1 = intersectionVertex.C_1;
     double c2 = intersectionVertex.C_2;
     intersectionVertex.clientIndex = 0;
     tess.CallCombine(c0, c1, c2, vertexIndexArray, vertexWeights, out intersectionVertex.clientIndex);
     if (intersectionVertex.clientIndex == 0)
     {
         if (!needed)
         {
             intersectionVertex.clientIndex = vertexIndexArray[0];
         }
         else
         {
             /* The only fatal error is when two edges are found to intersect,
              * but the user has not provided the callback necessary to handle
              * generated intersection points.
              */
             throw new Exception("You need to provided a callback to handle generated intersection points.");
         }
     }
 }
Exemplo n.º 37
0
        static double TransSign(ContourVertex u, ContourVertex v, ContourVertex w)
        {
            /* Returns a number whose sign matches TransEval(u,v,w) but which
             * is cheaper to evaluate.  Returns > 0, == 0 , or < 0
             * as v is above, on, or below the edge uw.
             */
            double gapL, gapR;
            if (!u.TransLeq(v) || !v.TransLeq(w))
            {
                throw new Exception();
            }

            gapL = v.y - u.y;
            gapR = w.y - v.y;
            if (gapL + gapR > 0)
            {
                return (v.x - w.x) * gapL + (v.x - u.x) * gapR;
            }
            /* vertical line */
            return 0;
        }
Exemplo n.º 38
0
        /*
         * Purpose: connect a "left" vertex (one where both edges go right)
         * to the processed portion of the mesh.  Let R be the active region
         * containing vEvent, and let U and L be the upper and lower edge
         * chains of R.  There are two possibilities:
         *
         * - the normal case: split R into two regions, by connecting vEvent to
         *   the rightmost vertex of U or L lying to the left of the sweep line
         *
         * - the degenerate case: if vEvent is close enough to U or L, we
         *   merge vEvent into that edge chain.  The sub-cases are:
         *	- merging with the rightmost vertex of U or L
         *	- merging with the active edge of U or L
         *	- merging with an already-processed portion of U or L
         */
        private static void ConnectLeftVertex(Tesselator tess, ContourVertex vEvent)
        {
            ActiveRegion regUp, regLo, reg;
            HalfEdge eUp, eLo, eNew;
            var tmp = new ActiveRegion();

            /* assert( vEvent.anEdge.Onext.Onext == vEvent.anEdge ); */

            /* Get a pointer to the active region containing vEvent */
            tmp.upperHalfEdge = vEvent.edgeThisIsOriginOf.otherHalfOfThisEdge;
            /* __GL_DICTLISTKEY */
            /* __gl_dictListSearch */
            regUp = Dictionary.dictSearch(tess.edgeDictionary, tmp).Key;
            regLo = RegionBelow(regUp);
            eUp = regUp.upperHalfEdge;
            eLo = regLo.upperHalfEdge;

            /* Try merging with U or L first */
            if (ContourVertex.EdgeSign(eUp.directionVertex, vEvent, eUp.originVertex) == 0)
            {
                ConnectLeftDegenerate(tess, regUp, vEvent);
                return;
            }

            /* Connect vEvent to rightmost processed vertex of either chain.
             * e.Dst is the vertex that we will connect to vEvent.
             */
            reg = eLo.directionVertex.VertLeq(eUp.directionVertex) ? regUp : regLo;

            if (regUp.inside || reg.fixUpperEdge)
            {
                if (reg == regUp)
                {
                    eNew = Mesh.meshConnect(vEvent.edgeThisIsOriginOf.otherHalfOfThisEdge, eUp.nextEdgeCCWAroundLeftFace);
                }
                else
                {
                    HalfEdge tempHalfEdge = Mesh.meshConnect(eLo.Dnext, vEvent.edgeThisIsOriginOf);

                    eNew = tempHalfEdge.otherHalfOfThisEdge;
                }
                if (reg.fixUpperEdge)
                {
                    FixUpperEdge(reg, eNew);
                }
                else
                {
                    ComputeWinding(tess, AddRegionBelow(tess, regUp, eNew));
                }
                SweepEvent(tess, vEvent);
            }
            else
            {
                /* The new vertex is in a region which does not belong to the polygon.
                 * We don''t need to connect this vertex to the rest of the mesh.
                 */
                AddRightEdges(tess, regUp, vEvent.edgeThisIsOriginOf, vEvent.edgeThisIsOriginOf, null, true);
            }
        }
Exemplo n.º 39
0
 static void Swap(ref ContourVertex a, ref ContourVertex b)
 {
     ContourVertex t = a;
     a = b;
     b = t;
 }
Exemplo n.º 40
0
        static double TransEval(ContourVertex u, ContourVertex v, ContourVertex w)
        {
            /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
             * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
             * Returns v.s - (uw)(v.t), ie. the signed distance from uw to v.
             * If uw is vertical (and thus passes thru v), the result is zero.
             *
             * The calculation is extremely accurate and stable, even when v
             * is very close to u or w.  In particular if we set v.s = 0 and
             * let r be the negated result (this evaluates (uw)(v.t)), then
             * r is guaranteed to satisfy MIN(u.s,w.s) <= r <= MAX(u.s,w.s).
             */
            double gapL, gapR;
            if (!u.TransLeq(v) || !v.TransLeq(w))
            {
                throw new Exception();
            }

            gapL = v.y - u.y;
            gapR = w.y - v.y;
            if (gapL + gapR > 0)
            {
                if (gapL < gapR)
                {
                    return (v.x - u.x) + (u.x - w.x) * (gapL / (gapL + gapR));
                }
                else
                {
                    return (v.x - w.x) + (w.x - u.x) * (gapR / (gapL + gapR));
                }
            }
            /* vertical line */
            return 0;
        }
Exemplo n.º 41
0
 static void GetIntersectData(Tesselator tess, ContourVertex isect,
        ContourVertex orgUp, ContourVertex dstUp,
        ContourVertex orgLo, ContourVertex dstLo)
 /*
  * We've computed a new intersection point, now we need a "data" pointer
  * from the user so that we can refer to this new vertex in the
  * rendering callbacks.
  */
 {
     int[] data4 = new int[4];
     double[] weights4 = new double[4];
     data4[0] = orgUp.clientIndex;
     data4[1] = dstUp.clientIndex;
     data4[2] = orgLo.clientIndex;
     data4[3] = dstLo.clientIndex;
     isect.C_0 = isect.C_1 = isect.C_2 = 0;
     VertexWeights(isect, orgUp, dstUp, out weights4[0], out weights4[1]);
     VertexWeights(isect, orgLo, dstLo, out weights4[2], out weights4[3]);
     CallCombine(tess, isect, data4, weights4, true);
 }
Exemplo n.º 42
0
 static void VertexWeights(ContourVertex isect, ContourVertex org, ContourVertex dst, out double weights0, out double weights1)
 /*
  * Find some weights which describe how the intersection vertex is
  * a linear combination of "org" and "dest".  Each of the two edges
  * which generated "isect" is allocated 50% of the weight; each edge
  * splits the weight between its org and dst according to the
  * relative distance to "isect".
  */
 {
     double t1 = VertL1dist(org, isect);
     double t2 = VertL1dist(dst, isect);
     weights0 = 0.5 * t2 / (t1 + t2);
     weights1 = 0.5 * t1 / (t1 + t2);
     isect.C_0 += weights0 * org.C_0 + weights1 * dst.C_0;
     isect.C_1 += weights0 * org.C_1 + weights1 * dst.C_1;
     isect.C_2 += weights0 * org.C_2 + weights1 * dst.C_2;
 }
Exemplo n.º 43
0
 static double VertL1dist(ContourVertex u, ContourVertex v)
 {
     return Math.Abs(u.x - v.x) + Math.Abs(u.y - v.y);
 }
Exemplo n.º 44
0
        /* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
        * mesh connectivity and topology.  It changes the mesh so that
        *	eOrg.Onext <- OLD( eDst.Onext )
        *	eDst.Onext <- OLD( eOrg.Onext )
        * where OLD(...) means the value before the meshSplice operation.
        *
        * This can have two effects on the vertex structure:
        *  - if eOrg.Org != eDst.Org, the two vertices are merged together
        *  - if eOrg.Org == eDst.Org, the origin is split into two vertices
        * In both cases, eDst.Org is changed and eOrg.Org is untouched.
        *
        * Similarly (and independently) for the face structure,
        *  - if eOrg.Lface == eDst.Lface, one loop is split into two
        *  - if eOrg.Lface != eDst.Lface, two distinct loops are joined into one
        * In both cases, eDst.Lface is changed and eOrg.Lface is unaffected.
        *
        * Some special cases:
        * If eDst == eOrg, the operation has no effect.
        * If eDst == eOrg.Lnext, the new face will have a single edge.
        * If eDst == eOrg.Lprev, the old face will have a single edge.
        * If eDst == eOrg.Onext, the new vertex will have a single edge.
        * If eDst == eOrg.Oprev, the old vertex will have a single edge.
        */
        public static void meshSplice(HalfEdge eOrg, HalfEdge eDst)
        {
            bool joiningLoops = false;
            bool joiningVertices = false;

            if (eOrg == eDst) return;

            if (eDst.originVertex != eOrg.originVertex)
            {
                /* We are merging two disjoint vertices -- destroy eDst.Org */
                joiningVertices = true;
                KillVertex(eDst.originVertex, eOrg.originVertex);
            }
            if (eDst.leftFace != eOrg.leftFace)
            {
                /* We are connecting two disjoint loops -- destroy eDst.Lface */
                joiningLoops = true;
                KillFace(eDst.leftFace, eOrg.leftFace);
            }

            /* Change the edge structure */
            Splice(eDst, eOrg);

            if (!joiningVertices)
            {
                var newVertex = new ContourVertex();

                /* We split one vertex into two -- the new vertex is eDst.Org.
                * Make sure the old vertex points to a valid half-edge.
                */
                MakeVertex(newVertex, eDst, eOrg.originVertex);
                eOrg.originVertex.edgeThisIsOriginOf = eOrg;
            }
            if (!joiningLoops)
            {
                var newFace = new Face();

                /* We split one loop into two -- the new loop is eDst.Lface.
                * Make sure the old face points to a valid half-edge.
                */
                MakeFace(newFace, eDst, eOrg.leftFace);
                eOrg.leftFace.halfEdgeThisIsLeftFaceOf = eOrg;
            }
        }
Exemplo n.º 45
0
        static void EdgeIntersect(ContourVertex o1, ContourVertex d1,
            ContourVertex o2, ContourVertex d2,
            ref ContourVertex v)
        /* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
         * The computed point is guaranteed to lie in the intersection of the
         * bounding rectangles defined by each edge.
         */
        {
            double z1, z2;
            /* This is certainly not the most efficient way to find the intersection
             * of two line segments, but it is very numerically stable.
             *
             * Strategy: find the two middle vertices in the VertLeq ordering,
             * and interpolate the intersection s-value from these.  Then repeat
             * using the TransLeq ordering to find the intersection t-value.
             */

            if (!o1.VertLeq(d1)) { Swap(ref o1, ref d1); }
            if (!o2.VertLeq(d2)) { Swap(ref o2, ref d2); }
            if (!o1.VertLeq(o2)) { Swap(ref o1, ref o2); Swap(ref d1, ref d2); }

            if (!o2.VertLeq(d1))
            {
                /* Technically, no intersection -- do our best */
                v.x = (o2.x + d1.x) / 2;
            }
            else if (d1.VertLeq(d2))
            {
                /* Interpolate between o2 and d1 */
                z1 = ContourVertex.EdgeEval(o1, o2, d1);
                z2 = ContourVertex.EdgeEval(o2, d1, d2);
                if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; }
                v.x = Interpolate(z1, o2.x, z2, d1.x);
            }
            else
            {
                /* Interpolate between o2 and d2 */
                z1 = ContourVertex.EdgeSign(o1, o2, d1);
                z2 = -ContourVertex.EdgeSign(o1, d2, d1);
                if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; }
                v.x = Interpolate(z1, o2.x, z2, d2.x);
            }

            /* Now repeat the process for t */

            if (!o1.TransLeq(d1)) { Swap(ref o1, ref d1); }
            if (!o2.TransLeq(d2)) { Swap(ref o2, ref d2); }
            if (!o1.TransLeq(o2)) { Swap(ref o1, ref o2); Swap(ref d1, ref d2); }

            if (!o2.TransLeq(d1))
            {
                /* Technically, no intersection -- do our best */
                v.y = (o2.y + d1.y) / 2;
            }
            else if (d1.TransLeq(d2))
            {
                /* Interpolate between o2 and d1 */
                z1 = TransEval(o1, o2, d1);
                z2 = TransEval(o2, d1, d2);
                if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; }
                v.y = Interpolate(z1, o2.y, z2, d1.y);
            }
            else
            {
                /* Interpolate between o2 and d2 */
                z1 = TransSign(o1, o2, d1);
                z2 = -TransSign(o1, d2, d1);
                if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; }
                v.y = Interpolate(z1, o2.y, z2, d2.y);
            }
        }
Exemplo n.º 46
0
		// __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
		// The loop consists of the two new half-edges.
		public HalfEdge MakeEdge()
		{
			ContourVertex newVertex1 = new ContourVertex();
			ContourVertex newVertex2 = new ContourVertex();
			Face newFace = new Face();
			HalfEdge e;

			e = MakeEdge(this.halfEdgeHead);

			MakeVertex(newVertex1, e, this.vertexHead);
			MakeVertex(newVertex2, e.otherHalfOfThisEdge, this.vertexHead);
			MakeFace(newFace, e, this.faceHead);
			return e;
		}
Exemplo n.º 47
0
        static bool CheckForIntersect(Tesselator tess, ActiveRegion regUp)
        /*
         * Check the upper and lower edges of the given region to see if
         * they intersect.  If so, create the intersection and add it
         * to the data structures.
         *
         * Returns true if adding the new intersection resulted in a recursive
         * call to AddRightEdges(); in this case all "dirty" regions have been
         * checked for intersections, and possibly regUp has been deleted.
         */
        {
            ActiveRegion regLo = RegionBelow(regUp);
            HalfEdge eUp = regUp.upperHalfEdge;
            HalfEdge eLo = regLo.upperHalfEdge;
            ContourVertex orgUp = eUp.originVertex;
            ContourVertex orgLo = eLo.originVertex;
            ContourVertex dstUp = eUp.directionVertex;
            ContourVertex dstLo = eLo.directionVertex;
            double tMinUp, tMaxLo;
            ContourVertex isect = new ContourVertex();
            ContourVertex orgMin;
            HalfEdge e;
            if (dstLo.VertEq(dstUp))
            {
                throw new Exception();
            }
            if (ContourVertex.EdgeSign(dstUp, tess.currentSweepVertex, orgUp) > 0)
            {
                throw new Exception();
            }
            if (ContourVertex.EdgeSign(dstLo, tess.currentSweepVertex, orgLo) < 0)
            {
                throw new Exception();
            }
            if (orgUp == tess.currentSweepVertex || orgLo == tess.currentSweepVertex)
            {
                throw new Exception();
            }
            if (regUp.fixUpperEdge || regLo.fixUpperEdge)
            {
                throw new Exception();
            }

            if (orgUp == orgLo)
            {
                return false;	/* right endpoints are the same */
            }

            tMinUp = Math.Min(orgUp.y, dstUp.y);
            tMaxLo = Math.Max(orgLo.y, dstLo.y);
            if (tMinUp > tMaxLo)
            {
                return false;	/* t ranges do not overlap */
            }

            if (orgUp.VertLeq(orgLo))
            {
                if (ContourVertex.EdgeSign(dstLo, orgUp, orgLo) > 0)
                {
                    return false;
                }
            }
            else
            {
                if (ContourVertex.EdgeSign(dstUp, orgLo, orgUp) < 0)
                {
                    return false;
                }
            }

            EdgeIntersect(dstUp, orgUp, dstLo, orgLo, ref isect);
            // The following properties are guaranteed:
            if (!(Math.Min(orgUp.y, dstUp.y) <= isect.y))
            {
                throw new System.Exception();
            }
            if (!(isect.y <= Math.Max(orgLo.y, dstLo.y)))
            {
                throw new System.Exception();
            }
            if (!(Math.Min(dstLo.x, dstUp.x) <= isect.x))
            {
                throw new System.Exception();
            }
            if (!(isect.x <= Math.Max(orgLo.x, orgUp.x)))
            {
                throw new System.Exception();
            }

            if (isect.VertLeq(tess.currentSweepVertex))
            {
                /* The intersection point lies slightly to the left of the sweep line,
                 * so move it until it''s slightly to the right of the sweep line.
                 * (If we had perfect numerical precision, this would never happen
                 * in the first place).  The easiest and safest thing to do is
                 * replace the intersection by tess.currentSweepVertex.
                 */
                isect.x = tess.currentSweepVertex.x;
                isect.y = tess.currentSweepVertex.y;
            }
            /* Similarly, if the computed intersection lies to the right of the
             * rightmost origin (which should rarely happen), it can cause
             * unbelievable inefficiency on sufficiently degenerate inputs.
             * (If you have the test program, try running test54.d with the
             * "X zoom" option turned on).
             */
            orgMin = orgUp.VertLeq(orgLo) ? orgUp : orgLo;
            if (orgMin.VertLeq(isect))
            {
                isect.x = orgMin.x;
                isect.y = orgMin.y;
            }

            if (isect.VertEq(orgUp) || isect.VertEq(orgLo))
            {
                /* Easy case -- intersection at one of the right endpoints */
                CheckForRightSplice(tess, regUp);
                return false;
            }

            if ((!dstUp.VertEq(tess.currentSweepVertex)
                && ContourVertex.EdgeSign(dstUp, tess.currentSweepVertex, isect) >= 0)
                || (!dstLo.VertEq(tess.currentSweepVertex)
                && ContourVertex.EdgeSign(dstLo, tess.currentSweepVertex, isect) <= 0))
            {
                /* Very unusual -- the new upper or lower edge would pass on the
                 * wrong side of the sweep currentSweepVertex, or through it.  This can happen
                 * due to very small numerical errors in the intersection calculation.
                 */
                if (dstLo == tess.currentSweepVertex)
                {
                    /* Splice dstLo into eUp, and process the new region(s) */
                    Mesh.meshSplitEdge(eUp.otherHalfOfThisEdge);
                    Mesh.meshSplice(eLo.otherHalfOfThisEdge, eUp);
                    regUp = TopLeftRegion(regUp);
                    eUp = RegionBelow(regUp).upperHalfEdge;
                    FinishLeftRegions(tess, RegionBelow(regUp), regLo);
                    AddRightEdges(tess, regUp, eUp.Oprev, eUp, eUp, true);
                    return true;
                }
                if (dstUp == tess.currentSweepVertex)
                {
                    /* Splice dstUp into eLo, and process the new region(s) */
                    Mesh.meshSplitEdge(eLo.otherHalfOfThisEdge);
                    Mesh.meshSplice(eUp.nextEdgeCCWAroundLeftFace, eLo.Oprev);
                    regLo = regUp;
                    regUp = TopRightRegion(regUp);
                    e = RegionBelow(regUp).upperHalfEdge.Rprev;
                    regLo.upperHalfEdge = eLo.Oprev;
                    eLo = FinishLeftRegions(tess, regLo, null);
                    AddRightEdges(tess, regUp, eLo.nextEdgeCCWAroundOrigin, eUp.Rprev, e, true);
                    return true;
                }

                /* Special case: called from ConnectRightVertex.  If either
                 * edge passes on the wrong side of tess.currentSweepVertex, split it
                 * (and wait for ConnectRightVertex to splice it appropriately).
                 */
                if (ContourVertex.EdgeSign(dstUp, tess.currentSweepVertex, isect) >= 0)
                {
                    regUp.RegionAbove().dirty = regUp.dirty = true;
                    Mesh.meshSplitEdge(eUp.otherHalfOfThisEdge);
                    eUp.originVertex.x = tess.currentSweepVertex.x;
                    eUp.originVertex.y = tess.currentSweepVertex.y;
                }
                if (ContourVertex.EdgeSign(dstLo, tess.currentSweepVertex, isect) <= 0)
                {
                    regUp.dirty = regLo.dirty = true;
                    Mesh.meshSplitEdge(eLo.otherHalfOfThisEdge);
                    eLo.originVertex.x = tess.currentSweepVertex.x;
                    eLo.originVertex.y = tess.currentSweepVertex.y;
                }
                /* leave the rest for ConnectRightVertex */
                return false;
            }

            /* General case -- split both edges, splice into new vertex.
             * When we do the splice operation, the order of the arguments is
             * arbitrary as far as correctness goes.  However, when the operation
             * creates a new face, the work done is proportional to the size of
             * the new face.  We expect the faces in the processed part of
             * the mesh (ie. eUp.Lface) to be smaller than the faces in the
             * unprocessed original contours (which will be eLo.Oprev.Lface).
             */
            Mesh.meshSplitEdge(eUp.otherHalfOfThisEdge);
            Mesh.meshSplitEdge(eLo.otherHalfOfThisEdge);
            Mesh.meshSplice(eLo.Oprev, eUp);
            eUp.originVertex.x = isect.x;
            eUp.originVertex.y = isect.y;
            tess.vertexPriorityQue.Add(out eUp.originVertex.priorityQueueHandle, eUp.originVertex); /* __gl_pqSortInsert */
            GetIntersectData(tess, eUp.originVertex, orgUp, dstUp, orgLo, dstLo);
            regUp.RegionAbove().dirty = regUp.dirty = regLo.dirty = true;
            return false;
        }
Exemplo n.º 48
0
        /*
         * Find some weights which describe how the intersection vertex is
         * a linear combination of "org" and "dest".  Each of the two edges
         * which generated "isect" is allocated 50% of the weight; each edge
         * splits the weight between its org and dst according to the
         * relative distance to "isect".
         */
        private static void VertexWeights(ContourVertex isect, ContourVertex org, ContourVertex dst, out double weights0,
                                          out double weights1)
        {
            double t1 = VertL1dist(org, isect);
            double t2 = VertL1dist(dst, isect);

            weights0 = 0.5*t2/(t1 + t2);
            weights1 = 0.5*t1/(t1 + t2);
            isect.coords[0] += weights0*org.coords[0] + weights1*dst.coords[0];
            isect.coords[1] += weights0*org.coords[1] + weights1*dst.coords[1];
            isect.coords[2] += weights0*org.coords[2] + weights1*dst.coords[2];
        }
Exemplo n.º 49
0
        static void ConnectLeftVertex(Tesselator tess, ContourVertex vEvent)
        /*
         * Purpose: connect a "left" vertex (one where both edges go right)
         * to the processed portion of the mesh.  Let R be the active region
         * containing vEvent, and let U and L be the upper and lower edge
         * chains of R.  There are two possibilities:
         *
         * - the normal case: split R into two regions, by connecting vEvent to
         *   the rightmost vertex of U or L lying to the left of the sweep line
         *
         * - the degenerate case: if vEvent is close enough to U or L, we
         *   merge vEvent into that edge chain.  The sub-cases are:
         *	- merging with the rightmost vertex of U or L
         *	- merging with the active edge of U or L
         *	- merging with an already-processed portion of U or L
         */
        {
            ActiveRegion regUp, regLo, reg;
            HalfEdge eUp, eLo, eNew;
            ActiveRegion tmp = new ActiveRegion();
            /* assert( vEvent.anEdge.Onext.Onext == vEvent.anEdge ); */

            /* Get a pointer to the active region containing vEvent */
            tmp.upperHalfEdge = vEvent.edgeThisIsOriginOf.otherHalfOfThisEdge;
            /* __GL_DICTLISTKEY */
            /* __gl_dictListSearch */
            regUp = Dictionary.dictSearch(tess.edgeDictionary, tmp).Key;
            regLo = RegionBelow(regUp);
            eUp = regUp.upperHalfEdge;
            eLo = regLo.upperHalfEdge;
            /* Try merging with U or L first */
            if (ContourVertex.EdgeSign(eUp.directionVertex, vEvent, eUp.originVertex) == 0)
            {
                ConnectLeftDegenerate(tess, regUp, vEvent);
                return;
            }

            /* Connect vEvent to rightmost processed vertex of either chain.
             * e.Dst is the vertex that we will connect to vEvent.
             */
            reg = eLo.directionVertex.VertLeq(eUp.directionVertex) ? regUp : regLo;
            if (regUp.inside || reg.fixUpperEdge)
            {
                if (reg == regUp)
                {
                    eNew = Mesh.meshConnect(vEvent.edgeThisIsOriginOf.otherHalfOfThisEdge, eUp.nextEdgeCCWAroundLeftFace);
                }
                else
                {
                    HalfEdge tempHalfEdge = Mesh.meshConnect(eLo.Dnext, vEvent.edgeThisIsOriginOf);
                    eNew = tempHalfEdge.otherHalfOfThisEdge;
                }
                if (reg.fixUpperEdge)
                {
                    FixUpperEdge(reg, eNew);
                }
                else
                {
                    ComputeWinding(tess, AddRegionBelow(tess, regUp, eNew));
                }
                SweepEvent(tess, vEvent);
            }
            else
            {
                /* The new vertex is in a region which does not belong to the polygon.
                 * We don''t need to connect this vertex to the rest of the mesh.
                 */
                AddRightEdges(tess, regUp, vEvent.edgeThisIsOriginOf, vEvent.edgeThisIsOriginOf, null, true);
            }
        }
Exemplo n.º 50
0
        /* KillVertex( vDel ) destroys a vertex and removes it from the global
        * vertex list.  It updates the vertex loop to point to a given new vertex.
        */
        private static void KillVertex(ContourVertex vDel, ContourVertex newOrg)
        {
            HalfEdge e, eStart = vDel.edgeThisIsOriginOf;
            ContourVertex vPrev, vNext;

            /* change the origin of all affected edges */
            e = eStart;
            do
            {
                e.originVertex = newOrg;
                e = e.nextEdgeCCWAroundOrigin;
            } while (e != eStart);

            /* delete from circular doubly-linked list */
            vPrev = vDel.prevVertex;
            vNext = vDel.nextVertex;
            vNext.prevVertex = vPrev;
            vPrev.nextVertex = vNext;
        }
Exemplo n.º 51
0
        static void SweepEvent(Tesselator tess, ContourVertex vEvent)
        /*
         * Does everything necessary when the sweep line crosses a vertex.
         * Updates the mesh and the edge dictionary.
         */
        {
            ActiveRegion regUp, reg;
            HalfEdge e, eTopLeft, eBottomLeft;
            tess.currentSweepVertex = vEvent; 	/* for access in EdgeLeq() */
            /* Check if this vertex is the right endpoint of an edge that is
             * already in the dictionary.  In this case we don't need to waste
             * time searching for the location to insert new edges.
             */
            e = vEvent.edgeThisIsOriginOf;
            while (e.regionThisIsUpperEdgeOf == null)
            {
                e = e.nextEdgeCCWAroundOrigin;
                if (e == vEvent.edgeThisIsOriginOf)
                {
                    /* All edges go right -- not incident to any processed edges */
                    ConnectLeftVertex(tess, vEvent);
                    return;
                }
            }

            /* Processing consists of two phases: first we "finish" all the
             * active regions where both the upper and lower edges terminate
             * at vEvent (ie. vEvent is closing off these regions).
             * We mark these faces "inside" or "outside" the polygon according
             * to their winding number, and delete the edges from the dictionary.
             * This takes care of all the left-going edges from vEvent.
             */
            regUp = TopLeftRegion(e.regionThisIsUpperEdgeOf);
            reg = RegionBelow(regUp);
            eTopLeft = reg.upperHalfEdge;
            eBottomLeft = FinishLeftRegions(tess, reg, null);
            /* Next we process all the right-going edges from vEvent.  This
             * involves adding the edges to the dictionary, and creating the
             * associated "active regions" which record information about the
             * regions between adjacent dictionary edges.
             */
            if (eBottomLeft.nextEdgeCCWAroundOrigin == eTopLeft)
            {
                /* No right-going edges -- add a temporary "fixable" edge */
                ConnectRightVertex(tess, regUp, eBottomLeft);
            }
            else
            {
                AddRightEdges(tess, regUp, eBottomLeft.nextEdgeCCWAroundOrigin, eTopLeft, eTopLeft, true);
            }
        }