Пример #1
0
 protected void GetPlanarPolys(PlanarRegion r, List <Polygon2d> polys)
 {
     try {
         MeshRegionBoundaryLoops loops = new MeshRegionBoundaryLoops(r.Mesh, r.Triangles);
         foreach (var loop in loops)
         {
             DCurve3   curve = loop.ToCurve();
             Polygon2d poly  = new Polygon2d();
             int       NV    = curve.VertexCount;
             for (int k = 0; k < NV; k++)
             {
                 poly.AppendVertex(curve[k].xy);
             }
             polys.Add(poly);
         }
     } catch (Exception) {
         // add each triangle as a polygon and let clipper sort it out
         Vector3d v0 = Vector3d.Zero, v1 = Vector3d.Zero, v2 = Vector3d.Zero;
         foreach (int tid in r.Triangles)
         {
             r.Mesh.GetTriVertices(tid, ref v0, ref v1, ref v2);
             Polygon2d p = new Polygon2d();
             p.AppendVertex(v0.xy); p.AppendVertex(v1.xy); p.AppendVertex(v2.xy);
             polys.Add(p);
         }
     }
 }
Пример #2
0
        static void Main()
        {
            Polygon2d poly = new Polygon2d();

            poly.AppendVertex(new Vector2d(0, 0));
            poly.AppendVertex(new Vector2d(100, 0));
            poly.AppendVertex(new Vector2d(100, 100));
            poly.AppendVertex(new Vector2d(0, 1000));
        }
Пример #3
0
        public static void test_tiling()
        {
            Vector2d         origin     = Vector2d.Zero;
            double           radius     = 22;
            Circle2d         circ       = new Circle2d(origin, radius);
            AxisAlignedBox2d elemBounds = circ.Bounds;
            //elemBounds.Max.x += radius / 2;

            AxisAlignedBox2d packBounds = new AxisAlignedBox2d(0, 0, 800, 400);
            double           spacing    = 5;
            Polygon2d        boundsPoly = new Polygon2d();

            for (int i = 0; i < 4; ++i)
            {
                boundsPoly.AppendVertex(packBounds.GetCorner(i));
            }

            //List<Vector2d> packed = TilingUtil.BoundedRegularTiling2(elemBounds, packBounds, spacing);
            List <Vector2d> packed = TilingUtil.BoundedCircleTiling2(elemBounds, packBounds, spacing);

            System.Console.WriteLine("packed {0}", packed.Count);

            SVGWriter writer = new SVGWriter();

            foreach (Vector2d t in packed)
            {
                writer.AddCircle(new Circle2d(origin + t, radius), SVGWriter.Style.Outline("black", 1.0f));
            }
            writer.AddPolygon(boundsPoly, SVGWriter.Style.Outline("red", 2.0f));
            writer.Write(TestUtil.GetTestOutputPath("test.svg"));
        }
Пример #4
0
        public static void TestOffsetAnimation()
        {
            Window window = new Window("TestFill");

            window.SetDefaultSize(600, 600);
            window.SetPosition(WindowPosition.Center);

            DMesh3            mesh  = StandardMeshReader.ReadMesh("c:\\scratch\\remesh.obj");
            MeshBoundaryLoops loops = new MeshBoundaryLoops(mesh);
            DCurve3           curve = loops[0].ToCurve();
            Polygon2d         poly  = new Polygon2d();

            foreach (Vector3d v in curve.Vertices)
            {
                poly.AppendVertex(v.xy);
            }
            Outer = new GeneralPolygon2d(poly);

            DebugViewCanvas view = new DebugViewCanvas();

            view.AddPolygon(Outer, Colorf.Black);


            DGraph2 graph = TopoOffset2d.QuickCompute(Outer, AnimOffset, AnimSpacing);

            view.AddGraph(graph, Colorf.Red);

            window.Add(view);
            window.ShowAll();

            Active = view;
        }
