Exemple #1
0
        public static CompiledDrawing FromFace(FillFace face)
        {
            var fill = new CompiledDrawing();

            // Simplify the face by subdividing overlapping curves
            var newFace = face.SubdivideOverlapping();

            // Build the fill polygons and triangulate them
            fill.Triangles = Triangulator.YMonotone.Triangulate(newFace.Contours.Select(FillPolygon).ToArray());

            // Collect all curve triangles
            var curves               = newFace.Contours.SelectMany(v => v.Where(c => c.Type != CurveType.Line)).ToArray();
            var curveTriangles       = new List <CurveTriangle>();
            var doubleCurveTriangles = new List <DoubleCurveTriangle>();

            if (curves.Length > 0)
            {
                // Check first if the last and first curve aren't joinable
                bool lastFirstJoin = curves.Length > 1 && FillFace.AreCurvesFusable(curves[curves.Length - 1], curves[0]);
                if (lastFirstJoin)
                {
                    doubleCurveTriangles.AddRange(FuseCurveTriangles(curves[curves.Length - 1], curves[0]));
                }
                else
                {
                    curveTriangles.AddRange(CurveVertex.MakeTriangleFan(curves[0].CurveVertices));
                }

                // Now, scan the curve list for pairs of scannable curves
                var k = lastFirstJoin ? 1 : 0;
                for (int i = k; i < curves.Length - k; i++)
                {
                    if (i < curves.Length - 1 && FillFace.AreCurvesFusable(curves[i], curves[i + 1]))
                    {
                        doubleCurveTriangles.AddRange(FuseCurveTriangles(curves[i], curves[i + 1]));
                        i++;
                    }
                    else
                    {
                        curveTriangles.AddRange(CurveVertex.MakeTriangleFan(curves[i].CurveVertices));
                    }
                }
            }

            fill.CurveTriangles       = curveTriangles.ToArray();
            fill.DoubleCurveTriangles = doubleCurveTriangles.ToArray();

            return(fill);
        }
