List <List <IntPoint> > PolygonsFromRoadOutline(float extensionDistance) { var polygons = new List <List <IntPoint> >(); var rnd = Parameters.roadNetworkDescription; foreach (var road in rnd.AllRoads) { var points = GeometrySampling.BuildSamplesFromRoadOutlineWithExtensionDistance( road, 0.5f, extensionDistance, Parameters.outermostLaneType); var path = new List <IntPoint>(points.Length); foreach (var point in points) { path.Add(new IntPoint( point.pose.pos.x * PlacementUtility.UpScaleFactor, point.pose.pos.z * PlacementUtility.UpScaleFactor)); } if (!Clipper.Orientation(path)) { path.Reverse(); } polygons.Add(path); points.Dispose(); } return(polygons); }
//------------------------------------------------------------------------------ private void FixOrientations() { //fixup orientations of all closed paths if the orientation of the //closed path with the lowermost vertex is wrong ... if (m_lowest.X >= 0 && !Clipper.Orientation(m_polyNodes.Childs[(int)m_lowest.X].m_polygon)) { for (int i = 0; i < m_polyNodes.ChildCount; i++) { PolyNode node = m_polyNodes.Childs[i]; if (node.m_endtype == EndType.etClosedPolygon || (node.m_endtype == EndType.etClosedLine && Clipper.Orientation(node.m_polygon))) { node.m_polygon.Reverse(); } } } else { for (int i = 0; i < m_polyNodes.ChildCount; i++) { PolyNode node = m_polyNodes.Childs[i]; if (node.m_endtype == EndType.etClosedLine && !Clipper.Orientation(node.m_polygon)) { node.m_polygon.Reverse(); } } } }
private void CutDual(List <IntPoint> poly, List <int> tmpIntersectingCuts, List <TileHandler.Cut> cuts, bool hasDual, List <List <IntPoint> > intermediateResult, PolyTree result) { this.clipper.Clear(); this.clipper.AddPolygon(poly, PolyType.ptSubject); for (int i = 0; i < tmpIntersectingCuts.Count; i++) { if (cuts[tmpIntersectingCuts[i]].isDual) { this.clipper.AddPolygon(cuts[tmpIntersectingCuts[i]].contour, PolyType.ptClip); } } this.clipper.Execute(ClipType.ctIntersection, intermediateResult, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero); this.clipper.Clear(); if (intermediateResult != null) { for (int j = 0; j < intermediateResult.Count; j++) { this.clipper.AddPolygon(intermediateResult[j], (!Clipper.Orientation(intermediateResult[j])) ? PolyType.ptSubject : PolyType.ptClip); } } for (int k = 0; k < tmpIntersectingCuts.Count; k++) { if (!cuts[tmpIntersectingCuts[k]].isDual) { this.clipper.AddPolygon(cuts[tmpIntersectingCuts[k]].contour, PolyType.ptClip); } } result.Clear(); this.clipper.Execute(ClipType.ctDifference, result, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero); }
private static List <XPolygon> FromPolyTree(PolyNode results, PathOrientation subjectOrientation, double scaleBy = 1000) { List <XPolygon> polygons = new List <XPolygon>(); foreach (PolyNode child in results.Childs) { PathOrientation orientation = Clipper.Orientation(child.Contour) == true ? PathOrientation.Anticlockwise : PathOrientation.Clockwise; XPolygon polygon = FromPath(child.Contour, scaleBy); polygons.Add(polygon); foreach (PolyNode childNode in child.Childs) { //polygon.InnerPaths.Add(FromPath(childNode.Contour, scaleBy)); //List<SimplePolygon> childPolygons = FromPolyTree(childNode, subjectOrientation, scaleBy); //polygons.AddRange(childPolygons); } if (orientation != subjectOrientation) { polygon.Reverse(); } //polygon.MakeLines(); } return(polygons); }
public override IReadOnlyList <Vector2> Apply(Func <double> random, INamedDataCollection metadata, IReadOnlyList <Vector2> footprint, IReadOnlyList <Vector2> basis, IReadOnlyList <Vector2> lot) { var c = new Clipper(); const int SCALE = 1000; c.AddPath(footprint.Select(a => new IntPoint((int)(a.X * SCALE), (int)(a.Y * SCALE))).ToList(), PolyType.ptSubject, true); var clip = _lot ? lot : basis; c.AddPath(clip.Select(a => new IntPoint((int)(a.X * SCALE), (int)(a.Y * SCALE))).ToList(), PolyType.ptClip, true); var solutions = new List <List <IntPoint> >(); c.Execute(ClipType.ctIntersection, solutions); var clipperSolution = solutions.Single(); Contract.Assume(clipperSolution != null); if (Clipper.Orientation(clipperSolution)) { clipperSolution.Reverse(); } return(clipperSolution.Select(a => new Vector2(a.X / (float)SCALE, a.Y / (float)SCALE)).ToArray()); }
private static Polygon ClprPathsToPolygon(Paths polygons) { Polygon result = null; if (polygons.Count <= 0) { return(null); } result = new Polygon(polygons.Count); for (int j = 0; j < polygons.Count; ++j) { bool hole = !Clipper.Orientation(polygons[j]); List <Vec2d> contour = new List <Vec2d>(polygons[j].Count); for (int i = 0; i < polygons[j].Count; ++i) { IntPoint p = polygons[j][i]; double x = p.X / PrecisionScale; double y = p.Y / PrecisionScale; contour.Add(new Vec2d(x, y)); } result.SetContourAndHole(j, contour, hole); } return(result); }
/// <summary> /// Offsets a polygon by the given distance. Counter-clockwise polygons will expand while clockwise polygons /// will contract. /// </summary> public static List <NativeArray <RigidTransform> > OffsetPolygon( NativeArray <RigidTransform> samples, float distance, Allocator allocator) { var solution = new List <List <IntPoint> >(); var polygon = FromSamplesToClipper(samples); // Clipper uses Even-Odd polygon boolean operations to calculate offsets, so offsetting a clockwise path // will result in an expanded offset path rather than a contracted path we're looking for. The offset // direction is reversed here to ensure that the orientation of the polygon determines the offset direction. var orientation = Clipper.Orientation(polygon); if (!orientation) { distance *= -1; } var clipperOffset = new ClipperOffset(); clipperOffset.AddPath(polygon, JoinType.jtRound, EndType.etClosedPolygon); clipperOffset.Execute(ref solution, distance * UpScaleFactor); if (!orientation) { for (var i = 0; i < solution.Count; i++) { solution[i].Reverse(); } } return(ConvertToSamples(solution, allocator)); }
private void FixOrientations() { if (m_lowest.X >= 0 && !Clipper.Orientation(m_polyNodes.Childs[(int)m_lowest.X].m_polygon)) { for (int i = 0; i < m_polyNodes.ChildCount; i++) { PolyNode polyNode = m_polyNodes.Childs[i]; if (polyNode.m_endtype == EndType.etClosedPolygon || (polyNode.m_endtype == EndType.etClosedLine && Clipper.Orientation(polyNode.m_polygon))) { polyNode.m_polygon.Reverse(); } } } else { for (int j = 0; j < m_polyNodes.ChildCount; j++) { PolyNode polyNode2 = m_polyNodes.Childs[j]; if (polyNode2.m_endtype == EndType.etClosedLine && !Clipper.Orientation(polyNode2.m_polygon)) { polyNode2.m_polygon.Reverse(); } } } }
/// <summary> /// Clean up a proposed corridor shape (primarily removing holes, which are invalid in a floorplan) /// </summary> /// <param name="clipper"></param> /// <param name="outline"></param> /// <param name="corridor"></param> /// <param name="width"></param> /// <returns></returns> public static List <List <IntPoint> > CleanCorridorPolygon(Clipper clipper, List <IntPoint> outline, IEnumerable <Vector2> corridor, float width) { //Clean up after the previous run, just in case clipper.Clear(); //Clip this spanning tree to the footprint of the floorplan (to create a polytree) var result = new List <List <IntPoint> >(); clipper.AddPath(outline, PolyType.ptClip, true); clipper.AddPath(corridor.Select(ToPoint).ToList(), PolyType.ptSubject, true); clipper.Execute(ClipType.ctIntersection, result); //Clean up after self, to be polite clipper.Clear(); //Keep simplifying, and removing holes until nothing happens do { //merge together vertices which are very close result = Clipper.CleanPolygons(result, width / 8); //Remove holes from the result var holes = result.RemoveAll(r => !Clipper.Orientation(r)); //Once we have one single polygon, or removing holes did nothing we've finished! if (result.Count == 1 || holes == 0) { return(result); } } while (result.Count > 0); //This shouldn't ever happen unless we simplify away to nothing return(result); }
private static List <IntPoint> UnifyClipper(List <IntPoint> path) { if (!Clipper.Orientation(path)) { path.Reverse(); } return(path); }
public void assertCCW() { Path path = getPathFromCurve(); if (!Clipper.Orientation(path)) { parametricObject.curve.Reverse(); } }
public void CheckIfHole() { if (Clipper.Orientation(this.toPolygon())) { Hole = false; } else { Hole = true; } }
protected override void OnUpdate() { var polygons = PolygonsFromRoadOutline(Parameters.extensionDistance); var clipper = new Clipper(); foreach (var polygon in polygons) { if (!Clipper.Orientation(polygon)) { polygon.Reverse(); } if (Clipper.Area(polygon) > 0) { clipper.AddPath(polygon, PolyType.ptSubject, true); } } var solution = new List <List <IntPoint> >(); clipper.Execute(ClipType.ctUnion, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero); solution.RemoveAll(IsSmallerThanMinimumArea); if (solution.Count == 0 && polygons.Count != 0) { throw new Exception($"Unable to create a polygon from " + $"{Parameters.roadNetworkDescription.name}"); } foreach (var polygon in solution) { var pathEntity = EntityManager.CreateEntity(m_SamplesArchetype); var orientation = Clipper.Orientation(polygon) ? PolygonOrientation.Outside : PolygonOrientation.Inside; var pathSamplesBuffer = EntityManager.GetBuffer <PointSampleGlobal>(pathEntity).Reinterpret <RigidTransform>(); var placementPathSamples = PlacementUtility.IntPointsToRigidTransforms(polygon, true, Allocator.TempJob); pathSamplesBuffer.AddRange(placementPathSamples); placementPathSamples.Dispose(); EntityManager.SetComponentData(pathEntity, new PolygonOrientationComponent { Orientation = orientation }); } }
private IReadOnlyList <IReadOnlyList <Vector2> > ShapesForRoom(IEnumerable <Vector2> roomFootprint, bool split = false) { Contract.Requires(roomFootprint != null); //Winding check var clipperRoomFootprint = roomFootprint.Select(ToPoint).ToList(); if (Clipper.Orientation(clipperRoomFootprint)) { clipperRoomFootprint.Reverse(); } //Contain within floor outer edge var solution = ClipToFloor(clipperRoomFootprint, split); if (solution == null) { return(null); } //Clip against other rooms if (_rooms.Count > 0) { var clips = solution.Select(a => ClipToRooms(a, split)); solution = clips.SelectMany(a => a).ToList(); if (solution.Count > 1 && !split) { return(null); } } //Ensure shapes are still clockwise wound (mutate in place to reverse) foreach (var shape in solution.Where(Clipper.Orientation)) { shape.Reverse(); } //Convert back to vectors and apply SAFE_DISTANCE shrink (all rooms are shrunk by this distance) return(solution .Select(shape => shape .Select(ToVector2) .Shrink(SAFE_DISTANCE) .ToArray() ).ToArray()); }
public static List <XPolygon> Clip(ClipType clipType, List <XPolygon> subjects, List <XPolygon> clips, double scaleBy = 1000) { List <XPolygon> results = new List <XPolygon>(); Paths subjPaths = ToPaths(subjects, scaleBy); Paths clipPaths = ToPaths(clips, scaleBy); Clipper clipper = new Clipper(); clipper.AddPaths(clipPaths, PolyType.ptSubject, closed: true); clipper.AddPaths(subjPaths, PolyType.ptClip, closed: true); PolyTree result = new PolyTree(); clipper.Execute(clipType, result, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); PathOrientation orientation = Clipper.Orientation(subjPaths.First()) == true ? PathOrientation.Anticlockwise : PathOrientation.Clockwise; return(FromPolyTree(result, orientation, scaleBy)); }
public bool isInside(float i, float j) { Paths boundingSolids = P_Plan.getTransformedSubjPaths(); Paths boundingHoles = P_Plan.getTransformedHolePaths(); bool pointIsInside = false; IntPoint ip = new IntPoint(i * AXGeometryTools.Utilities.IntPointPrecision, j * AXGeometryTools.Utilities.IntPointPrecision); if (boundingSolids != null) { if (boundingSolids != null) { foreach (Path path in boundingSolids) { if (Clipper.PointInPolygon(ip, path) == 1 && Clipper.Orientation(path)) { pointIsInside = true; break; } } } if (boundingHoles != null) { foreach (Path hole in boundingHoles) { if (Clipper.PointInPolygon(ip, hole) == 1) { pointIsInside = false; break; } } } } //exclude = (boundingIsVoid) ? ! exclude : exclude; //if (pointIsInside) //continue; return(pointIsInside); }
public bool isInside(float i, float j, Paths boundingSolids, Paths boundingHoles) { bool pointIsInside = false; IntPoint ip = new IntPoint(i * AXGeometryTools.Utilities.IntPointPrecision, j * AXGeometryTools.Utilities.IntPointPrecision); //Debug.Log(ip.X+", "+ip.Y); if (boundingSolids != null) { if (boundingSolids != null) { foreach (Path path in boundingSolids) { //Pather.printPath(path); if (Clipper.PointInPolygon(ip, path) == 1 && Clipper.Orientation(path)) { pointIsInside = true; break; } } } if (boundingHoles != null) { foreach (Path hole in boundingHoles) { if (Clipper.PointInPolygon(ip, hole) == 1) { pointIsInside = false; break; } } } } //exclude = (boundingIsVoid) ? ! exclude : exclude; //if (pointIsInside) //continue; return(pointIsInside); }
public static NativeArray <RigidTransform> OffsetPath( NativeArray <RigidTransform> samples, float distance, bool looped, Allocator allocator) { var solution = new List <List <IntPoint> >(); var polygon = FromSamplesToClipper(samples); if (!Clipper.Orientation(polygon)) { distance *= -1; } var clipperOffset = new ClipperOffset(); clipperOffset.AddPath(polygon, JoinType.jtRound, EndType.etOpenButt); clipperOffset.Execute(ref solution, distance * UpScaleFactor); return(IntPointsToRigidTransforms(solution[0], looped, allocator)); }
public void Draw(Color color) { if (points == null) { return; } var realColor = color; for (int i = 0, count = points.Count; i < count; ++i) { Gizmos.color = color; var path = points[i]; color.a = realColor.a * (Clipper.Orientation(path) ? 1.0f : 0.5f); for (int j = 0, pathCount = path.Count; j < pathCount; ++j) { Gizmos.DrawLine(path[j].ToVector2D(), path[(j + 1) % pathCount].ToVector2D()); } } }
private static Paths PolygonToClprPaths(Polygon polygon) { Paths result = new List <List <IntPoint> >(polygon.NumContours); for (int j = 0; j < polygon.NumContours; ++j) { result.Add(new List <IntPoint>(polygon[j].Count)); for (int i = 0; i < polygon[j].Count; ++i) { Vec2d v = polygon[j][i]; IntPoint p; p.X = (Int32)(v.X * PrecisionScale); p.Y = (Int32)(v.Y * PrecisionScale); result[j].Add(p); } if (Clipper.Orientation(result[j]) == polygon.IsHole(j)) { result[j].Reverse(); } } return(result); }
/// <summary> /// cws requires the project boundary to be counter clockwise. /// returns true if reversed /// </summary> public static string MakeCounterClockwise(string polygonWkt, out bool hasBeenReversed) { hasBeenReversed = false; var resultPolygonWkt = polygonWkt; var points = ConvertAndValidatePolygon(polygonWkt); var polygon = ClipperPolygon(points); var orientation = Clipper.Orientation(polygon); // "On Y-axis positive upward displays, Orientation will return true if the polygon's orientation is counter-clockwise" if (orientation == false) { var polygons = new List <List <IntPoint> > { polygon }; Clipper.ReversePolygons(new List <List <IntPoint> >(polygons)); hasBeenReversed = true; var polygonList = FromClipperPolygon(polygons[0]); resultPolygonWkt = polygonList.ToPolygonWKT(); } return(resultPolygonWkt); }
/// <summary> /// "sichere" Flächen erzeugen (ev. aufteilen) /// </summary> /// <param name="area"></param> /// <param name="maxsize">max. "quadratisches" Umgrenzung in MapUnits</param> /// <returns></returns> static List <DetailMap.Poly> MakeSafeAreas(DetailMap.Poly area, int maxsize) { List <DetailMap.Poly> lst = new List <DetailMap.Poly>(); ClipperPath p = MapUnitPointList2ClipperPath(area.GetMapUnitPoints()); bool counterclockwise = Clipper.Orientation(p); ClipperPaths newpolys = SplitClipperPath(MapUnitPointList2ClipperPath(area.GetMapUnitPoints()), maxsize); for (int i = 0; i < newpolys.Count; i++) { if (Clipper.Orientation(newpolys[i]) != counterclockwise) { newpolys[i].Reverse(); } } if (newpolys.Count > 1) // es ist eine Teilung erfolgt { foreach (var newpoly in newpolys) { DetailMap.Poly newarea = new DetailMap.Poly(area); newarea.Clear(); foreach (var pt in newpoly) { newarea.AddPoint(new MapUnitPoint((int)pt.X, (int)pt.Y), false); } lst.Add(newarea); } } else { lst.Add(area); } return(lst); }
public void redraw() { canvas.Children.Clear(); if (rooms.Count == 0 && decoration.Count == 0) { return; } c.Clear(); Polygons outline = new Polygons(); c.AddPolygons(rooms, PolyType.ptSubject); c.AddPolygons(decoration, PolyType.ptSubject); c.Execute(ClipType.ctUnion, outline, PolyFillType.pftNonZero, PolyFillType.pftNonZero); outline = Clipper.OffsetPolygons(outline, 10, JoinType.jtMiter); // Bevel inside corners of the outline foreach (Polygon p in outline) { // Skip holes if (!Clipper.Orientation(p)) { continue; } // Find the inside corners List <bool> corners = new List <bool>(); for (int j = 0; j < p.Count; ++j) { int i = (j + p.Count - 1) % p.Count; int k = (j + 1) % p.Count; IntPoint e1 = new IntPoint(p[j].X - p[i].X, p[j].Y - p[i].Y); IntPoint e2 = new IntPoint(p[j].X - p[k].X, p[j].Y - p[k].Y); int a = (int)(e1.X * e2.Y - e2.X * e1.Y); corners.Add(a > 0); } // Bevel them to the midpoints of the original lines for (int j = 0; j < p.Count; ++j) { int i = (j + p.Count - 1) % p.Count; int k = (j + 1) % p.Count; if (corners[j]) { if (!corners[i]) { corners.Insert(j, true); p.Insert(j, new IntPoint((p[i].X + p[j].X) / 2, (p[i].Y + p[j].Y) / 2)); ++j; ++k; } p[j] = new IntPoint((p[j].X + p[k].X) / 2, (p[j].Y + p[k].Y) / 2); } } } foreach (Polygon p in rooms) { canvas.Children.Add(ToSystemPolygon(p)); } foreach (Polygon p in outline) { canvas.Children.Add(ToSystemPolygon(p, Brushes.Yellow)); } UpdateLayout(); }
// GENERATE GRID_REPEATER public override GameObject generate(bool makeGameObjects, AXParametricObject initiator_po, bool isReplica) { //Debug.Log(parametricObject.Name + " Generate"); if (parametricObject == null || !parametricObject.isActive) { return(null); } if (repeaterToolU == null || repeaterToolV == null) { return(null); } preGenerate(); // NODE_MESH AXParametricObject nodeSrc_po = null; GameObject nodePlugGO = null; if (nodeSrc_p != null) { nodeSrc_po = nodeSrc_p.parametricObject; if (makeGameObjects && !parametricObject.combineMeshes) { nodePlugGO = nodeSrc_po.generator.generate(true, initiator_po, isReplica); } } // CELL_MESH AXParametricObject cellSrc_po = null; GameObject cellPlugGO = null; if (cellSrc_p != null) { cellSrc_po = cellSrc_p.parametricObject; if (makeGameObjects && !parametricObject.combineMeshes) { cellPlugGO = cellSrc_po.generator.generate(true, initiator_po, isReplica); } } // BAY_SPAN_U AXParametricObject spanUSrc_po = null; GameObject spanUPlugGO = null; if (spanUSrc_p != null) { spanUSrc_po = spanUSrc_p.parametricObject; if (makeGameObjects && !parametricObject.combineMeshes) { spanUPlugGO = spanUSrc_po.generator.generate(true, initiator_po, isReplica); } } // BAY_SPAN_V AXParametricObject spanVSrc_po = null; GameObject spanVPlugGO = null; if (spanVSrc_p != null) { spanVSrc_po = spanVSrc_p.parametricObject; if (makeGameObjects && !parametricObject.combineMeshes) { spanVPlugGO = spanVSrc_po.generator.generate(true, initiator_po, isReplica); } } if (nodeSrc_po == null && cellSrc_po == null && spanUSrc_po == null && spanVSrc_po == null) { AXParameter output_p = getPreferredOutputParameter(); if (output_p != null) { output_p.meshes = null; } return(null); } GameObject go = null; if (makeGameObjects && !parametricObject.combineMeshes) { go = ArchimatixUtils.createAXGameObject(parametricObject.Name, parametricObject); } // BOUNDING_SHAPE Paths boundingSolids = null; Paths boundingHoles = null; if (P_BoundingShape != null && P_BoundingShape.DependsOn != null) { AXParameter bounding_src_p = null; if (P_BoundingShape != null) { bounding_src_p = P_BoundingShape.DependsOn; // USING SINGLE SPLINE INPUT } boundingShapeSrc_po = bounding_src_p.parametricObject; AXShape.thickenAndOffset(ref P_BoundingShape, bounding_src_p); // now boundin_p has offset and thickened polytree or paths. boundingSolids = P_BoundingShape.getTransformedSubjPaths(); boundingHoles = P_BoundingShape.getTransformedHolePaths(); } List <AXMesh> ax_meshes = new List <AXMesh>(); Matrix4x4 localPlacement_mx = Matrix4x4.identity; // ----------------------------------- int max_reps = 150; int cellsU = Mathf.Clamp(repeaterToolU.cells, 1, max_reps); float actualBayU = repeaterToolU.actualBay; int cellsV = Mathf.Clamp(repeaterToolV.cells, 1, max_reps); float actualBayV = repeaterToolV.actualBay; shiftU = -cellsU * actualBayU / 2; shiftV = -cellsV * actualBayV / 2; // BAY SPAN // Spanners are meshers that get replicated and sized to fit the bay... // prepare mesh to iterate in each direction //List<AXMesh> ax_meshes_X = new List<AXMesh>(); //List<AXMesh> ax_meshes_Z = new List<AXMesh>(); AXMesh tmpMesh; if (spanUSrc_p != null) { //ax_meshes_X = spanUSrc_p.meshes; //ax_meshes_Z = spanUSrc_p.meshes; } /* NEED TO INTEGRATE THIS BACK IN IN THE FUTRE... * if (bay_span_source != null) * { * * // 1. cache source object * bay_span_source.cacheParameterValues(); * * * // Y_AXIS * * AXParameter p_bayv = parametricObject.getParameter("actual_bay_V"); * AXParameter p_bayv_client = null; * if (p_bayv != null) * { * foreach (AXRelation rel in p_bayv.relations) * { * p_bayv_client = rel.getRelatedTo(p_bayv); * p_bayv_client.intiateRipple_setFloatValueFromGUIChange(abayy); * } * } * * * AXParameter p_bayu = parametricObject.getParameter("actual_bay_U"); * AXParameter p_bayu_client = null; * * // X-AXIS * // For now, only set the boundaries. * // Perhaps later, may want to set other like controls as in Replicant * * // If there is a relation to actual_bay_U, propogate it * if (p_bayu != null) * { * foreach (AXRelation rel in p_bayu.relations) * { * p_bayu_client = rel.getRelatedTo(p_bayu); * p_bayu_client.intiateRipple_setFloatValueFromGUIChange(abayx); * } * } * * //bay_span_source.propagateParameterByBinding(1, bayx); * //bay_span_source.propagateParameterByBinding(2, bayy); * * // 2. re_generate with temporary values set by this Replicant * bay_span_source.generateOutputNow (makeGameObjects, parametricObject); * * // 3. Now that the bay_span_source has been regergrab the meshes from the input sources and add them here * AXParameter output_p = bay_span_source.getParameter("Output Mesh"); * foreach (AXMesh amesh in output_p.meshes) * ax_meshes_X.Add (amesh.Clone(amesh.transMatrix)); * * * * // Z-AXIS * // Use the bayz now to generate x * * if (p_bayu != null) * { * foreach (AXRelation rel in p_bayu.relations) * { * p_bayu_client = rel.getRelatedTo(p_bayu); * p_bayu_client.intiateRipple_setFloatValueFromGUIChange(abayz); * } * } * * //bay_span_source.propagateParameterByBinding(1, bayz); * * * // 2. re_generate with temporary values set by this Replicant * bay_span_source.generateOutputNow (makeGameObjects, parametricObject); * * // 3. Now that the bay_span_source has been regergrab the meshes from the input sources and add them here * foreach (AXMesh amesh in output_p.meshes) * ax_meshes_Z.Add (amesh.Clone(amesh.transMatrix)); * * * // 4. restore source object; as though we were never here! * bay_span_source.revertParametersFromCache(); * * //Debug.Log ("HAVE BAY SPAN -- " + output_p.meshes.Count); * * * } */ /* NEED TO INTEGRATE THIS BACK IN IN THE FUTRE... * if (cell_center_source != null) * { * // Y-AXIS * // For now, only set the boundaries. * // Perhaps later, may want to set other like controls as in Replicant * // 1. cache source object * cell_center_source.cacheParameterValues(); * * * * //bay_center_source.propagateParameterByBinding(1, bayx); * //bay_center_source.propagateParameterByBinding(3, bayz); * * // 2. re_generate with temporary values set by this Replicant * cell_center_source.generateOutputNow (makeGameObjects, parametricObject); * * // 3. Now that the bay_span_source has been regenerted, grab the meshes from the input sources and add them here * AXParameter bc_output_p = cell_center_source.getParameter("Output Mesh"); * foreach (AXMesh amesh in bc_output_p.meshes) * ax_meshes_Y.Add (amesh.Clone(amesh.transMatrix)); * * // 4. restore source object; as though we were never here! * cell_center_source.revertParametersFromCache(); * * } */ // BOUNDING List <AXMesh> boundingMeshes = new List <AXMesh>(); for (int i = 0; i <= cellsU; i++) { for (int k = 0; k <= cellsV; k++) { bool exclude = false; IntPoint ip = new IntPoint((i * actualBayU + shiftU) * AXGeometryTools.Utilities.IntPointPrecision, (k * actualBayV + shiftV) * AXGeometryTools.Utilities.IntPointPrecision); if (boundingSolids != null) { exclude = true; if (boundingSolids != null) { foreach (Path path in boundingSolids) { if (Clipper.PointInPolygon(ip, path) == 1 && Clipper.Orientation(path)) { exclude = false; break; } } } if (boundingHoles != null) { foreach (Path hole in boundingHoles) { if (Clipper.PointInPolygon(ip, hole) == 1) { exclude = true; break; } } } } exclude = (boundingIsVoid) ? !exclude : exclude; if (exclude) { continue; } // NODES if (nodeSrc_po != null && nodeSrc_p.meshes != null && ((i <= repeaterToolU.edgeCount || i >= cellsU - repeaterToolU.edgeCount) || (k <= repeaterToolV.edgeCount || k >= cellsV - repeaterToolV.edgeCount))) { string this_address = "node_" + i + "_" + k; // LOCAL PLACEMENT NODE localPlacement_mx = localNodeMatrixFromAddress(i, k); // AX_MESHES for (int mi = 0; mi < nodeSrc_p.meshes.Count; mi++) { AXMesh dep_amesh = nodeSrc_p.meshes [mi]; tmpMesh = dep_amesh.Clone(localPlacement_mx * dep_amesh.transMatrix); tmpMesh.subItemAddress = this_address; ax_meshes.Add(tmpMesh); } // BOUNDING boundingMeshes.Add(new AXMesh(nodeSrc_po.boundsMesh, localPlacement_mx * nodeSrc_po.generator.localMatrix)); // GAME_OBJECTS if (nodePlugGO != null && makeGameObjects && !parametricObject.combineMeshes) { Matrix4x4 mx = localPlacement_mx * nodeSrc_po.generator.localMatrixWithAxisRotationAndAlignment; GameObject copyGO = (GameObject)GameObject.Instantiate(nodePlugGO, AXUtilities.GetPosition(mx), AXUtilities.QuaternionFromMatrix(mx)); copyGO.transform.localScale = new Vector3(copyGO.transform.localScale.x * jitterScale.x, copyGO.transform.localScale.y * jitterScale.y, copyGO.transform.localScale.z * jitterScale.z); #if UNITY_EDITOR //if (parametricObject.model.isSelected(nodeSrc_po) && nodeSrc_po.selectedConsumerAddress == this_address) // Selection.activeGameObject = copyGO; #endif AXGameObject axgo = copyGO.GetComponent <AXGameObject>(); if (axgo != null) { axgo.consumerAddress = this_address; } copyGO.name = copyGO.name + "_" + this_address; copyGO.transform.parent = go.transform; } } // \NODES // CELL CENTERS if (cellSrc_po != null && cellSrc_p.meshes != null && i < cellsU && k < cellsV && ((i < repeaterToolU.edgeCount || i > cellsU - repeaterToolU.edgeCount - 1) || (k < repeaterToolV.edgeCount || k > cellsV - repeaterToolV.edgeCount - 1))) { string this_address = "cell_" + i + "_" + k; // LOCAL PLACEMENT localPlacement_mx = localCellMatrixFromAddress(i, k); // AX_MESHES for (int mi = 0; mi < cellSrc_p.meshes.Count; mi++) { AXMesh dep_amesh = cellSrc_p.meshes [mi]; tmpMesh = dep_amesh.Clone(localPlacement_mx * dep_amesh.transMatrix); tmpMesh.subItemAddress = this_address; ax_meshes.Add(tmpMesh); } // BOUNDING boundingMeshes.Add(new AXMesh(cellSrc_po.boundsMesh, localPlacement_mx * cellSrc_po.generator.localMatrix)); // GAME_OBJECTS if (cellPlugGO != null && makeGameObjects && !parametricObject.combineMeshes) { Matrix4x4 mx = localPlacement_mx * cellSrc_po.generator.localMatrixWithAxisRotationAndAlignment; GameObject copyGO = (GameObject)GameObject.Instantiate(cellPlugGO, AXUtilities.GetPosition(mx), AXUtilities.QuaternionFromMatrix(mx)); copyGO.transform.localScale = new Vector3(copyGO.transform.localScale.x * jitterScale.x, copyGO.transform.localScale.y * jitterScale.y, copyGO.transform.localScale.z * jitterScale.z); #if UNITY_EDITOR //if (parametricObject.model.isSelected(cellSrc_po) && cellSrc_po.selectedConsumerAddress == this_address) //Selection.activeGameObject = copyGO; #endif AXGameObject axgo = copyGO.GetComponent <AXGameObject>(); if (axgo != null) { axgo.consumerAddress = this_address; } copyGO.name = copyGO.name + "_" + this_address; copyGO.transform.parent = go.transform; } } // SPAN_U if (spanUSrc_po != null && spanUSrc_p.meshes != null && i < cellsU && k <= cellsV && ((i < repeaterToolV.edgeCount || i > cellsU - repeaterToolU.edgeCount - 1) || (k <= repeaterToolV.edgeCount || k > cellsV - repeaterToolV.edgeCount - 1))) { string this_address = "spanU_" + i + "_" + k; // LOCAL PLACEMENT SPAN_U localPlacement_mx = localSpanUMatrixFromAddress(i, k); // AX_MESHES for (int mi = 0; mi < spanUSrc_p.meshes.Count; mi++) { AXMesh dep_amesh = spanUSrc_p.meshes [mi]; tmpMesh = dep_amesh.Clone(localPlacement_mx * dep_amesh.transMatrix); tmpMesh.subItemAddress = this_address; ax_meshes.Add(tmpMesh); } // BOUNDING boundingMeshes.Add(new AXMesh(spanUSrc_po.boundsMesh, localPlacement_mx * spanUSrc_po.generator.localMatrix)); // GAME_OBJECTS if (spanUSrc_po != null && makeGameObjects && !parametricObject.combineMeshes) { Matrix4x4 mx = localPlacement_mx * spanUSrc_po.generator.localMatrixWithAxisRotationAndAlignment; GameObject copyGO = (GameObject)GameObject.Instantiate(spanUPlugGO, AXUtilities.GetPosition(mx), AXUtilities.QuaternionFromMatrix(mx)); copyGO.transform.localScale = new Vector3(copyGO.transform.localScale.x * jitterScale.x, copyGO.transform.localScale.y * jitterScale.y, copyGO.transform.localScale.z * jitterScale.z); #if UNITY_EDITOR //if (parametricObject.model.isSelected(spanUSrc_po) && spanUSrc_po.selectedConsumerAddress == this_address) // Selection.activeGameObject = copyGO; #endif AXGameObject axgo = copyGO.GetComponent <AXGameObject>(); if (axgo != null) { axgo.consumerAddress = this_address; } copyGO.name = copyGO.name + "_" + this_address; copyGO.transform.parent = go.transform; } } // SPAN_V if (spanVSrc_po != null && spanVSrc_p.meshes != null && i <= cellsU && k < cellsV && ((i <= repeaterToolU.edgeCount || i > cellsU - repeaterToolU.edgeCount - 1) || (k < repeaterToolV.edgeCount || k > cellsV - repeaterToolV.edgeCount - 1))) { string this_address = "spanV_" + i + "_" + k; // LOCAL PLACEMENT SPAN_U localPlacement_mx = localSpanVMatrixFromAddress(i, k); // AX_MESHES for (int mi = 0; mi < spanVSrc_p.meshes.Count; mi++) { AXMesh dep_amesh = spanVSrc_p.meshes [mi]; tmpMesh = dep_amesh.Clone(localPlacement_mx * dep_amesh.transMatrix); tmpMesh.subItemAddress = this_address; ax_meshes.Add(tmpMesh); } // BOUNDING boundingMeshes.Add(new AXMesh(spanVSrc_po.boundsMesh, localPlacement_mx * spanVSrc_po.generator.localMatrix)); // GAME_OBJECTS if (spanVSrc_po != null && makeGameObjects && !parametricObject.combineMeshes) { Matrix4x4 mx = localPlacement_mx * spanVSrc_po.generator.localMatrixWithAxisRotationAndAlignment; GameObject copyGO = (GameObject)GameObject.Instantiate(spanVPlugGO, AXUtilities.GetPosition(mx), AXUtilities.QuaternionFromMatrix(mx)); copyGO.transform.localScale = new Vector3(copyGO.transform.localScale.x * jitterScale.x, copyGO.transform.localScale.y * jitterScale.y, copyGO.transform.localScale.z * jitterScale.z); #if UNITY_EDITOR //if (parametricObject.model.isSelected(spanVSrc_po) && spanVSrc_po.selectedConsumerAddress == this_address) // Selection.activeGameObject = copyGO; #endif AXGameObject axgo = copyGO.GetComponent <AXGameObject>(); if (axgo != null) { axgo.consumerAddress = this_address; } copyGO.name = copyGO.name + "_" + this_address; copyGO.transform.parent = go.transform; } } } // k } //i GameObject.DestroyImmediate(nodePlugGO); GameObject.DestroyImmediate(cellPlugGO); GameObject.DestroyImmediate(spanUPlugGO); GameObject.DestroyImmediate(spanVPlugGO); // FINISH AX_MESHES parametricObject.finishMultiAXMeshAndOutput(ax_meshes, isReplica); // FINISH BOUNDS CombineInstance[] boundsCombinator = new CombineInstance[boundingMeshes.Count]; for (int bb = 0; bb < boundsCombinator.Length; bb++) { boundsCombinator[bb].mesh = boundingMeshes[bb].mesh; boundsCombinator[bb].transform = boundingMeshes[bb].transMatrix; } setBoundsWithCombinator(boundsCombinator); // FINISH GAME_OBJECTS if (makeGameObjects) { if (parametricObject.combineMeshes) { go = parametricObject.makeGameObjectsFromAXMeshes(ax_meshes, true); } Matrix4x4 tmx = parametricObject.generator.localMatrixWithAxisRotationAndAlignment; go.transform.rotation = AXUtilities.QuaternionFromMatrix(tmx); go.transform.position = AXUtilities.GetPosition(tmx); go.transform.localScale = parametricObject.getLocalScaleAxisRotated(); return(go); } return(null); }
public static bool Orientation(this Polygon polygon) { return(Clipper.Orientation(polygon)); }
// Token: 0x060005E2 RID: 1506 RVA: 0x000360CC File Offset: 0x000344CC private void CutPoly(Int3[] verts, int[] tris, ref Int3[] outVertsArr, ref int[] outTrisArr, out int outVCount, out int outTCount, Int3[] extraShape, Int3 cuttingOffset, Bounds realBounds, TileHandler.CutMode mode = (TileHandler.CutMode) 3, int perturbate = 0) { if (verts.Length == 0 || tris.Length == 0) { outVCount = 0; outTCount = 0; outTrisArr = new int[0]; outVertsArr = new Int3[0]; return; } List <IntPoint> list = null; if (extraShape == null && (mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 0) { throw new Exception("extraShape is null and the CutMode specifies that it should be used. Cannot use null shape."); } if ((mode & TileHandler.CutMode.CutExtra) != (TileHandler.CutMode) 0) { list = new List <IntPoint>(extraShape.Length); for (int i = 0; i < extraShape.Length; i++) { list.Add(new IntPoint((long)(extraShape[i].x + cuttingOffset.x), (long)(extraShape[i].z + cuttingOffset.z))); } } List <IntPoint> list2 = new List <IntPoint>(5); Dictionary <TriangulationPoint, int> dictionary = new Dictionary <TriangulationPoint, int>(); List <PolygonPoint> list3 = new List <PolygonPoint>(); IntRect b = new IntRect(verts[0].x, verts[0].z, verts[0].x, verts[0].z); for (int j = 0; j < verts.Length; j++) { b = b.ExpandToContain(verts[j].x, verts[j].z); } List <Int3> list4 = ListPool <Int3> .Claim(verts.Length * 2); List <int> list5 = ListPool <int> .Claim(tris.Length); PolyTree polyTree = new PolyTree(); List <List <IntPoint> > list6 = new List <List <IntPoint> >(); Stack <Polygon> stack = new Stack <Polygon>(); if (this.clipper == null) { this.clipper = new Clipper(0); } this.clipper.ReverseSolution = true; List <NavmeshCut> list7; if (mode == TileHandler.CutMode.CutExtra) { list7 = ListPool <NavmeshCut> .Claim(); } else { list7 = NavmeshCut.GetAllInRange(realBounds); } List <int> list8 = ListPool <int> .Claim(); List <IntRect> list9 = ListPool <IntRect> .Claim(); List <Int2> list10 = ListPool <Int2> .Claim(); List <List <IntPoint> > list11 = new List <List <IntPoint> >(); List <bool> list12 = ListPool <bool> .Claim(); List <bool> list13 = ListPool <bool> .Claim(); if (perturbate > 10) { Debug.LogError("Too many perturbations aborting : " + mode); Debug.Break(); outVCount = verts.Length; outTCount = tris.Length; outTrisArr = tris; outVertsArr = verts; return; } System.Random random = null; if (perturbate > 0) { random = new System.Random(); } for (int k = 0; k < list7.Count; k++) { Bounds bounds = list7[k].GetBounds(); Int3 @int = (Int3)bounds.min + cuttingOffset; Int3 int2 = (Int3)bounds.max + cuttingOffset; IntRect a = new IntRect(@int.x, @int.z, int2.x, int2.z); if (IntRect.Intersects(a, b)) { Int2 int3 = new Int2(0, 0); if (perturbate > 0) { int3.x = random.Next() % 6 * perturbate - 3 * perturbate; if (int3.x >= 0) { int3.x++; } int3.y = random.Next() % 6 * perturbate - 3 * perturbate; if (int3.y >= 0) { int3.y++; } } int count = list11.Count; list7[k].GetContour(list11); for (int l = count; l < list11.Count; l++) { List <IntPoint> list14 = list11[l]; if (list14.Count == 0) { Debug.LogError("Zero Length Contour"); list9.Add(default(IntRect)); list10.Add(new Int2(0, 0)); } else { IntRect item = new IntRect((int)list14[0].X + cuttingOffset.x, (int)list14[0].Y + cuttingOffset.y, (int)list14[0].X + cuttingOffset.x, (int)list14[0].Y + cuttingOffset.y); for (int m = 0; m < list14.Count; m++) { IntPoint value = list14[m]; value.X += (long)cuttingOffset.x; value.Y += (long)cuttingOffset.z; if (perturbate > 0) { value.X += (long)int3.x; value.Y += (long)int3.y; } list14[m] = value; item = item.ExpandToContain((int)value.X, (int)value.Y); } list10.Add(new Int2(@int.y, int2.y)); list9.Add(item); list12.Add(list7[k].isDual); list13.Add(list7[k].cutsAddedGeom); } } } } List <NavmeshAdd> allInRange = NavmeshAdd.GetAllInRange(realBounds); Int3[] array = verts; int[] array2 = tris; int num = -1; int n = -3; Int3[] array3 = null; Int3[] array4 = null; Int3 int4 = Int3.zero; if (allInRange.Count > 0) { array3 = new Int3[7]; array4 = new Int3[7]; int4 = (Int3)realBounds.extents; } for (;;) { n += 3; while (n >= array2.Length) { num++; n = 0; if (num >= allInRange.Count) { array = null; break; } if (array == verts) { array = null; } allInRange[num].GetMesh(cuttingOffset, ref array, out array2); } if (array == null) { break; } Int3 int5 = array[array2[n]]; Int3 int6 = array[array2[n + 1]]; Int3 int7 = array[array2[n + 2]]; IntRect a2 = new IntRect(int5.x, int5.z, int5.x, int5.z); a2 = a2.ExpandToContain(int6.x, int6.z); a2 = a2.ExpandToContain(int7.x, int7.z); int num2 = Math.Min(int5.y, Math.Min(int6.y, int7.y)); int num3 = Math.Max(int5.y, Math.Max(int6.y, int7.y)); list8.Clear(); bool flag = false; for (int num4 = 0; num4 < list11.Count; num4++) { int x = list10[num4].x; int y = list10[num4].y; if (IntRect.Intersects(a2, list9[num4]) && y >= num2 && x <= num3 && (list13[num4] || num == -1)) { Int3 int8 = int5; int8.y = x; Int3 int9 = int5; int9.y = y; list8.Add(num4); flag |= list12[num4]; } } if (list8.Count == 0 && (mode & TileHandler.CutMode.CutExtra) == (TileHandler.CutMode) 0 && (mode & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0 && num == -1) { list5.Add(list4.Count); list5.Add(list4.Count + 1); list5.Add(list4.Count + 2); list4.Add(int5); list4.Add(int6); list4.Add(int7); } else { list2.Clear(); if (num == -1) { list2.Add(new IntPoint((long)int5.x, (long)int5.z)); list2.Add(new IntPoint((long)int6.x, (long)int6.z)); list2.Add(new IntPoint((long)int7.x, (long)int7.z)); } else { array3[0] = int5; array3[1] = int6; array3[2] = int7; int num5 = Utility.ClipPolygon(array3, 3, array4, 1, 0, 0); if (num5 == 0) { continue; } num5 = Utility.ClipPolygon(array4, num5, array3, -1, 2 * int4.x, 0); if (num5 == 0) { continue; } num5 = Utility.ClipPolygon(array3, num5, array4, 1, 0, 2); if (num5 == 0) { continue; } num5 = Utility.ClipPolygon(array4, num5, array3, -1, 2 * int4.z, 2); if (num5 == 0) { continue; } for (int num6 = 0; num6 < num5; num6++) { list2.Add(new IntPoint((long)array3[num6].x, (long)array3[num6].z)); } } dictionary.Clear(); Int3 int10 = int6 - int5; Int3 int11 = int7 - int5; Int3 int12 = int10; Int3 int13 = int11; int12.y = 0; int13.y = 0; for (int num7 = 0; num7 < 16; num7++) { if ((mode >> (num7 & 31) & TileHandler.CutMode.CutAll) != (TileHandler.CutMode) 0) { if (1 << num7 == 1) { this.clipper.Clear(); this.clipper.AddPolygon(list2, PolyType.ptSubject); for (int num8 = 0; num8 < list8.Count; num8++) { this.clipper.AddPolygon(list11[list8[num8]], PolyType.ptClip); } polyTree.Clear(); this.clipper.Execute(ClipType.ctDifference, polyTree, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero); } else if (1 << num7 == 2) { if (!flag) { goto IL_1161; } this.clipper.Clear(); this.clipper.AddPolygon(list2, PolyType.ptSubject); for (int num9 = 0; num9 < list8.Count; num9++) { if (list12[list8[num9]]) { this.clipper.AddPolygon(list11[list8[num9]], PolyType.ptClip); } } list6.Clear(); this.clipper.Execute(ClipType.ctIntersection, list6, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero); this.clipper.Clear(); for (int num10 = 0; num10 < list6.Count; num10++) { this.clipper.AddPolygon(list6[num10], (!Clipper.Orientation(list6[num10])) ? PolyType.ptSubject : PolyType.ptClip); } for (int num11 = 0; num11 < list8.Count; num11++) { if (!list12[list8[num11]]) { this.clipper.AddPolygon(list11[list8[num11]], PolyType.ptClip); } } polyTree.Clear(); this.clipper.Execute(ClipType.ctDifference, polyTree, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero); } else if (1 << num7 == 4) { this.clipper.Clear(); this.clipper.AddPolygon(list2, PolyType.ptSubject); this.clipper.AddPolygon(list, PolyType.ptClip); polyTree.Clear(); this.clipper.Execute(ClipType.ctIntersection, polyTree, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero); } for (int num12 = 0; num12 < polyTree.ChildCount; num12++) { PolyNode polyNode = polyTree.Childs[num12]; List <IntPoint> contour = polyNode.Contour; List <PolyNode> childs = polyNode.Childs; if (childs.Count == 0 && contour.Count == 3 && num == -1) { for (int num13 = 0; num13 < contour.Count; num13++) { Int3 item2 = new Int3((int)contour[num13].X, 0, (int)contour[num13].Y); double num14 = (double)(int6.z - int7.z) * (double)(int5.x - int7.x) + (double)(int7.x - int6.x) * (double)(int5.z - int7.z); if (num14 == 0.0) { Debug.LogWarning("Degenerate triangle"); } else { double num15 = ((double)(int6.z - int7.z) * (double)(item2.x - int7.x) + (double)(int7.x - int6.x) * (double)(item2.z - int7.z)) / num14; double num16 = ((double)(int7.z - int5.z) * (double)(item2.x - int7.x) + (double)(int5.x - int7.x) * (double)(item2.z - int7.z)) / num14; item2.y = (int)Math.Round(num15 * (double)int5.y + num16 * (double)int6.y + (1.0 - num15 - num16) * (double)int7.y); list5.Add(list4.Count); list4.Add(item2); } } } else { Polygon polygon = null; int num17 = -1; for (List <IntPoint> list15 = contour; list15 != null; list15 = ((num17 >= childs.Count) ? null : childs[num17].Contour)) { list3.Clear(); for (int num18 = 0; num18 < list15.Count; num18++) { PolygonPoint polygonPoint = new PolygonPoint((double)list15[num18].X, (double)list15[num18].Y); list3.Add(polygonPoint); Int3 item3 = new Int3((int)list15[num18].X, 0, (int)list15[num18].Y); double num19 = (double)(int6.z - int7.z) * (double)(int5.x - int7.x) + (double)(int7.x - int6.x) * (double)(int5.z - int7.z); if (num19 == 0.0) { Debug.LogWarning("Degenerate triangle"); } else { double num20 = ((double)(int6.z - int7.z) * (double)(item3.x - int7.x) + (double)(int7.x - int6.x) * (double)(item3.z - int7.z)) / num19; double num21 = ((double)(int7.z - int5.z) * (double)(item3.x - int7.x) + (double)(int5.x - int7.x) * (double)(item3.z - int7.z)) / num19; item3.y = (int)Math.Round(num20 * (double)int5.y + num21 * (double)int6.y + (1.0 - num20 - num21) * (double)int7.y); dictionary[polygonPoint] = list4.Count; list4.Add(item3); } } Polygon polygon2; if (stack.Count > 0) { polygon2 = stack.Pop(); polygon2.AddPoints(list3); } else { polygon2 = new Polygon(list3); } if (polygon == null) { polygon = polygon2; } else { polygon.AddHole(polygon2); } num17++; } try { P2T.Triangulate(polygon); } catch (PointOnEdgeException) { Debug.LogWarning(string.Concat(new object[] { "PointOnEdgeException, perturbating vertices slightly ( at ", num7, " in ", mode, ")" })); this.CutPoly(verts, tris, ref outVertsArr, ref outTrisArr, out outVCount, out outTCount, extraShape, cuttingOffset, realBounds, mode, perturbate + 1); return; } for (int num22 = 0; num22 < polygon.Triangles.Count; num22++) { DelaunayTriangle delaunayTriangle = polygon.Triangles[num22]; list5.Add(dictionary[delaunayTriangle.Points._0]); list5.Add(dictionary[delaunayTriangle.Points._1]); list5.Add(dictionary[delaunayTriangle.Points._2]); } if (polygon.Holes != null) { for (int num23 = 0; num23 < polygon.Holes.Count; num23++) { polygon.Holes[num23].Points.Clear(); polygon.Holes[num23].ClearTriangles(); if (polygon.Holes[num23].Holes != null) { polygon.Holes[num23].Holes.Clear(); } stack.Push(polygon.Holes[num23]); } } polygon.ClearTriangles(); if (polygon.Holes != null) { polygon.Holes.Clear(); } polygon.Points.Clear(); stack.Push(polygon); } } } IL_1161 :; } } } Dictionary <Int3, int> dictionary2 = this.cached_Int3_int_dict; dictionary2.Clear(); if (this.cached_int_array.Length < list4.Count) { this.cached_int_array = new int[Math.Max(this.cached_int_array.Length * 2, list4.Count)]; } int[] array5 = this.cached_int_array; int num24 = 0; for (int num25 = 0; num25 < list4.Count; num25++) { int num26; if (!dictionary2.TryGetValue(list4[num25], out num26)) { dictionary2.Add(list4[num25], num24); array5[num25] = num24; list4[num24] = list4[num25]; num24++; } else { array5[num25] = num26; } } outTCount = list5.Count; if (outTrisArr == null || outTrisArr.Length < outTCount) { outTrisArr = new int[outTCount]; } for (int num27 = 0; num27 < outTCount; num27++) { outTrisArr[num27] = array5[list5[num27]]; } outVCount = num24; if (outVertsArr == null || outVertsArr.Length < outVCount) { outVertsArr = new Int3[outVCount]; } for (int num28 = 0; num28 < outVCount; num28++) { outVertsArr[num28] = list4[num28]; } for (int num29 = 0; num29 < list7.Count; num29++) { list7[num29].UsedForCut(); } ListPool <Int3> .Release(list4); ListPool <int> .Release(list5); ListPool <int> .Release(list8); ListPool <Int2> .Release(list10); ListPool <bool> .Release(list12); ListPool <bool> .Release(list13); ListPool <IntRect> .Release(list9); ListPool <NavmeshCut> .Release(list7); }
/// <summary> /// This approach extends the idea in Job.WithCode() by manually generating batches of work with one job per batch for better load balancing. /// Setup is tedious, but is slightly faster (~1-2ms) than Entities.ForEach with a separate buffer. We should probably avoid this pattern due to the large overhead and brittle code. /// /// Test results: /// Total: 36ms /// Setup: 1.12ms /// Combine: 2.12ms /// </summary> private List <List <IntPoint> > PolygonsFromRoadOutlineIJobParallelFor(float extensionDistance, JobHandle jobHandle) { Profiler.BeginSample("PolygonsFromRoadOutlineIJobParallelFor"); Profiler.BeginSample("PolygonsFromRoadOutlineIJobParallelFor_Setup"); var polygons = new List <List <IntPoint> >(); var outlineJobParams = new NativeList <OutlineJobParams>(300, Allocator.TempJob); var sampleCountTotal = 0; Entities.ForEach((int entityInQueryIndex, Entity entity, ref EcsRoad road) => { var sampleCount = GeometrySampling.ComputeSampleCountForRoadOutline(road, .5f); outlineJobParams.Add(new OutlineJobParams { entity = entity, startIndex = sampleCountTotal, count = sampleCount }); sampleCountTotal += sampleCount; }).Run(); var samples = new NativeArray <PointSampleGlobal>(sampleCountTotal, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var ecsRoadGetter = GetComponentDataFromEntity <EcsRoad>(true); var geometryGetter = GetBufferFromEntity <Geometry>(true); var laneSectionGetter = GetBufferFromEntity <EcsLaneSection>(true); var laneGetter = GetBufferFromEntity <EcsLane>(true); var laneOffsetGetter = GetBufferFromEntity <LaneOffset>(true); var laneWidthRecordGetter = GetBufferFromEntity <LaneWidthRecord>(true); var batchSize = samples.Length / 64; var jobBatches = new NativeList <JobHandle>(Allocator.TempJob); int currentBatchSize = 0; int currentBatchStartIndex = 0; for (int i = 0; i < outlineJobParams.Length; i++) { var currentJobParams = outlineJobParams[i]; currentBatchSize += currentJobParams.count; if (currentBatchSize >= batchSize || i == outlineJobParams.Length - 1) { var job = new BuildSamplesJob() { extensionDistance = extensionDistance, outlineJobBatch = new OutlineJobBatch { startIndex = currentBatchStartIndex, count = i - currentBatchStartIndex + 1 }, outlineJobParams = outlineJobParams, ecsRoadGetter = ecsRoadGetter, geometryGetter = geometryGetter, laneSectionGetter = laneSectionGetter, laneGetter = laneGetter, laneOffsetGetter = laneOffsetGetter, laneWidthRecordGetter = laneWidthRecordGetter, samples = samples }.Schedule(jobHandle); jobBatches.Add(job); currentBatchSize = 0; currentBatchStartIndex = i + 1; } } Profiler.EndSample(); Profiler.BeginSample("PolygonsFromRoadOutlineIJobParallelFor_CompleteJob"); JobHandle.CombineDependencies(jobBatches).Complete(); Profiler.EndSample(); Profiler.BeginSample("PolygonsFromRoadOutlineIJobParallelFor_Combine"); foreach (var outlineJobParam in outlineJobParams) { var sampleSlice = new NativeSlice <PointSampleGlobal>(samples, outlineJobParam.startIndex, outlineJobParam.count); var path = new List <IntPoint>(sampleSlice.Length); foreach (var point in sampleSlice) { path.Add(new IntPoint( point.pose.pos.x * PlacementUtility.UpScaleFactor, point.pose.pos.z * PlacementUtility.UpScaleFactor)); } if (!Clipper.Orientation(path)) { path.Reverse(); } polygons.Add(path); } outlineJobParams.Dispose(); jobBatches.Dispose(); samples.Dispose(); Profiler.EndSample(); Profiler.EndSample(); return(polygons); }
protected override JobHandle OnUpdate(JobHandle inputDeps) { List <List <IntPoint> > polygons; switch (Parameters.processingScheme) { case ProcessingScheme.JobWithCode: polygons = PolygonsFromRoadOutlineJobWithCode(Parameters.extensionDistance, inputDeps); break; case ProcessingScheme.IJobParallelFor: polygons = PolygonsFromRoadOutlineIJobParallelFor(Parameters.extensionDistance, inputDeps); break; case ProcessingScheme.EntityForEachTempDynamicArrays: polygons = PolygonsFromRoadOutlineEntityForEach(Parameters.extensionDistance, inputDeps); break; case ProcessingScheme.EntityForEachSeparateBuffer: polygons = PolygonsFromRoadOutlineEntityForEachSeparateBuffer(Parameters.extensionDistance, inputDeps); break; default: throw new NotSupportedException(); } Profiler.BeginSample("Clipper"); var clipper = new Clipper(); foreach (var polygon in polygons) { if (!Clipper.Orientation(polygon)) { polygon.Reverse(); } if (Clipper.Area(polygon) > 0) { clipper.AddPath(polygon, PolyType.ptSubject, true); } } var solution = new List <List <IntPoint> >(); clipper.Execute(ClipType.ctUnion, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero); solution.RemoveAll(IsSmallerThanMinimumArea); Profiler.EndSample(); Profiler.BeginSample("Create sample entities"); foreach (var polygon in solution) { var entity = EntityManager.CreateEntity(m_SamplesArchetype); EntityManager.SetComponentData(entity, new PolygonOrientationComponent { Orientation = Clipper.Orientation(polygon) ? PolygonOrientation.Outside : PolygonOrientation.Inside }); var buffer = EntityManager.GetBuffer <PointSampleGlobal>(entity); var count = polygon.Count; for (var i = 0; i < polygon.Count; i++) { var previousPoint = polygon[((i - 1) % count + count) % count]; var point = polygon[i]; var nextPoint = polygon[(i + 1) % polygon.Count]; var v1 = new float3(point.X - previousPoint.X, 0, point.Y - previousPoint.Y); var v2 = new float3(nextPoint.X - point.X, 0, nextPoint.Y - point.Y); var rotation = quaternion.LookRotation(v2 + v1, new float3(0, 1, 0)); var fromClipperToGlobal = new PointSampleGlobal(new RigidTransform { pos = new float3( point.X * PlacementUtility.DownScaleFactor, 0, point.Y * PlacementUtility.DownScaleFactor), rot = rotation }); buffer.Add(fromClipperToGlobal); } } Profiler.EndSample(); return(inputDeps); }
/// <summary> /// Gets the Isovist polygon. /// </summary> /// <param name="vantagePoint">The vantage point.</param> /// <param name="viewDepth">The view depth.</param> /// <param name="edges">The edges.</param> /// <returns>BarrierPolygons.</returns> public BarrierPolygon IsovistPolygon(UV vantagePoint, double viewDepth, HashSet <UVLine> edges) { /*first and expand and shrink operation is performed to merge the shadowing edges*/ double expandShrinkFactor = Math.Pow(10.0, this.PolygonalBooleanPrecision) * UnitConversion.Convert(0.075, Length_Unit_Types.FEET, UnitType); //offsetting the excluded area of each edge INTPolygons offsetedPolygons = new INTPolygons(); ClipperOffset clipperOffset = new ClipperOffset(); foreach (UVLine edgeItem in edges) { clipperOffset.AddPath(this.excludedArea(vantagePoint, viewDepth + 1, edgeItem), ClipperLib.JoinType.jtMiter, EndType.etClosedPolygon); INTPolygons plygns = new INTPolygons(); clipperOffset.Execute(ref plygns, expandShrinkFactor); offsetedPolygons.AddRange(plygns); clipperOffset.Clear(); } //Unioning the expanded exclusions INTPolygons offsetUnioned = new INTPolygons(); Clipper c = new Clipper(); c.AddPaths(offsetedPolygons, PolyType.ptSubject, true); c.Execute(ClipType.ctUnion, offsetUnioned, PolyFillType.pftNonZero, PolyFillType.pftNonZero); //shrink the polygons to retain their original size INTPolygons results = new INTPolygons(); clipperOffset.Clear(); clipperOffset.AddPaths(offsetUnioned, JoinType.jtMiter, EndType.etClosedPolygon); clipperOffset.Execute(ref results, -expandShrinkFactor); clipperOffset.Clear(); offsetUnioned.Clear(); /* * What ever is a hole in the resulting mereged polygon is the visibility polygon * Now we classify the polygons based on being a hole or not */ //filtering out the holes that do not include the center INTPolygons holesNOT = new INTPolygons(); INTPolygons holesIncludingCenter = new INTPolygons(); IntPoint iCenter = ConvertUVToIntPoint(vantagePoint); foreach (INTPolygon item in results) { if (!Clipper.Orientation(item)) { if (Clipper.PointInPolygon(iCenter, item) == 1) { holesIncludingCenter.Add(item); } } else { holesNOT.Add(item); } } if (holesIncludingCenter.Count == 0) { //there is no hole. The shadow polygones should clip the potential field of visibility (i.e. circle) by an subtraction operation INTPolygon circle = createCircle(vantagePoint, viewDepth); //subtraction c.Clear(); c.AddPath(circle, PolyType.ptSubject, true); c.AddPaths(holesNOT, PolyType.ptClip, true); INTPolygons isovistPolygon = new INTPolygons(); c.Execute(ClipType.ctDifference, isovistPolygon); //searching for a polygon that includes the center foreach (INTPolygon item in isovistPolygon) { if (Clipper.PointInPolygon(iCenter, item) == 1) { BarrierPolygon isovist = this.ConvertINTPolygonToBarrierPolygon(item); results = null; c = null; clipperOffset = null; offsetedPolygons = null; circle = null; holesNOT = null; holesIncludingCenter = null; isovistPolygon = null; return(isovist); } } MessageBox.Show(string.Format("Isovist not found!\nNo hole detected\n{0} polygons can be isovist", isovistPolygon.Count.ToString())); } else if (holesIncludingCenter.Count == 1) { INTPolygons isovistPolygon = holesIncludingCenter; foreach (INTPolygon item in isovistPolygon) { if (Clipper.PointInPolygon(iCenter, item) == 1) { item.Reverse(); BarrierPolygon isovist = this.ConvertINTPolygonToBarrierPolygon(item); results = null; c = null; clipperOffset = null; offsetedPolygons = null; holesNOT = null; holesIncludingCenter = null; isovistPolygon = null; return(isovist); } } MessageBox.Show(string.Format("Isovist not found!\nOne hole detected\n{0} polygons can be isovist", isovistPolygon.Count.ToString())); } else if (holesIncludingCenter.Count > 1) { MessageBox.Show("Isovist not found!\nMore than one hole found that can include the vantage point"); } return(null); }
private void CutPoly(ListView <NavmeshCut> InNavmeshCuts, VInt3[] verts, int[] tris, ref VInt3[] outVertsArr, ref int[] outTrisArr, out int outVCount, out int outTCount, VInt3[] extraShape, VInt3 cuttingOffset, Bounds realBounds, SGameTileHandler.CutMode mode = (SGameTileHandler.CutMode) 3, int perturbate = 0) { if (verts.Length == 0 || tris.Length == 0) { outVCount = 0; outTCount = 0; outTrisArr = new int[0]; outVertsArr = new VInt3[0]; return; } List <IntPoint> list = null; if (extraShape == null && (mode & SGameTileHandler.CutMode.CutExtra) != (SGameTileHandler.CutMode) 0) { throw new Exception("extraShape is null and the CutMode specifies that it should be used. Cannot use null shape."); } if ((mode & SGameTileHandler.CutMode.CutExtra) != (SGameTileHandler.CutMode) 0) { list = new List <IntPoint>(extraShape.Length); for (int i = 0; i < extraShape.Length; i++) { list.Add(new IntPoint((long)(extraShape[i].x + cuttingOffset.x), (long)(extraShape[i].z + cuttingOffset.z))); } } List <IntPoint> list2 = new List <IntPoint>(5); Dictionary <TriangulationPoint, int> dictionary = new Dictionary <TriangulationPoint, int>(); List <PolygonPoint> list3 = new List <PolygonPoint>(); IntRect b = new IntRect(verts[0].x, verts[0].z, verts[0].x, verts[0].z); for (int j = 0; j < verts.Length; j++) { b = b.ExpandToContain(verts[j].x, verts[j].z); } List <VInt3> list4 = ListPool <VInt3> .Claim(verts.Length * 2); List <int> list5 = ListPool <int> .Claim(tris.Length); PolyTree polyTree = new PolyTree(); List <List <IntPoint> > list6 = new List <List <IntPoint> >(); Stack <Polygon> stack = new Stack <Polygon>(); if (this.clipper == null) { this.clipper = new Clipper(0); } this.clipper.set_ReverseSolution(true); this.clipper.set_StrictlySimple(true); ListView <NavmeshCut> listView; if (mode == SGameTileHandler.CutMode.CutExtra) { listView = new ListView <NavmeshCut>(); } else { listView = new ListView <NavmeshCut>(InNavmeshCuts); } List <int> list7 = ListPool <int> .Claim(); List <IntRect> list8 = ListPool <IntRect> .Claim(); List <VInt2> list9 = ListPool <VInt2> .Claim(); List <List <IntPoint> > list10 = new List <List <IntPoint> >(); List <bool> list11 = ListPool <bool> .Claim(); List <bool> list12 = ListPool <bool> .Claim(); if (perturbate > 10) { Debug.LogError("Too many perturbations aborting : " + mode); Debug.Break(); outVCount = verts.Length; outTCount = tris.Length; outTrisArr = tris; outVertsArr = verts; return; } Random random = null; if (perturbate > 0) { random = new Random(); } for (int k = 0; k < listView.Count; k++) { Bounds bounds = listView[k].GetBounds(); VInt3 vInt = (VInt3)bounds.min + cuttingOffset; VInt3 vInt2 = (VInt3)bounds.max + cuttingOffset; IntRect a = new IntRect(vInt.x, vInt.z, vInt2.x, vInt2.z); if (IntRect.Intersects(a, b)) { VInt2 vInt3 = new VInt2(0, 0); if (perturbate > 0) { vInt3.x = random.Next() % 6 * perturbate - 3 * perturbate; if (vInt3.x >= 0) { vInt3.x++; } vInt3.y = random.Next() % 6 * perturbate - 3 * perturbate; if (vInt3.y >= 0) { vInt3.y++; } } int count = list10.get_Count(); listView[k].GetContour(list10); for (int l = count; l < list10.get_Count(); l++) { List <IntPoint> list13 = list10.get_Item(l); if (list13.get_Count() == 0) { Debug.LogError("Zero Length Contour"); list8.Add(default(IntRect)); list9.Add(new VInt2(0, 0)); } else { IntRect intRect = new IntRect((int)list13.get_Item(0).X + cuttingOffset.x, (int)list13.get_Item(0).Y + cuttingOffset.y, (int)list13.get_Item(0).X + cuttingOffset.x, (int)list13.get_Item(0).Y + cuttingOffset.y); for (int m = 0; m < list13.get_Count(); m++) { IntPoint intPoint = list13.get_Item(m); intPoint.X += (long)cuttingOffset.x; intPoint.Y += (long)cuttingOffset.z; if (perturbate > 0) { intPoint.X += (long)vInt3.x; intPoint.Y += (long)vInt3.y; } list13.set_Item(m, intPoint); intRect = intRect.ExpandToContain((int)intPoint.X, (int)intPoint.Y); } list9.Add(new VInt2(vInt.y, vInt2.y)); list8.Add(intRect); list11.Add(listView[k].isDual); list12.Add(listView[k].cutsAddedGeom); } } } } ListView <NavmeshAdd> listView2 = new ListView <NavmeshAdd>(); VInt3[] array = verts; int[] array2 = tris; int num = -1; int n = -3; VInt3[] array3 = null; VInt3[] array4 = null; VInt3 vInt4 = VInt3.zero; if (listView2.Count > 0) { array3 = new VInt3[7]; array4 = new VInt3[7]; vInt4 = (VInt3)realBounds.extents; } while (true) { n += 3; while (n >= array2.Length) { num++; n = 0; if (num >= listView2.Count) { array = null; break; } if (array == verts) { array = null; } listView2[num].GetMesh(cuttingOffset, ref array, out array2); } if (array == null) { break; } VInt3 vInt5 = array[array2[n]]; VInt3 vInt6 = array[array2[n + 1]]; VInt3 vInt7 = array[array2[n + 2]]; IntRect a2 = new IntRect(vInt5.x, vInt5.z, vInt5.x, vInt5.z); a2 = a2.ExpandToContain(vInt6.x, vInt6.z); a2 = a2.ExpandToContain(vInt7.x, vInt7.z); int num2 = Math.Min(vInt5.y, Math.Min(vInt6.y, vInt7.y)); int num3 = Math.Max(vInt5.y, Math.Max(vInt6.y, vInt7.y)); list7.Clear(); bool flag = false; for (int num4 = 0; num4 < list10.get_Count(); num4++) { int x = list9.get_Item(num4).x; int y = list9.get_Item(num4).y; if (IntRect.Intersects(a2, list8.get_Item(num4)) && y >= num2 && x <= num3 && (list12.get_Item(num4) || num == -1)) { VInt3 vInt8 = vInt5; vInt8.y = x; VInt3 vInt9 = vInt5; vInt9.y = y; list7.Add(num4); flag |= list11.get_Item(num4); } } if (list7.get_Count() == 0 && (mode & SGameTileHandler.CutMode.CutExtra) == (SGameTileHandler.CutMode) 0 && (mode & SGameTileHandler.CutMode.CutAll) != (SGameTileHandler.CutMode) 0 && num == -1) { list5.Add(list4.get_Count()); list5.Add(list4.get_Count() + 1); list5.Add(list4.get_Count() + 2); list4.Add(vInt5); list4.Add(vInt6); list4.Add(vInt7); } else { list2.Clear(); if (num == -1) { list2.Add(new IntPoint((long)vInt5.x, (long)vInt5.z)); list2.Add(new IntPoint((long)vInt6.x, (long)vInt6.z)); list2.Add(new IntPoint((long)vInt7.x, (long)vInt7.z)); } else { array3[0] = vInt5; array3[1] = vInt6; array3[2] = vInt7; int num5 = Utility.ClipPolygon(array3, 3, array4, 1, 0, 0); if (num5 == 0) { continue; } num5 = Utility.ClipPolygon(array4, num5, array3, -1, 2 * vInt4.x, 0); if (num5 == 0) { continue; } num5 = Utility.ClipPolygon(array3, num5, array4, 1, 0, 2); if (num5 == 0) { continue; } num5 = Utility.ClipPolygon(array4, num5, array3, -1, 2 * vInt4.z, 2); if (num5 == 0) { continue; } for (int num6 = 0; num6 < num5; num6++) { list2.Add(new IntPoint((long)array3[num6].x, (long)array3[num6].z)); } } dictionary.Clear(); VInt3 vInt10 = vInt6 - vInt5; VInt3 vInt11 = vInt7 - vInt5; VInt3 vInt12 = vInt10; VInt3 vInt13 = vInt11; vInt12.y = 0; vInt13.y = 0; for (int num7 = 0; num7 < 16; num7++) { if ((mode >> (num7 & 31) & SGameTileHandler.CutMode.CutAll) != (SGameTileHandler.CutMode) 0) { if (1 << num7 == 1) { this.clipper.Clear(); this.clipper.AddPolygon(list2, 0); for (int num8 = 0; num8 < list7.get_Count(); num8++) { this.clipper.AddPolygon(list10.get_Item(list7.get_Item(num8)), 1); } polyTree.Clear(); this.clipper.Execute(2, polyTree, 0, 1); } else if (1 << num7 == 2) { if (!flag) { goto IL_1173; } this.clipper.Clear(); this.clipper.AddPolygon(list2, 0); for (int num9 = 0; num9 < list7.get_Count(); num9++) { if (list11.get_Item(list7.get_Item(num9))) { this.clipper.AddPolygon(list10.get_Item(list7.get_Item(num9)), 1); } } list6.Clear(); this.clipper.Execute(0, list6, 0, 1); this.clipper.Clear(); for (int num10 = 0; num10 < list6.get_Count(); num10++) { this.clipper.AddPolygon(list6.get_Item(num10), (!Clipper.Orientation(list6.get_Item(num10))) ? 0 : 1); } for (int num11 = 0; num11 < list7.get_Count(); num11++) { if (!list11.get_Item(list7.get_Item(num11))) { this.clipper.AddPolygon(list10.get_Item(list7.get_Item(num11)), 1); } } polyTree.Clear(); this.clipper.Execute(2, polyTree, 0, 1); } else if (1 << num7 == 4) { this.clipper.Clear(); this.clipper.AddPolygon(list2, 0); this.clipper.AddPolygon(list, 1); polyTree.Clear(); this.clipper.Execute(0, polyTree, 0, 1); } for (int num12 = 0; num12 < polyTree.get_ChildCount(); num12++) { PolyNode polyNode = polyTree.get_Childs().get_Item(num12); List <IntPoint> contour = polyNode.get_Contour(); List <PolyNode> childs = polyNode.get_Childs(); if (childs.get_Count() == 0 && contour.get_Count() == 3 && num == -1) { for (int num13 = 0; num13 < contour.get_Count(); num13++) { VInt3 vInt14 = new VInt3((int)contour.get_Item(num13).X, 0, (int)contour.get_Item(num13).Y); double num14 = (double)(vInt6.z - vInt7.z) * (double)(vInt5.x - vInt7.x) + (double)(vInt7.x - vInt6.x) * (double)(vInt5.z - vInt7.z); if (num14 == 0.0) { Debug.LogWarning("Degenerate triangle"); } else { double num15 = ((double)(vInt6.z - vInt7.z) * (double)(vInt14.x - vInt7.x) + (double)(vInt7.x - vInt6.x) * (double)(vInt14.z - vInt7.z)) / num14; double num16 = ((double)(vInt7.z - vInt5.z) * (double)(vInt14.x - vInt7.x) + (double)(vInt5.x - vInt7.x) * (double)(vInt14.z - vInt7.z)) / num14; vInt14.y = (int)Math.Round(num15 * (double)vInt5.y + num16 * (double)vInt6.y + (1.0 - num15 - num16) * (double)vInt7.y); list5.Add(list4.get_Count()); list4.Add(vInt14); } } } else { Polygon polygon = null; int num17 = -1; for (List <IntPoint> list14 = contour; list14 != null; list14 = ((num17 >= childs.get_Count()) ? null : childs.get_Item(num17).get_Contour())) { list3.Clear(); for (int num18 = 0; num18 < list14.get_Count(); num18++) { PolygonPoint polygonPoint = new PolygonPoint((double)list14.get_Item(num18).X, (double)list14.get_Item(num18).Y); list3.Add(polygonPoint); VInt3 vInt15 = new VInt3((int)list14.get_Item(num18).X, 0, (int)list14.get_Item(num18).Y); double num19 = (double)(vInt6.z - vInt7.z) * (double)(vInt5.x - vInt7.x) + (double)(vInt7.x - vInt6.x) * (double)(vInt5.z - vInt7.z); if (num19 == 0.0) { Debug.LogWarning("Degenerate triangle"); } else { double num20 = ((double)(vInt6.z - vInt7.z) * (double)(vInt15.x - vInt7.x) + (double)(vInt7.x - vInt6.x) * (double)(vInt15.z - vInt7.z)) / num19; double num21 = ((double)(vInt7.z - vInt5.z) * (double)(vInt15.x - vInt7.x) + (double)(vInt5.x - vInt7.x) * (double)(vInt15.z - vInt7.z)) / num19; vInt15.y = (int)Math.Round(num20 * (double)vInt5.y + num21 * (double)vInt6.y + (1.0 - num20 - num21) * (double)vInt7.y); dictionary.set_Item(polygonPoint, list4.get_Count()); list4.Add(vInt15); } } Polygon polygon2; if (stack.get_Count() > 0) { polygon2 = stack.Pop(); polygon2.AddPoints(list3); } else { polygon2 = new Polygon(list3); } if (polygon == null) { polygon = polygon2; } else { polygon.AddHole(polygon2); } num17++; } try { P2T.Triangulate(polygon); } catch (PointOnEdgeException) { Debug.LogWarning(string.Concat(new object[] { "PointOnEdgeException, perturbating vertices slightly ( at ", num7, " in ", mode, ")" })); this.CutPoly(InNavmeshCuts, verts, tris, ref outVertsArr, ref outTrisArr, out outVCount, out outTCount, extraShape, cuttingOffset, realBounds, mode, perturbate + 1); return; } for (int num22 = 0; num22 < polygon.get_Triangles().get_Count(); num22++) { DelaunayTriangle delaunayTriangle = polygon.get_Triangles().get_Item(num22); list5.Add(dictionary.get_Item(delaunayTriangle.Points._0)); list5.Add(dictionary.get_Item(delaunayTriangle.Points._1)); list5.Add(dictionary.get_Item(delaunayTriangle.Points._2)); } if (polygon.get_Holes() != null) { for (int num23 = 0; num23 < polygon.get_Holes().get_Count(); num23++) { polygon.get_Holes().get_Item(num23).get_Points().Clear(); polygon.get_Holes().get_Item(num23).ClearTriangles(); if (polygon.get_Holes().get_Item(num23).get_Holes() != null) { polygon.get_Holes().get_Item(num23).get_Holes().Clear(); } stack.Push(polygon.get_Holes().get_Item(num23)); } } polygon.ClearTriangles(); if (polygon.get_Holes() != null) { polygon.get_Holes().Clear(); } polygon.get_Points().Clear(); stack.Push(polygon); } } } IL_1173 :; } } } Dictionary <VInt3, int> dictionary2 = this.cached_Int3_int_dict; dictionary2.Clear(); if (this.cached_int_array.Length < list4.get_Count()) { this.cached_int_array = new int[Math.Max(this.cached_int_array.Length * 2, list4.get_Count())]; } int[] array5 = this.cached_int_array; int num24 = 0; for (int num25 = 0; num25 < list4.get_Count(); num25++) { int num26; if (!dictionary2.TryGetValue(list4.get_Item(num25), ref num26)) { dictionary2.Add(list4.get_Item(num25), num24); array5[num25] = num24; list4.set_Item(num24, list4.get_Item(num25)); num24++; } else { array5[num25] = num26; } } outTCount = list5.get_Count(); if (outTrisArr == null || outTrisArr.Length < outTCount) { outTrisArr = new int[outTCount]; } for (int num27 = 0; num27 < outTCount; num27++) { outTrisArr[num27] = array5[list5.get_Item(num27)]; } outVCount = num24; if (outVertsArr == null || outVertsArr.Length < outVCount) { outVertsArr = new VInt3[outVCount]; } for (int num28 = 0; num28 < outVCount; num28++) { outVertsArr[num28] = list4.get_Item(num28); } for (int num29 = 0; num29 < listView.Count; num29++) { listView[num29].UsedForCut(); } ListPool <VInt3> .Release(list4); ListPool <int> .Release(list5); ListPool <int> .Release(list7); ListPool <VInt2> .Release(list9); ListPool <bool> .Release(list11); ListPool <bool> .Release(list12); ListPool <IntRect> .Release(list8); }