Пример #5
0
        public Polygon2d GetPolygon(bool update = true)
        {
            if (update)
            {
                Update();
            }

            Polygon2d poly = new Polygon2d();

            for (int i = 0; i < ellipse.Length; i++)
            {
                Vector2 p = ellipse[i];

                if (animationEnabled)
                {
                    foreach (Attractor v in attractors)
                    {
                        p = v.Apply(p);
                    }
                    p = ellipse[i] + (p - ellipse[i]) * distrStrength;

                    float aC = Mathf.Max(0f, ceilRange - Vector2.Angle(Vector2.up, p)) / ceilRange;
                    p.y += (Random.value - 0.5f) * aC * cNoise * noiseScale;

                    float aF = Mathf.Max(0f, floorRange - Vector2.Angle(Vector2.down, p)) / floorRange;
                    p.y += (Random.value - 0.5f) * aF * fNoise * noiseScale;
                }

                poly.AppendVertex(p);
            }
            //Draw(poly);
            return(poly);
        }
Пример #6
0
        public List <GeneralPolygon2d> GetSolids()
        {
            Frame3f f = frameL;

            if (OutputSpace != CoordSpace.ObjectCoords)
            {
                f = SceneTransforms.TransformTo(f, SO, CoordSpace.ObjectCoords, OutputSpace);
            }

            PlanarComplex complex = new PlanarComplex();

            foreach (DCurve3 c in localCurves.Loops)
            {
                Polygon2d poly = new Polygon2d();
                for (int i = 0; i < c.VertexCount; ++i)
                {
                    Vector2f uv = f.ToPlaneUV((Vector3f)c[i], 2);
                    poly.AppendVertex(uv);
                }
                complex.Add(poly);
            }
            PlanarComplex.FindSolidsOptions options = PlanarComplex.FindSolidsOptions.SortPolygons;
            var info = complex.FindSolidRegions(options);

            return(info.Polygons);
        }
Пример #7
0
        /// <summary>
        /// Construct the set of polygons-with-holes that represents the input string
        /// </summary>
        static List <GeneralPolygon2d> GetPolygons(string s, string fontName = "Consolas", FontStyle style = FontStyle.Regular, int emSize = 128)
        {
            GraphicsPath path = new GraphicsPath();

            string       text   = s;
            FontFamily   font   = new FontFamily(fontName);
            Point        origin = new Point(0, 0);
            StringFormat format = new StringFormat();

            path.AddString(text, font, (int)style, emSize, origin, format);
            path.Flatten();

            PlanarComplex complex = new PlanarComplex();


            Polygon2d cur_poly = new Polygon2d();

            for (int i = 0; i < path.PathPoints.Length; ++i)
            {
                PointF   pt = path.PathPoints[i];
                Vector2d v  = new Vector2d(pt.X, pt.Y);

                int type  = path.PathTypes[i] & 0x7;
                int flags = path.PathTypes[i] & 0xF8;

                if (type == 0)
                {
                    cur_poly = new Polygon2d();
                    cur_poly.AppendVertex(v);
                }
                else if (type == 1)
                {
                    cur_poly.AppendVertex(v);
                    if ((flags & 0x80) != 0)
                    {
                        // [RMS] some characters have a duplicate start/end point after Flatten(). Some do not. Clusterfuck!
                        int iLast = cur_poly.VertexCount - 1;
                        if (cur_poly[0].Distance(cur_poly[iLast]) < 0.001)
                        {
                            cur_poly.RemoveVertex(iLast);  // we just duplicated first point
                        }
                        complex.Add(cur_poly);
                    }
                }
            }


            PlanarComplex.SolidRegionInfo solids = complex.FindSolidRegions(0.0f, false);
            List <GeneralPolygon2d>       result = solids.Polygons;

            foreach (var gp in result)
            {
                gp.Transform((v) => { return(new Vector2d(v.x, emSize - v.y)); });
            }

            return(result);
        }
        public static void compute_distance_image()
        {
            DMesh3            mesh  = StandardMeshReader.ReadMesh("c:\\scratch\\remesh.obj");
            MeshBoundaryLoops loops = new MeshBoundaryLoops(mesh);
            DCurve3           curve = loops[0].ToCurve();
            Polygon2d         poly  = new Polygon2d();

            foreach (Vector3d v in curve.Vertices)
            {
                poly.AppendVertex(v.xy);
            }
            int      N        = 1024;
            double   cellsize = poly.Bounds.MaxDim / (double)N;
            Vector2d o        = poly.Bounds.Min;

            o -= 4 * cellsize * Vector2d.One;
            N += 8;

            ShiftGridIndexer2 indexer = new ShiftGridIndexer2(poly.Bounds.Min, cellsize);

            double[] df   = new double[N * N];
            double   maxd = 0;

            for (int yi = 0; yi < N; ++yi)
            {
                for (int xi = 0; xi < N; ++xi)
                {
                    Vector2d p = indexer.FromGrid(new Vector2i(xi, yi));
                    double   d = Math.Sqrt(poly.DistanceSquared(p));
                    df[yi * N + xi] = d;
                    maxd            = Math.Max(d, maxd);
                }
            }

            SKBitmap bmp = new SKBitmap(N, N);

            for (int yi = 0; yi < N; ++yi)
            {
                for (int xi = 0; xi < N; ++xi)
                {
                    double d = df[yi * N + xi];
                    float  f = (float)(d / maxd);
                    byte   b = (byte)(int)(f * 255);
                    bmp.SetPixel(xi, yi, new SKColor(b, b, b));
                }
            }

            using (var image = SKImage.FromBitmap(bmp))
                using (var data = image.Encode(SKEncodedImageFormat.Png, 80)) {
                    // save the data to a stream
                    using (var stream = File.OpenWrite("c:\\scratch\\distances.png")) {
                        data.SaveTo(stream);
                    }
                }
        }