Exemple #2
0
        internal static CompiledDrawing CompileCurves(List <Curve> curves, SvgFillRule fillRule)
        {
            // Reunite all intersections to subdivide the curves
            var curveRootSets = new SortedDictionary <double, Double2> [curves.Count];

            for (int i = 0; i < curveRootSets.Length; i++)
            {
                curveRootSets[i] = new SortedDictionary <double, Double2>()
                {
                    [0] = curves[i].At(0), [1] = curves[i].At(1)
                }
            }
            ;

            // Get all intersections
            for (int i = 0; i < curves.Count; i++)
            {
                for (int j = i + 1; j < curves.Count; j++)
                {
                    foreach (var pair in Curve.Intersections(curves[i], curves[j]))
                    {
                        if (!GeometricUtils.Inside01(pair.A) || !GeometricUtils.Inside01(pair.B))
                        {
                            continue;
                        }

                        curveRootSets[i][pair.A] = curves[i].At(pair.A);
                        curveRootSets[j][pair.B] = curves[j].At(pair.B);
                    }
                }
            }

            // Cluster the intersections
            var curveRootClusters = DerivePointClustersFromRootSets(curveRootSets);

            // Finally, we can start building the DCEL
            var dcel = new DCEL.DCEL();

            for (int i = 0; i < curves.Count; i++)
            {
                var prevPair = new KeyValuePair <double, int>(double.NaN, 0);
                foreach (var curPair in curveRootClusters[i])
                {
                    if (!double.IsNaN(prevPair.Key))
                    {
                        Curve curve;
                        if (prevPair.Key == 0 && curPair.Key == 1)
                        {
                            curve = curves[i];
                        }
                        else
                        {
                            curve = curves[i].Subcurve(prevPair.Key, curPair.Key);
                        }

                        foreach (var c in curve.Simplify())
                        {
                            // Skip degenerate curves
                            if (c.IsDegenerate)
                            {
                                continue;
                            }
                            dcel.AddCurve(c, prevPair.Value, curPair.Value);
                            //Console.WriteLine(dcel);
                            //Console.ReadLine();
                        }
                    }

                    prevPair = curPair;
                }
            }

            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Now, we remove wedges and assign the fill numbers

            dcel.RemoveWedges();
            //Console.WriteLine(dcel);
            //Console.ReadLine();
            dcel.AssignFillNumbers();
            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Pick the appropriate predicate for the fill rule
            Func <DCEL.Face, bool> facePredicate;

            if (fillRule == SvgFillRule.EvenOdd)
            {
                facePredicate = f => f.FillNumber % 2 != 0;
            }
            else
            {
                facePredicate = f => f.FillNumber != 0;
            }

            // Simplify the faces
            dcel.SimplifyFaces(facePredicate);
            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Generate the filled faces
            var fills = dcel.Faces.Where(facePredicate).Select(face =>
                                                               new FillFace(face.Contours.Select(contour =>
                                                                                                 contour.CyclicalSequence.Select(e => e.Curve).ToArray()).ToArray()));

            // Generace the filled faces
            return(CompiledDrawing.ConcatMany(fills.Select(CompiledDrawing.FromFace)));
        }
        internal static CompiledDrawing CompileCurves(List <Curve> curves, FillRule fillRule)
        {
            // Reunite all intersections to subdivide the curves
            var curveRootSets = new SortedDictionary <double, Double2> [curves.Count];

            for (int i = 0; i < curveRootSets.Length; i++)
            {
                curveRootSets[i] = new SortedDictionary <double, Double2>()
                {
                    [0] = curves[i].At(0), [1] = curves[i].At(1)
                }
            }
            ;

            // Get all intersections
            for (int i = 0; i < curves.Count; i++)
            {
                for (int j = i + 1; j < curves.Count; j++)
                {
                    foreach (var pair in Curve.Intersections(curves[i], curves[j]))
                    {
                        if (!GeometricUtils.Inside01(pair.A) || !GeometricUtils.Inside01(pair.B))
                        {
                            continue;
                        }

                        var a = curves[i].At(pair.A);
                        var b = curves[j].At(pair.B);

                        if (!DoubleUtils.RoughlyEquals(a / 16, b / 16))
                        {
                            //Console.WriteLine(string.Join(" ", Curve.Intersections(curves[i], curves[j]).Select(c => $"({c.A} {c.B})")));
                            Debug.Assert(false, "Problem here...");
                        }

                        curveRootSets[i][pair.A] = curveRootSets[j][pair.B] = (a + b) / 2;
                    }
                }
            }

            //for (int i = 0; i < curves.Count; i++)
            //Curve.RemoveSimilarRoots(curveRootSets[i]);

            // Finally, we can start building the DCEL
            var dcel = new DCEL.DCEL();

            for (int i = 0; i < curves.Count; i++)
            {
                KeyValuePair <double, Double2> prevPair = new KeyValuePair <double, Double2>(double.NaN, new Double2());
                foreach (var curPair in curveRootSets[i])
                {
                    if (!double.IsNaN(prevPair.Key))
                    {
                        Curve curve;
                        if (prevPair.Key == 0 && curPair.Key == 1)
                        {
                            curve = curves[i];
                        }
                        else
                        {
                            curve = curves[i].Subcurve(prevPair.Key, curPair.Key);
                        }

                        foreach (var c in curve.Simplify())
                        {
                            //if (c.IsDegenerate) continue;
                            dcel.AddCurve(c, prevPair.Value, curPair.Value);
                            //Console.WriteLine(dcel);
                            //Console.ReadLine();
                        }
                    }

                    prevPair = curPair;
                }
            }

            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Now, we remove wedges and assign the fill numbers
            dcel.RemoveWedges();
            //Console.WriteLine(dcel);
            //Console.ReadLine();
            dcel.AssignFillNumbers();
            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Pick the appropriate predicate for the fill rule
            Func <DCEL.Face, bool> facePredicate;

            if (fillRule == FillRule.Evenodd)
            {
                facePredicate = f => f.FillNumber % 2 != 0;
            }
            else
            {
                facePredicate = f => f.FillNumber != 0;
            }

            // Simplify the faces
            dcel.SimplifyFaces(facePredicate);
            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Generate the filled faces
            var fills = dcel.Faces.Where(facePredicate).Select(face =>
                                                               new FillFace(face.Contours.Select(contour =>
                                                                                                 contour.CyclicalSequence.Select(e => e.Curve).ToArray()).ToArray()));

            // Generace the filled faces
            return(CompiledDrawing.ConcatMany(fills.Select(CompiledDrawing.FromFace)));
        }