using Autodesk.Revit.DB; namespace ShrlAlgoToolkit.RevitAddins.RvIndependent.MetroGauges; using Curve = LandXMLData.Curve; using Interval = LandXMLData.Interval; using LandXMLData_Alignment = LandXMLData.Alignment; using LandXMLData_CircCurve = LandXMLData.CircCurve; using LandXMLData_Spiral = LandXMLData.Spiral; using Line = LandXMLData.Line; public class CircuitHelper { /// /// 获取线路所有竖曲线区间 /// /// /// public Dictionary> DictCir(LandXMLData_Alignment al) { var prof = al.GroundProfile; Dictionary> dictcir = new(); for (int i = 0; i < prof.Count - 1; i++) { if (prof[i].GetType() == typeof(CircCurve)) { LandXMLData_CircCurve c = (LandXMLData_CircCurve)prof[i]; SpaceXYZ stap = new(prof[i - 1].First, prof[i - 1].Second); SpaceXYZ pi = new(prof[i].First, prof[i].Second); SpaceXYZ endp = new(prof[i + 1].First, prof[i + 1].Second); List pts = GetStartCenterEnd(c, stap, pi, endp); dictcir.Add(c, pts); } } return dictcir; } /// /// 得到区域内的参考点 /// /// /// /// /// public List Get3DRefPointOfRegion(LandXMLData_Alignment align, Region reg, double interval) { List pts = new(); for (double i = reg.StartStation; i < reg.EndStation; i += interval) { XYZ pt = new(GetHorizonCoord(i, align).X, GetHorizonCoord(i, align).Y, GetElevAtStation(i, align)); pts.Add(pt); } XYZ lastp = GetHorizonCoord(reg.EndStation, align); XYZ lastpt = new(lastp.X, lastp.Y, GetElevAtStation(reg.EndStation, align)); pts.Add(lastpt); return pts; } /// /// 获取圆曲线上的点(坐标英制) /// /// 沿着线路方向从圆曲线起点行走过的距离 /// /// public SpaceXYZ GetArcPtCoord(double length, Curve c) { double r = Math.Sqrt( Math.Pow(c.Center.Second - c.Start.Second, 2.0) + Math.Pow(c.Center.First - c.Start.First, 2.0) ); //弧度 double rad = length / r; //计算圆心起点直线与X轴弧度(带符号) double num3 = Math.Atan2(c.Start.First - c.Center.First, c.Start.Second - c.Center.Second); double Xrad = num3 < 0.0 ? (2 * Math.PI) + num3 : num3; //总弧度 double Totalrad = c.Length / r; //斜率判断圆弧左转右转(起点与圆心直线斜率小于终点与圆心直线斜率,左转,逆时针;大于则右转) int dir = -1; if ( ((c.Start.Second - c.Center.Second) * (c.End.First - c.Center.First)) - ((c.Start.First - c.Center.First) * (c.End.Second - c.Center.Second)) < 0.0 ) { rad = -rad; } if (Math.Abs(Totalrad) > Math.PI) { rad = -rad; } double x = (r * Math.Cos((-dir * rad) + Xrad)) + c.Center.Second; double y = (r * Math.Sin((-dir * rad) + Xrad)) + c.Center.First; return new SpaceXYZ(x * 1000 / 304.8, y * 1000 / 304.8, 0); } /// /// 纵断圆弧高程(英制) /// /// /// /// /// /// public static double GetArcY(double station, LandXMLData_CircCurve c, SpaceXYZ circleCenter, double radius) { double[] y = new double[2]; //(x-x0)^2*+y0^2-R^2 double num = Math.Pow(radius, 2.0) - Math.Pow(station - circleCenter.Station, 2.0); //4*R^2-4(x-x0)^2 //double num2 = 4.0 * Math.Pow(circleCenter.Bottom, 2.0) - 4.0 * num; //y-y0的开方 double num3 = Math.Sqrt(num); //y-y0值的不同符号 y[0] = circleCenter.Elevation - num3; y[1] = circleCenter.Elevation + num3; SpaceXYZ pvi = new(c.First, c.Second); double elevation; { double l1 = GetLength(pvi, new SpaceXYZ(station, y[0])); double l2 = GetLength(pvi, new SpaceXYZ(station, y[1])); elevation = l1 <= l2 ? y[0] : y[1]; } return elevation * 1000 / 304.8; } /// /// 获取圆心坐标 /// /// /// /// /// /// /// /// public SpaceXYZ GetCircleCenter(double x1, double y1, double x2, double y2, double r, bool bump) { double c1 = ((x2 * x2) - (x1 * x1) + (y2 * y2) - (y1 * y1)) / (2 * (x2 - x1)); double c2 = (y2 - y1) / (x2 - x1); //斜率 double a = (c2 * c2) + 1; double b = (2 * x1 * c2) - (2 * c1 * c2) - (2 * y1); double c = (x1 * x1) - (2 * x1 * c1) + (c1 * c1) + (y1 * y1) - (r * r); //为true时,为凹曲线,false为凸曲线 if (bump) { double y = (-b + Math.Sqrt((b * b) - (4 * a * c))) / (2 * a); double x = c1 - (c2 * y); return new SpaceXYZ(x, y); } else { double y = (-b - Math.Sqrt((b * b) - (4 * a * c))) / (2 * a); double x = c1 - (c2 * y); return new SpaceXYZ(x, y); } } /// /// 获取任意桩号位置的高程 /// /// /// /// public double GetElevAtStation(double station, LandXMLData_Alignment al) { double elev = 0.0; var prof = al.GroundProfile; //var liprof = al.Profile.ProfileCurve; //var prof = liprof[0]; Dictionary> dictcir = DictCir(al); //+0.1保证终点桩号的小数能满足条件 for (int i = 0; i < prof.Count - 1; i++) { if (station >= prof[i].First && station <= prof[i + 1].First + 0.1) { SpaceXYZ stap = new(prof[i].First, prof[i].Second); SpaceXYZ endp = new(prof[i + 1].First, prof[i + 1].Second); elev = GetLineY(station, stap, endp); foreach (KeyValuePair> cir in dictcir) { if (station >= cir.Value[0].Station && station <= cir.Value[2].Station) { elev = GetArcY(station, cir.Key, cir.Value[1], cir.Key.Radius); return elev; } } return elev; } } //if (prof[i].GetType() == typeof(TextPoint2D)) //{ // SpaceXYZ stap = new SpaceXYZ(prof[i].First, prof[i].Second); // SpaceXYZ endp = new SpaceXYZ(prof[i + 1].First, prof[i + 1].Second); // elev = GetLinePtY(station, stap, endp); //} //GetStartAndEndSta() return elev; } /// /// 获取任意桩号位置的水平坐标 /// /// /// /// public SpaceXYZ GetHorizonCoord(double station, LandXMLData_Alignment al) { List hc = al.CoordGeom.HorizonCurve; SpaceXYZ p = new(0.0, 0.0, 0.0); Dictionary dicts = GetIntervalRegion(al); //if (station > al.Length + al.StationStart) //{ // return p; //} foreach (KeyValuePair dict in dicts) { double sta = dict.Value.StartStation; double end = dict.Value.EndStation; //加0.1保证终点桩号的小数能满足条件 if (station >= dict.Value.StartStation && station <= dict.Value.EndStation + 0.1) { double distance = station - dict.Value.StartStation; if (dict.Key.GetType() == typeof(Autodesk.Revit.DB.Curve)) { Curve c = (Curve)dict.Key; //公制转英制,但是显示的时候英制转为公制 p = GetArcPtCoord(distance, c); //ReferencePoint refpt = formdoc.FamilyCreate.NewReferencePoint(p); //refpts.Append(refpt); //SpaceXYZ spt = new SpaceXYZ(p.X, p.Y, p.Z); //spt.Station = j + station; //spt.Bottom = GetElevAtStation(spt.Station, al); //spts.Add(spt); } else if (dict.Key.GetType() == typeof(Line)) { Line l = (Line)dict.Key; p = GetLinePtCoord(distance, l); } //else if (dict.Key.GetType() == typeof(landxml.Spiral)) else { LandXMLData_Spiral s = (LandXMLData_Spiral)dict.Key; p = GetSpiralPtCoord(distance, s); } } } return p; } /// /// 得到平曲线参考点 /// /// /// /// public List GetHorizonPts(LandXMLData_Alignment al, Document doc) { List pts = new(); var hc = al.CoordGeom.HorizonCurve; //double station = al.StationStart; for (int i = 0; i < hc.Count; i++) { //if (i - 1 >= 0) //{ // station += hc[i - 1].Length; //} if (hc[i].GetType() == typeof(Autodesk.Revit.DB.Curve)) { Curve c = (Curve)hc[i]; for (int j = 0; j < c.Length; j++) { //公制转英制,但是显示的时候英制转为公制 XYZ p = GetArcPtCoord(j, c); pts.Add(p); //ReferencePoint refpt = formdoc.FamilyCreate.NewReferencePoint(p); //refpts.Append(refpt); //SpaceXYZ spt = new SpaceXYZ(p.X, p.Y, p.Z); //spt.Station = j + station; //spt.Bottom = GetElevAtStation(spt.Station, al); //spts.Add(spt); } } else if (hc[i].GetType() == typeof(Autodesk.Revit.DB.Line)) { Line l = (Line)hc[i]; for (int j = 0; j < l.Length; j++) { XYZ p = GetLinePtCoord(j, l); pts.Add(p); } } else if (hc[i].GetType() == typeof(Spiral)) { LandXMLData_Spiral s = (LandXMLData_Spiral)hc[i]; for (int j = 0; j < s.Length; j++) { XYZ p = GetSpiralPtCoord(j, s); pts.Add(p); } } } //最后一点 XYZ last = new XYZ(hc[hc.Count - 1].End.Second, hc[hc.Count - 1].End.First, 0.0) * 1000 / 304.8; pts.Add(last); //ReferencePointArray array = new ReferencePointArray(); //for (int i = 0; i < pts.Count; i++) //{ // ReferencePoint refp = doc.FamilyCreate.NewReferencePoint(pts[i]); // array.Append(refp); //} return pts; } /// /// 按曲线类型获取区域 /// /// /// public Dictionary GetIntervalRegion(LandXMLData_Alignment al) { var hc = al.CoordGeom.HorizonCurve; Dictionary regions = new(); regions.Clear(); double currentsta = al.StationStart; double endsta = 0.0; if (al != null) { for (int i = 0; i < hc.Count; i++) { if (i - 1 >= 0) { //currentsta += Math.Round(hc[i - 1].Length, 3, MidpointRounding.AwayFromZero); currentsta += hc[i - 1].Length; } Region re = new(currentsta, endsta); if (hc[i].GetType() == typeof(Autodesk.Revit.DB.Curve)) { Curve c = (Curve)hc[i]; //re.EndStation = Math.Round(c.Length + currentsta, 3, MidpointRounding.AwayFromZero); re.EndStation = c.Length + currentsta; } else if (hc[i].GetType() == typeof(Autodesk.Revit.DB.Line)) { Line l = (Line)hc[i]; //re.EndStation = Math.Round(l.Length + currentsta, 3, MidpointRounding.AwayFromZero); re.EndStation = l.Length + currentsta; } else { LandXMLData_Spiral s = (LandXMLData_Spiral)hc[i]; re.EndStation = s.Length + currentsta; } regions.Add(hc[i], re); } } //return allregions; return regions; } /// /// 计算两点直线距离 /// /// /// /// public static double GetLength(SpaceXYZ p1, SpaceXYZ p2) { double num = p1.Station - p2.Station; double num2 = p1.Elevation - p2.Elevation; return Math.Sqrt((num * num) + (num2 * num2)); } /// /// 获取直线上的点(坐标英制) /// /// 沿着线路方向从直线起点行走过的距离 /// /// public SpaceXYZ GetLinePtCoord(double length, Line line) { XYZ startCoord = new(line.Start.Second, line.Start.First, 0); XYZ endCoord = new(line.End.Second, line.End.First, 0); //Autodesk.Revit.DB.Point stapt = Autodesk.Revit.DB.Point.Create(startCoord); XYZ xyz = endCoord - startCoord; double length2 = xyz.GetLength(); //if (length > line.Length) //{ // System.Windows.MessageBox.ShowAhead("长度错误"); //} XYZ p = xyz * length / length2; XYZ pt = p + startCoord; SpaceXYZ sp = new(pt.X * 1000 / 304.8, pt.Y * 1000 / 304.8, pt.Z * 1000 / 304.8); return sp; } /// /// 纵断直线高程(英制) /// /// /// /// /// public double GetLineY(double station, SpaceXYZ startpoint, SpaceXYZ endpoint) { double deltaY = endpoint.Elevation - startpoint.Elevation; double deltaX = endpoint.Station - startpoint.Station; double k = deltaY / deltaX; double c = startpoint.Elevation - (k * startpoint.Station); double elev = (k * station) + c; return elev * 1000 / 304.8; //double[] lineBetween2Points = GetLineBetween2Points(startpoint, endpoint); //if (lineBetween2Points[1] != 0.0) //{ // return (-lineBetween2Points[0] * station - lineBetween2Points[2]) / lineBetween2Points[1]; //} //if (startpoint.Bottom <= endpoint.Bottom) //{ // return endpoint.Bottom; //} //return startpoint.Bottom; } /// /// 获取缓和曲线上的点(坐标英制) /// /// 沿着线路方向从缓和曲线起点行走过的距离 /// 缓和曲线 /// 坐标点 public SpaceXYZ GetSpiralPtCoord(double length, LandXMLData_Spiral spiral) { //左右转向 double num = ((spiral.PI.Second - spiral.Start.Second) * (spiral.End.First - spiral.Start.First)) - ((spiral.PI.First - spiral.Start.First) * (spiral.End.Second - spiral.Start.Second)); //转角符号右为正,左为负 double direction = num >= 0.0 ? 1 : -1; //根据起始半径,1:起点为直线,起始曲率半径无穷大;0:起点为圆曲线,起始半径为圆曲线半径,判断是前缓和曲线还是后缓和曲线,前为1,后为0 int fOrb = spiral.RadiusStart is double.PositiveInfinity or double.MaxValue ? 1 : 0; //n3为1取终点半径,n3为0取起点半径(圆曲线半径) double R = fOrb != 0 ? spiral.RadiusEnd : spiral.RadiusStart; //(缓和曲线长/圆曲线半径)^2 用于计算TotalX,TotalY num = spiral.Length * spiral.Length / (R * R); //x,y方向总距离 spiral.TotalX = spiral.Length * (1.0 - (num / 40.0) + (num * num / 3456.0)); spiral.TotalY = num * R / 6.0 * (1.0 - (num / 56.0) + (num * num / 7040.0)); //当前长度 double l = length; double totalx = 0.0; double totaly = 0.0; double num8 = 1.0; if (fOrb == 0) { l = spiral.Length - length; num8 = -1.0; //x,y方向总距离 totalx = spiral.TotalX; totaly = spiral.TotalY; } num = l * l / (2.0 * R * spiral.Length); double x = totalx + (num8 * l * (1.0 - (num * num / 10.0) + (Math.Pow(num, 4.0) / 216.0))); double y = direction * (-totaly + (l * ((num / 3.0) - (Math.Pow(num, 3.0) / 42.0) + (Math.Pow(num, 5.0) / 1320.0)))); //转东北距同时转英制 return TransformXYtoNE(x, y, direction * num8, spiral); } /// /// 获取圆弧纵断线起点圆心终点 /// /// /// /// /// /// public List GetStartCenterEnd(LandXMLData_CircCurve c, SpaceXYZ start, SpaceXYZ pi, SpaceXYZ end) { List li = new(); //圆心角 double w = c.CurveLength / c.Radius; //交点距圆弧起点桩号距离(X轴) double l = Math.Tan(w / 2) * c.Radius; //起点交点连线 double θ1 = RadianFromHorizon(start, pi); //交点终点连线 double θ2 = RadianFromHorizon(pi, end); //圆曲线起点 SpaceXYZ startpoint = new(pi.Station - (l * Math.Cos(θ1)), pi.Elevation - (l * Math.Sin(θ1))); SpaceXYZ endpoint = new(pi.Station + (l * Math.Cos(θ2)), pi.Elevation + (l * Math.Sin(θ2))); li.Add(startpoint); if (θ2 - θ1 > 0) { //凹曲线 //SpaceXYZ centerpoint = new SpaceXYZ(start.Station - c.Radius * Math.Sin(θ1), start.Bottom + c.Radius * Math.Cos(θ1)); SpaceXYZ centerpoint = GetCircleCenter( startpoint.Station, startpoint.Elevation, endpoint.Station, endpoint.Elevation, c.Radius, true ); li.Add(centerpoint); } else { //凸曲线 //SpaceXYZ centerpoint = new SpaceXYZ(start.Station + c.Radius * Math.Sin(θ1), start.Bottom - c.Radius * Math.Cos(θ1)); SpaceXYZ centerpoint = GetCircleCenter( startpoint.Station, startpoint.Elevation, endpoint.Station, endpoint.Elevation, c.Radius, false ); li.Add(centerpoint); } //圆曲线终点 li.Add(endpoint); return li; } /// /// 纵断直线与X的夹角(弧度) /// /// /// /// public double RadianFromHorizon(SpaceXYZ start, SpaceXYZ end) { return Math.Atan((start.Elevation - end.Elevation) / (start.Station - end.Station)); } /// /// 坐标转换 /// /// /// /// public static XYZ TransformPoint(XYZ point, Transform transform) { double x = point.X; double y = point.Y; double z = point.Z; //获取变换的原点和基向量 XYZ b0 = transform.get_Basis(0); XYZ b1 = transform.get_Basis(1); XYZ b2 = transform.get_Basis(2); XYZ origin = transform.Origin; //对原来坐标系统的点在新的坐标系统进行变换 double xTemp = (x * b0.X) + (y * b1.X) + (z * b2.X) + origin.X; double yTemp = (x * b0.Y) + (y * b1.Y) + (z * b2.Y) + origin.Y; double zTemp = (x * b0.Z) + (y * b1.Z) + (z * b2.Z) + origin.Z; return new XYZ(xTemp, yTemp, zTemp); } /// /// 缓和曲线坐标转东北距(坐标英制) /// /// /// /// /// /// public SpaceXYZ TransformXYtoNE(double x, double y, double signTotalY, LandXMLData_Spiral spi) { double DeltaY = spi.End.First - spi.Start.First; double DeltaX = spi.End.Second - spi.Start.Second; spi.TotalY = signTotalY * spi.TotalY; double num3 = ((spi.TotalX * DeltaY) - (spi.TotalY * DeltaX)) / (Math.Pow(spi.TotalX, 2.0) + Math.Pow(spi.TotalY, 2.0)); double num4 = ((spi.TotalX * DeltaX) + (spi.TotalY * DeltaY)) / (Math.Pow(spi.TotalX, 2.0) + Math.Pow(spi.TotalY, 2.0)); double num5 = (num4 * x) - (num3 * y); double num6 = (num3 * x) + (num4 * y); num6 += spi.Start.First; return new SpaceXYZ((num5 + spi.Start.Second) * 1000 / 304.8, num6 * 1000 / 304.8, 0.0); } }