Пример #9
0
        Polygon2d make_poly(DMesh3 mesh, EdgeLoop loop)
        {
            Polygon2d poly = new Polygon2d();

            for (int k = 0; k < loop.VertexCount; ++k)
            {
                Vector3d v = mesh.GetVertex(loop.Vertices[k]);
                poly.AppendVertex(v.xy);
            }
            return(poly);
        }
Пример #10
0
        Polygon2d to_polygon(EdgeSpan span, Frame3f polyFrame)
        {
            int       NV   = span.VertexCount;
            Polygon2d poly = new Polygon2d();

            for (int k = 0; k < NV; ++k)
            {
                poly.AppendVertex(polyFrame.ToPlaneUV((Vector3f)span.GetVertex(k), 2));
            }
            return(poly);
        }
Пример #11
0
        public static void Restore(Polygon2d polygon, BinaryReader reader)
        {
            int count = reader.ReadInt32();

            for (int i = 0; i < count; ++i)
            {
                double x = reader.ReadDouble();
                double y = reader.ReadDouble();
                polygon.AppendVertex(new Vector2D(x, y));
            }
        }
Пример #12
0
        public Cvt(IReadOnlyCollection <Vertex> polygon, CvtSettings settings)
        {
            if (settings == null)
            {
                throw new ArgumentException("Please, define CvtSettings object");
            }
            Polygon = new Polygon2d();
            foreach (Vertex vertex in polygon)
            {
                Polygon.AppendVertex(new Vector2d(vertex.X, vertex.Y));
            }

            Settings = settings;
        }
Пример #13
0
        public static Polygon2d ConvertFromClipper(CPolygon clipper_poly, double nIntScale)
        {
            double scale = 1.0 / (double)nIntScale;

            int       N    = clipper_poly.Count;
            Polygon2d poly = new Polygon2d();

            for (int i = 0; i < N; ++i)
            {
                IntPoint p = clipper_poly[i];
                Vector2d v = new Vector2d((double)p.X * scale, (double)p.Y * scale);
                poly.AppendVertex(v);
            }
            return(poly);
        }
Пример #14
0
        /// <summary>
        /// create Polygon by projecting polygon3 into frame
        /// </summary>
        public MeshInsertProjectedPolygon(DMesh3 mesh, DCurve3 polygon3, Frame3f frame, int seedTri)
        {
            if (polygon3.Closed == false)
            {
                throw new Exception("MeshInsertPolyCurve(): only closed polygon3 supported for now");
            }

            Mesh         = mesh;
            ProjectFrame = frame;
            SeedTriangle = seedTri;

            Polygon = new Polygon2d();
            foreach (Vector3d v3 in polygon3.Vertices)
            {
                Vector2f uv = frame.ToPlaneUV((Vector3f)v3, 2);
                Polygon.AppendVertex(uv);
            }
        }
Пример #15
0
        static GeneralPolygon2d GetPolygonFromMesh(string sPath)
        {
            DMesh3            mesh  = StandardMeshReader.ReadMesh(sPath);
            MeshBoundaryLoops loops = new MeshBoundaryLoops(mesh);

            PlanarComplex complex = new PlanarComplex();

            foreach (var loop in loops)
            {
                Polygon2d poly  = new Polygon2d();
                DCurve3   curve = MeshUtil.ExtractLoopV(mesh, loop.Vertices);
                foreach (Vector3d v in curve.Vertices)
                {
                    poly.AppendVertex(v.xy);
                }
                complex.Add(poly);
            }

            PlanarComplex.SolidRegionInfo solids = complex.FindSolidRegions(0.0, false);
            return(solids.Polygons[0]);
        }
