public Polygon Clip(Polygon clippingPoly, ClipType type = ClipType.ctIntersection) { List <List <IntPoint> > list = new List <List <IntPoint> >(); list.Add(GetPath()); List <List <IntPoint> > list2 = new List <List <IntPoint> >(); list2.Add(clippingPoly.GetPath()); Clipper clipper = new Clipper(0); PolyTree polytree = new PolyTree(); clipper.AddPaths(list, PolyType.ptSubject, true); clipper.AddPaths(list2, PolyType.ptClip, true); clipper.Execute(type, polytree, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); List <List <IntPoint> > list3 = Clipper.PolyTreeToPaths(polytree); if (list3.Count > 0) { List <Vector2> list4 = new List <Vector2>(); for (int i = 0; i < list3[0].Count; i++) { List <Vector2> list5 = list4; IntPoint intPoint = list3[0][i]; float x = (float)intPoint.X * 0.0001f; IntPoint intPoint2 = list3[0][i]; list5.Add(new Vector2(x, (float)intPoint2.Y * 0.0001f)); } return(new Polygon(list4)); } return(null); }
public static bool addSteinerPointsAtOffset(ref Polygon _polygon, ref ClipperOffset co, float offset, int seglenBigInt) { PolyTree resPolytree = new AXClipperLib.PolyTree(); co.Execute(ref resPolytree, (double)(-offset * AXGeometryTools.Utilities.IntPointPrecision)); Paths paths = Clipper.PolyTreeToPaths(resPolytree); if (paths != null && paths.Count > 0 && paths[0] != null && paths[0].Count > 0) { foreach (Path path in paths) { if (path != null && path.Count > 0) { Path ppp = Pather.segmentPath(path, seglenBigInt); if (ppp != null && ppp.Count > 0) { foreach (IntPoint ip in ppp) { _polygon.AddSteinerPoint(new TriangulationPoint((double)ip.X / (double)AXGeometryTools.Utilities.IntPointPrecision, (double)ip.Y / (double)AXGeometryTools.Utilities.IntPointPrecision)); } } } } return(true); } return(false); }
private IEnumerable <CPolygon> GrowAndClipMergedCpg_Overlap(CPolygon mergedcpg, double dblProp, string strSimplification, string strBufferStyle, double dblMiterLimit) { //dblProp = 0.2; //dblProp = 1; double dblCurrentScale = _dblStartScale + dblProp * (_dblTargetScale - _dblStartScale); double dblCurrentGrow = dblProp * _dblTotalGrow * CConstants.dblFclipper; double dblCurrentEpsilon = Math.Min(dblCurrentGrow / dblMiterLimit, _dblEpsilon * dblCurrentScale * CConstants.dblFclipper); double dblCurrentErosion = _dblErosion * dblCurrentScale * CConstants.dblFclipper; //double dblCurrentDilation = Math.Max(dblCurrentEpsilon / 2, dblProp * _dblDilation * dblCurrentScale * CConstants.dblFclipper); double dblCurrentDilation = (dblCurrentGrow - dblMiterLimit * dblCurrentErosion) / (dblMiterLimit - 1); //dblCurrentErosion = 0; //dblCurrentDilation = 0; var clipPathsFirstLevel = clipperMethods.GenerateClipPathsByCpgEb(mergedcpg.ClipCpgLt); var LastAndClippedPath = new Paths(); if (mergedcpg.SubCpgLt == null || mergedcpg.SubCpgLt.Count < 2) { LastAndClippedPath.AddRange(DilateErodeOffsetSimplifyCpg(mergedcpg, dblCurrentGrow, dblCurrentDilation, dblCurrentErosion, dblCurrentEpsilon, strSimplification, strBufferStyle, dblMiterLimit)); } else { //var SubCpgLt = mergedcpg.SubCpgLt; var submergedcpglt = MergeCloseCpgsAndAddBridges(mergedcpg.SubCpgLt, false, //---Merge---// dblCurrentGrow, dblCurrentDilation, dblCurrentEpsilon); //var BridgeCpipeDt = mergedcpg.BridgeCpipeDt; foreach (var submergedcpg in submergedcpglt) { LastAndClippedPath.AddRange(DilateErodeOffsetSimplifyCpg(submergedcpg, dblCurrentGrow, dblCurrentDilation, dblCurrentErosion, dblCurrentEpsilon, strSimplification, strBufferStyle, dblMiterLimit)); } } //CSaveFeature.SaveCEdgeEb(clipperMethods.ScaleCEdgeEb( // clipperMethods.ConvertPathsToCEdgeEb(LastAndClippedPath, true), 1 / CConstants.dblFclipper), // "GrownPathsWithoutMergeOrClip", blnVisible: false); LastAndClippedPath.AddRange(mergedcpg.LastTimePaths); var unitedPaths = clipperMethods.Clip_Paths(LastAndClippedPath, true, mergedcpg.LastTimePaths, true, ClipType.ctUnion); //var unitedPaths = LastAndClippedPath; var clippedPolyTree = clipperMethods.Clip_PolyTree(unitedPaths, true, clipPathsFirstLevel, true, ClipType.ctIntersection); mergedcpg.LastTimePaths = Clipper.PolyTreeToPaths(clippedPolyTree); var GrownAndClippedCpg = clipperMethods.GenerateCpgEbByPolyTree(clippedPolyTree, mergedcpg.ID, true); //CSaveFeature.SavePolyTreeAsCpgEb(clippedPolyTree, "GrownMergeClipPolyTree", // pesriSimpleFillStyle: esriSimpleFillStyle.esriSFSNull, blnVisible: false); return(GrownAndClippedCpg); }
public float Area() { float area = 0; foreach (var poly in Clipper.PolyTreeToPaths(polyTree)) { area += (float)Clipper.Area(poly); } return(area); }
public void Union(Slice other) { Clipper c = new Clipper(); c.Clear(); c.AddPaths(Clipper.PolyTreeToPaths(polyTree), PolyType.ptSubject, true); c.AddPaths(Clipper.PolyTreeToPaths(other.polyTree), PolyType.ptClip, true); polyTree = new PolyTree(); c.Execute(ClipType.ctUnion, polyTree); }
public void Subtract(Slice other) { Clipper c = new Clipper(); c.Clear(); c.AddPaths(Clipper.PolyTreeToPaths(polyTree), PolyType.ptSubject, true); c.AddPaths(Clipper.PolyTreeToPaths(other.polyTree), PolyType.ptClip, true); polyTree = new PolyTree(); c.Execute(ClipType.ctDifference, polyTree); }
public bool Contains(Slice other) { // To contain another slice: // 1. Area of the union must be the same // 2. Area of this - other must be less float thisArea = this.Area(); Paths otherPolygons = Clipper.PolyTreeToPaths(other.polyTree); Paths thesePolygons = Clipper.PolyTreeToPaths(polyTree); Slice s = new Slice(this); Clipper c = new Clipper(); c.Clear(); c.AddPaths(thesePolygons, PolyType.ptSubject, true); c.AddPaths(otherPolygons, PolyType.ptClip, true); s.polyTree = new PolyTree(); c.Execute(ClipType.ctUnion, s.polyTree); float area_union = s.Area(); if (area_union > thisArea) { return(false); } return(true); //c.Clear(); //c.AddPaths(thesePolygons, PolyType.ptSubject, true); //c.AddPaths(otherPolygons, PolyType.ptClip, true); //s.polyTree = new PolyTree(); //c.Execute(ClipType.ctDifference, s.polyTree); //float area_difference = s.Area(); //if (area_difference < thisArea) //{ // return true; //} //return false; }
public static void DrawPathsFit(AXParameter p, Vector2 offset, float size, Color color) { if (p == null) { return; } bool isClosed = (p.shapeState == ShapeState.Closed || p.thickness > 0); float rot = 0; //p.Parent.floatValue("Rot_Z"); Paths paths = null; if (p.polyTree != null) { paths = Clipper.PolyTreeToPaths(p.polyTree); } else if (p.paths != null) { paths = p.paths; } Rect t_bounds = AXGeometryTools.Utilities.getClipperBounds(p.transformedControlPaths); float t_maxdim = (t_bounds.width > t_bounds.height) ? t_bounds.width : t_bounds.height; float t_scale = size / t_maxdim; Rect p_bounds = AXGeometryTools.Utilities.getClipperBounds(paths); float p_maxdim = (p_bounds.width > p_bounds.height) ? p_bounds.width : p_bounds.height; float p_scale = size / p_maxdim; float scale = t_scale; Rect bounds = t_bounds; if (p_scale < t_scale) { scale = p_scale; bounds = p_bounds; } offset += scale * new Vector2(-(bounds.x + bounds.width / 2), bounds.y + bounds.height / 2); // DRAW CONTROL_PATHS control paths //if(p.transformedControlPaths != null) if (p.transformedButUnscaledOutputPaths != null) { foreach (Path cpath in p.transformedButUnscaledOutputPaths) { drawPath(AXGeometryTools.Utilities.path2Vec2s(cpath, rot, scale), offset, isClosed, Color.gray); } } if (p.transformedAndScaledButNotOffsetdOutputPaths != null) { foreach (Path cpath in p.transformedAndScaledButNotOffsetdOutputPaths) { drawPath(AXGeometryTools.Utilities.path2Vec2s(cpath, rot, scale), offset, isClosed, Color.cyan); } } if (paths != null) { foreach (Path path in paths) { drawPath(AXGeometryTools.Utilities.path2Vec2s(path, rot, scale), offset, isClosed, color); } } // axis Vector2[] xaxis = new Vector2[2]; xaxis[0] = new Vector2(-5, 0); xaxis[1] = new Vector2(5, 0); Vector2[] yaxis = new Vector2[2]; yaxis[0] = new Vector2(0, -5); yaxis[1] = new Vector2(0, 5); drawPath(xaxis, offset, false, Color.gray); drawPath(yaxis, offset, false, Color.gray); }
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 --- // } // }
/* GENERATE LINE */ public void generateLine() { if (inputs.Count == 0) { return; } Clipper c = new Clipper(Clipper.ioPreserveCollinear); c.PreserveCollinear = true; AXParameter input = null; AXParameter src = null; //Debug.Log ("GENERATE LINE"); // // DON'T ALTER AN "OPEN" SHAPE OR RAIL IF IT IS NOT BEING COMBINED WITH OTHER INPUTS AND IS NOT THICKENED OR OFFSET if (inputs.Count == 1 && inputs[0].offset == 0 && inputs[0].thickness == 0) { if (inputs[0].DependsOn != null) { difference.polyTree = inputs[0].DependsOn.polyTree; difference.paths = inputs[0].DependsOn.paths; } //Archimatix.printPath(output.paths[0]); return; } // GROUPED COMBINE grouped.paths = new Paths(); foreach (AXParameter inp in inputs) { if (inp.paths == null) { continue; } foreach (Path _path in inp.paths) { grouped.paths.Add(_path); } } // EACH INPUT (PREPROCESSING) for (int i = 0; i < inputs.Count; i++) { input = inputs [i]; src = input.DependsOn; if (src != null && src.parametricObject != null && !src.parametricObject.isActive) { continue; } if (src == null) { continue; } input.polyTree = null; thickenAndOffset(ref input, src); // Add as a Solid or Void (subj or clip) to Clipper c //bool isClosed = (input.shapeState == ShapeState.Closed || input.polyType == PolyType.ptSubject) ? true : false; bool isClosed = true; if (input.polyTree != null) { c.AddPaths(AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(input.polyTree)), input.polyType, isClosed); } else if (input.paths != null) { c.AddPaths(AXGeometryTools.Utilities.cleanPaths(input.paths), input.polyType, isClosed); } } // end inputs preprocessing // COMBINE INPUTS // Output AX.Generators.Generator2D gener2D = parametricObject.generator as AX.Generators.Generator2D; // DIFFERENCE if ((difference.Dependents != null && difference.Dependents.Count > 0) || combineType == CombineType.Difference) { difference.polyTree = new AXClipperLib.PolyTree(); c.Execute(ClipType.ctDifference, difference.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); thickenAndOffset(ref difference, difference); AXGeometryTools.Utilities.transformPolyTree(difference.polyTree, gener2D.localMatrix); if (difference.reverse) { AXGeometryTools.Utilities.reversePolyTree(difference.polyTree); } AX.Generators.Generator2D.deriveStatsETC(difference); } // INTERSECTION //if((intersection.Dependents != null && intersection.Dependents.Count > 0) || combineType == CombineType.Intersection) //{ intersection.polyTree = new AXClipperLib.PolyTree(); c.Execute(ClipType.ctIntersection, intersection.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); thickenAndOffset(ref intersection, intersection); AXGeometryTools.Utilities.transformPolyTree(intersection.polyTree, gener2D.localMatrix); if (intersection.reverse) { AXGeometryTools.Utilities.reversePolyTree(intersection.polyTree); } AX.Generators.Generator2D.deriveStatsETC(intersection); //} // UNION if ((union.Dependents != null && union.Dependents.Count > 0) || combineType == CombineType.Union) { union.polyTree = new AXClipperLib.PolyTree(); c.Execute(ClipType.ctUnion, union.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); thickenAndOffset(ref union, union); AXGeometryTools.Utilities.transformPolyTree(intersection.polyTree, gener2D.localMatrix); if (union.reverse) { AXGeometryTools.Utilities.reversePolyTree(union.polyTree); } AX.Generators.Generator2D.deriveStatsETC(union); } }
/* * public override void initializeBays(string pName) * { * if (parametricObject.isInitialized) * return; * * parametricObject.isInitialized = true; * * RadialRepeaterTool gener = repeaterToolU as RadialRepeaterTool; * * switch(pName) * { * case "Node Shape": * if (repeaterToolU != null) * gener.radius = 3.5f * nodeSrc_p.parametricObject.bounds.size.x ; * break; * case "Cell Shape": * if (repeaterToolU != null) * gener.radius = 2.5f * cellSrc_p.parametricObject.bounds.size.x ; * break; * } * } */ // SHAPE_REPEATER_2D :: GENERATE public override GameObject generate(bool makeGameObjects, AXParametricObject initiator_po, bool isReplica) { if (parametricObject == null || !parametricObject.isActive) { return(null); } if ((P_Corner == null || cornerSrc_p == null) && (P_Node == null || inputSrc_p == null) && (P_Cell == null || cellSrc_p == null)) { if (P_Output != null) { P_Output.paths = null; P_Output.polyTree = null; } return(null); } // PRE_GENERATE preGenerate(); planSrc_p = P_Plan.DependsOn; // getUpstreamSourceParameter(P_Plan); planSrc_po = (planSrc_p != null) ? planSrc_p.parametricObject : null; P_Plan.polyTree = null; AXShape.thickenAndOffset(ref P_Plan, planSrc_p); if (P_Plan.reverse) { P_Plan.doReverse(); } planPaths = P_Plan.getPaths(); if (planPaths == null || planPaths.Count == 0) { return(null); } // ** CREATE PLAN_SPLINES ** if (planPaths != null && planPaths.Count > 0) { planSplines = new Spline[planPaths.Count]; if (planSplines != null) { for (int i = 0; i < planSplines.Length; i++) { planSplines[i] = new Spline(planPaths[i], (P_Plan.shapeState == ShapeState.Closed) ? true : false); } } } AXParameter P_cornerOutput = new AXParameter(); P_cornerOutput.parametricObject = parametricObject; AXParameter P_nodeOutput = new AXParameter(); P_nodeOutput.parametricObject = parametricObject; AXParameter P_cellOutput = new AXParameter(); P_cellOutput.parametricObject = parametricObject; // PROCESS SHAPE INPUTS if (cornerSrc_p != null) { P_Corner.polyTree = null; AXShape.thickenAndOffset(ref P_Corner, cornerSrc_p); } if (inputSrc_p != null) { P_Node.polyTree = null; AXShape.thickenAndOffset(ref P_Node, inputSrc_p); } if (cellSrc_p != null) { P_Cell.polyTree = null; AXShape.thickenAndOffset(ref P_Cell, cellSrc_p); } bool doPolyTreeNodes = false; //bool doPolyTreeCells = false; // NODE //Matrix4x4 tm = Matrix4x4.identity; // NODE SHAPES Paths nodeSourcePaths = null; //Clipper nodeClipper = null; if (P_Node != null) { if (P_Node.polyTree != null) { nodeSourcePaths = AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(P_Node.polyTree)); doPolyTreeNodes = true; //nodeClipper = new Clipper(); } else { nodeSourcePaths = P_Node.getClonePaths(); P_nodeOutput.paths = new Paths(); } } // CELL SHAPES Paths cellSourcePaths = null; //Clipper cellClipper = null; if (P_Cell != null) { if (P_Cell.polyTree != null) { cellSourcePaths = AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(P_Cell.polyTree)); doPolyTreeNodes = true; //cellClipper = new Clipper(); } else { cellSourcePaths = P_Cell.getClonePaths(); P_cornerOutput.paths = new Paths(); } } // BREAK CORNER SHAPES Paths cornerSourcePaths = null; Clipper cornerClipper = null; if (P_Corner != null) { if (P_Corner.polyTree != null) { cornerSourcePaths = AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(P_Corner.polyTree)); doPolyTreeNodes = true; cornerClipper = new Clipper(); } else { cornerSourcePaths = P_Corner.getClonePaths(); P_cornerOutput.paths = new Paths(); } } // FOR EACH PATH for (int path_i = 0; path_i < planPaths.Count; path_i++) { // **** PREPARE EACH SPLINE *** // Spline planSpline = planSplines[path_i]; planSpline.breakAngleCorners = cornerBreakAngle; planSpline.shapeState = P_Plan.shapeState; // Create subsplines between each break point planSpline.getSmoothSubsplineIndicies(0, maxSegmentLength); // Debug.Log("planSpline.subsplines.Count="+ planSpline.subsplines.Count ); // foreach(SubsplineIndices si in planSpline.subsplines) // si.print(); planSpline.groupNearBreakAngleVertices(inset * 2); // **** PREPARE EACH SPLINE *** // Matrix4x4 localPlacement_mx = Matrix4x4.identity; if (planSpline.insetSpanSplines != null && planSpline.insetSpanSplines.Count > 0) { for (int si = 0; si < planSpline.insetSpanSplines.Count; si++) { planSpline.insetSpanSplines[si].setRepeaterTransforms(si, inset, bay); } // SPAN NODES - SHAPES ALONG SUBSPLINES if (nodeSrc_p != null && nodeSrc_p.meshes != null) { int endCount = (P_Plan != null && P_Plan.shapeState == ShapeState.Open) ? planSpline.insetSpanSplines.Count - 1 : planSpline.insetSpanSplines.Count; for (int i = 0; i < endCount; i++) { //SubsplineIndices rsi = planSpline.subsplines[i]; Spline spanSpline = planSpline.insetSpanSplines[i]; List <Matrix4x4> nodeMatrices = spanSpline.repeaterNodeTransforms; // on each of these nodes, place a nodePlug instance. bool spanNodesAtBreakCorners = true; int starter = spanNodesAtBreakCorners ? 0 : 1; int ender = (inset > 0 || spanNodesAtBreakCorners) ? nodeMatrices.Count : nodeMatrices.Count - 1; //string this_address = ""; if (nodeMatrices != null) { for (int ii = starter; ii < ender; ii++) { //this_address = "node_"+path_i+"_"+i+"_"+ii; //Debug.Log("this_address="+this_address); // LOCAL_PLACEMENT localPlacement_mx = localMatrixFromAddress(RepeaterItem.Node, path_i, i, ii); if (doPolyTreeNodes) { cornerClipper.AddPaths(AX.Generators.Generator2D.transformPaths(nodeSourcePaths, localPlacement_mx), PolyType.ptSubject, true); } else { Paths tmp = AX.Generators.Generator2D.transformPaths(nodeSourcePaths, localPlacement_mx); P_cornerOutput.paths.AddRange(tmp); } } } } } // CELL NODES - SHAPES ALONG SUBSPLINES if (cellSrc_p != null && cellSrc_p.meshes != null) { int endCount = (P_Plan != null && P_Plan.shapeState == ShapeState.Open) ? planSpline.insetSpanSplines.Count - 1 : planSpline.insetSpanSplines.Count; for (int i = 0; i < endCount; i++) { //SubsplineIndices rsi = planSpline.subsplines[i]; Spline spanSpline = planSpline.insetSpanSplines[i]; List <Matrix4x4> cellMatrices = spanSpline.repeaterCellTransforms; // on each of these nodes, place a nodePlug instance. bool spanNodesAtBreakCorners = true; int starter = spanNodesAtBreakCorners ? 0 : 1; int ender = (inset > 0 || spanNodesAtBreakCorners) ? cellMatrices.Count : cellMatrices.Count - 1; //string this_address = ""; if (cellMatrices != null) { for (int ii = starter; ii < ender; ii++) { //this_address = "cell_"+path_i+"_"+i+"_"+ii; //Debug.Log("this_address="+this_address); // LOCAL_PLACEMENT localPlacement_mx = localMatrixFromAddress(RepeaterItem.Cell, path_i, i, ii); if (doPolyTreeNodes) { cornerClipper.AddPaths(AX.Generators.Generator2D.transformPaths(cellSourcePaths, localPlacement_mx), PolyType.ptSubject, true); } else { Paths tmp = AX.Generators.Generator2D.transformPaths(nodeSourcePaths, localPlacement_mx); P_cornerOutput.paths.AddRange(tmp); } } } } } } if (cornerSourcePaths != null && cornerSourcePaths.Count > 0) { // CORNERS for (int bi = 0; bi < planSpline.breakIndices.Count; bi++) { //tm = Matrix4x4.TRS(new Vector3(2*i-2, 2*j-2, 0), Quaternion.identity, Vector3.one); localPlacement_mx = localMatrixFromAddress(RepeaterItem.Corner, path_i, planSpline.breakIndices[bi]); if (doPolyTreeNodes) { cornerClipper.AddPaths(AX.Generators.Generator2D.transformPaths(cornerSourcePaths, localPlacement_mx), PolyType.ptSubject, true); } else { Paths tmp = AX.Generators.Generator2D.transformPaths(cornerSourcePaths, localPlacement_mx); P_cornerOutput.paths.AddRange(tmp); } } } if (doPolyTreeNodes) { P_cornerOutput.polyTree = new AXClipperLib.PolyTree(); cornerClipper.Execute(ClipType.ctDifference, P_cornerOutput.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); } } P_Output.polyTree = null; if (cornerSrc_p != null || cellSrc_p == null || nodeSrc_p == null) { // JUST NODES AXShape.thickenAndOffset(ref P_Output, P_cornerOutput); } /* * else if (nodeSrc_p != null && (cellSrc_p == null || (P_cellOutput.paths == null && P_cellOutput.polyTree == null))) * { * // JUST NODES * AXShape.thickenAndOffset(ref P_Output, P_nodeOutput); * } * * else if (nodeSrc_p == null && cellSrc_p != null) * { * // JUST CELLS * AXShape.thickenAndOffset(ref P_Output, P_cellOutput); * } * else * { * // BOTH TO COMBINE * clipper = new Clipper(); * * if (P_nodeOutput.polyTree == null) * clipper.AddPaths(P_nodeOutput.paths, PolyType.ptSubject, true); * else * clipper.AddPaths(AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(P_nodeOutput.polyTree)), PolyType.ptSubject, true); * * if (P_cellOutput.polyTree == null) * clipper.AddPaths(P_cellOutput.paths, PolyType.ptSubject, true); * else * clipper.AddPaths(AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(P_cellOutput.polyTree)), PolyType.ptSubject, true); * * * P_Output.polyTree = new AXClipperLib.PolyTree(); * clipper.Execute(ClipType.ctUnion, P_Output.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); * * AXShape.thickenAndOffset(ref P_Output, P_Output); * } */ if (P_Output.polyTree != null) { transformPolyTree(P_Output.polyTree, localMatrix); } else if (P_nodeOutput.paths != null) { P_Output.paths = transformPaths(P_nodeOutput.paths, localMatrix); P_Output.transformedControlPaths = P_nodeOutput.paths; } //base.generate(false, initiator_po, isReplica); calculateBounds(); return(null); } // \generate
// SHAPE_REPEATER_2D :: GENERATE public override GameObject generate(bool makeGameObjects, AXParametricObject initiator_po, bool isReplica) { if ((P_Node == null || inputSrc_p == null) && (P_Cell == null || cellSrc_p == null)) { if (P_Output != null) { P_Output.paths = null; P_Output.polyTree = null; } return(null); } if (repeaterToolU == null || repeaterToolV == null) { return(null); } // PRE_GENERATE preGenerate(); AXParameter P_nodeOutput = new AXParameter(); P_nodeOutput.parametricObject = parametricObject; AXParameter P_cellOutput = new AXParameter(); P_cellOutput.parametricObject = parametricObject; // PROCESS NODE INPUT if (inputSrc_p != null) { P_Node.polyTree = null; AXShape.thickenAndOffset(ref P_Node, inputSrc_p); //P_nodeOutput.polyTree = null; //AXShape.thickenAndOffset(ref P_nodeOutput, P_Node); } if (cellSrc_p != null) { P_Cell.polyTree = null; AXShape.thickenAndOffset(ref P_Cell, cellSrc_p); //P_cellOutput.polyTree = null; //AXShape.thickenAndOffset(ref P_cellOutput, P_Cell); } bool doPolyTreeNodes = false; bool doPolyTreeCells = false; // NODE Matrix4x4 tm = Matrix4x4.identity; Paths tmpPaths = null; Clipper clipper = null; if (nodeSrc_p != null) { if (P_Node.polyTree != null) { tmpPaths = AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(P_Node.polyTree)); doPolyTreeNodes = true; clipper = new Clipper(); } else { tmpPaths = P_Node.getClonePaths(); P_nodeOutput.paths = new Paths(); } //Debug.Log("tmpPaths="+tmpPaths.Count); if (tmpPaths != null && tmpPaths.Count > 0) { for (int i = 0; i <= repeaterToolU.cells; i++) { for (int j = 0; j <= repeaterToolV.cells; j++) { if ((i <= repeaterToolU.edgeCount || i >= repeaterToolU.cells - repeaterToolU.edgeCount) || (j <= repeaterToolV.edgeCount || j >= repeaterToolV.cells - repeaterToolV.edgeCount)) { //tm = Matrix4x4.TRS(new Vector3(2*i-2, 2*j-2, 0), Quaternion.identity, Vector3.one); tm = localMatrixFromAddress(RepeaterItem.Node, i, j); if (doPolyTreeNodes) { clipper.AddPaths(AX.Generators.Generator2D.transformPaths(tmpPaths, tm), PolyType.ptSubject, true); } else { Paths tmp = AX.Generators.Generator2D.transformPaths(tmpPaths, tm); P_nodeOutput.paths.AddRange(tmp); } } } } if (doPolyTreeNodes) { P_nodeOutput.polyTree = new AXClipperLib.PolyTree(); clipper.Execute(ClipType.ctDifference, P_nodeOutput.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); } } } // CELL // PROCESS CELL INPUT if (cellSrc_p != null) { if (P_Cell.polyTree != null) { tmpPaths = AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(P_Cell.polyTree)); doPolyTreeCells = true; clipper = new Clipper(); } else { tmpPaths = P_Cell.getClonePaths(); P_cellOutput.paths = new Paths(); } if (tmpPaths != null && tmpPaths.Count > 0) { for (int i = 0; i < repeaterToolU.cells; i++) { for (int j = 0; j < repeaterToolV.cells; j++) { tm = localMatrixFromAddress(RepeaterItem.Cell, i, j); if (doPolyTreeCells) { clipper.AddPaths(AX.Generators.Generator2D.transformPaths(tmpPaths, tm), PolyType.ptSubject, true); } else { Paths tmp = AX.Generators.Generator2D.transformPaths(tmpPaths, tm); P_cellOutput.paths.AddRange(tmp); } } } if (doPolyTreeCells) { P_cellOutput.polyTree = new AXClipperLib.PolyTree(); clipper.Execute(ClipType.ctDifference, P_cellOutput.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); } } } /* * if ( P_Output.polyTree != null) * { * transformPolyTree(P_Output.polyTree, localMatrix); * } * else if (P_Output.paths != null) * { * P_Output.paths = transformPaths(P_Output.paths, localMatrix); * P_Output.transformedControlPaths = P_Output.paths; * } */ P_Output.polyTree = null; if (nodeSrc_p != null && cellSrc_p == null) { // JUST NODES AXShape.thickenAndOffset(ref P_Output, P_nodeOutput); } else if (nodeSrc_p == null && cellSrc_p != null) { // JUST CELLS AXShape.thickenAndOffset(ref P_Output, P_cellOutput); } else { // BOTH TO COMBINE clipper = new Clipper(); if (P_nodeOutput.polyTree == null) { clipper.AddPaths(P_nodeOutput.paths, PolyType.ptSubject, true); } else { clipper.AddPaths(AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(P_nodeOutput.polyTree)), PolyType.ptSubject, true); } if (P_cellOutput.polyTree == null) { clipper.AddPaths(P_cellOutput.paths, PolyType.ptSubject, true); } else { clipper.AddPaths(AXGeometryTools.Utilities.cleanPaths(Clipper.PolyTreeToPaths(P_cellOutput.polyTree)), PolyType.ptSubject, true); } P_Output.polyTree = new AXClipperLib.PolyTree(); clipper.Execute(ClipType.ctUnion, P_Output.polyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); AXShape.thickenAndOffset(ref P_Output, P_Output); } if (P_Output.polyTree != null) { transformPolyTree(P_Output.polyTree, localMatrix); } else if (P_nodeOutput.paths != null) { P_Output.paths = transformPaths(P_nodeOutput.paths, localMatrix); P_Output.transformedControlPaths = P_nodeOutput.paths; } else if (P_cellOutput.paths != null) { P_Output.paths = transformPaths(P_cellOutput.paths, localMatrix); P_Output.transformedControlPaths = P_cellOutput.paths; } //base.generate(false, initiator_po, isReplica); calculateBounds(); return(null); } // \generate
// SHAPE :: GENERATE public override GameObject generate(bool makeGameObjects, AXParametricObject initiator_po, bool isReplica) { if (inputSrc_p == null) { return(null); } P_Input.polyTree = null; AXShape.thickenAndOffset(ref P_Input, inputSrc_p); P_Output.polyTree = null; AXShape.thickenAndOffset(ref P_Output, P_Input); // now take the output and segment it.... Paths subjPaths = null; if (P_Output.polyTree != null) { subjPaths = Clipper.PolyTreeToPaths(P_Output.polyTree); P_Output.polyTree = null; } else { subjPaths = P_Output.getPaths(); } Path src_path = subjPaths[0]; Paths segmentedPaths = new Paths(); float y0 = 0; float height = parametricObject.floatValue("height"); int segs = parametricObject.intValue("segments"); float segHgt = height / segs; float zone_y; // int zoneCursor = 0; // begin the first zone path (or segment) Path zonePath = new Path(); zonePath.Add(src_path[0]); // loop through segments in path for (int v = 0; v < (src_path.Count - 1); v++) { Debug.Log("v=" + v); IntPoint thisVert = src_path[v]; IntPoint nextVert = src_path[v + 1]; float slope = 0; if (nextVert.Y - thisVert.Y != 0) { slope = (0.0f + (nextVert.X - thisVert.X)) / (0.0f + (nextVert.Y - thisVert.Y)); } // do these y's cross over a segment line? for (int zone = zoneCursor; zone < segs; zone++) { zone_y = (y0 + zone * segHgt) * AXGeometryTools.Utilities.IntPointPrecision; Debug.Log("zone=" + zone + ", zone_y=" + zone_y + ",y0= " + y0 + ", segHgt=" + segHgt + ", segs=" + segs); if (thisVert.Y < zone_y && nextVert.Y > zone_y) { // we have a crossover float newX = (zone_y - thisVert.Y) * slope + thisVert.X; // make a new point IntPoint segPt = new IntPoint(newX, zone_y); zonePath.Add(segPt); segmentedPaths.Add(zonePath); zonePath = new Path(); zonePath.Add(segPt); //no need to look at zone less than this again } } // Now add the upper vert... zonePath.Add(nextVert); } segmentedPaths.Add(zonePath); Debug.Log("segmentedPaths: " + segmentedPaths.Count); P_Output.paths = segmentedPaths; return(null); }
// GENERATE EXTRUDE public override GameObject generate(bool makeGameObjects, AXParametricObject initiator_po, bool renderToOutputParameter) { //Debug.Log ("===> [" + parametricObject.Name + "] EXTRUDE generate ... MAKE_GAME_OBJECTS="+makeGameObjects); if (parametricObject == null || !parametricObject.isActive) { return(null); } // RESULTING MESHES ax_meshes = new List <AXMesh>(); //Debug.Log(" ******** A "); preGenerate(); // PLAN - // The plan may have multiple paths. Each may generate a separate GO. if (P_Plan == null || planSrc_p == null || !planSrc_p.parametricObject.isActive) { return(null); } //Debug.Log(" ******** B " + planSrc_p.parametricObject.Name + "." + planSrc_p.Name); // Offset is bevel and !bevelOut float originalOffset = P_Plan.offset; // set back by the max bevel - later consider taper and lip.... if (!bevelOut) { /* * float bevelMax = (bevelTop > bevelBottom) ? bevelTop : bevelBottom; * * if (bevelMax > 0 ) * { * offsetModified -= bevelMax; * //P_Plan.joinType = JoinType.jtMiter; * } */ P_Plan.offset -= (bevelBottom > bevelTop) ? bevelBottom : bevelTop; } // Splitting concave shapes? // THis is a pecial case. An ssumption is mad of no holes // so that we can deal only with paths. if (parametricObject.splitConcaveShapes) //P_Plan.offset != 0) { // SPLIT INTO CONCAVES ** ** ** ** ** ** if no holes, and makeConcave, Paths paths; AXParameter tmpSrc = (!renderToOutputParameter && P_Plan.Dependents != null) ? P_Plan : planSrc_p; if (tmpSrc.polyTree != null) { paths = Clipper.PolyTreeToPaths(tmpSrc.polyTree); } else { paths = tmpSrc.paths; } //Pather.printPaths(P_Plan.paths); if (paths != null) { P_Plan.paths = new Paths(); foreach (Path path in paths) { Paths splitPaths = Pather.splitIntoConvexPaths(path); splitPaths = Pather.offset(splitPaths, P_Plan.offset); P_Plan.paths.AddRange(splitPaths); } } P_Plan.polyTree = null; // SPLIT INTO CONCAVES ** ** ** ** ** ** ** ** if no holes, and makeConcave, } else { //Debug.Log("A: "+planSrc_p.paths[0].Count); P_Plan.polyTree = null; // Debug.Log("EXTRUED " + parametricObject.Name); // Pather.printPaths(P_Plan.paths); if (!renderToOutputParameter && P_Plan.Dependents != null) { // Some Replicant has set the paths of this Plan_P manually AXShape.thickenAndOffset(ref P_Plan, P_Plan); } else { AXShape.thickenAndOffset(ref P_Plan, planSrc_p); } } P_Plan.offset = originalOffset; //Debug.Log("B: " +P_Plan.paths[0].Count); // DEFAULT SECTION -- USING BI_CHAMFER_SIDEflipX Path sectionPath = new Path(); sectionPath = AXTurtle.BiChamferSide(extrude, bevelTop, bevelBottom, bevelSegs, true, taper, lipTop, lipBottom, lipEdge, lipEdgeBottom, segs); AXParameter sec_p = new AXParameter(); sec_p.Parent = parametricObject; sec_p.parametricObject = parametricObject; sec_p.Type = AXParameter.DataType.Shape; sec_p.shapeState = ShapeState.Open; sec_p.paths = new Paths(); sec_p.paths.Add(sectionPath); if (parametricObject.boolValue("Bevel Hard Edge")) { sec_p.breakGeom = 0; sec_p.breakNorm = 0; } //StopWatch sw = new StopWatch(); //Debug.Log("Extrude ===================== "); GameObject retGO = generateFirstPass(initiator_po, makeGameObjects, P_Plan, sec_p, Matrix4x4.identity, renderToOutputParameter); //Debug.Log("Extrude Done ===================== " + sw.duration()); // FINISH AX_MESHES parametricObject.finishMultiAXMeshAndOutput(ax_meshes, true); //renderToOutputParameter); // FINISH BOUNDING setBoundaryFromAXMeshes(ax_meshes); //Debug.Log("Extrude: "+ parametricObject.bounds); return(retGO); }
public static void DrawOutputPaths(Texture2D canvas, AXParametricObject po, float texSize, float imageSize) { if (po == null) { return; } // GET OUTPUT PARAMETER AXParameter p = po.getPreferredOutputSplineParameter(); if (p == null) { return; } bool isClosed = (p.shapeState == ShapeState.Closed); Paths paths = null; if (p.polyTree != null) { paths = Clipper.PolyTreeToPaths(p.polyTree); } else if (p.paths != null) { paths = p.paths; } Rect bounds = AXGeometryTools.Utilities.getClipperBounds(paths); float maxdim = (bounds.width > bounds.height) ? bounds.width : bounds.height; float scale = imageSize / maxdim; long[] shifter = AXGeometryTools.Utilities.getShifterToPathsCenter(paths); Paths centeredPaths = AXGeometryTools.Utilities.shiftPathsAsGroup(paths, shifter); //Archimatix.printPaths(centeredPaths); Vector2 offset = new Vector2(texSize / 2, texSize / 2); float rot = po.floatValue("Rot_Z"); Color lineColor = Color.magenta; lineColor = new Color(1, .5f, 1); foreach (Path path in centeredPaths) { Library.DrawPathsOnTexture(canvas, AXGeometryTools.Utilities.path2Vec2s(path, rot, scale), offset, isClosed, lineColor); } // AXES long s = (shifter[2] / 18); Path xaxis = new Path(); xaxis.Add(new IntPoint(-s - shifter[0], -shifter[1])); xaxis.Add(new IntPoint(s - shifter[0], -shifter[1])); Library.DrawPathsOnTexture(canvas, AXGeometryTools.Utilities.path2Vec2s(xaxis, rot, scale), offset, false, Color.white); Path yaxis = new Path(); yaxis.Add(new IntPoint(-shifter[0], -s - shifter[1])); yaxis.Add(new IntPoint(-shifter[0], s - shifter[1])); Library.DrawPathsOnTexture(canvas, AXGeometryTools.Utilities.path2Vec2s(yaxis, rot, scale), offset, false, Color.white); }
// GENERATE WINWALL public override GameObject generate(bool makeGameObjects, AXParametricObject initiator_po, bool renderToOutputParameter) { if (parametricObject == null || !parametricObject.isActive) { return(null); } //Debug.Log("PlanSweep::generate()"); // RESULTING MESHES ax_meshes = new List <AXMesh>(); preGenerate(); // PLAN // The plan may have multiple paths. Each may generate a separate GO. if (P_Plan == null) { return(null); } planSrc_p = getUpstreamSourceParameter(P_Plan); planSrc_po = (planSrc_p != null) ? planSrc_p.parametricObject : null; if (planSrc_p == null || !planSrc_p.parametricObject.isActive) { return(null); } planIsClosed = (P_Plan.hasThickness || P_Plan.shapeState == ShapeState.Closed) ? true : false; P_Plan.polyTree = null; Paths planPaths = planSrc_p.getPaths(); Path planPath = planPaths[0]; Spline planSpline = new Spline(planPath, planIsClosed, P_Plan.breakGeom, P_Plan.breakNorm); Paths offsetPaths = Pather.wallOffsets(planSpline, .5f, .5f); Pather.printPaths(offsetPaths); // each path, step through and mak a rectangle // segment wide and height and then subtract windows. //Then make poly and add to combiner Path window = AXTurtle.Rectangle(1, 1, false); //window.Reverse(); Pather.shiftPath(window, new IntPoint(10000, 5000)); Debug.Log("=========="); Pather.printPath(window); Pather rightPather = new Pather(offsetPaths[0]); int[] rightLengths = rightPather.segment_lengths; for (int i = 0; i < rightLengths.Length; i++) { Debug.Log(rightLengths[i]); int next_i = (i == rightLengths.Length - 1) ? 0 : i + 1; Path rect = AXTurtle.Rectangle(rightLengths[next_i] / 10000f, 3, false); Clipper c = new Clipper(); c.AddPath(rect, PolyType.ptSubject, true); // fenestration c.AddPath(window, PolyType.ptClip, true); AXClipperLib.PolyTree polytree = new AXClipperLib.PolyTree(); c.Execute(ClipType.ctDifference, polytree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); Paths pathResult = Clipper.PolyTreeToPaths(polytree); Pather.printPaths(pathResult); Mesh mesh = AXPolygon.triangulate(polytree, new AXTexCoords()); Matrix4x4 wallm = Matrix4x4.TRS(new Vector3(offsetPaths[0][i].X / 10000f, 0, offsetPaths[0][i].Y / 10000f), Quaternion.Euler(-90, planSpline.edgeRotations[i], 0), Vector3.one); ax_meshes.Add(new AXMesh(mesh, wallm)); } parametricObject.finishMultiAXMeshAndOutput(ax_meshes, renderToOutputParameter); // FINISH BOUNDING setBoundaryFromAXMeshes(ax_meshes); if (makeGameObjects) { return(parametricObject.makeGameObjectsFromAXMeshes(ax_meshes)); } return(null); }