/// <summary> /// Returns the list of Dynamo curves that defines the Alignment. /// </summary> /// <returns>A list of lines and arcs that decribe the Alignment.</returns> /// <remarks>The tool returns only lines and arcs.</remarks> public IList <Curve> GetCurves() { Utils.Log("Alignment.GetCurves Started..."); IList <Curve> output = new List <Curve>(); foreach (AeccAlignmentEntity e in this._entities) { switch (e.Type) { case AeccAlignmentEntityType.aeccTangent: { AeccAlignmentTangent a = e as AeccAlignmentTangent; output.Add(Line.ByStartPointEndPoint( Point.ByCoordinates(a.StartEasting, a.StartNorthing), Point.ByCoordinates(a.EndEasting, a.EndNorthing))); break; } case AeccAlignmentEntityType.aeccArc: { AeccAlignmentArc a = e as AeccAlignmentArc; Arc arc = null; if (!a.Clockwise) { arc = Arc.ByCenterPointStartPointEndPoint( Point.ByCoordinates(a.CenterEasting, a.CenterNorthing), Point.ByCoordinates(a.StartEasting, a.StartNorthing), Point.ByCoordinates(a.EndEasting, a.EndNorthing)); } else { arc = Arc.ByCenterPointStartPointEndPoint( Point.ByCoordinates(a.CenterEasting, a.CenterNorthing), Point.ByCoordinates(a.EndEasting, a.EndNorthing), Point.ByCoordinates(a.StartEasting, a.StartNorthing)); } output.Add(arc); //var p1 = a.PassThroughPoint1; //var p2 = a.PassThroughPoint2; //var p3 = a.PassThroughPoint3; //output.Add(Arc.ByThreePoints(Point.ByCoordinates(p1.X, p1.Y), // Point.ByCoordinates(p2.X, p2.Y), // Point.ByCoordinates(p3.X, p3.Y))); break; } case AeccAlignmentEntityType.aeccSpiralCurveSpiralGroup: { AeccAlignmentSCSGroup a = e as AeccAlignmentSCSGroup; AeccAlignmentEntity before = this._entities.Item(e.EntityBefore); AeccAlignmentEntity after = this._entities.Item(e.EntityAfter); Curve beforeCurve = null; Curve afterCurve = null; if (before.Type == AeccAlignmentEntityType.aeccTangent) { AeccAlignmentTangent b = before as AeccAlignmentTangent; beforeCurve = Line.ByStartPointEndPoint( Point.ByCoordinates(b.StartEasting, b.StartNorthing), Point.ByCoordinates(b.EndEasting, b.EndNorthing)); } else if (before.Type == AeccAlignmentEntityType.aeccArc) { AeccAlignmentArc b = before as AeccAlignmentArc; beforeCurve = Arc.ByCenterPointStartPointEndPoint( Point.ByCoordinates(b.CenterEasting, b.CenterNorthing), Point.ByCoordinates(b.StartEasting, b.StartNorthing), Point.ByCoordinates(b.EndEasting, b.EndNorthing)); } if (after.Type == AeccAlignmentEntityType.aeccTangent) { AeccAlignmentTangent b = after as AeccAlignmentTangent; afterCurve = Line.ByStartPointEndPoint( Point.ByCoordinates(b.StartEasting, b.StartNorthing), Point.ByCoordinates(b.EndEasting, b.EndNorthing)); } else if (after.Type == AeccAlignmentEntityType.aeccArc) { AeccAlignmentArc b = after as AeccAlignmentArc; afterCurve = Arc.ByCenterPointStartPointEndPoint( Point.ByCoordinates(b.CenterEasting, b.CenterNorthing), Point.ByCoordinates(b.StartEasting, b.StartNorthing), Point.ByCoordinates(b.EndEasting, b.EndNorthing)); } if (afterCurve != null && beforeCurve != null) { output.Add(Curve.ByBlendBetweenCurves(beforeCurve, afterCurve)); } // Andrew Milford wrote the code for the spirals using Fourier approximation // Get some parameters int entCnt = a.SubEntityCount; for (int i = 0; i < entCnt; i++) { AeccAlignmentEntity subEnt = a.SubEntity(i); AeccAlignmentEntityType alignType = subEnt.Type; switch (alignType) { case AeccAlignmentEntityType.aeccTangent: break; case AeccAlignmentEntityType.aeccArc: AeccAlignmentArc arc = subEnt as AeccAlignmentArc; Arc dArc = null; if (!arc.Clockwise) { dArc = Arc.ByCenterPointStartPointEndPoint( Point.ByCoordinates(arc.CenterEasting, arc.CenterNorthing), Point.ByCoordinates(arc.StartEasting, arc.StartNorthing), Point.ByCoordinates(arc.EndEasting, arc.EndNorthing)); } else { dArc = Arc.ByCenterPointStartPointEndPoint( Point.ByCoordinates(arc.CenterEasting, arc.CenterNorthing), Point.ByCoordinates(arc.EndEasting, arc.EndNorthing), Point.ByCoordinates(arc.StartEasting, arc.StartNorthing)); } output.Add(dArc); break; case AeccAlignmentEntityType.aeccSpiral: // calculate the spiral intervals AeccAlignmentSpiral s = subEnt as AeccAlignmentSpiral; double radIn = s.RadiusIn; double radOut = s.RadiusOut; double length = s.Length; AeccAlignmentSpiralDirectionType dir = s.Direction; // Identify the spiral is the start or end bool isStart = true; double radius; if (Double.IsInfinity(radIn)) { // Start Spiral radius = radOut; } else { // End Spiral radius = radIn; isStart = false; } double A = s.A; // Flatness of spiral double RL = radius * length; //double A = Math.Sqrt(radius * length); List <Point> pts = new List <Point>(); double n = 0; double interval = 2; // 2 meters intervals TODO what if the curve is shorter than 2 meters? int num = Convert.ToInt32(Math.Ceiling(length / interval)); double step = length / num; double dirStart = s.StartDirection; double dirEnd = s.EndDirection; Point ptPI = Point.ByCoordinates(s.PIEasting, s.PINorthing, 0); Point ptStart = Point.ByCoordinates(s.StartEasting, s.StartNorthing, 0); Point ptEnd = Point.ByCoordinates(s.EndEasting, s.EndNorthing, 0); Point pt; double angRot; /* * Paolo Serra - Implementation of Fourier's Transform for the clothoid for a given number of terms * x = Sum[(-1)^t * n ^(4*t+1) / ((2*t)!*(4*t+1)*(2*RL)^(2*t))] for t = 0 -> N * y = Sum[(-1)^t * n ^(4*t+3) / ((2^t + 1)!*(4*t+3)*(2*RL)^(2*t + 1))] for t = 0 -> N */ for (int j = 0; j <= num; j++) { double x = 0; double y = 0; for (int t = 0; t < 8; t++) // first 8 terms of the transform { x += Math.Pow(-1, t) * Math.Pow(n, 4 * t + 1) / (Factorial(2 * t) * (4 * t + 1) * Math.Pow(2 * RL, 2 * t)); y += Math.Pow(-1, t) * Math.Pow(n, 4 * t + 3) / (Factorial(2 * t + 1) * (4 * t + 3) * Math.Pow(2 * RL, 2 * t + 1)); } //double x = n - ((Math.Pow(n, 5)) / (40 * Math.Pow(RL, 2))) + ((Math.Pow(n, 9)) / (3456 * Math.Pow(RL, 4))) - ((Math.Pow(n, 13)) / (599040 * Math.Pow(RL, 6))) + ((Math.Pow(n, 17)) / (175472640 * Math.Pow(RL, 8))); //double y = ((Math.Pow(n, 3)) / (6 * RL)) - ((Math.Pow(n, 7)) / (336 * Math.Pow(RL, 3))) + (Math.Pow(n, 11) / (42240 * Math.Pow(RL, 5))) - (Math.Pow(n, 15) / (9676800 * Math.Pow(RL, 7))); // Flip the Y offset if start spiral is CW OR end spiral is CCW if ((isStart && dir == AeccAlignmentSpiralDirectionType.aeccAlignmentSpiralDirectionRight) || (!isStart && dir == AeccAlignmentSpiralDirectionType.aeccAlignmentSpiralDirectionLeft) ) { y *= -1; } pts.Add(Point.ByCoordinates(x, y, 0)); n += step; } // Create spiral at 0,0 NurbsCurve spiralBase = NurbsCurve.ByControlPoints(pts, 3); // Degree by default is 3 if (isStart) { pt = ptStart; angRot = 90 - (dirStart * (180 / Math.PI)); } else { pt = ptEnd; angRot = 270 - (dirEnd * (180 / Math.PI)); } // Coordinate system on outer spiral point CoordinateSystem csOrig = CoordinateSystem.ByOrigin(pt); CoordinateSystem cs = csOrig.Rotate(pt, Vector.ZAxis(), angRot); NurbsCurve spiral = (NurbsCurve)spiralBase.Transform(cs); output.Add(spiral); break; default: break; } } break; } } } output = SortCurves(output); Utils.Log("Alignment.GetCurves Completed."); return(output); }
/// <summary> /// Returns the list of Dynamo curves that defines the Alignment. /// </summary> /// <param name="tessellation">The length of the tessellation for spirals, by default is 1 unit.</param> /// <returns>A list of curves that represent the Alignment.</returns> /// <remarks>The tool returns only lines and arcs.</remarks> public IList <Curve> GetCurves(double tessellation = 1) { Utils.Log(string.Format("Alignment.GetCurves {0} Started...", this.Name)); IList <Curve> output = new List <Curve>(); if (this._entities == null) { Utils.Log(string.Format("ERROR: Alignment Entities are null", "")); var stations = this.GeometryStations.ToList(); stations.AddRange(this.PIStations.ToList()); stations.AddRange(this.SuperTransStations.ToList()); stations.Sort(); var pts = new List <Point>(); foreach (var s in stations) { pts.Add(this.PointByStationOffsetElevation(s)); } pts = Point.PruneDuplicates(pts).ToList(); output.Add(PolyCurve.ByPoints(pts)); return(output); } Utils.Log(string.Format("Total Entities: {0}", this._entities.Count)); try { var entities = new List <AeccAlignmentEntity>(); for (int c = 0; c < this._entities.Count; ++c) { try { var ce = this._entities.Item(c); Utils.Log(string.Format("Entity: {0}", ce.Type)); if (ce.Type != AeccAlignmentEntityType.aeccArc && ce.Type != AeccAlignmentEntityType.aeccTangent) { int count = ce.SubEntityCount; if (count > 0) { for (int i = 0; i < ce.SubEntityCount; ++i) { try { var se = ce.SubEntity(i); Utils.Log(string.Format("SubEntity: {0}", se.Type)); entities.Add(se); } catch (Exception ex) { Utils.Log(string.Format("ERROR1: {0} {1}", ex.Message, ex.StackTrace)); } } } else { entities.Add(ce); } } else { entities.Add(ce); } } catch (Exception ex) { Utils.Log(string.Format("ERROR2: {0} {1}", ex.Message, ex.StackTrace)); } } Utils.Log(string.Format("Missing Entities: {0}", this._entities.Count - entities.Count)); foreach (AeccAlignmentEntity e in entities) { try { switch (e.Type) { case AeccAlignmentEntityType.aeccTangent: { //Utils.Log(string.Format("Tangent..", "")); AeccAlignmentTangent a = e as AeccAlignmentTangent; var start = Point.ByCoordinates(a.StartEasting, a.StartNorthing); var end = Point.ByCoordinates(a.EndEasting, a.EndNorthing); output.Add(Line.ByStartPointEndPoint(start, end)); start.Dispose(); end.Dispose(); //Utils.Log(string.Format("OK", "")); break; } case AeccAlignmentEntityType.aeccArc: { //Utils.Log(string.Format("Arc..", "")); AeccAlignmentArc a = e as AeccAlignmentArc; Point center = Point.ByCoordinates(a.CenterEasting, a.CenterNorthing); Point start = Point.ByCoordinates(a.StartEasting, a.StartNorthing); Point end = Point.ByCoordinates(a.EndEasting, a.EndNorthing); Arc arc = null; if (!a.Clockwise) { arc = Arc.ByCenterPointStartPointEndPoint(center, start, end); } else { arc = Arc.ByCenterPointStartPointEndPoint(center, end, start); } output.Add(arc); center.Dispose(); start.Dispose(); end.Dispose(); //Utils.Log(string.Format("OK", "")); break; } default: { //Utils.Log(string.Format("Curve...", "")); try { AeccAlignmentCurve a = e as AeccAlignmentCurve; var pts = new List <Point>(); double start = this.Start; try { start = a.StartingStation; } catch (Exception ex) { Utils.Log(string.Format("ERROR11: {0} {1}", ex.Message, ex.StackTrace)); break; } //Utils.Log(string.Format("start: {0}", start)); double length = a.Length; //Utils.Log(string.Format("length: {0}", length)); int subs = Convert.ToInt32(Math.Ceiling(length / tessellation)); if (subs < 10) { subs = 10; } double delta = length / subs; for (int i = 0; i < subs + 1; ++i) { try { double x = 0; double y = 0; this._alignment.PointLocation(start + i * delta, 0, out x, out y); pts.Add(Point.ByCoordinates(x, y)); } catch (Exception ex) { Utils.Log(string.Format("ERROR21: {2} {0} {1}", ex.Message, ex.StackTrace, start + i * delta)); } } //Utils.Log(string.Format("Points: {0}", pts.Count)); if (pts.Count < 2) { Utils.Log(string.Format("ERROR211: not enough points to create a spiral", "")); break; } NurbsCurve spiral = NurbsCurve.ByPoints(pts); // Degree by default is 3 output.Add(spiral); foreach (var pt in pts) { if (pts != null) { pt.Dispose(); } } pts.Clear(); //Utils.Log(string.Format("OK", "")); //prevStation += length; } catch (Exception ex) { Utils.Log(string.Format("ERROR22: {0} {1}", ex.Message, ex.StackTrace)); } break; } } } catch (Exception ex) { Utils.Log(string.Format("ERROR3: {0} {1}", ex.Message, ex.StackTrace)); } } } catch (Exception ex) { Utils.Log(string.Format("ERROR4: {0} {1}", ex.Message, ex.StackTrace)); } output = SortCurves(output); Utils.Log("Alignment.GetCurves Completed."); return(output); }