Пример #16
0
        public List <Polygon2d> GetPolygons()
        {
            Frame3f f = frameL;

            if (OutputSpace != CoordSpace.ObjectCoords)
            {
                f = SceneTransforms.TransformTo(f, SO, CoordSpace.ObjectCoords, OutputSpace);
            }

            List <Polygon2d> polygons = new List <Polygon2d>();

            foreach (DCurve3 c in localCurves.Loops)
            {
                Polygon2d poly = new Polygon2d();
                for (int i = 0; i < c.VertexCount; ++i)
                {
                    Vector2f uv = f.ToPlaneUV((Vector3f)c[i], 2);
                    poly.AppendVertex(uv);
                }
                polygons.Add(poly);
            }
            return(polygons);
        }
Пример #17
0
        public static void test_uv_insert_segment()
        {
            DMesh3 mesh = TestUtil.LoadTestInputMesh("plane_250v.obj");

            mesh.EnableVertexUVs(Vector2f.Zero);

            MeshTransforms.ConvertYUpToZUp(mesh);

            DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh);

            spatial.Build();
            int tid = spatial.FindNearestTriangle(Vector3d.Zero);

            //Polygon2d poly = Polygon2d.MakeRectangle(Vector2d.Zero, 5, 5);
            Polygon2d poly = Polygon2d.MakeCircle(5, 13);
            //PolyLine2d poly = new PolyLine2d( new Vector2d[] { -5 * Vector2d.One, 5 * Vector2d.One });


            //int tri_edge0 = mesh.GetTriEdge(tid, 0);
            //Index2i edge0_tris = mesh.GetEdgeT(tri_edge0);
            //Index2i edge0_verts = mesh.GetEdgeV(tri_edge0);
            //Vector3d v0 = mesh.GetVertex(edge0_verts.a), v1 = mesh.GetVertex(edge0_verts.b);
            //Vector3d c = mesh.GetTriCentroid(tid);
            //Polygon2d poly = new Polygon2d(new Vector2d[] {
            //    Vector2d.Lerp(v0.xy, v1.xy, -0.25),
            //    Vector2d.Lerp(v0.xy, v1.xy, 1.5),
            //    c.xy
            //});

            MeshInsertUVPolyCurve insert = new MeshInsertUVPolyCurve(mesh, poly);

            insert.Apply();



            Polygon2d     test_poly = new Polygon2d();
            List <double> distances = new List <double>();
            List <int>    nearests  = new List <int>();

            for (int i = 0; i < insert.Loops[0].VertexCount; ++i)
            {
                Vector2d v = mesh.GetVertex(insert.Loops[0].Vertices[i]).xy;
                test_poly.AppendVertex(v);
                int iNear; double fNear;
                distances.Add(poly.DistanceSquared(v, out iNear, out fNear));
                nearests.Add(iNear);
            }

            System.Console.WriteLine("inserted loop poly has {0} edges", insert.Loops[0].EdgeCount);

            // find a triangle connected to loop that is inside the polygon
            //   [TODO] maybe we could be a bit more robust about this? at least
            //   check if triangle is too degenerate...
            int seed_tri = -1;

            for (int i = 0; i < insert.Loops[0].EdgeCount; ++i)
            {
                Index2i  et   = mesh.GetEdgeT(insert.Loops[0].Edges[i]);
                Vector3d ca   = mesh.GetTriCentroid(et.a);
                bool     in_a = poly.Contains(ca.xy);
                Vector3d cb   = mesh.GetTriCentroid(et.b);
                bool     in_b = poly.Contains(cb.xy);
                if (in_a && in_b == false)
                {
                    seed_tri = et.a;
                    break;
                }
                else if (in_b && in_a == false)
                {
                    seed_tri = et.b;
                    break;
                }
            }
            Util.gDevAssert(seed_tri != -1);

            // flood-fill inside loop
            HashSet <int>     loopEdges = new HashSet <int>(insert.Loops[0].Edges);
            MeshFaceSelection sel       = new MeshFaceSelection(mesh);

            sel.FloodFill(seed_tri, null, (eid) => { return(loopEdges.Contains(eid) == false); });

            // delete inside loop
            MeshEditor editor = new MeshEditor(mesh);

            editor.RemoveTriangles(sel, true);


            MeshTransforms.ConvertZUpToYUp(mesh);

            TestUtil.WriteTestOutputMesh(mesh, "insert_uv_segment.obj");



            //OBJWriter writer = new OBJWriter();
            //var s = new System.IO.StreamWriter(Program.TEST_OUTPUT_PATH + "mesh_local_param.obj", false);
            //List<WriteMesh> wm = new List<WriteMesh>() { new WriteMesh(mesh) };
            //WriteOptions opt = new WriteOptions() {
            //    bCombineMeshes = false, bWriteGroups = false, bPerVertexColors = true, bPerVertexUVs = true,
            //    AsciiHeaderFunc = () => { return "mttllib checkerboard.mtl\r\nusemtl checkerboard\r\n"; }
            //};
            //writer.Write(s, wm, opt);
            //s.Close();
        }
