// use the clipper library to return an offset to the given polygon. Positive offset expands the polygon, negative contracts // note that this returns an array of polygons public static NFP[] polygonOffsetDeepNest(NFP polygon, double offset) { if (offset == 0 || GeometryUtil._almostEqual(offset, 0)) { return(new[] { polygon }); } var p = svgToClipper(polygon).ToList(); var miterLimit = 4; var co = new ClipperLib.ClipperOffset(miterLimit, Config.curveTolerance * Config.clipperScale); co.AddPath(p.ToList(), ClipperLib.JoinType.jtMiter, ClipperLib.EndType.etClosedPolygon); var newpaths = new List <List <ClipperLib.IntPoint> >(); co.Execute(ref newpaths, offset * Config.clipperScale); var result = new List <NFP>(); for (var i = 0; i < newpaths.Count; i++) { result.Add(clipperToSvg(newpaths[i])); } return(result.ToArray()); }
public List <List <Vector3> > Offset(float amount, float height) { var orderedPoints = GetAllOrderedIntPoints(); var result = new List <List <Vector3> >(); foreach (var path in orderedPoints) { Debug.Log("New path"); foreach (var intpoint in path.Points) { Debug.Log("Ordered point: " + intpoint.X + ", " + intpoint.Y); } var co = new ClipperLib.ClipperOffset(); var endType = path.IsClosedLoop ? ClipperLib.EndType.etClosedLine : ClipperLib.EndType.etOpenSquare; co.AddPath(path.Points, ClipperLib.JoinType.jtSquare, endType); var results = new List <List <ClipperLib.IntPoint> >(); co.Execute(ref results, (int)(amount * 1000.0f)); result.AddRange(results.Select( xs => xs.Select( x => new Vector3((float)x.X / 1000.0f, height, (float)x.Y / 1000.0f)).ToList())); } return(result); }
public List<List<IntPoint>> Run (List<List<IntPoint>> subject, double scale) { var clipperOffset = new ClipperOffset (miterLimit, arcTolerance); clipperOffset.AddPaths (subject, joinType, endType); var result = new List<List<IntPoint>> (); clipperOffset.Execute (ref result, scale * delta); return result; }
public override List<List<IntPoint>> GetCopyOfClipperPolygon(double relativeWidth, List<List<IntPoint>> outerPolygon) { var delta = (-2 * relativeWidth) * ClosedSymbolBase.ClipperScalingInt; var clipper = new ClipperOffset(); clipper.AddPaths(outerPolygon, JoinType.jtMiter, EndType.etClosedPolygon); var result = new List<List<IntPoint>>(); clipper.Execute(ref result, delta); return result; }
//------------------------------------------------------------------------------ public static Paths OffsetPaths(Paths pp, double delta, JoinType jt, EndType et) { Paths result = new Paths(); ClipperOffset co = new ClipperOffset(); co.AddPaths(pp, jt, et); co.Execute(ref result, delta); return(result); }
/// <summary> /// 对一个点集路径进行偏移 需要注意 对于一个闭合路径 使用ClipperOffset 得到的结果,会有两个点集,第一个结果为外圈点集,第二结果为内圈点集 /// </summary> public static List <List <IntPoint> > _GetOffsetPonts_clipper_Path(Path_xyz _Path_xyz_RedLine, double _offset) { Paths solution = new Paths(); ClipperOffset _Co = new ClipperOffset();//ClipperOffset构造函数。其包含可选参数 Path _Path_RedLine = Path_xyzToPath(_Path_xyz_RedLine); _Co.AddPath(_Path_RedLine, JoinType.jtSquare, EndType.etClosedLine); _offset = _offset * 1000; //放大倍数与clipper_methods中放大倍数保持一致 _Co.Execute(ref solution, _offset); return(solution); //一根线偏移后,应该具有四个端点,为矩形 }
public static Polygons Offset(this Polygons polygons, double distance) { var offseter = new ClipperOffset(); offseter.AddPaths(polygons, JoinType.jtRound, EndType.etClosedPolygon); var solution = new Polygons(); offseter.Execute(ref solution, distance); return(solution); }
public static bool GetPoint(Vector2[] quad, bool outter, out List<Vector2> list, bool isClose=true) { List<IntPoint> quadLines = new List<IntPoint>(); for(int i=0; i < quad.Length; i++){ Vector3 from = quad[i]; IntPoint to = new IntPoint(from.x * DrawHelper.ClipScalling, from.y * DrawHelper.ClipScalling); quadLines.Add(to); // IntPoint to = quad[i+1]; // to = new IntPoint(to.X * scale.X * scalling, to.Y * scale.Y * scalling); // quadLines.Add(to); } EndType endType = EndType.etOpenButt; if(isClose){ endType = EndType.etClosedPolygon; } //Debug.Log("endType: " + endType); ClipperOffset co = new ClipperOffset(); co.AddPath(quadLines, JoinType.jtMiter, endType); Paths solution = new Paths(); double delta = -DrawHelper.WallThick/2 * DrawHelper.ClipScalling; if(outter){ delta = -delta; } co.MiterLimit = 8; co.Execute(ref solution, delta); list = new List<Vector2>(); if(solution.Count > 0){ foreach(IntPoint p in solution[0]){ Vector3 re = new Vector3(p.X * 1.0f/DrawHelper.ClipScalling, p.Y * 1.0f/DrawHelper.ClipScalling, 0f); if(!isClose){ //Debug.Log("result: " + re); } list.Add(re); } list.Add(list[0]); return Clipper.Orientation(solution[0]); } else{ Debug.LogError("no solution.."); } return true; }
public void assignNewBuildings(string data) { ClipperLib.ClipperOffset co = new ClipperLib.ClipperOffset(); InvisBuildingJsonRepsonse res = JsonUtility.FromJson <InvisBuildingJsonRepsonse>(data); for (int i = 0; i < res.response.Length; ++i) { bool duplicate = false; for (int j = 0; j < all_buildings.Count; ++j) { if (res.response[i].id == all_buildings[j].id) { duplicate = true; } } if (!duplicate) { // invisible building and fade building GameObject fb = Instantiate(Resources.Load("FadeBuilding"), new Vector3(0, 0, 0), Quaternion.identity) as GameObject; fb.transform.SetParent(building_container); List <ClipperLib.IntPoint> path = new List <ClipperLib.IntPoint>(); for (int k = 0; k < res.response[i].building.Length; k += 2) { path.Add(new ClipperLib.IntPoint(res.response[i].building[k] * prec, res.response[i].building[k + 1] * prec)); } co.AddPath(path, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon); List <List <ClipperLib.IntPoint> > l = new List <List <ClipperLib.IntPoint> >(); co.Execute(ref l, -smaller * prec); co.Clear(); InvisBuildingJsonRepsonse_Building ibb = new InvisBuildingJsonRepsonse_Building(); ibb.startPoint = res.response[i].startPoint; ibb.id = res.response[i].id; ibb.building = new float[l[0].Count * 2]; //ibb.building = for (int k = 0; k < l[0].Count; ++k) { ibb.building[k * 2] = l[0][k].X / prec; ibb.building[k * 2 + 1] = l[0][k].Y / prec; } fb.GetComponent <InvisBuilding>().init(res.response[i], poi_handler); all_buildings.Add(fb.GetComponent <InvisBuilding>()); } } }
/// <summary> /// 使用clipper对 单根个线段进行偏移,其结果点集是一个矩形路径 /// </summary> public static List <IntPoint> _GetOffsetPonts_clipper_line(Curve _curve, double _offset) { //拿出线段断点转化为 Intpont XYZ _startPoint = _curve.GetEndPoint(0); XYZ _endPoint = _curve.GetEndPoint(1); Path_xyz _Path_xyz = new Path_xyz() { _startPoint, _endPoint }; Path _Path = Path_xyzToPath(_Path_xyz); Paths solution = new Paths(); //开展偏移工作 ClipperOffset _Co = new ClipperOffset();//ClipperOffset构造函数。其包含可选参数 _Co.AddPath(_Path, JoinType.jtSquare, EndType.etClosedLine); _offset = _offset * _multiple; //放大倍数与clipper_methods中放大倍数保持一致 _Co.Execute(ref solution, _offset); return(solution[0]); //一根线偏移后,应该具有四个端点,为矩形 }
public static NFP[] offset(NFP polygon, double offset, JoinType jType = JoinType.jtMiter, double clipperScale = 10000000, double curveTolerance = 0.72, double miterLimit = 4) { var p = ScaleUpPaths(polygon, clipperScale).ToList(); var co = new ClipperLib.ClipperOffset(miterLimit, curveTolerance * clipperScale); co.AddPath(p.ToList(), jType, ClipperLib.EndType.etClosedPolygon); var newpaths = new List <List <ClipperLib.IntPoint> >(); co.Execute(ref newpaths, offset * clipperScale); var result = new List <NFP>(); for (var i = 0; i < newpaths.Count; i++) { result.Add(clipperToSvg(newpaths[i])); } return(result.ToArray()); }
public static PolygonSet offsetLineSquare(PolygonSet p, float d) { if (float.IsNaN(d)) { return p; } ClipperOffset co = new ClipperOffset(); co.AddPaths(p, JoinType.jtSquare, EndType.etClosedPolygon); PolygonSet solution = new PolygonSet(); co.Execute(ref solution, d); return solution; }
public void Offset(float offset) { Paths polygons = Clipper.ClosedPathsFromPolyTree(polyTree); ClipperOffset co = new ClipperOffset(); co.ArcTolerance = scale * .0001f; co.AddPaths(polygons, JoinType.jtRound, EndType.etClosedPolygon); polyTree = new PolyTree(); Paths offsetPaths = new Paths(); co.Execute(ref offsetPaths, scale * offset); offsetPaths = Clipper.CleanPolygons(offsetPaths, scale * .0001f); polyTree = PolygonsToPolyTree(offsetPaths); }
private PolyTreeEdgesRetained PrepairPolyTree(Collider2D[] floorColliders, Collider2D[] wallColliders) { if(floorColliders.Length == 0) { throw new System.Exception("No colliders in the scene on the floor layer."); } PolyTreeEdgesRetained TreeAndEdges = new PolyTreeEdgesRetained(); TreeAndEdges.Edges = new List<List<IntPoint>>(); TreeAndEdges.Tree = new PolyTree(); Clipper finalClipper = new Clipper(); if (floorColliders.Length > 0) { Clipper tempC = new Clipper(); ClipperOffset tempCo = new ClipperOffset(); foreach (Collider2D d in floorColliders) { List<IntPoint> p = PolygonFromCollider2D(d, false); if (p != null && p.Count != 0) { if (ClipperLib.Clipper.Orientation(p)) p.Reverse(); tempC.AddPath(p, PolyType.ptSubject, true); } } List<List<IntPoint>> solution = new List<List<IntPoint>>(); tempC.Execute(ClipType.ctUnion, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero); tempC.Clear(); foreach (List<IntPoint> intPoints in solution) { tempCo.AddPath(intPoints, (JoinType)GenerationInformation.JoinType, EndType.etClosedPolygon); TreeAndEdges.Edges.Add(intPoints); } solution.Clear(); tempCo.Execute(ref solution, -GenerationInformation.ColliderPadding * GenerationInformation.CalculationScaleFactor); finalClipper.AddPaths(solution, PolyType.ptSubject, true); } if(wallColliders.Length > 0) { Clipper tempC = new Clipper(); ClipperOffset tempCo = new ClipperOffset(); foreach (Collider2D d in wallColliders) { List<IntPoint> p = PolygonFromCollider2D(d, false); if (p != null && p.Count != 0) { if (ClipperLib.Clipper.Orientation(p)) p.Reverse(); tempC.AddPath(p, PolyType.ptSubject, true); } } List<List<IntPoint>> solution = new List<List<IntPoint>>(); tempC.Execute(ClipType.ctUnion, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero); tempC.Clear(); foreach (List<IntPoint> intPoints in solution) { tempCo.AddPath(intPoints, (JoinType)GenerationInformation.JoinType, EndType.etClosedPolygon); TreeAndEdges.Edges.Add(intPoints); } solution.Clear(); tempCo.Execute(ref solution, GenerationInformation.ColliderPadding * GenerationInformation.CalculationScaleFactor); finalClipper.AddPaths(solution, PolyType.ptClip, true); } finalClipper.Execute(ClipType.ctDifference, TreeAndEdges.Tree, PolyFillType.pftPositive, PolyFillType.pftEvenOdd); return TreeAndEdges; }
public static PolygonSet offsetLineRound(Polygon p, float d) { if (float.IsNaN(d)) { return new List<List<IntPoint>>() {p}; } ClipperOffset co = new ClipperOffset(); co.AddPath(p, JoinType.jtRound, EndType.etClosedPolygon); PolygonSet solution = new PolygonSet(); co.Execute(ref solution, d); return solution; }
public void CreateSideWalks(List<GameObject> streetWeb, List<List<Vector3>> streetsPoly) { List<GameObject> sideWalks = new List<GameObject>(); for (int i = 0; i < streetWeb.Count; i++) { GameObject sideWalk = new GameObject("sideWalk", typeof(MeshRenderer), typeof(MeshFilter)); sideWalk.transform.parent = this.transform; sideWalk.GetComponent<MeshRenderer>().material = (Material)Resources.Load("SideWalkMat"); List<List<IntPoint>> solution = new List<List<IntPoint>>(); //transform vertices of each mesh in points for clipper //List<IntPoint> intPoint = FromVecToIntPoint(streetWeb[i].GetComponent<MeshFilter>().sharedMesh.vertices); List<IntPoint> intPoint = FromVecToIntPoint(streetsPoly[i].ToArray()); //offset each mesh ClipperOffset co = new ClipperOffset(); co.AddPath(intPoint, JoinType.jtRound, EndType.etOpenRound); co.Execute(ref solution, 1000.0); List<Vector2> vertices2D = new List<Vector2>(); for (int j = 0; j < solution.Count; j++) { vertices2D = vertices2D.Concat(FromIntPointToVec(solution[j])).ToList(); } // Use the triangulator to get indices for creating triangles Triangulator tr = new Triangulator(vertices2D.ToArray()); int[] indices = tr.Triangulate(); // Create the Vector3 vertices Vector3[] vertices = new Vector3[vertices2D.Count]; for (int k = 0; k < vertices.Length; k++) { vertices[k] = new Vector3(vertices2D[k].x, 0f, vertices2D[k].y); } // Create the mesh Mesh msh = new Mesh(); msh.vertices = vertices; msh.triangles = indices; msh.RecalculateNormals(); msh.RecalculateBounds(); // Set up game object with mesh; sideWalk.GetComponent<MeshFilter>().mesh = msh; sideWalks.Add(sideWalk); } //foreach intersectionCluster unify streets and sidewalks and subtract int swNumber = 1; foreach (HashSet<int> cluster in intersectionClusters) { Mesh newMesh = Subtract(UnifyPolygons(sideWalks, "sidewalks", cluster), UnifyPolygons(streetWeb, "streets", cluster)); //build 3D sidewalk List<GameObject> objs = new List<GameObject>(); GameObject sub = new GameObject("unifiedSideWalks", typeof(MeshFilter), typeof(MeshRenderer)); sub.transform.parent = this.transform; sub.GetComponent<MeshRenderer>().material = (Material)Resources.Load("SideWalkMat"); sub.GetComponent<MeshFilter>().mesh = newMesh; objs.Add(sub); GameObject sub1 = new GameObject("unifiedSideWalks", typeof(MeshFilter), typeof(MeshRenderer)); sub1.transform.parent = this.transform; sub1.GetComponent<MeshRenderer>().material = (Material)Resources.Load("SideWalkMat"); sub1.GetComponent<MeshFilter>().mesh = newMesh; sub1.transform.position = new Vector3(0f, 0.2f, 0f); objs.Add(sub1); GameObject sidewalk = new GameObject("sidewalk", typeof(MeshFilter), typeof(MeshRenderer)); sidewalk.transform.parent = this.transform; sidewalk.GetComponent<MeshRenderer>().material = (Material)Resources.Load("SideWalkMat"); sidewalk.GetComponent<MeshFilter>().sharedMesh = MeshOps.CreateSolid(newMesh, 0.15f); objs.Add(sidewalk); UnifyAndClearMesh(objs, "sideWalk" + swNumber, (Material)Resources.Load("SideWalkMat")); swNumber += 1; } foreach (GameObject sw in sideWalks) DestroyImmediate(sw.gameObject); }
//--------------------------------------------------------------------------- private void DrawBitmap(bool justClip = false) { Cursor.Current = Cursors.WaitCursor; try { if (!justClip) { if (rbTest2.Checked) GenerateAustPlusRandomEllipses((int)nudCount.Value); else GenerateRandomPolygon((int)nudCount.Value); } using (Graphics newgraphic = Graphics.FromImage(mybitmap)) using (GraphicsPath path = new GraphicsPath()) { newgraphic.SmoothingMode = SmoothingMode.AntiAlias; newgraphic.Clear(Color.White); if (rbNonZero.Checked) path.FillMode = FillMode.Winding; //draw subjects ... foreach (Polygon pg in subjects) { PointF[] pts = PolygonToPointFArray(pg, scale); path.AddPolygon(pts); pts = null; } using (Pen myPen = new Pen(Color.FromArgb(196, 0xC3, 0xC9, 0xCF), (float)0.6)) using (SolidBrush myBrush = new SolidBrush(Color.FromArgb(127, 0xDD, 0xDD, 0xF0))) { newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); path.Reset(); //draw clips ... if (rbNonZero.Checked) path.FillMode = FillMode.Winding; foreach (Polygon pg in clips) { PointF[] pts = PolygonToPointFArray(pg, scale); path.AddPolygon(pts); pts = null; } myPen.Color = Color.FromArgb(196, 0xF9, 0xBE, 0xA6); myBrush.Color = Color.FromArgb(127, 0xFF, 0xE0, 0xE0); newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); //do the clipping ... if ((clips.Count > 0 || subjects.Count > 0) && !rbNone.Checked) { Polygons solution2 = new Polygons(); Clipper c = new Clipper(); c.AddPaths(subjects, PolyType.ptSubject, true); c.AddPaths(clips, PolyType.ptClip, true); solution.Clear(); #if UsePolyTree bool succeeded = c.Execute(GetClipType(), solutionTree, GetPolyFillType(), GetPolyFillType()); //nb: we aren't doing anything useful here with solutionTree except to show //that it works. Convert PolyTree back to Polygons structure ... Clipper.PolyTreeToPolygons(solutionTree, solution); #else bool succeeded = c.Execute(GetClipType(), solution, GetPolyFillType(), GetPolyFillType()); #endif if (succeeded) { //SaveToFile("solution", solution); myBrush.Color = Color.Black; path.Reset(); //It really shouldn't matter what FillMode is used for solution //polygons because none of the solution polygons overlap. //However, FillMode.Winding will show any orientation errors where //holes will be stroked (outlined) correctly but filled incorrectly ... path.FillMode = FillMode.Winding; //or for something fancy ... if (nudOffset.Value != 0) { ClipperOffset co = new ClipperOffset(); co.AddPaths(solution, JoinType.jtRound, EndType.etClosedPolygon); co.Execute(ref solution2, (double)nudOffset.Value * scale); } else solution2 = new Polygons(solution); foreach (Polygon pg in solution2) { PointF[] pts = PolygonToPointFArray(pg, scale); if (pts.Count() > 2) path.AddPolygon(pts); pts = null; } myBrush.Color = Color.FromArgb(127, 0x66, 0xEF, 0x7F); myPen.Color = Color.FromArgb(255, 0, 0x33, 0); myPen.Width = 1.0f; newgraphic.FillPath(myBrush, path); newgraphic.DrawPath(myPen, path); //now do some fancy testing ... using (Font f = new Font("Arial", 8)) using (SolidBrush b = new SolidBrush(Color.Navy)) { double subj_area = 0, clip_area = 0, int_area = 0, union_area = 0; c.Clear(); c.AddPaths(subjects, PolyType.ptSubject, true); c.Execute(ClipType.ctUnion, solution2, GetPolyFillType(), GetPolyFillType()); foreach (Polygon pg in solution2) subj_area += Clipper.Area(pg); c.Clear(); c.AddPaths(clips, PolyType.ptClip, true); c.Execute(ClipType.ctUnion, solution2, GetPolyFillType(), GetPolyFillType()); foreach (Polygon pg in solution2) clip_area += Clipper.Area(pg); c.AddPaths(subjects, PolyType.ptSubject, true); c.Execute(ClipType.ctIntersection, solution2, GetPolyFillType(), GetPolyFillType()); foreach (Polygon pg in solution2) int_area += Clipper.Area(pg); c.Execute(ClipType.ctUnion, solution2, GetPolyFillType(), GetPolyFillType()); foreach (Polygon pg in solution2) union_area += Clipper.Area(pg); using (StringFormat lftStringFormat = new StringFormat()) using (StringFormat rtStringFormat = new StringFormat()) { lftStringFormat.Alignment = StringAlignment.Near; lftStringFormat.LineAlignment = StringAlignment.Near; rtStringFormat.Alignment = StringAlignment.Far; rtStringFormat.LineAlignment = StringAlignment.Near; Rectangle rec = new Rectangle(pictureBox1.ClientSize.Width - 108, pictureBox1.ClientSize.Height - 116, 104, 106); newgraphic.FillRectangle(new SolidBrush(Color.FromArgb(196, Color.WhiteSmoke)), rec); newgraphic.DrawRectangle(myPen, rec); rec.Inflate(new Size(-2, 0)); newgraphic.DrawString("Areas", f, b, rec, rtStringFormat); rec.Offset(new Point(0, 14)); newgraphic.DrawString("subj: ", f, b, rec, lftStringFormat); newgraphic.DrawString((subj_area / 100000).ToString("0,0"), f, b, rec, rtStringFormat); rec.Offset(new Point(0, 12)); newgraphic.DrawString("clip: ", f, b, rec, lftStringFormat); newgraphic.DrawString((clip_area / 100000).ToString("0,0"), f, b, rec, rtStringFormat); rec.Offset(new Point(0, 12)); newgraphic.DrawString("intersect: ", f, b, rec, lftStringFormat); newgraphic.DrawString((int_area / 100000).ToString("0,0"), f, b, rec, rtStringFormat); rec.Offset(new Point(0, 12)); newgraphic.DrawString("---------", f, b, rec, rtStringFormat); rec.Offset(new Point(0, 10)); newgraphic.DrawString("s + c - i: ", f, b, rec, lftStringFormat); newgraphic.DrawString(((subj_area + clip_area - int_area) / 100000).ToString("0,0"), f, b, rec, rtStringFormat); rec.Offset(new Point(0, 10)); newgraphic.DrawString("---------", f, b, rec, rtStringFormat); rec.Offset(new Point(0, 10)); newgraphic.DrawString("union: ", f, b, rec, lftStringFormat); newgraphic.DrawString((union_area / 100000).ToString("0,0"), f, b, rec, rtStringFormat); rec.Offset(new Point(0, 10)); newgraphic.DrawString("---------", f, b, rec, rtStringFormat); } } } //end if succeeded } //end if something to clip pictureBox1.Image = mybitmap; } } } finally { Cursor.Current = Cursors.Default; } }
public List<GameObject> CreateStreets(List<List<Vector3>> streetsPoly) { List<GameObject> streets = new List<GameObject>(); for (int i = 0; i < streetsPoly.Count; i++) { GameObject street = new GameObject("street" + i, typeof(MeshRenderer), typeof(MeshFilter)); street.transform.parent = this.transform; street.GetComponent<MeshRenderer>().material = (Material)Resources.Load("StreetMat"); List<List<IntPoint>> solution = new List<List<IntPoint>>(); //transform vertices of each mesh in points for clipper List<IntPoint> intPoint = FromVecToIntPoint(streetsPoly[i].ToArray()); //offset each mesh ClipperOffset co = new ClipperOffset(); co.AddPath(intPoint, JoinType.jtRound, EndType.etOpenRound); co.Execute(ref solution, 700.0); List<Vector2> vertices2D = new List<Vector2>(); for (int j = 0; j < solution.Count; j++) { vertices2D = vertices2D.Concat(FromIntPointToVec(solution[j])).ToList(); } // Use the triangulator to get indices for creating triangles Triangulator tr = new Triangulator(vertices2D.ToArray()); int[] indices = tr.Triangulate(); // Create the Vector3 vertices Vector3[] vertices = new Vector3[vertices2D.Count]; for (int k = 0; k < vertices.Length; k++) { vertices[k] = new Vector3(vertices2D[k].x, 0f, vertices2D[k].y); } // Create the mesh Mesh msh = new Mesh(); msh.vertices = vertices; msh.triangles = indices; msh.RecalculateNormals(); msh.RecalculateBounds(); // Set up game object with mesh; street.GetComponent<MeshFilter>().mesh = msh; street.AddComponent<MeshCollider>(); street.transform.position = new Vector3(street.transform.position.x, 0.02f, street.transform.position.z); streets.Add(street); } DrawStreetLineMesh(streetsPoly, streets); return streets; }
//static GameObject CreateBaseMeshFromColl(LevelBase l, Transform, LevelShape[] s) //{ //} public void CreateForLine(List<Vector2> vecs, float thickness) { float factor = 100; ClipperOffset off = new ClipperOffset(); Clipper c = new Clipper(); for (int i = 1; i < vecs.Count; i++) { Vector2 start = vecs[i - 1]; Vector2 end = vecs[i]; List<List<IntPoint>> sol = new List<List<IntPoint>>(); List<IntPoint> l = new List<IntPoint>() { new IntPoint((int)(start.x * factor), (int)(start.y * factor)), new IntPoint((int)(end.x * factor), (int)(end.y * factor)) }; off.AddPath(l, JoinType.jtSquare, EndType.etOpenSquare); off.Execute(ref sol, thickness); c.AddPaths(sol, PolyType.ptSubject, true); } List<List<IntPoint>> polys = new List<List<IntPoint>>(); c.Execute(ClipType.ctUnion, polys); //off.AddPath() }
/// <summary> /// Create a slice from an open path with the given width /// </summary> /// <param name="path"></param> /// <param name="width"></param> /// <param name="plane"></param> public Slice(LineStrip path, float width, Plane plane, bool closed = false) { this.plane = plane; transform = plane.CreateMatrix(); transform = Matrix4.Mult(transform, Matrix4.CreateScale(scale)); inverseTransform = Matrix4.Invert(transform); polyTree = new PolyTree(); ClipperOffset co = new ClipperOffset(); co.ArcTolerance = scale * 0.0001f; if (closed) { co.AddPath(LineStripToPolygon(path), JoinType.jtRound, EndType.etClosedLine); } else { co.AddPath(LineStripToPolygon(path), JoinType.jtRound, EndType.etOpenRound); } co.Execute(ref this.polyTree, scale * width / 2.0f); }
private PolyTree Offset(PolyTree input, double delta) { var clipperOffset = new ClipperOffset(); for (var currentNode = input.GetFirst(); currentNode != null; currentNode = currentNode.GetNext()) { clipperOffset.AddPath(currentNode.Contour, JoinType.jtMiter, EndType.etClosedPolygon); } var result = new PolyTree(); clipperOffset.Execute(ref result, delta); return result; }
public void DrawSegment(List<Vector3> segment, List<Mesh> intersectionPolys, List<GameObject> lines) { List<List<IntPoint>> solution = new List<List<IntPoint>>(); //transform vertices of each mesh in points for clipper List<IntPoint> intPoint = FromVecToIntPoint(segment.ToArray()); //offset each mesh ClipperOffset co = new ClipperOffset(); co.AddPath(intPoint, JoinType.jtRound, EndType.etOpenRound); co.Execute(ref solution, 100.0); List<Vector2> vertices2D = new List<Vector2>(); for (int j = 0; j < solution.Count; j++) { vertices2D = vertices2D.Concat(FromIntPointToVec(solution[j])).ToList(); } // Use the triangulator to get indices for creating triangles Triangulator tr = new Triangulator(vertices2D.ToArray()); int[] indices = tr.Triangulate(); // Create the Vector3 vertices Vector3[] vertices = new Vector3[vertices2D.Count]; for (int k = 0; k < vertices.Length; k++) { vertices[k] = new Vector3(vertices2D[k].x, 0f, vertices2D[k].y); } // Create the mesh Mesh msh = new Mesh(); msh.vertices = vertices; msh.triangles = indices; msh.RecalculateNormals(); msh.RecalculateBounds(); Mesh newMesh = ExecuteMultiDifferencePoly(msh, intersectionPolys); GameObject lineSegment = new GameObject("segment", typeof(MeshFilter), typeof(MeshRenderer)); lineSegment.GetComponent<MeshFilter>().sharedMesh = newMesh; lines.Add(lineSegment); }
public List<List<Vector3>> Offset(float amount, float height) { var orderedPoints = GetAllOrderedIntPoints(); var result = new List<List<Vector3>>(); foreach (var path in orderedPoints) { Debug.Log("New path"); foreach (var intpoint in path.Points) { Debug.Log("Ordered point: " + intpoint.X + ", " + intpoint.Y); } var co = new ClipperLib.ClipperOffset(); var endType = path.IsClosedLoop ? ClipperLib.EndType.etClosedLine : ClipperLib.EndType.etOpenSquare; co.AddPath(path.Points, ClipperLib.JoinType.jtSquare, endType); var results = new List<List<ClipperLib.IntPoint>>(); co.Execute(ref results, (int)(amount * 1000.0f)); result.AddRange(results.Select( xs => xs.Select( x => new Vector3((float)x.X / 1000.0f, height, (float)x.Y / 1000.0f)).ToList())); } return result; }
private void RecalculateVertices() { if (points.Count < 2) { return; } vertexPositionColorArray = null; var lineColor = Color.Red; #region clipper List<IntPoint> clipperPath = new List<IntPoint>(points.Count); foreach (var point in points) { clipperPath.Add(new IntPoint(point.X * ClipperScale, point.Y * ClipperScale)); } List<List<IntPoint>> clipperSolution = new List<List<IntPoint>>(); ClipperOffset clipperOffset = new ClipperOffset(); clipperOffset.AddPath(clipperPath, JoinType.jtRound, EndType.etOpenRound); clipperOffset.Execute(ref clipperSolution, lineThickness / 2.0f * ClipperScale); #endregion #region triangle.net InputGeometry InputGeometry = new InputGeometry(); Mesh TriangleMesh = new Mesh(); for (int iii = 0; iii < clipperSolution.Count; iii++) { var trianglePath = clipperSolution[iii].Select(p => new TrianglePoint(p.X / (float)ClipperScale, p.Y / (float)ClipperScale)).ToList(); if (iii == 0) { InputGeometry.AddRing(trianglePath); } else { InputGeometry.AddRingAsHole(trianglePath); } } #endregion if (InputGeometry.Count > 0) { TriangleMesh.Triangulate(InputGeometry); vertexPositionColorArray = TriangleMesh.GetTriangleList().Select(v => new VertexPositionColor(new Vector3((float)v.X, (float)v.Y, 0.0f), lineColor)).ToArray(); vertexBuffer = new VertexBuffer(GraphicsDevice, VertexPositionColor.VertexDeclaration, vertexPositionColorArray.Length, BufferUsage.WriteOnly); vertexBuffer.SetData<VertexPositionColor>(vertexPositionColorArray); } }
private void AddCharacterMeshes(string currentText, TypeFacePrinter printer) { int newIndex = asyncMeshGroups.Count; StyledTypeFace typeFace = printer.TypeFaceStyle; for (int i = 0; i < currentText.Length; i++) { string letter = currentText[i].ToString(); TypeFacePrinter letterPrinter = new TypeFacePrinter(letter, typeFace); if (CharacterHasMesh(letterPrinter, letter)) { #if true Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2); #else Mesh textMesh = VertexSourceToMesh.Extrude(letterPrinter, unscaledLetterHeight / 2); // this is the code to make rounded tops // convert the letterPrinter to clipper polygons List<List<IntPoint>> insetPoly = VertexSourceToPolygon.CreatePolygons(letterPrinter); // inset them ClipperOffset clipper = new ClipperOffset(); clipper.AddPaths(insetPoly, JoinType.jtMiter, EndType.etClosedPolygon); List<List<IntPoint>> solution = new List<List<IntPoint>>(); clipper.Execute(solution, 5.0); // convert them back into a vertex source // merge both the inset and original vertex sources together // convert the new vertex source into a mesh (triangulate them) // offset the inner loop in z // create the polygons from the inner loop to a center point so that there is the rest of an approximation of the bubble // make the mesh for the bottom // add the top and bottom together // done #endif asyncMeshGroups.Add(new MeshGroup(textMesh)); PlatingMeshGroupData newMeshInfo = new PlatingMeshGroupData(); newMeshInfo.spacing = printer.GetOffsetLeftOfCharacterIndex(i); asyncPlatingDatas.Add(newMeshInfo); asyncMeshGroupTransforms.Add(Matrix4X4.Identity); PlatingHelper.CreateITraceableForMeshGroup(asyncPlatingDatas, asyncMeshGroups, newIndex, null); asyncMeshGroupTransforms[newIndex] *= Matrix4X4.CreateTranslation(new Vector3(0, 0, unscaledLetterHeight / 2)); newIndex++; } processingProgressControl.PercentComplete = ((i + 1) * 95 / currentText.Length); } }
List<List<IntPoint>> Offset(List<List<IntPoint>> polygons, double delta) { var result = new List<List<IntPoint>>(); var clipper = new ClipperOffset(); clipper.AddPaths(polygons, JoinType.jtSquare, EndType.etClosedPolygon); clipper.Execute(ref result, delta); return result; }
public static Polygons Offset(this Polygons polygons, long distance) { ClipperOffset offseter = new ClipperOffset(); offseter.AddPaths(polygons, JoinType.jtMiter, EndType.etClosedPolygon); Paths solution = new Polygons(); offseter.Execute(ref solution, distance); return solution; }
/// <summary> /// Offsets the specified polylines. /// </summary> /// <param name="polylines">A list of polylines</param> /// <param name="openFilletType">Optional: line endtype (Butt, Square, Round)</param> /// <param name="closedFilltetType">Optional: join type: Round, Miter (uses miter parameter) or Square</param> /// <param name="plane">Plane to project the polylines to</param> /// <param name="tolerance">Tolerance: Cutoff point. Eg. point {1.245; 9.244351; 19.3214} with precision {0.1} will be cut /// off to {1.2; 9.2; 19.3}.</param> /// <param name="distance">Distances to offset set of shapes.</param> /// <param name="miter">Miter deterimines how long narrow spikes can become before they are cut off: A miter setting of 2 /// means not longer than 2 times the offset distance. A miter of 25 will give big spikes.</param> /// <param name="arcTolerance">The arc tolerance.</param> /// <param name="outContour">The out contour.</param> /// <param name="outHoles">The out holes.</param> public static void Offset(IEnumerable <Polyline> polylines, List <OpenFilletType> openFilletType, List <ClosedFilletType> closedFilltetType, Plane plane, double tolerance, IEnumerable <double> distance, double miter, double arcTolerance, out List <List <Polyline> > outContour, out List <List <Polyline> > outHoles, EndType endType = default) { outContour = new List <List <Polyline> >(); outHoles = new List <List <Polyline> >(); /* * iEndType: How to handle open ended polygons. * Open Closed * etOpenSquare etClosedLine (fill inside & outside) * etOpenRound etClosedPolygon (fill outside only) * etOpenButt * * See: http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/EndType.htm */ /* * jtJoinType * How to fill angles of closed polygons * jtRound: Round * jtMiter: Square with variable distance * jtSquare: Square with fixed distance (jtMiter = 1) */ var cOffset = new ClipperOffset(miter, arcTolerance); var i = 0; foreach (var pl in polylines) { var et = EndType.etOpenButt; var jt = JoinType.jtSquare; if (pl.IsClosed) { et = EndType.etClosedLine; } else if (openFilletType.Count != 0) { var oft = IndexOrLast(openFilletType, i); switch (oft) { case OpenFilletType.Butt: et = EndType.etOpenButt; break; case OpenFilletType.Round: et = EndType.etOpenRound; break; case OpenFilletType.Square: et = EndType.etOpenSquare; break; } } else { et = EndType.etOpenButt; } if (closedFilltetType.Count != 0) { var cft = IndexOrLast(closedFilltetType, i); switch (cft) { case ClosedFilletType.Miter: jt = JoinType.jtMiter; break; case ClosedFilletType.Round: jt = JoinType.jtRound; break; case ClosedFilletType.Square: jt = JoinType.jtSquare; break; } } else { jt = JoinType.jtSquare; } if (endType != default) { et = endType; } cOffset.AddPath(pl.ToPath2D(plane, tolerance), jt, et); i++; } foreach (var offsetDistance in distance) { var tree = new PolyTree(); cOffset.Execute(ref tree, offsetDistance / tolerance); var holes = new List <Polyline>(); var contours = new List <Polyline>(); foreach (var path in tree.Iterate()) { if (path.Contour.Count == 0) { continue; } Polyline polyline = path.Contour.ToPolyline(plane, tolerance, !path.IsOpen); if (path.IsHole) { holes.Add(polyline); } else { contours.Add(polyline); } } outContour.Add(contours); outHoles.Add(holes); } }