/// <summary> 判断半边道路的挖填情况 </summary> /// <param name="center"></param> /// <param name="leftSide">左侧还是右侧</param> /// <param name="slopeFill">此侧边坡的填挖情况</param> /// <param name="treatmentDepth">浅挖路基的翻挖压实处理的最底部距离路面顶的深度,一般为1.5m左右</param> /// <param name="ground">自然地面</param> /// <returns>此侧路基中,需要进行翻挖压实处理的路基宽度。 /// 当边坡为填方时(且道路中线处为挖方),此时自然地面线一般会与路面线相交,返回相交后靠近道路中线侧的挖方宽度; /// 如果自然地面线与路面线不相交(),则将此侧道路按全挖方考虑,且为全浅挖</returns> private static double HalfRoadShallowCut(SectionInfo center, bool leftSide, bool?slopeFill, double treatmentDepth, Polyline ground) { var centerCutWidth = 0.0; var halfRoadWidth = leftSide ? center.CenterX - center.LeftRoadEdge.X : center.RightRoadEdge.X - center.CenterX; // 路面+路肩 if (slopeFill == null || !slopeFill.Value) { // 说明不是填方 centerCutWidth = halfRoadWidth; } else { // 说明中心为挖方,而边坡为填方 var bottomPt = new Point2d(center.CenterX, center.CenterY - treatmentDepth); var inters = new CurveCurveIntersector2d(ground.Get2dLinearCurve(), new Ray2d(bottomPt, new Vector2d(leftSide ? -1 : 1, 0))); if (inters.NumberOfIntersectionPoints == 0) { centerCutWidth = halfRoadWidth; } else { centerCutWidth = Math.Abs(inters.GetIntersectionPoint(0).X - center.CenterX); if (centerCutWidth > halfRoadWidth) { centerCutWidth = halfRoadWidth; } } } return(centerCutWidth); }
private static List <Point2d> CalcGeologPtsByDepth(Point2d p0, Point2d p1, int[] interval, List <Point2d> groundSurfPoly, double depthMultipier) { List <Point2d> polygonPts = new List <Point2d>(); LineSegment2d geologSegment = new LineSegment2d(p0, p1); //начало отрезка LineSegment2d surfSegment0 = new LineSegment2d(groundSurfPoly[interval[0]], groundSurfPoly[interval[0] + 1]); Line2d vert0 = new Line2d(p0, Vector2d.YAxis); CurveCurveIntersector2d intersector0 = new CurveCurveIntersector2d(vert0, surfSegment0); if (intersector0.NumberOfIntersectionPoints > 0) { Point2d surfPt0 = intersector0.GetPointOnCurve2(0).Point; double depth0 = (surfPt0.Y - p0.Y) * depthMultipier; Point2d convertedGeologPt0 = surfPt0 - Vector2d.YAxis * depth0; polygonPts.Add(convertedGeologPt0); } //все точки поверхности между началом и концом отрезка if (!geologSegment.Direction.IsParallelTo(Vector2d.YAxis)) { for (int i = interval[0]; i <= interval[1]; i++) { Point2d surfPt = groundSurfPoly[i]; Line2d vert = new Line2d(surfPt, Vector2d.YAxis); CurveCurveIntersector2d intersector = new CurveCurveIntersector2d(vert, geologSegment); if (intersector.NumberOfIntersectionPoints > 0) { Point2d geologPt = intersector.GetPointOnCurve2(0).Point; double depth = (surfPt.Y - geologPt.Y) * depthMultipier; Point2d convertedGeologPt = surfPt - Vector2d.YAxis * depth; polygonPts.Add(convertedGeologPt); } } } //конец отрезка LineSegment2d surfSegment1 = new LineSegment2d(groundSurfPoly[interval[1] - 1], groundSurfPoly[interval[1]]); Line2d vert1 = new Line2d(p1, Vector2d.YAxis); CurveCurveIntersector2d intersector1 = new CurveCurveIntersector2d(vert1, surfSegment1); if (intersector1.NumberOfIntersectionPoints > 0) { Point2d surfPt1 = intersector1.GetPointOnCurve2(0).Point; double depth1 = (surfPt1.Y - p1.Y) * depthMultipier; Point2d convertedGeologPt1 = surfPt1 - Vector2d.YAxis * depth1; polygonPts.Add(convertedGeologPt1); } return(polygonPts); }
/// <summary> /// Расчет пересечений двух линий /// С учетом допусков автокада /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="p3"></param> /// <param name="p4"></param> /// <returns></returns> public static Point2d?GetLinesIntersectionAcad(Point2d p1, Point2d p2, Point2d p3, Point2d p4) { Point2d? pt = null; LineSegment2d line1 = new LineSegment2d(p1, p2); LineSegment2d line2 = new LineSegment2d(p3, p4); CurveCurveIntersector2d intersector = new CurveCurveIntersector2d(line1, line2); if (intersector.NumberOfIntersectionPoints > 0) { pt = intersector.GetIntersectionPoint(0); } return(pt); }
/// <summary> 构造函数 </summary> /// <param name="docMdf"></param> /// <param name="roadCurve"></param> /// <param name="groundCurve"></param> public LongitudinalSection(DocumentModifier docMdf, CompositeCurve3d roadCurve, CompositeCurve3d groundCurve) { _docMdf = docMdf; RoadCurve2d = roadCurve.Get2dLinearCurve(); GroundCurve2d = groundCurve.Get2dLinearCurve(); // StartStation = RoadCurve2d.StartPoint.X; EndStation = RoadCurve2d.EndPoint.X; // 求交点 Intersects = new CurveCurveIntersector2d(RoadCurve2d, GroundCurve2d); GetIntersects(); //_road = Curve.CreateFromGeCurve(roadCurve) as Polyline; //_ground = Curve.CreateFromGeCurve(groundCurve) as Polyline; }
private PointOnCurve2d GetSplitPt(CivilDB.Structure str, bool start) { Curve2d strPosCurve = StructurePosCurve(str); CurveCurveIntersector2d intersector = new CurveCurveIntersector2d(PositionCurve, strPosCurve); if (intersector.NumberOfIntersectionPoints > 0) { intersector.OrderWithRegardsTo1(); //взять точку пересечения, которая имеет имеет наибольший параметр PositionCurve для начальной точки //и наименьший для конечной точки return(start ? intersector.GetPointOnCurve1(intersector.NumberOfIntersectionPoints - 1) : intersector.GetPointOnCurve1(0)); } return(null); }
private double?[,] GetZArray(Point2dCollection[] collections, double sizeX) { var distance = TechProcess.Tool.Diameter / 2; var countX = (int)(sizeX / StepX2) + 1; var zArray = new double?[collections.Length, countX]; var intersector = new CurveCurveIntersector2d(); Acad.SetLimitProgressor(collections.Length); var rays = Enumerable.Range(0, countX).Select(p => new Ray2d(new Point2d(p * StepX2, 0), Vector2d.YAxis)).ToList(); for (int i = 0; i < collections.Length; i++) { Acad.ReportProgressor(); if (collections[i] == null) { continue; } var polylene = new PolylineCurve2d(collections[i]); var offsetCurve = polylene.GetTrimmedOffset(distance, OffsetCurveExtensionType.Fillet)[0]; for (int j = 0; j < countX; j++) { intersector.Set(offsetCurve, rays[j]); if (intersector.NumberOfIntersectionPoints == 1) { zArray[i, j] = intersector.GetIntersectionPoint(0).Y - distance; } } //if (i < 50) //{ // Draw.Pline(polylene.GetSamplePoints(10).Select(p => new Point3d(p.X + i * 100, p.Y + 1000, 0))); // Draw.Pline(offsetCurve.GetSamplePoints(10).Select(p => new Point3d(p.X + i * 100, p.Y + 1000, 0))); //} //else //{ polylene.Dispose(); offsetCurve.Dispose(); //} } rays.ForEach(p => p.Dispose()); intersector.Dispose(); return(zArray); }
/// <summary> 纵断面中某个桩号所对应的填方高度,如果为负值,则代表挖方高度 </summary> /// <param name="station"></param> /// <returns></returns> public double GetFillHeight(double station) { var intersVerticalRoad = new CurveCurveIntersector2d(RoadCurve2d, new Line2d(new Point2d(station, 0), new Vector2d(0, 1))); var intersVerticalGround = new CurveCurveIntersector2d(GroundCurve2d, new Line2d(new Point2d(station, 0), new Vector2d(0, 1))); if (intersVerticalRoad.NumberOfIntersectionPoints == 0 || intersVerticalGround.NumberOfIntersectionPoints == 0) { // 这种情况一般不会出现 } else { var yRoad = intersVerticalRoad.GetIntersectionPoint(0).Y; var yGround = intersVerticalGround.GetIntersectionPoint(0).Y; return(yRoad - yGround); } return(0.0); }
private bool AddIntersection(LineSegment2d intersectionSeg, LinearEntity2d vert, HatchNestingNode hatchNode, SortedSet <Node> vertSorted) { bool result = false; CurveCurveIntersector2d intersector = new CurveCurveIntersector2d(intersectionSeg, vert); if (intersector.NumberOfIntersectionPoints > 0) { Point2d intersectionPt = intersector.GetPointOnCurve1(0).Point; //если точка пересечения контура и вертикали имеет ту же координату X, //что и начало или конец контура, то это пересечение не учитывается! if (!Utils.LengthIsEquals(intersectionPt.X, hatchNode.Extents.MinPoint.X) && !Utils.LengthIsEquals(intersectionPt.X, hatchNode.Extents.MaxPoint.X)) //допуск { double param = hatchNode.Boundary.GetParameterOf(intersectionPt); Node newIntersectionNode = new Node(hatchNode, param, intersectionPt); if (!vertSorted.Contains(newIntersectionNode))//TODO: Нужен учет допуска??? { result = true; notVisited.Add(newIntersectionNode); vertSorted.Add(newIntersectionNode); SortedSet <Node> boundarySorted = null; boundariesSorted.TryGetValue(hatchNode, out boundarySorted); if (boundarySorted == null) { boundarySorted = new SortedSet <Node>(new NodeParamComparer());//сортировка по параметру!!! boundariesSorted.Add(hatchNode, boundarySorted); } if (boundarySorted.Contains(newIntersectionNode)) { throw new Exception("Ошибка логики обхода полигона. Получены 2 точки с одинаковым параметром на одной кривой"); } boundarySorted.Add(newIntersectionNode); } } } return(result); }
public static List <Point2d> GetProcessPoints1(Curve profile, int index, double step, double shift, bool isMinToolCoord, double?begin, double?end, bool isProfileStep = false) //, bool isExactlyBegin, bool isExactlyEnd) { var result = new List <Point2d>(); var start = 10000D; var rayVector = index == 0 ? -Vector2d.YAxis : -Vector2d.XAxis; var p0 = begin ?? Math.Max(profile.StartPoint[index], profile.EndPoint[index]); var p1 = end ?? Math.Min(profile.StartPoint[index], profile.EndPoint[index]); var dir = Math.Sign(p1 - p0); using (var curve = profile.ToCompositeCurve2d()) using (var ray = new Ray2d()) using (var intersector = new CurveCurveIntersector2d()) { var pos = p0; Point2d?point0 = null; var length = profile.Length(); int curveSign = dir * Math.Sign(curve.EndPoint[index] - curve.StartPoint[index]); double? dist = null; while (dir > 0 ? pos <p1 : pos> p1) { double?max = null; for (int i = 0; i <= 10; i++) { var rayPoint = GetPoint(pos + i * (shift / 10) * dir, start, index); ray.Set(rayPoint, rayVector); intersector.Set(curve, ray); if (intersector.NumberOfIntersectionPoints > 0) { var intersect = intersector.GetIntersectionPoint(0); max = Math.Max(max ?? double.MinValue, intersect[1 - index]); if (!point0.HasValue && i == 0) { point0 = intersect; } } } if (max.HasValue) { var toolCoord = pos + shift * dir * (isMinToolCoord ^ dir < 0 ? 0 : 1); result.Add(GetPoint(toolCoord, max.Value, index)); } if (isProfileStep && point0.HasValue) { if (!dist.HasValue) { dist = curve.GetLength(0, curve.GetParameterOf(point0.Value)); } dist += step * curveSign; if (dist < 0 || dist > length) { break; } var point = curve.EvaluatePoint(curve.GetParameterAtLength(0, dist.Value, true)); pos = point[index]; } else { pos += step * dir; } } } return(result); }
/// <summary> 低填路堤 </summary> /// <param name="centerAxis"></param> /// <param name="width"> 左右路堤坡底之间的宽度</param> /// <param name="height"> 自然地面以下地基加固的高度</param> /// <returns></returns> public static bool IsThinFill(Database db, SubgradeSection centerAxis, out double width, out double height) { var center = centerAxis.XData; height = 0.0; width = 0.0; // 1. 基本判断标准 var depth = center.CenterElevation_Road - center.CenterElevation_Ground; double leftWidth1 = 0.0; double rightWidth1 = 0.0; // 道路中心为填方,而且左右至少有一侧为填方边坡 if (depth >= 0 && depth <= _criterion.低填最大高度 && ((center.LeftSlopeFill == null || center.LeftSlopeFill.Value) || (center.RightSlopeFill == null || center.RightSlopeFill.Value))) { // 道路中心线 与 自然地面线的交点 var centerGroundPt = new Point3d(center.CenterX, center.GetYFromElev(center.CenterElevation_Ground), 0); // 左侧低填处理的宽度 var leftRoadWidth = center.CenterX - center.LeftRoadEdge.X; if (center.LeftSlopeFill == null || !center.LeftSlopeFill.Value) { // 无边坡线或者是挖方 leftWidth1 = leftRoadWidth; } else { var leftSlope = center.LeftSlopeHandle.GetDBObject <Polyline>(db); if (leftSlope == null) { leftWidth1 = leftRoadWidth; } else { // 先计算填方边坡线与 var leftInters = new CurveCurveIntersector2d(leftSlope.Get2dLinearCurve(), new Ray2d(centerGroundPt.ToXYPlane(), new Vector2d(-1, 0))); if (leftInters.NumberOfIntersectionPoints == 0) { leftWidth1 = leftRoadWidth; } else { leftWidth1 = Math.Abs(leftInters.GetIntersectionPoint(0).X - center.CenterX); } } } // 右侧低填处理的宽度 var rightRoadWidth = center.RightRoadEdge.X - center.CenterX; if (center.RightSlopeFill == null || !center.RightSlopeFill.Value) { // 无边坡线或者是挖方 rightWidth1 = rightRoadWidth; } else { var rightSlope = center.RightSlopeHandle.GetDBObject <Polyline>(db); if (rightSlope == null) { rightWidth1 = rightRoadWidth; } else { // 先计算填方边坡线与 var rightInters = new CurveCurveIntersector2d(rightSlope.Get2dLinearCurve(), new Ray2d(centerGroundPt.ToXYPlane(), new Vector2d(1, 0))); if (rightInters.NumberOfIntersectionPoints == 0) { rightWidth1 = rightRoadWidth; } else { rightWidth1 = Math.Abs(rightInters.GetIntersectionPoint(0).X - center.CenterX); } } } width = leftWidth1 + rightWidth1; // if (width > 0) { // 低填路堤的自然地面下部地基处理的高度 height = _criterion.低填处理高度 - (center.CenterElevation_Road - center.CenterElevation_Ground); if (height < 0) { height = 0; } return(true); } } return(false); }
/// <summary> /// 判断某一侧边坡是否为陡坡路堤 /// </summary> /// <param name="slp">某一侧边坡,其值可能为null,表示此侧没有边坡线 </param> /// <param name="ground">边坡所对应的自然地面线</param> /// <param name="treatedWidth"></param> /// <param name="setReinforcement">是否要设置加筋结构,比如铺设三层土工格栅</param> /// <returns></returns> private bool IsSteepFill(SectionInfo sec, bool left, SlopeLine slp, Polyline ground, out double treatedWidth, out double stairArea, out bool setReinforcement) { treatedWidth = 0; stairArea = 0; setReinforcement = false; var slopeFill = (slp == null) || slp.XData.FillCut; // ---------------------------------------------------------------------------------------- // 确定进行搜索的左右边界:路基边缘(或边坡脚) 到 道路中线 var cGround = ground.Get2dLinearCurve(); double edgeXleft; double edgeXright; var succ = sec.GetFillSlopeXRange(left, slp, cGround, _docMdf.acDataBase, out edgeXleft, out edgeXright); if (!succ) { return(false); } // ---------------------------------------------------------------------------------------- // ---------此时 [edgeXleft ~ edgeXright] 区间内应该都是填方区域 -------------------------- // var segCounts = (int)Math.Ceiling((edgeXright - edgeXleft) / _criterion.最小迭代宽度); // 其值最小为1 var xInterval = (edgeXright - edgeXleft) / segCounts; var xYs = new List <double[]>(); var cSlope = slp?.Pline.Get2dLinearCurve(); for (int i = 0; i <= segCounts; i++) { var x = edgeXleft + i * xInterval; double yGround; var inters = new CurveCurveIntersector2d(cGround, new Line2d(new Point2d(x, 0), new Vector2d(0, 1))); // 没有交点的情况一般不会出现,因为自然地面线的范围很广 yGround = inters.NumberOfIntersectionPoints == 0 ? 0 : inters.GetIntersectionPoint(0).Y; double ySlope; if (cSlope == null) // 表示没有边坡线 { ySlope = 0; } else { inters = new CurveCurveIntersector2d(cSlope, new Line2d(new Point2d(x, 0), new Vector2d(0, 1))); // 没有交点的情况必然会出现,即x对应路基位置,而不是对应边坡位置,比如当路基下的自然地面线是向路基中心倾斜时。 ySlope = inters.NumberOfIntersectionPoints == 0 ? sec.CenterY : inters.GetIntersectionPoint(0).Y; } // xYs.Add(new double[3] { x, yGround, ySlope }); } // 每隔x间距时,自然地面的Y值 var xyGround = xYs.Select(r => new double[] { r[0], r[1] }).ToList(); // 开始求斜率(集合中至少有两个元素)。每个元素为三分量向量,分别为 X 坐标、X对应的自然地面的Y坐标,X对应的边坡的Y坐标 double maxRatio = 0; double maxYFill; var lastX = xYs[0]; maxYFill = lastX[2] - lastX[1]; for (int i = 1; i < xYs.Count; i++) { var thisX = xYs[i]; maxRatio = Math.Max(maxRatio, Math.Abs((thisX[1] - lastX[1]) / (thisX[0] - lastX[0]))); maxYFill = Math.Max(maxYFill, Math.Abs(thisX[2] - thisX[1])); // lastX = thisX; } // 判断是否为陡坡路堤 if (maxRatio >= (1 / _criterion.陡坡坡比)) { // 道路中心与边坡均为填方 treatedWidth = edgeXright - edgeXleft; stairArea = CalculateStairArea(xyGround, edgeXleft, edgeXright); if (slopeFill && treatedWidth > 0 && maxYFill >= _criterion.加筋体对应填方段最小高度) { setReinforcement = true; } return(true); } // return(false); }
/// <summary> 初始化每一个填挖交界点所占据的几何区间 </summary> /// <param name="longitudinalSection"></param> /// <returns></returns> private void ConstructIntersectRange(LongitudinalSection longitudinalSection) { var inters = longitudinalSection.Intersects; // // 将结果整理为二维数组,用来进行表格输出 var rows = new List <object[]>(); var header = new object[] { "交界点坐标", "交界方式", "10m填方段最大高度", "10m挖方段最大高度", "处理方式" }; rows.Add(header); int interval = 2; var fillLargerThan = 5.0; int fillCheckLength = 10; var arrCutToFill = ArrayConstructor.FromRangeAri(0, fillCheckLength, interval); var arrFillToCut = ArrayConstructor.FromRangeAri(0, -fillCheckLength, -interval); var blocks = Options_Collections.RangeBlocks; for (int i = 0; i < inters.NumberOfIntersectionPoints; i++) { var ptRoad = inters.GetPointOnCurve1(i); var ptGround = inters.GetPointOnCurve2(i); // 排除桥梁等结构区域 if (blocks.Any(r => r.ContainsStation(ptRoad.Point.X))) { continue; } // var fillToCut = longitudinalSection.FilltoCut(ptRoad, ptGround); var arrDx = fillToCut ? arrFillToCut : arrCutToFill; var intersX = ptRoad.Point.X; // 填挖交界处的路基,在填方段10m范围内高度H<5m时,按断面A实施,H>5m时,按断面B实施。 var maxVerticalDiff_Fill = 0.0; foreach (var dx in arrDx) { var x = intersX + dx; var intersVerticalRoad = new CurveCurveIntersector2d(longitudinalSection.RoadCurve2d, new Line2d(new Point2d(x, 0), new Vector2d(0, 1))); var intersVerticalGround = new CurveCurveIntersector2d(longitudinalSection.GroundCurve2d, new Line2d(new Point2d(x, 0), new Vector2d(0, 1))); if (intersVerticalRoad.NumberOfIntersectionPoints == 0 || intersVerticalGround.NumberOfIntersectionPoints == 0) { break; } else { var verticalDiff = intersVerticalRoad.GetIntersectionPoint(0).Y - intersVerticalGround.GetIntersectionPoint(0).Y; if (verticalDiff > maxVerticalDiff_Fill) { maxVerticalDiff_Fill = verticalDiff; } } } var maxVerticalDiff_Cut = 0.0; foreach (var dx in arrDx) { var x = intersX - dx; var intersVerticalRoad = new CurveCurveIntersector2d(longitudinalSection.RoadCurve2d, new Line2d(new Point2d(x, 0), new Vector2d(0, 1))); var intersVerticalGround = new CurveCurveIntersector2d(longitudinalSection.GroundCurve2d, new Line2d(new Point2d(x, 0), new Vector2d(0, 1))); if (intersVerticalRoad.NumberOfIntersectionPoints == 0 || intersVerticalGround.NumberOfIntersectionPoints == 0) { break; } else { var verticalDiff = intersVerticalGround.GetIntersectionPoint(0).Y - intersVerticalRoad.GetIntersectionPoint(0).Y; if (verticalDiff > maxVerticalDiff_Cut) { maxVerticalDiff_Cut = verticalDiff; } } } string fill = fillToCut ? "填 - 挖" : "挖 - 填"; var reinforce = (maxVerticalDiff_Fill > fillLargerThan) ? "超挖换填 + 土工格栅" : "超挖换填"; // rows.Add(new object[] { ptRoad.Point.X, fill, maxVerticalDiff_Fill, maxVerticalDiff_Cut, reinforce }); } var sheetArr = ArrayConstructor.FromList2D(listOfRows: rows); // sheetArr = sheetArr.InsertVector<object, string, object>(true, new[] { header }, new[] { -1.5f, }); // 输出到表格 var sheet_Infos = new List <WorkSheetData> { new WorkSheetData(WorkSheetDataType.SteepSlope, "纵向填挖交界", sheetArr) }; ExportWorkSheetDatas(sheet_Infos); // }
/// <summary> /// 判断某一侧边坡的填方边坡类型 /// </summary> /// <param name="slp">某一侧边坡,其值可能为null,表示此侧没有边坡线 </param> /// <param name="ground">边坡所对应的自然地面线</param> /// <param name="treatedWidth"></param> /// <param name="stairArea">某一侧边坡所挖台阶面积</param> /// <returns></returns> private FillSlopeType GetFillSlopeType(SectionInfo sec, bool left, SlopeLine slp, Polyline ground, out double treatedWidth, out double stairArea) { treatedWidth = 0; stairArea = 0.0; double edgeXleft; double edgeXright; var cGround = ground.Get2dLinearCurve(); var succ = sec.GetFillSlopeXRange(left, slp, cGround, _docMdf.acDataBase, out edgeXleft, out edgeXright); if (!succ) { return(FillSlopeType.Other); } // 必须是填方边坡 if ((left && (sec.LeftSlopeFill == null || !sec.LeftSlopeFill.Value)) || (!left && (sec.RightSlopeFill == null || !sec.RightSlopeFill.Value))) { return(FillSlopeType.Other); } // 有路肩墙 if ((left && sec.LeftRetainingWallType == RetainingWallType.路肩墙) || (!left && sec.RightRetainingWallType == RetainingWallType.路肩墙)) { return(FillSlopeType.Other); } // var segCounts = (int)Math.Ceiling((edgeXright - edgeXleft) / _criterion.最小迭代宽度); // 其值最小为1 var xInterval = (edgeXright - edgeXleft) / segCounts; var xYs = new List <double[]>(); for (int i = 0; i <= segCounts; i++) { var x = edgeXleft + i * xInterval; double yGround; var inters = new CurveCurveIntersector2d(cGround, new Line2d(new Point2d(x, 0), new Vector2d(0, 1))); // 没有交点的情况一般不会出现,因为自然地面线的范围很广 yGround = inters.NumberOfIntersectionPoints == 0 ? 0 : inters.GetIntersectionPoint(0).Y; // xYs.Add(new double[] { x, yGround }); } // 开始求斜率(集合中至少有两个元素)。每个元素为三分量向量,分别为 X 坐标、X对应的自然地面的Y坐标,X对应的边坡的Y坐标 double maxRatio = 0; bool hasStairExcav = false; var lastX = xYs[0]; for (int i = 1; i < xYs.Count; i++) { var thisX = xYs[i]; var segRatio = Math.Abs((thisX[1] - lastX[1]) / (thisX[0] - lastX[0])); if ((segRatio > 1 / _criterion.填方坡比下限) && (segRatio > 1 / _criterion.填方坡比下限)) { hasStairExcav = true; } maxRatio = Math.Max(maxRatio, segRatio); // lastX = thisX; } if (!hasStairExcav) { return(FillSlopeType.Other); } else { // 判断是否为陡坡路堤,如果是,则不计入挖台阶工程量表中(因为在陡坡路堤工程量表中已经计入) if (maxRatio >= (1 / _criterion.陡坡坡比)) { treatedWidth = 0; return(FillSlopeType.SteepSlope); } else { // treatedWidth = edgeXright - edgeXleft; stairArea = Exporter_SteepSlope.CalculateStairArea(xYs, edgeXleft, edgeXright); return(FillSlopeType.StairExcav); } } }
/// <summary> /// 计算道路横断面的某一侧中,从路面中心到边坡外边缘的范围内,属于填方的区域在 AutoCAD 几何中的 X 范围 /// </summary> /// <param name="sec"></param> /// <param name="left"></param> /// <param name="slp"> 某一侧边坡,其值可能为null,表示此侧没有边坡线 </param> /// <param name="cGround"></param> /// <param name="db"></param> /// <param name="edgeXleft">此侧边坡的填方左边界</param> /// <param name="edgeXright">此侧边坡的填方右边界</param> /// <returns>如果没有填方区域,则返回 false </returns> public bool GetFillSlopeXRange(bool left, SlopeLine slp, CompositeCurve2d cGround, Database db, out double edgeXleft, out double edgeXright) { edgeXleft = 0.0; edgeXright = 0.0; var centerFill = IsCenterFill(); var slopeFill = slp == null || slp.XData.FillCut; if (!centerFill && (slp == null || !slopeFill)) { return(false); } // 确定进行搜索的左右边界:路基边缘(或边坡脚) 到 道路中线 double roadEdge = left ? LeftRoadEdge.X : RightRoadEdge.X; double slopeEdge = roadEdge; // 边坡的坡脚的 X 值 if (slp != null && slp.XData.Slopes.Count > 0) { var data = slp.XData; slopeEdge = data.Slopes[data.Slopes.Count - 1].OuterPoint.X; } if (centerFill && slopeFill) { // 道路中心与边坡均为填方 double edgeX1 = CenterX; edgeXleft = Math.Min(edgeX1, slopeEdge); edgeXright = Math.Max(edgeX1, slopeEdge); } else { // 说明 坡脚与道路中心这二者中有一个为挖方,另一个为填方 var roadSurfHandle = left ? LeftRoadSurfaceHandle : RightRoadSurfaceHandle; var roadSurf = roadSurfHandle.GetDBObject <Polyline>(db); var cRoad = roadSurf.Get2dLinearCurve(); var inters = new CurveCurveIntersector2d(cRoad, cGround); double iX; if (inters.NumberOfIntersectionPoints > 0) { iX = inters.GetIntersectionPoint(0).X; } else { // 这种情况极少会出现,但测试中确实会有,即自然地面线与挖方坡底边沟相交,而不与路面相交 iX = roadEdge; } // 自然地面与路面的交点 var roadWidth = Math.Abs((roadEdge - CenterX)); var innerRatio = Math.Abs((iX - CenterX) / roadWidth); if ((centerFill && innerRatio > 0.5)) { // 靠道路中心为填方,边坡为挖方 if (left) { edgeXleft = iX; edgeXright = CenterX; } else { edgeXleft = CenterX; edgeXright = iX; } } else if (!centerFill && innerRatio <= 0.5) { // 靠道路中心为挖方,边坡为填方 if (left) { edgeXleft = slopeEdge; edgeXright = iX; } else { edgeXleft = iX; edgeXright = slopeEdge; } } else { // 填方区域太小 return(false); } } return(true); }
private void Create3dProfile(object arg) { try { if (doc != null) { List <ObjectId> toHighlight = new List <ObjectId>(); using (doc.LockDocument()) { Editor ed = doc.Editor; Database db = doc.Database; using (Transaction tr = db.TransactionManager.StartTransaction()) { //найти координату X начала профиля (крайнюю левую) double minx = double.PositiveInfinity; List <ObjectId> allSelected = new List <ObjectId>(soilHatchIds); foreach (ObjectId id in allSelected) { Entity ent = null; try { ent = (Entity)tr.GetObject(id, OpenMode.ForRead); } catch (Autodesk.AutoCAD.Runtime.Exception) { continue; } Extents3d?ext = ent.Bounds; if (ext != null) { Point3d minPt = ext.Value.MinPoint; if (minx > minPt.X) { minx = minPt.X; } } } //Штриховки должны быть заранее раскиданы по слоям в соответствии с ИГЭ! //пересчет всех точек штриховок в координаты: //X - положение отностиельно начала профиля с учетом горизонтального масштаба профиля, //Y - отметка расчитанная согласно базовой отметке с учетом вертикального масштаба профиля Matrix2d transform = new Matrix2d(new double[] { HorScaling, 0, 0, 0, VertScaling, 0, 0, 0, 1 }) * Matrix2d.Displacement(new Vector2d(-minx, -ElevBasePoint.Value.Y + ElevationInput / VertScaling)); C5.IntervalHeap <HatchEvent> eventQueue = new C5.IntervalHeap <HatchEvent>(); List <HatchData> allHatchData = new List <HatchData>(); List <Point2dCollection> selfintersectingLoops = new List <Point2dCollection>(); foreach (ObjectId id in soilHatchIds) { //получить все точки штриховок с учетом возможных дуг, сплайнов и проч //Для каждой штриховки создается набор композитных кривых, состоящих из линейных сегментов Hatch hatch = null; try { hatch = (Hatch)tr.GetObject(id, OpenMode.ForRead); } catch (Autodesk.AutoCAD.Runtime.Exception) { continue; } List <CompositeCurve2d> boundaries = new List <CompositeCurve2d>(); List <Extents2d> extends = new List <Extents2d>(); List <Point2dCollection> ptsCollList = new List <Point2dCollection>(); List <List <double> > ptParamsList = new List <List <double> >(); for (int i = 0; i < hatch.NumberOfLoops; i++) { HatchLoop hl = hatch.GetLoopAt(i); if (!hl.LoopType.HasFlag(HatchLoopTypes.SelfIntersecting) && !hl.LoopType.HasFlag(HatchLoopTypes.Textbox) && !hl.LoopType.HasFlag(HatchLoopTypes.TextIsland) && !hl.LoopType.HasFlag(HatchLoopTypes.NotClosed)) { List <Curve2d> curves = Utils.GetHatchLoopCurves(hl); List <Curve2d> compositeCurveElems = new List <Curve2d>(); double _minx = double.PositiveInfinity; double _miny = double.PositiveInfinity; double _maxx = double.NegativeInfinity; double _maxy = double.NegativeInfinity; Action <Point2d> updateExtends = new Action <Point2d>(p => { _minx = p.X < _minx ? p.X : _minx; _miny = p.Y < _miny ? p.Y : _miny; _maxx = p.X > _maxx ? p.X : _maxx; _maxy = p.Y > _maxy ? p.Y : _maxy; }); Point2dCollection ptsColl = new Point2dCollection(); List <double> ptParams = new List <double>(); double currParam = 0; foreach (Curve2d c in curves) { if (!(c is LineSegment2d)) { Interval interval = c.GetInterval(); PointOnCurve2d[] samplePts = c.GetSamplePoints(interval.LowerBound, interval.UpperBound, 0.02); Point2d[] pts = samplePts.Select(p => transform * p.Point).ToArray(); for (int n = 0; n < pts.Length - 1; n++) { LineSegment2d lineSeg = new LineSegment2d(pts[n], pts[n + 1]); compositeCurveElems.Add(lineSeg); ptsColl.Add(pts[n]); ptParams.Add(currParam); updateExtends(pts[n]); currParam += lineSeg.Length; } } else { LineSegment2d lineSeg = (LineSegment2d)c; lineSeg.TransformBy(transform); compositeCurveElems.Add(lineSeg); ptsColl.Add(lineSeg.StartPoint); ptParams.Add(currParam); updateExtends(lineSeg.StartPoint); currParam += lineSeg.Length; } } CompositeCurve2d boundary = new CompositeCurve2d(compositeCurveElems.ToArray()); Extents2d ext = new Extents2d(_minx, _miny, _maxx, _maxy); boundaries.Add(boundary); ptsCollList.Add(ptsColl); ptParamsList.Add(ptParams); extends.Add(ext); } } //контуры штриховок не могут иметь самопересечений! #region Проверка на пересечения //проверка на самопересечения //bool badBoundaries = false; HashSet <int> badBoundaries = new HashSet <int>(); HashSet <int> splitBoundaries = new HashSet <int>();//Если 2 контура в одной штриховке пересекаются, то разносить их по разным штриховкам //List<HatchData> decomposeHatchData = new List<HatchData>();//TODO: самопересекающиеся полигоны нужно разбить на отдельные по количеству самопересечний. for (int i = 0; i < boundaries.Count; i++) { CompositeCurve2d b = boundaries[i]; CurveCurveIntersector2d intersector = new CurveCurveIntersector2d(b, b); if (intersector.NumberOfIntersectionPoints > 0) { //если происходит только наложение??? badBoundaries.Add(i); selfintersectingLoops.Add(ptsCollList[i]); } } if (boundaries.Count > 1) { //проверка на взаимные пересечения. //Исп RBush для того чтобы избежать проверки на пересечение каждого с каждым и квадратичной сложности //(работает только если контуры разнесены) //Не брать в расчет пересечения по касательной RBush <Spatial> boundariesRBush = new RBush <Spatial>(); List <Spatial> spatialData = new List <Spatial>(); for (int i = 0; i < extends.Count; i++) { spatialData.Add(new Spatial(extends[i], i)); } boundariesRBush.BulkLoad(spatialData); foreach (Spatial s in spatialData) { IReadOnlyList <Spatial> nearestNeighbors = boundariesRBush.Search(s.Envelope); if (nearestNeighbors.Count > 1) { CompositeCurve2d thisCurve = boundaries[(int)s.Obj]; foreach (Spatial n in nearestNeighbors) { if (!s.Equals(n)) { CompositeCurve2d otherCurve = boundaries[(int)n.Obj]; CurveCurveIntersector2d intersector = new CurveCurveIntersector2d(thisCurve, otherCurve); if (intersector.NumberOfIntersectionPoints > 0 || intersector.OverlapCount > 0) { bool matches = false; //Проверить, что кривые не накладываются друг на друга по всей длине (то есть полностью совпадают) if (intersector.OverlapCount > 0) { //сумма длин всех интервалов перекрытия равна общей длине кривой double thisCurveOverlapLength = 0; double otherCurveOverlapLength = 0; for (int i = 0; i < intersector.OverlapCount; i++) { Interval[] intervals = intersector.GetOverlapRanges(i); Interval thisOverlapInterval = intervals[0]; thisCurveOverlapLength += thisOverlapInterval.Length; Interval otherOverlapInterval = intervals[1]; otherCurveOverlapLength += otherOverlapInterval.Length; } Interval thisCurveInterval = thisCurve.GetInterval(); Interval otherCurveInterval = otherCurve.GetInterval(); if (Utils.LengthIsEquals(thisCurveOverlapLength, thisCurveInterval.Length) && Utils.LengthIsEquals(otherCurveOverlapLength, otherCurveInterval.Length)) { matches = true; } } if (!matches) { splitBoundaries.Add((int)s.Obj); splitBoundaries.Add((int)n.Obj); } else { badBoundaries.Add((int)s.Obj); badBoundaries.Add((int)n.Obj); } } } } } } } splitBoundaries.ExceptWith(badBoundaries); List <HatchData> splitHatchData = new List <HatchData>(); if (badBoundaries.Count > 0 || splitBoundaries.Count > 0) { List <CompositeCurve2d> boundariesClear = new List <CompositeCurve2d>(); List <Extents2d> extendsClear = new List <Extents2d>(); List <Point2dCollection> ptsCollListClear = new List <Point2dCollection>(); List <List <double> > ptParamsListClear = new List <List <double> >(); for (int i = 0; i < boundaries.Count; i++) { if (!badBoundaries.Contains(i) && !splitBoundaries.Contains(i)) { boundariesClear.Add(boundaries[i]); extendsClear.Add(extends[i]); ptsCollListClear.Add(ptsCollList[i]); ptParamsListClear.Add(ptParamsList[i]); } } foreach (int index in splitBoundaries) { splitHatchData.Add(new HatchData( new HatchNestingNode( boundaries[index], extends[index], ptsCollList[index], ptParamsList[index], hatch))); } boundaries = boundariesClear; extends = extendsClear; ptsCollList = ptsCollListClear; ptParamsList = ptParamsListClear; } #endregion //определяется вложенность контуров штриховки //ЕСЛИ ШТРИХОВКА СОСТОИТ ИЗ 2 И БОЛЕЕ КОНТУРОВ, КОТОРЫЕ НЕ ВЛОЖЕНЫ ДРУГ В ДРУГА, //ТО ЭТИ КОНТУРЫ ДОЛЖНЫ РАССМАТРИВАТЬСЯ КАК ОТДЕЛЬНЫЕ ШТРИХОВКИ!!! HatchNestingTree hatchNestingTree = new HatchNestingTree(boundaries, extends, ptsCollList, ptParamsList, hatch); List <HatchData> currHatchData = hatchNestingTree.GetHatchData(); currHatchData.AddRange(splitHatchData);//добавить контуры, полученные из взаимно пересекающихся контуров //currHatchData.AddRange(decomposeHatchData); allHatchData.AddRange(currHatchData); //Каждая штриховка имеет диапазон по X от начала до конца по оси. //В общую очередь событий сохраняются события начала и конца штриховки foreach (HatchData hd in currHatchData) { hd.AddEventsToQueue(eventQueue); } } //Трассу разбить на отрезки, на которых будут вставлены прямолинейные сегменты штриховок Polyline alignmentPoly = null; try { alignmentPoly = (Polyline)tr.GetObject(AlignmentPolyId, OpenMode.ForRead); } catch (Autodesk.AutoCAD.Runtime.Exception) { return; } int segments = alignmentPoly.NumberOfVertices - 1; List <AlignmentSegment> alignmentSegments = new List <AlignmentSegment>(); Action <Point2d, Point2d> addAlignmentSegment = new Action <Point2d, Point2d>((p0, p1) => { double start = alignmentPoly.GetDistAtPoint(new Point3d(p0.X, p0.Y, 0)); double end = alignmentPoly.GetDistAtPoint(new Point3d(p1.X, p1.Y, 0)); if (Math.Abs(start - end) > Tolerance.Global.EqualPoint)//TODO: Это спорный момент - ведь может быть большое множество очень коротких участков подряд! { Vector2d startDir = p1 - p0; alignmentSegments.Add(new AlignmentSegment(start, end, p0, startDir)); } }); for (int i = 0; i < segments; i++) { SegmentType segmentType = alignmentPoly.GetSegmentType(i); Point2d startLoc = alignmentPoly.GetPoint2dAt(i); Point2d endLoc = alignmentPoly.GetPoint2dAt(i + 1); switch (segmentType) { case SegmentType.Line: addAlignmentSegment(startLoc, endLoc); break; case SegmentType.Arc: CircularArc2d arc = new CircularArc2d(startLoc, endLoc, alignmentPoly.GetBulgeAt(i), false); Interval interval = arc.GetInterval(); PointOnCurve2d[] samplePts = arc.GetSamplePoints(interval.LowerBound, interval.UpperBound, 0.1); for (int n = 0; n < samplePts.Length - 1; n++) { addAlignmentSegment(samplePts[n].Point, samplePts[n + 1].Point); } break; } } //проход по каждому отрезку трассы (диапазон отрезка - диапазон длины полилинии) HashSet <HatchData> currentHatchData = new HashSet <HatchData>(); foreach (AlignmentSegment alignmentSegment in alignmentSegments) { if (eventQueue.Count == 0) { break; //штриховки закончились } //Получить те штриховки, диапазон по X которых пересекается с диапазоном текущего отрезка //(СКАНИРУЮЩАЯ ЛИНИЯ: события - начало, конец штриховки) HashSet <HatchData> intervalHatchData = new HashSet <HatchData>(currentHatchData);//штриховки пришедшие из предыдущего участка остаются все //Собрать все события до конца сегмента //Если при проходе от начала до конца сегмента какая-то штриховка проходится полностью от начала до конца, то //все ее контуры без изменений должны быть переданы для создания М-полигона!!! (для них обход графа не нужен!) HashSet <HatchData> startedInsideInterval = new HashSet <HatchData>(); List <HatchData> hatchesCompletelyInsideInterval = new List <HatchData>(); while (eventQueue.Count > 0) { HatchEvent nextEvent = eventQueue.FindMin(); if (nextEvent.Position > alignmentSegment.End) { break; } else if (nextEvent.Start) { //добавить штриховку в текущий набор HatchData hd = eventQueue.DeleteMin().HatchData; currentHatchData.Add(hd); //добавлять в набор текущего интервла только в том случае, //если сканирующая линия еще не дошла до конца интервала if (nextEvent.Position < alignmentSegment.End && !Utils.LengthIsEquals(nextEvent.Position, alignmentSegment.End)) //Допуск нужен { startedInsideInterval.Add(hd); intervalHatchData.Add(hd); } } else { //убрать штриховку из текущего набора HatchData hd = eventQueue.DeleteMin().HatchData; currentHatchData.Remove(hd); if (startedInsideInterval.Contains(hd)) { hatchesCompletelyInsideInterval.Add(hd); } } } foreach (HatchData hd in hatchesCompletelyInsideInterval) { HatchSegmentData hsd = new HatchSegmentData(hd); alignmentSegment.HatchSegmentData.Add(hsd); hsd.Polygons = hd.GetAllBoundaries(); } intervalHatchData.ExceptWith(hatchesCompletelyInsideInterval); foreach (HatchData hd in intervalHatchData) { HatchSegmentData hsd = new HatchSegmentData(hd); alignmentSegment.HatchSegmentData.Add(hsd); //для каждой штриховки выполнить построение и обход графа сегмента штриховки HatchSegmentGraph graph = new HatchSegmentGraph(alignmentSegment.Start, alignmentSegment.End, hd, doc.Editor); //сохранить наборы полигонов для текущего диапазона hsd.Polygons = graph.Result; } } //для каждого диапазона создать полученные полигоны в 3d BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable; BlockTableRecord ms = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); BlockTableRecord btr = new BlockTableRecord();//Каждый профиль в отдельный блок btr.Name = Guid.NewGuid().ToString(); ObjectId btrId = bt.Add(btr); tr.AddNewlyCreatedDBObject(btr, true); foreach (AlignmentSegment alignmentSegment in alignmentSegments) { List <Entity> flatObjs = new List <Entity>(); foreach (HatchSegmentData hsd in alignmentSegment.HatchSegmentData) { //PlaneSurface hsd.GetNesting(); Dictionary <Point2dCollection, List <Point2dCollection> > bwhs = hsd.GetBoundariesWithHoles(); foreach (KeyValuePair <Point2dCollection, List <Point2dCollection> > bwh in bwhs) { //создать Region Region region = null; using (Polyline poly = new Polyline()) { for (int i = 0; i < bwh.Key.Count; i++) { poly.AddVertexAt(i, bwh.Key[i], 0, 0, 0); } poly.Closed = true; DBObjectCollection coll = new DBObjectCollection(); coll.Add(poly); try { DBObjectCollection regionColl = Region.CreateFromCurves(coll); foreach (DBObject dbo in regionColl) { region = (Region)dbo; break; } } catch { } } //из Region создать PlaneSurface if (region != null) { using (PlaneSurface planeSurface = new PlaneSurface()) { planeSurface.CreateFromRegion(region); planeSurface.LayerId = hsd.Hatch.LayerId; planeSurface.ColorIndex = 256; ObjectId planeSurfaceId = ms.AppendEntity(planeSurface); tr.AddNewlyCreatedDBObject(planeSurface, true); //вырезать отверстия в PlaneSurface foreach (Point2dCollection holePts2d in bwh.Value) { if (holePts2d.Count < 3) { continue; } using (Polyline poly = new Polyline()) { for (int i = 0; i < holePts2d.Count; i++) { poly.AddVertexAt(i, holePts2d[i], 0, 0, 0); } poly.Closed = true; ObjectIdCollection trimPolyColl = new ObjectIdCollection(); trimPolyColl.Add(ms.AppendEntity(poly)); tr.AddNewlyCreatedDBObject(poly, true); List <Point2d> ptsList = new List <Point2d>(holePts2d.ToArray()); Point2d pickPt2d = Utils.GetAnyPointInsidePoligon(ptsList, Utils.DirectionIsClockwise(ptsList)); try { AcadDB.Surface.TrimSurface(planeSurfaceId, new ObjectIdCollection(), trimPolyColl, new Vector3dCollection() { Vector3d.ZAxis }, new Point3d(pickPt2d.X, pickPt2d.Y, 0), -Vector3d.ZAxis, false, false); } catch /*(Exception ex)*/ { //Вывод в командную строку Utils.ErrorToCommandLine(doc.Editor, "Ошибка при попытке вырезания отверстия в поверхности" /*, ex*/); } //Удалить все объекты, добавленные в чертеж! poly.Erase(); } } flatObjs.Add((Entity)planeSurface.Clone()); //Удалить все объекты, добавленные в чертеж! planeSurface.Erase(); } region.Dispose(); } } } foreach (Entity ent in flatObjs) { ent.TransformBy(alignmentSegment.Transform); /*ms*/ btr.AppendEntity(ent); tr.AddNewlyCreatedDBObject(ent, true); ent.Dispose(); } } BlockReference br = new BlockReference(Point3d.Origin, btrId); ms.AppendEntity(br); tr.AddNewlyCreatedDBObject(br, true); if (selfintersectingLoops.Count > 0) { Utils.ErrorToCommandLine(doc.Editor, "Отбраковано самопересекающихся контуров штриховок - " + selfintersectingLoops.Count + " (отмечены на профиле)"); ObjectId layerId = Utils.CreateLayerIfNotExists("САМОПЕРЕСЕКАЮЩИЙСЯ КОНТУР ШТРИХОВКИ", db, tr, color: Color.FromColorIndex(ColorMethod.ByAci, 1), lineWeight: LineWeight.LineWeight200); Matrix2d returnTransform = transform.Inverse(); foreach (Point2dCollection pts in selfintersectingLoops) { using (Polyline selfIntersectingPoly = new Polyline()) { selfIntersectingPoly.LayerId = layerId; selfIntersectingPoly.ColorIndex = 256; for (int i = 0; i < pts.Count; i++) { Point2d pt = pts[i].TransformBy(returnTransform); selfIntersectingPoly.AddVertexAt(i, pt, 0, 0, 0); } toHighlight.Add(ms.AppendEntity(selfIntersectingPoly)); tr.AddNewlyCreatedDBObject(selfIntersectingPoly, true); //selfIntersectingPoly.Highlight(); } } } tr.Commit(); } } ps.Visible = false; if (toHighlight.Count > 0) { using (Transaction tr = doc.Database.TransactionManager.StartTransaction()) { foreach (ObjectId id in toHighlight) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead); ent.Highlight(); } tr.Commit(); } } } } catch (System.Exception ex) { GeologyConvertationCommand.ClosePalette(null, null); CommonException(ex, "Ошибка при создании 3d профиля геологии"); } }
/// <summary> /// 计算一段填方区间(填方段的两个边界交点之间的区间)的挖台阶量 /// </summary> /// <param name="startStation"></param> /// <param name="endStation"></param> private List <LongitudinalStairExcav> CalculateFillRange(double startStation, double endStation) { if (endStation - startStation < _criterion.最小区间宽度) { return(null); } // 求分段交点(集合中至少有两个值) var xy = new List <double[]>(); for (double x = startStation; x < endStation; x += _criterion.台阶宽度) { var intersVerticalGround = new CurveCurveIntersector2d(_longitudinalSection.GroundCurve2d, new Line2d(new Point2d(x, 0), new Vector2d(0, 1))); xy.Add(new double[] { x, intersVerticalGround.GetIntersectionPoint(0).Y }); } var stairsInFillZone = new List <LongitudinalStairExcav>(); // 计算此区间内所有坡度较陡的台阶 for (int i = 0; i < xy.Count - 1; i++) { var ratio = Math.Abs((xy[i + 1][1] - xy[i][1]) / ((xy[i + 1][0] - xy[i][0]))); if (ratio > _criterion.临界纵坡) { // 挖台阶的三角形面积 var area = Math.Abs((xy[i + 1][0] - xy[i][0]) * (xy[i + 1][1] - xy[i][1])) / 2; stairsInFillZone.Add(new LongitudinalStairExcav(xy[i][0], xy[i + 1][0], stairArea: area)); } } // 这里为了避免区间太密,作出一个强制处理:对同一个填方桩号区间内的所有满足条件的台阶区间进行合并,保证合并后的每一个区间的长度不小于设定的最小宽度 // 但是处理之后,总的挖台阶面积还是此区间内有效的台阶的三角形面积之和 int count = stairsInFillZone.Count; if (count == 0 || stairsInFillZone[count - 1].EndStation - stairsInFillZone[0].StartStation < _criterion.最小区间宽度) { // 表示此填方区间内,所有的台阶(算上分离的)之间的距离都小于 10 m,此时认为不作挖台阶处理 return(null); } else { var stairsInFillZone1 = new List <LongitudinalStairExcav>(); // 将一些分离的台阶进行合并,确保其距离不小于10m;但是处理之后,总的挖台阶面积还是此区间内有效的台阶的三角形面积之和 // 1. 将直接相连的台阶进行合并 var lastStair = stairsInFillZone[0]; LongitudinalStairExcav thisStair; stairsInFillZone1.Add(lastStair); for (int i = 1; i < count; i++) { thisStair = stairsInFillZone[i]; if (lastStair.IsMergeable(thisStair)) { lastStair.Merge(thisStair); } else { lastStair = thisStair; stairsInFillZone1.Add(thisStair); } } // 合并后,整个填方区间内,剩下相互分离的多个台阶子区间 // 2. 对于初步合并后自身宽度不足10m,左右10m内又没有其他台阶的项,直接删除 count = stairsInFillZone1.Count; if (count == 1) { // 如果合并后只剩一段,则直接返回 return(stairsInFillZone1); } else { // 从小桩号往大桩号前进式合并 stairsInFillZone = new List <LongitudinalStairExcav>(); LongitudinalStairExcav validatedStair; LongitudinalStairExcav backStair = stairsInFillZone1[0]; LongitudinalStairExcav frontStair = stairsInFillZone1[1]; // 整个填方段起码有三段分离的台阶子区间 for (int i = 0; i < count - 1; i++) { frontStair = stairsInFillZone1[i + 1]; validatedStair = MergeSeperatedStair(backStair, ref frontStair); if (validatedStair != null) { stairsInFillZone.Add(validatedStair); } backStair = frontStair; } // 最后一个子区间 if (frontStair.GetLength() >= _criterion.最小区间宽度) { stairsInFillZone.Add(frontStair); } return(stairsInFillZone); } } }
protected override void BuildProcessing(MillingCommandGenerator generator) { var toolThickness = Tool.Thickness.Value; var profile = ProcessingArea[0].GetCurve(); if (Delta != 0) { profile = (Curve)profile.GetOffsetCurves(Delta)[0]; } var zMax = profile.GetStartEndPoints().Max(p => p.Y); generator.SetZSafety(ZSafety, zMax); var xMax = 0D; using (var curve = profile.ToCompositeCurve2d()) using (var ray = new Ray2d()) using (var intersector = new CurveCurveIntersector2d()) { var angleC = 360; var gCode = 2; for (var z = StartZ; z > 0; z -= StepZ) { var xMin = RadiusMin; for (int i = 0; i < 3; i++) { ray.Set(new Point2d(0, z + i * toolThickness / 2), Vector2d.XAxis); intersector.Set(curve, ray); if (intersector.NumberOfIntersectionPoints == 1) { xMin = Math.Max(xMin, intersector.GetIntersectionPoint(0).X); } } if (xMin == 0) { throw new Exception("Нет точек пересечения с профилем"); } var x = Math.Max(xMin, RadiusMax - Penetration); var s = x - xMin; int passCount = (int)Math.Ceiling(s / Penetration); var dx = s > Consts.Epsilon ? s / passCount : 1; if (generator.IsUpperTool) { generator.Move(0, -x - ZSafety, angleC: 0, angleA: 90); } else { generator.Transition(y: -x - ZSafety, feed: CuttingFeed); } generator.Transition(z: z); do { var arc = new Arc(new Point3d(0, 0, z), x, Math.PI * 1.5, Math.PI * 1.5 - Consts.Epsilon); generator.Cutting(0, -x, z, PenetrationFeed); generator.GCommand(CommandNames.Cutting, gCode, angleC: angleC, curve: arc, center: arc.Center.To2d(), feed: CuttingFeed); angleC = 360 - angleC; gCode = 5 - gCode; x -= dx; }while (x >= xMin - Consts.Epsilon); xMax = Math.Max(xMin, RadiusMax); } generator.Transition(y: -xMax - ZSafety, feed: PenetrationFeed); generator.Uplifting(); } }