Пример #18
0
        public static void test_tube_generator()
        {
            Polygon2d  circle_path = Polygon2d.MakeCircle(50, 64);
            PolyLine2d arc_path    = new PolyLine2d(circle_path.Vertices.Take(circle_path.VertexCount / 2));
            Polygon2d  irreg_path  = new Polygon2d();

            for (int k = 0; k < circle_path.VertexCount; ++k)
            {
                irreg_path.AppendVertex(circle_path[k]);
                k += k / 2;
            }
            PolyLine2d irreg_arc_path = new PolyLine2d(irreg_path.Vertices.Take(circle_path.VertexCount - 1));

            Polygon2d square_profile = Polygon2d.MakeCircle(7, 32);

            square_profile.Translate(4 * Vector2d.One);
            //square_profile[0] = 20 * square_profile[0].Normalized;

            bool no_shared = true;

            WriteGeneratedMesh(
                new TubeGenerator(circle_path, Frame3f.Identity, square_profile)
            {
                WantUVs = true, NoSharedVertices = no_shared
            },
                "tubegen_loop_standarduv.obj");

            WriteGeneratedMesh(
                new TubeGenerator(irreg_path, Frame3f.Identity, square_profile)
            {
                WantUVs = true, NoSharedVertices = no_shared
            },
                "tubegen_irregloop_standarduv.obj");

            WriteGeneratedMesh(
                new TubeGenerator(arc_path, Frame3f.Identity, square_profile)
            {
                WantUVs = true, NoSharedVertices = no_shared
            },
                "tubegen_arc_standarduv.obj");

            WriteGeneratedMesh(
                new TubeGenerator(irreg_arc_path, Frame3f.Identity, square_profile)
            {
                WantUVs = true, NoSharedVertices = no_shared
            },
                "tubegen_irregarc_standarduv.obj");



            // append tube border around each hole of input mesh
            DMesh3            inMesh   = TestUtil.LoadTestInputMesh("n_holed_bunny.obj");
            Polygon2d         bdrycirc = Polygon2d.MakeCircle(0.25, 6);
            MeshBoundaryLoops loops    = new MeshBoundaryLoops(inMesh);

            foreach (EdgeLoop loop in loops)
            {
                DCurve3       curve = loop.ToCurve().ResampleSharpTurns();
                TubeGenerator gen   = new TubeGenerator(curve, bdrycirc)
                {
                    NoSharedVertices = false
                };
                MeshEditor.Append(inMesh, gen.Generate().MakeDMesh());
            }
            TestUtil.WriteTestOutputMesh(inMesh, "boundary_tubes.obj");
        }
