public static Polygons GetCorrectedWinding(this Polygons polygonsToFix) { polygonsToFix = Clipper.CleanPolygons(polygonsToFix); var boundsPolygon = new Polygon(); IntRect bounds = Clipper.GetBounds(polygonsToFix); bounds.minX -= 10; bounds.minY -= 10; bounds.maxY += 10; bounds.maxX += 10; boundsPolygon.Add(new IntPoint(bounds.minX, bounds.minY)); boundsPolygon.Add(new IntPoint(bounds.maxX, bounds.minY)); boundsPolygon.Add(new IntPoint(bounds.maxX, bounds.maxY)); boundsPolygon.Add(new IntPoint(bounds.minX, bounds.maxY)); var clipper = new Clipper(); clipper.AddPaths(polygonsToFix, PolyType.ptSubject, true); clipper.AddPath(boundsPolygon, PolyType.ptClip, true); var intersectionResult = new PolyTree(); clipper.Execute(ClipType.ctIntersection, intersectionResult); Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult); return(outputPolygons); }
private Polygons FixWinding(Polygons polygonsToPathAround) { polygonsToPathAround = Clipper.CleanPolygons(polygonsToPathAround); Polygon boundsPolygon = new Polygon(); IntRect bounds = Clipper.GetBounds(polygonsToPathAround); bounds.minX -= 10; bounds.maxY += 10; bounds.maxX += 10; bounds.minY -= 10; boundsPolygon.Add(new IntPoint(bounds.minX, bounds.minY)); boundsPolygon.Add(new IntPoint(bounds.maxX, bounds.minY)); boundsPolygon.Add(new IntPoint(bounds.maxX, bounds.maxY)); boundsPolygon.Add(new IntPoint(bounds.minX, bounds.maxY)); Clipper clipper = new Clipper(); clipper.AddPaths(polygonsToPathAround, PolyType.ptSubject, true); clipper.AddPath(boundsPolygon, PolyType.ptClip, true); PolyTree intersectionResult = new PolyTree(); clipper.Execute(ClipType.ctIntersection, intersectionResult); Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult); return(outputPolygons); }
private Polygons FixWinding(Polygons polygonsToPathAround) { polygonsToPathAround = Clipper.CleanPolygons(polygonsToPathAround); Polygon boundsPolygon = new Polygon(); IntRect bounds = Clipper.GetBounds(polygonsToPathAround); bounds.left -= 10; bounds.bottom += 10; bounds.right += 10; bounds.top -= 10; boundsPolygon.Add(new IntPoint(bounds.left, bounds.top)); boundsPolygon.Add(new IntPoint(bounds.right, bounds.top)); boundsPolygon.Add(new IntPoint(bounds.right, bounds.bottom)); boundsPolygon.Add(new IntPoint(bounds.left, bounds.bottom)); Clipper clipper = new Clipper(); clipper.AddPaths(polygonsToPathAround, PolyType.ptSubject, true); clipper.AddPath(boundsPolygon, PolyType.ptClip, true); PolyTree intersectionResult = new PolyTree(); clipper.Execute(ClipType.ctIntersection, intersectionResult); Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult); Clipper.ReversePaths(outputPolygons); return(outputPolygons); }
//------------------------------------------------------------------------------ public void Execute(ref List <List <IntPoint> > solution, double delta) { solution.Clear(); FixOrientations(); DoOffset(delta); //now clean up 'corners' ... Clipper clpr = new Clipper(); clpr.AddPaths(m_destPolys, PolyType.ptSubject, true); if (delta > 0) { clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive); } else { IntRect r = Clipper.GetBounds(m_destPolys); List <IntPoint> outer = new List <IntPoint>(4); outer.Add(new IntPoint(r.left - 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.top - 10)); outer.Add(new IntPoint(r.left - 10, r.top - 10)); clpr.AddPath(outer, PolyType.ptSubject, true); clpr.ReverseSolution = true; clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative); if (solution.Count > 0) { solution.RemoveAt(0); } } }
public static Polygons GetCorrectedWinding(this Polygons polygonsToFix) { polygonsToFix = Clipper.CleanPolygons(polygonsToFix); Polygon boundsPolygon = new Polygon(); IntRect bounds = Clipper.GetBounds(polygonsToFix); bounds.left -= 10; bounds.bottom += 10; bounds.right += 10; bounds.top -= 10; boundsPolygon.Add(new IntPoint(bounds.left, bounds.top)); boundsPolygon.Add(new IntPoint(bounds.right, bounds.top)); boundsPolygon.Add(new IntPoint(bounds.right, bounds.bottom)); boundsPolygon.Add(new IntPoint(bounds.left, bounds.bottom)); Clipper clipper = new Clipper(); clipper.AddPaths(polygonsToFix, PolyType.ptSubject, true); clipper.AddPath(boundsPolygon, PolyType.ptClip, true); PolyTree intersectionResult = new PolyTree(); clipper.Execute(ClipType.ctIntersection, intersectionResult); Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult); return(outputPolygons); }
private static void CleanUpSolution(Polygons solution, double delta) { Clipper clpr = new Clipper(); clpr.AddPolygons(solution, PolyType.Subject); if (delta > 0) { clpr.Execute(ClipType.Union, solution, PolyFillType.Positive, PolyFillType.Positive); } else { RectangleL r = clpr.GetBounds(); Polygon outer = new Polygon(4); outer.Add(new Vector2(r.left - 10, r.bottom + 10)); outer.Add(new Vector2(r.right + 10, r.bottom + 10)); outer.Add(new Vector2(r.right + 10, r.top - 10)); outer.Add(new Vector2(r.left - 10, r.top - 10)); clpr.AddPolygon(outer, PolyType.Subject); clpr.Execute(ClipType.Union, solution, PolyFillType.Negative, PolyFillType.Negative); if (solution.Count > 0) { solution.RemoveAt(0); for (int i = 0; i < solution.Count; i++) { solution[i].Reverse(); } } } }
public static void SaveToSvg(this Polygons polygons, string filename) { double scaleDenominator = 150; IntRect bounds = Clipper.GetBounds(polygons); long temp = bounds.maxY; bounds.maxY = bounds.minY; bounds.minY = temp; IntPoint size = new IntPoint(bounds.maxX - bounds.minX, bounds.maxY - bounds.minY); double scale = Max(size.X, size.Y) / scaleDenominator; StreamWriter stream = new StreamWriter(filename); stream.Write("<!DOCTYPE html><html><body>\n"); stream.Write("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" style='width:{0}px;height:{1}px'>\n".FormatWith((int)(size.X / scale), (int)(size.Y / scale))); stream.Write("<marker id='MidMarker' viewBox='0 0 10 10' refX='5' refY='5' markerUnits='strokeWidth' markerWidth='10' markerHeight='10' stroke='lightblue' stroke-width='2' fill='none' orient='auto'>"); stream.Write("<path d='M 0 0 L 10 5 M 0 10 L 10 5'/>"); stream.Write("</marker>"); stream.Write("<g fill-rule='evenodd' style=\"fill: gray; stroke:black;stroke-width:1\">\n"); stream.Write("<path marker-mid='url(#MidMarker)' d=\""); for (int polygonIndex = 0; polygonIndex < polygons.Count; polygonIndex++) { Polygon polygon = polygons[polygonIndex]; for (int intPointIndex = 0; intPointIndex < polygon.Count; intPointIndex++) { if (intPointIndex == 0) { stream.Write("M"); } else { stream.Write("L"); } stream.Write("{0},{1} ", (double)(polygon[intPointIndex].X - bounds.minX) / scale, (double)(polygon[intPointIndex].Y - bounds.maxY) / scale); } stream.Write("Z\n"); } stream.Write("\"/>"); stream.Write("</g>\n"); for (int openPolygonIndex = 0; openPolygonIndex < polygons.Count; openPolygonIndex++) { Polygon openPolygon = polygons[openPolygonIndex]; if (openPolygon.Count < 1) { continue; } stream.Write("<polyline marker-mid='url(#MidMarker)' points=\""); for (int n = 0; n < openPolygon.Count; n++) { stream.Write("{0},{1} ", (double)(openPolygon[n].X - bounds.minX) / scale, (double)(openPolygon[n].Y - bounds.maxY) / scale); } stream.Write("\" style=\"fill: none; stroke:red;stroke-width:1\" />\n"); } stream.Write("</svg>\n"); stream.Write("</body></html>"); stream.Close(); }
public static IntPoint getCenter(Paths paths) { if (paths == null) { return(new IntPoint()); } IntRect ir = Clipper.GetBounds(paths); return(new IntPoint((ir.left + (ir.right - ir.left) / 2), (ir.bottom + (ir.top - ir.bottom) / 2))); }
//------------------------------------------------------------------------------ public void Execute(ref PolyTree solution, double delta) { solution.Clear(); FixOrientations(); DoOffset(delta); //now clean up 'corners' ... Clipper clpr = new Clipper(); clpr.AddPaths(m_destPolys, PolyType.ptSubject, true); if (delta > 0) { clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive); } else { IntRect r = Clipper.GetBounds(m_destPolys); List <IntPoint> outer = new List <IntPoint>(4); outer.Add(new IntPoint(r.left - 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.top - 10)); outer.Add(new IntPoint(r.left - 10, r.top - 10)); clpr.AddPath(outer, PolyType.ptSubject, true); clpr.ReverseSolution = true; clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative); //remove the outer PolyNode rectangle ... if (solution.ChildCount == 1 && solution.Childs[0].ChildCount > 0) { PolyNode outerNode = solution.Childs[0]; solution.Childs.Capacity = outerNode.ChildCount; solution.Childs[0] = outerNode.Childs[0]; solution.Childs[0].m_Parent = solution; for (int i = 1; i < outerNode.ChildCount; i++) { solution.AddChild(outerNode.Childs[i]); } } else { solution.Clear(); } } }
public static Paths offset(Paths paths, float offset) { // Set cleaning precision IntRect brect = Clipper.GetBounds(paths); int cleanPolygonPrecision = 2; if ((brect.right - brect.left) > 10000) { cleanPolygonPrecision = 30; } // Clean... AXClipperLib.JoinType jt = AXClipperLib.JoinType.jtSquare; paths = AXGeometryTools.Utilities.cleanPaths(paths, cleanPolygonPrecision); Paths resPaths = new Paths(); AXClipperLib.PolyTree resPolytree = null; // OFFSETTER ClipperOffset co = new ClipperOffset(); co.MiterLimit = 2.0f; foreach (Path path in paths) { co.Clear(); resPolytree = null; co.AddPath(path, jt, AXClipperLib.EndType.etClosedPolygon); //JoinType.jtSquare, AXClipperLib.EndType.etClosedPolygon); // this resPolytree has transformed curves in it resPolytree = new AXClipperLib.PolyTree(); co.Execute(ref resPolytree, (double)(offset * AXGeometryTools.Utilities.IntPointPrecision)); resPaths.AddRange(Clipper.ClosedPathsFromPolyTree(resPolytree)); } return(resPaths); }
public static long[] getShifterToPathsCenter(Paths paths) { long[] shifter = new long[3]; if (paths == null) { return(shifter); } IntRect ir = Clipper.GetBounds(paths); shifter[0] = ir.left + (ir.right - ir.left) / 2; shifter[1] = ir.bottom + (ir.top - ir.bottom) / 2; shifter[2] = Math.Max((ir.right - ir.left), (ir.top - ir.bottom)); return(shifter); }
public override void calculateBounds() { AXParameter SelectedOutput = S_InputShape.getSelectedOutputParameter(); Paths paths = (SelectedOutput != null) ? SelectedOutput.getPaths() : null; //Debug.Log(parametricObject.Name + ": " + P_Output); if (paths == null) return; IntRect cb = Clipper.GetBounds(SelectedOutput.getPaths()); Vector3 size = new Vector3(cb.right-cb.left, cb.bottom-cb.top, 0);///Archimatix.IntPointPrecision; Vector3 center = new Vector3(cb.left+size.x/2, cb.top+size.y/2, 0); parametricObject.bounds = new Bounds( (center/AXGeometryTools.Utilities.IntPointPrecision-new Vector3(transX, transY, 0)), size/AXGeometryTools.Utilities.IntPointPrecision); }
public static Rect getClipperBounds(Paths paths) { if (paths == null) { return(new Rect()); } /* * Debug.Log ("get bounds from these paths"); * foreach(Path p in paths) * Debug.Log (Archimatix.pathToString(p)); */ IntRect ir = Clipper.GetBounds(paths); float x1 = ((float)ir.left) / IntPointPrecision; float y1 = ((float)ir.top) / IntPointPrecision; float x2 = ((float)ir.right) / IntPointPrecision; float y2 = ((float)ir.bottom) / IntPointPrecision; return(new Rect(x1, y1, x2 - x1, y2 - y1)); }
public void AddAdhesion(AdhesionType type, double diameter, bool add_to_polies = true /*else to fill*/, int distance = 12, int miter_dist = 5) { if (type == AdhesionType.NONE) { return; } Polygon2D outside_poly = null; if (add_to_polies) { // Select largest outer poly outside_poly = this.Polygons.Where(p => p.Hierarchy == 0).First(); } else { // Get bounds instead of poly, because order and contents are not sure for fill... var rect = Clipper.GetBounds(this.FillPolygons.Select(p => p.IntPoints).ToList()); outside_poly = new Polygon2D(new Path() { new IntPoint(rect.top, rect.left), new IntPoint(rect.top, rect.right), new IntPoint(rect.bottom, rect.right), new IntPoint(rect.bottom, rect.left), }); } if (outside_poly == null) { return; } List <Polygon2D> adhesion_polies = null; switch (type) { case AdhesionType.SKIRT: { // Separated rings around ground poly const int rings = 2; adhesion_polies = new List <Polygon2D>(rings + this.Polygons.Count); for (int offsetted_line = 0; offsetted_line < rings; offsetted_line++) { var offset = diameter * (distance - offsetted_line); adhesion_polies.AddRange(outside_poly.Offset(offset, miter_dist) .Where(p => p.FilterShorts())); } break; } case AdhesionType.BRIM: { // Number of offsets going to ground poly, from distance away adhesion_polies = new List <Polygon2D>(distance + this.Polygons.Count); for (int offsetted_line = 0; offsetted_line < distance; offsetted_line++) { var offset = diameter * (distance - offsetted_line); adhesion_polies.AddRange(outside_poly.Offset(offset, miter_dist) .Where(p => p.FilterShorts())); } break; } } // Mark flags for proper drawing of colour, useless otherwise adhesion_polies.ForEach(p => { p.IsInfill = true; p.IsSupport = true; p.IsShell = true; p.IsSurface = true; p.IsAdhesion = true; }); adhesion_polies.AddRange(this.Polygons); this.Polygons = adhesion_polies; }
public static void thickenAndOffset(ref AXParameter sp, AXParameter src) { if (sp == null || src == null) { return; } //sp.polyTree = null; float thickness = sp.thickness; float roundness = sp.roundness; float offset = sp.offset; bool flipX = sp.flipX; //Debug.Log(sp.parametricObject.Name + "." + sp.Name +"."+ sp.offset); //bool srcIsCC = src.isCCW(); Paths subjPaths = src.getClonePaths(); if (subjPaths == null) { return; } // FLIP_X if (flipX) { //Debug.Log(subjPaths.Count); //AXGeometryTools.Utilities.printPaths(subjPaths); subjPaths = AXGeometryTools.Utilities.transformPaths(subjPaths, Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1, 1, 1))); sp.transformedControlPaths = AXGeometryTools.Utilities.transformPaths(sp.transformedControlPaths, Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1, 1, 1))); } // SYMMETRY if (sp.symmetry) { if (subjPaths != null && subjPaths.Count > 0) { for (int i = 0; i < subjPaths.Count; i++) { Path orig = subjPaths[i]; Path sym = new Path(); float seperation = sp.symSeperation * AXGeometryTools.Utilities.IntPointPrecision; float apex = .1f * seperation; for (int j = 0; j < orig.Count; j++) { sym.Add(new IntPoint(orig[j].X + seperation / 2, orig[j].Y)); } // midpoint. slightly raised sym.Add(new IntPoint(0, orig[orig.Count - 1].Y + apex)); for (int j = orig.Count - 1; j >= 0; j--) { sym.Add(new IntPoint(-orig[j].X - seperation / 2, orig[j].Y)); } subjPaths[i] = sym; } } } AX.Generators.Generator2D gener2D = sp.parametricObject.generator as AX.Generators.Generator2D; if (subjPaths != null && gener2D != null && (gener2D.scaleX != 1 || gener2D.scaleY != 1)) { sp.transformedButUnscaledOutputPaths = AX.Generators.Generator2D.transformPaths(subjPaths, gener2D.localUnscaledMatrix); } else { sp.transformedButUnscaledOutputPaths = null; } //cleanPolygonPrecision IntRect brect = Clipper.GetBounds(subjPaths); if ((brect.right - brect.left) < 10000) { cleanPolygonPrecision = 2; } else { cleanPolygonPrecision = 30; } //Debug.Log("cleanPolygonPrecision="+cleanPolygonPrecision); /* * if (offset_p.FloatVal == 0 && wallthick_p.FloatVal == 0) * { * sp.polyTree = src.polyTree; * sp.paths = src.paths; * return; * } * */ //sp.polyTree = null; //Debug.Log("new count a = " + subjPaths[0].Count); bool hasOffset = false; sp.hasThickness = false; Paths resPaths = new Paths(); AXClipperLib.PolyTree resPolytree = null; ClipperOffset co = new ClipperOffset(); //co.ArcTolerance = sp.arcTolerance; float smooth = (float)(120 / (sp.arcTolerance * sp.arcTolerance)); float smoothLOD = ((smooth - .048f) * sp.parametricObject.model.segmentReductionFactor) + .048f; co.ArcTolerance = (float)(Mathf.Sqrt(120 / smoothLOD)); co.MiterLimit = 2.0f; //if (offset != 0) // 1. Offset? Can't offset an open shape if (sp.shapeState == ShapeState.Closed && (sp.endType == AXClipperLib.EndType.etClosedLine || sp.endType == AXClipperLib.EndType.etClosedPolygon)) { //AXClipperLib.JoinType jt = (sp.endType == AXClipperLib.EndType.etClosedLine) ? JoinType.jtMiter : sp.joinType;//output.joinType; AXClipperLib.JoinType jt = (sp.parametricObject.model.segmentReductionFactor < .15f) ? AXClipperLib.JoinType.jtSquare : sp.joinType; //output.joinType; //Debug.Log ("sp.endType="+sp.endType+", jt="+jt); if (roundness != 0) { // reduce co.Clear(); if (subjPaths != null) { co.AddPaths(AXGeometryTools.Utilities.cleanPaths(subjPaths, cleanPolygonPrecision), jt, AXClipperLib.EndType.etClosedPolygon); //JoinType.jtSquare, AXClipperLib.EndType.etClosedPolygon); } co.Execute(ref subjPaths, (double)(-roundness * AXGeometryTools.Utilities.IntPointPrecision)); } offset += roundness; if (subjPaths != null) { subjPaths = Clipper.SimplifyPolygons(subjPaths, PolyFillType.pftNonZero); } co.Clear(); hasOffset = true; // if (offset != 0 || thickness == 0) { // --! PUC ** Removed because the pass thru was causing a problem with Instance2D of a ShapeMerger // Do Offset // = true; if (subjPaths != null) { // After changes made mid April to allow for FlipX, this started doubling the localMatrix and thus became redundent, though not sure why. //if (gener2D != null) // sp.transformedAndScaledButNotOffsetdOutputPaths = AX.Generators.Generator2D.transformPaths(subjPaths, gener2D.localMatrix); co.AddPaths(AXGeometryTools.Utilities.cleanPaths(subjPaths, cleanPolygonPrecision), jt, AXClipperLib.EndType.etClosedPolygon); //JoinType.jtSquare, AXClipperLib.EndType.etClosedPolygon); // this resPolytree has transformed curves in it resPolytree = new AXClipperLib.PolyTree(); co.Execute(ref resPolytree, (double)(offset * AXGeometryTools.Utilities.IntPointPrecision)); } // } if (thickness > 0) { // No offset, but is closed sp.transformedAndScaledButNotOffsetdOutputPaths = null; if (src.polyTree != null) { if (thickness > 0) { resPaths = subjPaths; // Clipper.PolyTreeToPaths(src.polyTree); } else { resPolytree = src.polyTree; } } else { resPaths = subjPaths; } } } else { //resPolytree = src.polyTree; if (src.polyTree != null) { if (thickness > 0) { resPaths = subjPaths; // Clipper.PolyTreeToPaths(src.polyTree); } else { resPolytree = src.polyTree; } } else { resPaths = subjPaths; } } // 2. Thickness? //subjPaths = sp.getPaths(); if ((sp.endType != AXClipperLib.EndType.etClosedPolygon) && thickness > 0) //input.endType != AXClipperLib.EndType.etClosedPolygon) { { // this is a wall if (resPaths != null && gener2D != null) { sp.transformedFullyAndOffsetdButNotThickenedOutputPaths = AX.Generators.Generator2D.transformPaths(resPaths, gener2D.localMatrix); } sp.hasThickness = true; co.Clear(); if (resPolytree != null) // closed block has happened { co.AddPaths(AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(resPolytree), cleanPolygonPrecision), sp.joinType, sp.endType); //input.endType); } else if (resPaths != null) { co.AddPaths(AXGeometryTools.Utilities.cleanPaths(resPaths, cleanPolygonPrecision), sp.joinType, sp.endType); //input.endType); } resPolytree = new AXClipperLib.PolyTree(); co.Execute(ref resPolytree, (double)(thickness * AXGeometryTools.Utilities.IntPointPrecision)); } else { sp.transformedFullyAndOffsetdButNotThickenedOutputPaths = null; } // 3. Update input data //Debug.Log(sp.parametricObject.Name + "." + sp.Name + " here ["+hasOffset+"] " + (! sp.symmetry) + " " + (! flipX) + " " + (! hasOffset) + " " + (! hasThicken) + " " + (roundness == 0)); // SIMPLE PASSTHRU? if (!sp.symmetry && !flipX && !hasOffset && !sp.hasThickness && roundness == 0) { // SIMPLE PASS THROUGH sp.polyTree = src.polyTree; sp.paths = src.paths; } else { if (resPolytree == null) { //sp.paths = resPaths; //Generator2D.transformPaths(resPaths, gener2D.localMatrix); //if (Clipper.Orientation(resPaths[0]) != srcIsCC) // AXGeometryTools.Utilities.reversePaths(ref resPaths); sp.paths = AXGeometryTools.Utilities.cleanPaths(resPaths, cleanPolygonPrecision); } else { //Generator2D.transformPolyTree(resPolytree, gener2D.localMatrix); //if (resPolytree != null && resPolytree.Childs.Count > 0 && Clipper.Orientation(resPolytree.Childs[0].Contour) != srcIsCC) // AXGeometryTools.Utilities.reversePolyTree(resPolytree); sp.polyTree = resPolytree; } } // REVERSE if (sp.reverse) { if (sp.polyTree != null) { AXGeometryTools.Utilities.reversePolyTree(sp.polyTree); } else if (sp.paths != null && sp.paths.Count > 0) { for (int i = 0; i < sp.paths.Count; i++) { sp.paths[i].Reverse(); } } } // if (sp.paths != null && sp.paths.Count > 0) // { // // SUBDIVISION // Debug.Log("sp.paths.Count="+sp.paths.Count); // // for(int i=0; i<sp.paths.Count; i++) // { // // // Path path = sp.paths[i]; // Path subdivPath = new Path(); // // for (int j=0; j<path.Count-1; j++) // { // subdivPath.Add(path[j]); // Vector2 v0 = new Vector2(path[j].X, path[j].Y); // Vector2 v1 = new Vector2(path[j+1].X, path[j+1].Y); // // Debug.Log("["+i+"]["+j+"] " + Vector2.Distance(v0, v1)/10000); // Vector2 newp = Vector2.Lerp(v0, v1, .5f); // // subdivPath.Add(new IntPoint(newp.x, newp.y)); // } // subdivPath.Add(path[path.Count-1]); // // // sp.paths[i] = subdivPath; // // Debug.Log("------------"); // AXGeometryTools.Utilities.printPath(sp.paths[i]); // } // // SUBDIVISION --- // } // }
public void carveTerrain() { Terrain terrain = parametricObject.terrain; if (terrain != null) { if (parametricObject.heightsOrig == null) { memorizeTerrain(); } // BOUNDING_SHAPE if (P_Plan != null && P_Plan.DependsOn != null) { if (planSrc_po != null) { AXShape.thickenAndOffset(ref P_Plan, planSrc_p); // now boundin_p has offset and thickened polytree or paths. } } int hmWidth = terrain.terrainData.heightmapWidth; int hmHeight = terrain.terrainData.heightmapHeight; Paths subjPaths = P_Plan.getTransformedSubjPaths(); Paths holePaths = P_Plan.getTransformedHolePaths(); //Pather.printPaths(subjPaths); if (subjPaths == null) { return; } IntRect bounds = Clipper.GetBounds(subjPaths); // if (prevBounds.right > 0) // { // bounds.left = ( prevBounds.left < bounds.left ) ? prevBounds.left : bounds.left; // bounds.right = ( prevBounds.right > bounds.right ) ? prevBounds.right : bounds.right; // // // bounds.top = ( prevBounds.top < bounds.top ) ? prevBounds.top : bounds.top; // bounds.bottom = ( prevBounds.bottom > bounds.bottom ) ? prevBounds.bottom : bounds.bottom; // } float percentHgt = height / terrain.terrainData.size.y; //Debug.Log(bounds.left +"->"+bounds.right+" :: " + bounds.top+ "->"+bounds.bottom); int padding = 50000; bounds.left -= padding; bounds.right += padding; bounds.top -= padding; bounds.bottom += padding; int from_i = (int)((bounds.left / AXGeometryTools.Utilities.IntPointPrecision) * hmWidth / terrain.terrainData.size.x); int to_i = (int)((bounds.right / AXGeometryTools.Utilities.IntPointPrecision) * hmWidth / terrain.terrainData.size.x); int from_j = (int)((bounds.top / AXGeometryTools.Utilities.IntPointPrecision) * hmHeight / terrain.terrainData.size.z); int to_j = (int)((bounds.bottom / AXGeometryTools.Utilities.IntPointPrecision) * hmHeight / terrain.terrainData.size.z); //Debug.Log(from_i +"->"+to_i+" :: " + from_j+ "->"+to_j); from_i = Mathf.Max(0, from_i); to_i = Mathf.Min(to_i, hmWidth); from_j = Mathf.Max(0, from_j); to_j = Mathf.Min(to_j, hmHeight); //Debug.Log(from_i +"->"+to_i+" :: " + from_j+ "->"+to_j); // patch to be redrawn float[,] heights = new float[(to_j - from_j), (to_i - from_i)]; //Debug.Log(heights.GetLength(0) +" -- " + heights.GetLength(1)); if (from_i < to_i && from_j < to_j) { // we set each sample of the terrain in the size to the desired height for (int i = from_i; i < to_i; i++) { for (int j = from_j; j < to_j; j++) { // GET i, j in realworld coords float x = terrain.terrainData.size.x * i / hmWidth; float y = terrain.terrainData.size.z * j / hmHeight; //Debug.Log("[" + i + ", " + j + "] :: " + x +", " + y); if (isInside(x, y, subjPaths, holePaths)) { heights [j - from_j, i - from_i] = percentHgt; } else { heights [j - from_j, i - from_i] = parametricObject.heightsOrig [j, i]; } } } // set the new height terrain.terrainData.SetHeights(from_i, from_j, heights); } //prevBounds = bounds; } }