public void CurvesAreSimilar_NurbsCurve() { var a1 = Point.ByCoordinates(0, 0); var a2 = Point.ByCoordinates(1, 1); var a3 = Point.ByCoordinates(2, -1); var a4 = Point.ByCoordinates(3, 0); var b1 = Point.ByCoordinates(0, 0); var b2 = Point.ByCoordinates(1, -1); var b3 = Point.ByCoordinates(2, 1); var b4 = Point.ByCoordinates(3, 0); var c1 = Point.ByCoordinates(3, 0); var c2 = Point.ByCoordinates(2, 1); var c3 = Point.ByCoordinates(1, -1); var c4 = Point.ByCoordinates(0, 0); var nurbs1 = NurbsCurve.ByPoints(new[] { a1, a2, a3, a4 }); var nurbs2 = NurbsCurve.ByPoints(new[] { b1, b2, b3, b4 }); var nurbs3 = NurbsCurve.ByPoints(new[] { c1, c2, c3, c4 }); var revitNurbs1 = nurbs1.ToRevitType(); var revitNurbs2 = nurbs2.ToRevitType(); var revitNurbs3 = nurbs3.ToRevitType(); Assert.True(CurveUtils.CurvesAreSimilar(revitNurbs1, revitNurbs1)); Assert.False(CurveUtils.CurvesAreSimilar(revitNurbs1, revitNurbs2)); Assert.False(CurveUtils.CurvesAreSimilar(revitNurbs2, revitNurbs3)); }
public void NurbsCurve_ProvidesGoodApproximationForDegree2Curve() { var pts = new[] { Point.ByCoordinates(0, 0, 0) , Point.ByCoordinates(0, 1, 1) , Point.ByCoordinates(0, 1, 0) }; var bspline = NurbsCurve.ByPoints(pts, 2); var revitCurve = bspline.ToRevitType(false); Assert.IsAssignableFrom <Autodesk.Revit.DB.NurbSpline>(revitCurve); var revitSpline = (Autodesk.Revit.DB.NurbSpline)revitCurve; Assert.AreEqual(3, revitSpline.Degree); var tessPts = revitSpline.Tessellate().Select(x => x.ToPoint(false)); //assert the tesselation is very close to original curve foreach (var pt in tessPts) { var closestPt = bspline.ClosestPointTo(pt); Assert.Less(closestPt.DistanceTo(pt), 1e-6); } revitCurve.GetEndPoint(0).ShouldBeApproximately(bspline.StartPoint); revitCurve.GetEndPoint(1).ShouldBeApproximately(bspline.EndPoint); }
/// <summary> /// Given some size parameters, returns a lofted surface with random bumps. /// </summary> public static Surface WobblySurface( double baseX, double baseY, double baseZ, double width, double length, double maxHeight, int uCount, int vCount) { double dx = width / (uCount - 1); double dy = length / (vCount - 1); Random rnd = new Random(); List <Curve> curves = new List <Curve>(); List <Point> pts = null; for (double y = baseY; y <= baseY + length; y += dy) { pts = new List <Point>(); for (double x = baseX; x <= baseX + width; x += dx) { pts.Add(Point.ByCoordinates(x, y, baseZ + maxHeight * rnd.NextDouble())); } curves.Add(NurbsCurve.ByPoints(pts)); } Surface surface = Surface.ByLoft(curves); return(surface); }
public void NurbsCurve_AcceptsStraightReplicatedDegree3NurbsCurve() { var points = Enumerable.Range(0, 10) .Select(x => Autodesk.DesignScript.Geometry.Point.ByCoordinates(x, 0, 0)); var nurbsCurve = NurbsCurve.ByPoints(points, 3); var revitCurve = nurbsCurve.ToRevitType(false); Assert.IsAssignableFrom <Autodesk.Revit.DB.NurbSpline>(revitCurve); var revitSpline = (Autodesk.Revit.DB.NurbSpline)revitCurve; Assert.AreEqual(3, revitSpline.Degree); var tessPts = revitSpline.Tessellate().Select(x => x.ToPoint(false)); //assert the tesselation is very close to original curve foreach (var pt in tessPts) { var closestPt = nurbsCurve.ClosestPointTo(pt); Assert.Less(closestPt.DistanceTo(pt), 1e-6); } revitCurve.GetEndPoint(0).ShouldBeApproximately(nurbsCurve.StartPoint); revitCurve.GetEndPoint(1).ShouldBeApproximately(nurbsCurve.EndPoint); }
/// <summary> /// The logarithmic spiral can be distinguished from the Archimedean spiral by the fact that /// the distances between the turnings of a logarithmic spiral increase in geometric progression, /// while in an Archimedean spiral these distances are constant. /// </summary> /// <param name="angle">360 completes 1 circulation</param> /// <param name="scale">Determines the scale of the spiral</param> /// <param name="growth">This determines the factor of increase along the spiral. WARNING: Values beyond 0.3 may not give any meaningful visualization</param> /// <search>log,equiangular,growth,marvelous</search> public static NurbsCurve Logarithmic(double angle = 1800, double scale = 0.5, double growth = 0.1) { if (angle == 0.0) { throw new ArgumentException("The angle value can't be 0.", "angle"); } if (angle < 0.0) { angle = angle * -1; } int numPts = 1000; angle = degToRad(angle); var pts = new List <Point>(); for (int i = 0; i < numPts; ++i) { double currAngle = (double)i / 1000.0 * angle; double radius = scale * Math.Pow(eulerConstant(), (growth * currAngle)); double xVal = radius * Math.Cos(currAngle); double yVal = radius * Math.Sin(currAngle); pts.Add(Point.ByCoordinates(xVal, yVal, 0)); } return(NurbsCurve.ByPoints(pts)); }
/// <summary> /// The Archimedean spiral is formed by locus of points corresponding to the locations over time of a point moving away from a /// fixed point with a constant speed along a line which rotates with constant angular velocity. /// </summary> /// <param name="angle">360 completes 1 circulation</param> /// <param name="innerRadius">Changing this will change the starting place of the spiral</param> /// <param name="turnDistance">This controls the distance between successive turnings.</param> /// <search>archimedes,arithmetic</search> public static NurbsCurve Archimedean(double angle = 3600, double innerRadius = 0.2, double turnDistance = 0.2) { if (angle == 0.0) { throw new ArgumentException("The angle value can't be 0.", "angle"); } if (angle < 0.0) { angle = angle * -1; } int numPts = 1000; angle = degToRad(angle); var pts = new List <Point>(); for (int i = 0; i < numPts; ++i) { double currAngle = (double)i / 1000.0 * angle; double radius = innerRadius + turnDistance * currAngle; double xVal = radius * Math.Cos(currAngle); double yVal = radius * Math.Sin(currAngle); pts.Add(Point.ByCoordinates(xVal, yVal, 0)); } return(NurbsCurve.ByPoints(pts)); }
public void IsLineLike_Curve_CorrectlyIdentifiesStraightNurbsCurve() { var points = Enumerable.Range(0, 10) .Select(x => Autodesk.DesignScript.Geometry.Point.ByCoordinates(x, 0)); var nurbsCurve = NurbsCurve.ByPoints(points, 3); var revitCurve = nurbsCurve.ToRevitType(false); Assert.True(CurveUtils.IsLineLike(revitCurve)); }
public void IsLineLike_Curve_CorrectlyIdentifiesNonStraightNurbsCurve() { var points = new[] { Point.ByCoordinates(5, 5, 0), Point.ByCoordinates(0, 0, 0), Point.ByCoordinates(-5, 5, 0), Point.ByCoordinates(-10, 5, 0) }; var nurbsCurve = NurbsCurve.ByPoints(points, 3); Assert.False(CurveUtils.IsLineLike(nurbsCurve.ToRevitType(false))); }
public void NurbsCurve_AcceptsStraightReplicatedDegree3NurbsCurve() { var points = Enumerable.Range(0, 10) .Select(x => Autodesk.DesignScript.Geometry.Point.ByCoordinates(x, 0, 0)); var nurbsCurve = NurbsCurve.ByPoints(points, 3); var revitCurve = nurbsCurve.ToRevitType(false); Assert.IsAssignableFrom <Autodesk.Revit.DB.Line>(revitCurve); revitCurve.GetEndPoint(0).ShouldBeApproximately(nurbsCurve.StartPoint); revitCurve.GetEndPoint(1).ShouldBeApproximately(nurbsCurve.EndPoint); }
/// <summary> /// 沿Surface生成指定数量的Curve /// </summary> /// <param name="surface">基面</param> /// <param name="number">线数量</param> /// <param name="accuracy">精度</param> /// <param name="direction">方向,0为U方向,1为V方向</param> /// <returns></returns> public static List <Curve> ByAlongSurface(Surface surface, int number, int accuracy = 3, int direction = 0) { double[] parameters = new double[accuracy]; for (int i = 0; i < accuracy; i++) { if (i == accuracy) { parameters[i] = 1; } else { parameters[i] = i * (1.0 / (accuracy - 1)); } } List <Curve> baseCurves = new List <Curve>(); foreach (var i in parameters) { var tmp = surface.GetIsoline(1 - direction, i); baseCurves.Add(tmp); tmp.Dispose(); } // 线数量 double[] ts = new double[number]; for (int i = 0; i < number; i++) { if (i == number - 1) { ts[i] = 1; } else { ts[i] = i * (1.0 / (number - 1)); } } List <Curve> outCurves = new List <Curve>(); foreach (var t in ts) { List <Point> pts = new List <Point>(); foreach (var crv in baseCurves) { pts.Add(crv.PointAtParameter(t)); } var tmp = NurbsCurve.ByPoints(pts); outCurves.Add(tmp); tmp.Dispose(); } return(outCurves); }
public void ByCurve_Curve_AcceptsStraightDegree3NurbsCurve() { var points = Enumerable.Range(0, 10) .Select(x => Autodesk.DesignScript.Geometry.Point.ByCoordinates(x, 0)); var nurbsCurve = NurbsCurve.ByPoints(points, 3); var modelCurve = ModelCurve.ByCurve(nurbsCurve); Assert.NotNull(nurbsCurve); modelCurve.Curve.Length.ShouldBeApproximately(9); modelCurve.Curve.StartPoint.ShouldBeApproximately(Point.Origin()); modelCurve.Curve.EndPoint.ShouldBeApproximately(Point.ByCoordinates(9, 0, 0)); }
public void ByCurve_Curve_AcceptsStraightDegree3NurbsCurve() { var points = Enumerable.Range(0, 10) .Select(x => Autodesk.DesignScript.Geometry.Point.ByCoordinates(x, 0)); var nurbsCurve = NurbsCurve.ByPoints(points, 3); Assert.NotNull(nurbsCurve); var detailCurve = DetailCurve.ByCurve(Revit.Application.Document.Current.ActiveView, nurbsCurve); Assert.NotNull(detailCurve); detailCurve.Curve.Length.ShouldBeApproximately(9); detailCurve.Curve.StartPoint.ShouldBeApproximately(Point.Origin()); detailCurve.Curve.EndPoint.ShouldBeApproximately(Point.ByCoordinates(9, 0, 0)); }
/// <summary> /// A lituus is a spiral in which the angle is inversely proportional to the square of the radius. /// </summary> /// <param name="angle">360 completes 1 circulation</param> /// <param name="scale">Determines the scale of the spiral</param> /// <search>lituus,cotes</search> public static NurbsCurve Lituus(double angle = 3600, double scale = 5) { if (angle == 0.0) { throw new ArgumentException("The angle value can't be 0.", "angle"); } if (scale == 0.0) { throw new ArgumentException("The scale value can't be 0.", "scale"); } if (angle < 0.0) { angle = angle * -1; } int numPts = 1000; angle = degToRad(angle); var pts = new List <Point>(); for (int i = 1; i <= numPts; ++i) { double currAngle = (double)i / 1000.0 * angle; double radius = Math.Sqrt(1 / currAngle); double xVal = scale * radius * Math.Cos(currAngle); double yVal = scale * radius * Math.Sin(currAngle); pts.Add(Point.ByCoordinates(xVal, yVal, 0)); } return(NurbsCurve.ByPoints(pts)); }
public static Dictionary <string, object> CreateTopo(string filePath, LINE.Geometry.Interval2d location = null) { // Get the file information List <string> fileInfo = Elk.Common.ElkLib.TopoFileInfo(filePath); // output parameters List <List <Point> > topoPoints = null; List <NurbsCurve> curves = null; NurbsSurface ns = null; // try to get the scale double scale = 1.0; try { scale = Elk.DynamoCommon.GetRevitUnitScale(); } catch { } if (filePath != null && System.IO.File.Exists(filePath) && location != null) { List <List <LINE.Geometry.Point3d> > pts = ElkLib.ProcessTopoFile(filePath, scale, location); Point[][] surfPoints = new Point[pts.Count][]; topoPoints = new List <List <Point> >(); curves = new List <NurbsCurve>(); for (int i = 0; i < pts.Count; i++) { List <LINE.Geometry.Point3d> rowPoints = pts[i]; List <Point> crvPts = new List <Point>(); for (int j = 0; j < rowPoints.Count; j++) { Point dynPoint = Point.ByCoordinates(rowPoints[j].X, rowPoints[j].Y, rowPoints[j].Z); crvPts.Add(dynPoint); } surfPoints[i] = crvPts.ToArray(); topoPoints.Add(crvPts); NurbsCurve nc = NurbsCurve.ByPoints(crvPts, 3); //PolyCurve pc = PolyCurve.ByPoints(crvPts, false); curves.Add(nc); } try { ns = NurbsSurface.ByPoints(surfPoints, 3, 3); } catch { ns = null; } return(new Dictionary <string, object> { { "Info", fileInfo }, { "Points", topoPoints }, { "Curves", curves }, { "Surface", ns } }); } else { return(new Dictionary <string, object> { { "Info", fileInfo }, { "Points", null }, { "Curves", null }, { "Surface", null } }); } }
/// <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); }
/// <summary> /// GPS Viewer that takes a GPX file (/path/name.gpx as string) and gives a bitmap image of the plot. Use Watch Image node to view the result. /// Limitations: 1. Only the first track will be plotted /// 2. All the track segments will be joined as one. /// 3. The track will be approximated to suit the http request requiements /// WARNNG: The google maps allows only 25000 requests per day per application, please be considerate in number of requests you use. /// </summary> /// <param name="gpxFile">Use File Path node OR String /path/name.gpx</param> /// <param name="lineWidth">Thickness of the plotted track (1-9)</param> /// <param name="mapHeight">Height of the bitmap map (400 - 800)</param> /// <param name="mapWidth">Width of the bitmap map (400 - 800)</param> /// <search>GPS,view,plot,track,gpx</search> public static Bitmap plotTrack(string gpxFile, int mapWidth = 400, int mapHeight = 400, int lineWidth = 1) { if (mapWidth > 800) { mapWidth = 800; } else if (mapWidth < 400) { mapWidth = 400; } if (mapHeight > 800) { mapHeight = 800; } else if (mapHeight < 400) { mapHeight = 400; } if (lineWidth > 9) { lineWidth = 9; } else if (lineWidth < 1) { lineWidth = 1; } List <string> trackSegments = new List <string>(); //open the xml doc XmlDocument doc = new XmlDocument(); doc.Load(gpxFile); //namespace of the gps viewer string namespc = "http://www.topografix.com/GPX/1/1"; XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable); mgr.AddNamespace("", namespc); //get all trks //only one track is going to be supported because of the limitation in url encoding XmlNodeList trksList = doc.GetElementsByTagName("trk"); List <XmlNode> trks = new List <XmlNode>(trksList.Cast <XmlNode>()); //foreach code for all tracks -- but we will take only the first track //foreach (var trk in trks) //{ XmlNode trk = trks[0]; List <XmlNode> trksegs = ProcessNodes(trk.ChildNodes, "trkseg"); List <Autodesk.DesignScript.Geometry.Point> pts = new List <Autodesk.DesignScript.Geometry.Point>(); //get aggregate of all the trkpoints and store it in pts -- note we just approximately join the tracksegments foreach (XmlNode trkseg in trksegs) { List <XmlNode> trkpts = ProcessNodes(trkseg.ChildNodes, "trkpt"); foreach (XmlNode trkpt in trkpts) { double tempLat = Double.Parse(trkpt.Attributes["lat"].Value); double tempLng = Double.Parse(trkpt.Attributes["lon"].Value); Autodesk.DesignScript.Geometry.Point m = Autodesk.DesignScript.Geometry.Point.ByCoordinates(tempLat, tempLng, 0); pts.Add(m); } } bool status = true; string encodedString = ""; int originalNumPts = pts.Count; int currentNumPts = originalNumPts; int iterationCount = 0; List <Autodesk.DesignScript.Geometry.Point> simplifiedPts = pts; do { //first encode all the raw coordinates encodedString = Encode(simplifiedPts); //webrequests cant go beyond 2048 characters if (encodedString.Length > (2048 - 100)) { //need to reduce the number of points by 5% currentNumPts = (int)(currentNumPts * (1 - 0.05 * ++iterationCount)); NurbsCurve crv = NurbsCurve.ByPoints(simplifiedPts); simplifiedPts.Clear(); List <double> parameter = Enumerable.Range(0, currentNumPts).Select(i => 0 + (1 - 0) * ((double)i / (currentNumPts - 1))).ToList <double>(); foreach (double para in parameter) { simplifiedPts.Add(crv.PointAtParameter(para)); } status = false; } else { status = true; } } while (status == false); StringBuilder finalStr = new StringBuilder(); finalStr.Append(String.Format("https://maps.googleapis.com/maps/api/staticmap?size={0}x{1}", mapWidth, mapHeight)); finalStr.Append(String.Format("&path=color:0xFF0000FF%7Cweight:{0}%7Cenc:", lineWidth)); finalStr.Append(encodedString); Uri uri = new Uri(finalStr.ToString(), UriKind.Absolute); WebRequest http = HttpWebRequest.Create(finalStr.ToString()); http.ContentType = "text/plain"; HttpWebResponse response = (HttpWebResponse)http.GetResponse(); Stream stream = response.GetResponseStream(); Bitmap bitmap = (Bitmap)Bitmap.FromStream(stream); return(bitmap); }