Пример #19
0
        // exports svg w/ different containments of point set (created by slicing mesh)
        public static void containment_demo_svg()
        {
            DMesh3 mesh = TestUtil.LoadTestInputMesh("bunny_solid.obj");

            MeshTransforms.Scale(mesh, 4);

            AxisAlignedBox3d meshBounds = mesh.CachedBounds;
            Vector3d         origin     = meshBounds.Center;

            origin -= 0.2 * meshBounds.Height * Vector3d.AxisY;
            Frame3f      plane = new Frame3f(origin, new Vector3d(1, 3, 0).Normalized);
            MeshPlaneCut cut   = new MeshPlaneCut(mesh, plane.Origin, plane.Z);

            cut.Cut();

            AxisAlignedBox2d polyBounds = AxisAlignedBox2d.Empty;
            List <Polygon2d> polys      = new List <Polygon2d>();

            foreach (EdgeLoop loop in cut.CutLoops)
            {
                Polygon2d poly = new Polygon2d();
                foreach (int vid in loop.Vertices)
                {
                    poly.AppendVertex(mesh.GetVertex(vid).xz);
                }
                poly.Rotate(new Matrix2d(90, true), Vector2d.Zero);
                polys.Add(poly);
                polyBounds.Contain(poly.Bounds);
            }

            SVGWriter svg       = new SVGWriter();
            var       polyStyle = SVGWriter.Style.Outline("red", 1.0f);
            var       contStyle = SVGWriter.Style.Outline("black", 1.0f);

            for (int k = 0; k < 3; ++k)
            {
                double          shift = (k == 2) ? 1.4f : 1.1f;
                Vector2d        tx    = (k - 1) * (polyBounds.Width * shift) * Vector2d.AxisX;
                List <Vector2d> pts   = new List <Vector2d>();
                foreach (Polygon2d poly in polys)
                {
                    var p2 = new Polygon2d(poly).Translate(tx);
                    pts.AddRange(p2.Vertices);
                    svg.AddPolygon(p2, polyStyle);
                }

                if (k == 0)
                {
                    ConvexHull2 hull = new ConvexHull2(pts, 0.001, QueryNumberType.QT_DOUBLE);
                    svg.AddPolygon(hull.GetHullPolygon(), contStyle);
                }
                else if (k == 1)
                {
                    ContMinBox2 contbox = new ContMinBox2(pts, 0.001, QueryNumberType.QT_DOUBLE, false);
                    svg.AddPolygon(new Polygon2d(contbox.MinBox.ComputeVertices()), contStyle);
                }
                else if (k == 2)
                {
                    ContMinCircle2 contcirc = new ContMinCircle2(pts);
                    svg.AddCircle(contcirc.Result, contStyle);
                }
            }


            svg.Write(TestUtil.GetTestOutputPath("contain_demos.svg"));
        }
Пример #20
0
        public static void test_arrangement_demo()
        {
            DMesh3 mesh = TestUtil.LoadTestInputMesh("spheres_and_planes.obj");

            MeshTransforms.Scale(mesh, 8);
            AxisAlignedBox3d meshBounds      = mesh.CachedBounds;
            Vector3d         origin          = meshBounds.Center;
            double           simplify_thresh = 5.0;

            Frame3f      plane = new Frame3f(origin, Vector3d.AxisY);
            MeshPlaneCut cut   = new MeshPlaneCut(mesh, plane.Origin, plane.Z);

            cut.Cut();

            Arrangement2d builder = new Arrangement2d(new AxisAlignedBox2d(1024.0));

            // insert all cut edges
            HashSet <Vector2d> srcpts = new HashSet <Vector2d>();

            foreach (EdgeLoop loop in cut.CutLoops)
            {
                Polygon2d poly = new Polygon2d();
                foreach (int vid in loop.Vertices)
                {
                    poly.AppendVertex(mesh.GetVertex(vid).xz);
                }

                poly.Simplify(simplify_thresh, 0.01, true);
                foreach (Vector2d v in poly.Vertices)
                {
                    srcpts.Add(v);
                }

                builder.Insert(poly);
            }
            foreach (EdgeSpan span in cut.CutSpans)
            {
                PolyLine2d pline = new PolyLine2d();
                foreach (int vid in span.Vertices)
                {
                    pline.AppendVertex(mesh.GetVertex(vid).xz);
                }
                pline.Simplify(simplify_thresh, 0.01, true);
                foreach (Vector2d v in pline)
                {
                    srcpts.Add(v);
                }
                builder.Insert(pline);
            }

            SVGWriter svg = new SVGWriter();

            svg.AddGraph(builder.Graph);

            var vtx_style = SVGWriter.Style.Outline("red", 1.0f);

            foreach (int vid in builder.Graph.VertexIndices())
            {
                Vector2d v = builder.Graph.GetVertex(vid);
                if (srcpts.Contains(v) == false)
                {
                    svg.AddCircle(new Circle2d(v, 2), vtx_style);
                }
            }

            svg.Write(TestUtil.GetTestOutputPath("arrangement.svg"));
        }