/// <summary> /// Try to fit a circle to two curves using tangent relationships. /// </summary> /// <param name="c1">First curve to touch.</param> /// <param name="c2">Second curve to touch.</param> /// <param name="t1">Parameter on first curve close to desired solution.</param> /// <param name="t2">Parameter on second curve closet to desired solution.</param> /// <returns>Valid circle on success, Circle.Unset on failure.</returns> /// <since>5.0</since> public static Circle TryFitCircleTT(Curve c1, Curve c2, double t1, double t2) { if (c1 == null) { throw new ArgumentNullException("c1"); } if (c2 == null) { throw new ArgumentNullException("c2"); } if (!RhinoMath.IsValidDouble(t1)) { throw new ArgumentNullException("t1"); } if (!RhinoMath.IsValidDouble(t2)) { throw new ArgumentNullException("t2"); } Circle rc = Circle.Unset; if (!UnsafeNativeMethods.ON_Circle_TryFitTT(c1.ConstPointer(), c2.ConstPointer(), t1, t2, ref rc)) { rc = Circle.Unset; } Runtime.CommonObject.GcProtect(c1, c2); return(rc); }
/// <summary> /// This is the method that actually does the work. /// </summary> protected override void SolveInstance(IGH_DataAccess data) { var x = 0.0; if (!data.GetData(0, ref x)) { return; } if (!RhinoMath.IsValidDouble(x)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "X Value is invalid"); return; } var y = 0.0; if (!data.GetData(1, ref y)) { return; } if (!RhinoMath.IsValidDouble(y)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Y Value is invalid"); return; } var sum = MooseCommon.Utility.Sum(x, y); data.SetData(0, sum); }
private bool CalculatePlaneAngle(Point3d point) { if (System.Math.Abs(m_plane.ValueAt(point)) > 0.000001) { return(false); } if (m_base_point.DistanceTo(point) <= RhinoMath.ZeroTolerance) { return(false); } Vector3d v = point - m_base_point; v.Unitize(); Vector3d zerov = m_ref_point - m_base_point; double r = zerov.Length; zerov.Unitize(); double dot = zerov * v; if (!RhinoMath.IsValidDouble(dot)) { dot = 1.0; } else if (dot > 1.0) { dot = 1.0; } else if (dot < -1.0) { dot = -1.0; } double test_angle = Math.Acos(dot); Vector3d zaxis = Vector3d.CrossProduct(m_plane.XAxis, m_plane.YAxis); zaxis.Unitize(); v = Vector3d.CrossProduct(zaxis, zerov); v.Unitize(); Plane yplane = new Plane(m_base_point, v); if (yplane.ValueAt(point) < 0.0) { test_angle = 2.0 * Math.PI - test_angle; } m_angle = test_angle; Plane arc_plane = new Plane(m_plane.Origin, zerov, v); m_arc = new Arc(arc_plane, r, m_angle); return(m_arc.IsValid); }
private void OnFormClosing(object sender, FormClosingEventArgs e) { if (OnlyNumbers && (e.CloseReason == CloseReason.UserClosing || e.CloseReason == CloseReason.None) && DialogResult == System.Windows.Forms.DialogResult.OK) { string text = GetText(); if (!string.IsNullOrEmpty(text)) { double d; if (!double.TryParse(text, out d)) { e.Cancel = true; return; } if ((RhinoMath.IsValidDouble(MinimumNumberValue) && d < MinimumNumberValue) || (RhinoMath.IsValidDouble(MaximumNumberValue) && d > MaximumNumberValue)) { e.Cancel = true; } } } }
private static void ComputeDeviation(Rectangle3d rec, Rhino.Collections.Point3dList pts, out double dev, out double angdev) { dev = double.MaxValue; for (int i = 0; i < 4; i++) { dev = Math.Min(dev, rec.Corner(i).DistanceTo(pts[i])); } angdev = double.MaxValue; for (int i = 0; i < 4; i++) { int j = (i == 3) ? 0 : i + 1; Vector3d re = rec.Corner(i) - rec.Corner(j); Vector3d pe = pts[i] - pts[j]; double ad = Vector3d.VectorAngle(re, pe); if (RhinoMath.IsValidDouble(ad)) { angdev = Math.Min(angdev, ad); } } }
/// <summary> /// Try to fit a circle to three curves using tangent relationships. /// </summary> /// <param name="c1">First curve to touch.</param> /// <param name="c2">Second curve to touch.</param> /// <param name="c3">Third curve to touch.</param> /// <param name="t1">Parameter on first curve close to desired solution.</param> /// <param name="t2">Parameter on second curve closet to desired solution.</param> /// <param name="t3">Parameter on third curve close to desired solution.</param> /// <returns>Valid circle on success, Circle.Unset on failure.</returns> public static Circle TryFitCircleTTT(Curve c1, Curve c2, Curve c3, double t1, double t2, double t3) { if (c1 == null) { throw new ArgumentNullException("c1"); } if (c2 == null) { throw new ArgumentNullException("c2"); } if (c3 == null) { throw new ArgumentNullException("c3"); } if (!RhinoMath.IsValidDouble(t1)) { throw new ArgumentNullException("t1"); } if (!RhinoMath.IsValidDouble(t2)) { throw new ArgumentNullException("t2"); } if (!RhinoMath.IsValidDouble(t3)) { throw new ArgumentNullException("t3"); } Circle rc = Circle.Unset; if (!UnsafeNativeMethods.ON_Circle_TryFitTTT(c1.ConstPointer(), c2.ConstPointer(), c3.ConstPointer(), t1, t2, t3, ref rc)) { rc = Circle.Unset; } return(rc); }
protected override void SolveInstance(IGH_DataAccess DA) { if (DA.Iteration > 1) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "超出数据已被忽视"); return; } Mesh tm = new Mesh(); if (!DA.GetData(0, ref tm) && !tm.IsValid) { return; } List <Mesh> o = new List <Mesh>(3); DA.GetDataList(1, o); List <Point3d> pl = new List <Point3d>(); if (!DA.GetDataList(2, pl)) { return; } int a = 0; if (!DA.GetData(3, ref a)) { return; } #region 制作网格上用于测量的点阵 BoundingBox mb = new BoundingBox(); foreach (Point3f p3f in tm.Vertices) { mb.Union(new Point3d(p3f)); } double px = mb.Min.X; double py = mb.Min.Y; int rx = (int)Math.Ceiling((mb.Max.X - px) / a); int ry = (int)Math.Ceiling((mb.Max.Y - py) / a); List <Point3d> grid = new List <Point3d>(rx * ry); for (int ix = 0; ix < rx; ix++) { for (int iy = 0; iy < ry; iy++) { Ray3d ray = new Ray3d(new Point3d(px, py, mb.Min.Z), Vector3d.ZAxis); double pmd = Intersection.MeshRay(tm, ray); if (RhinoMath.IsValidDouble(pmd) && pmd > 0.0) { grid.Add(ray.PointAt(pmd)); } py += a; } px += a; py = mb.Min.Y; } //获取网格上点阵制作栅格点阵z射线,与网格相交,交点加入grid #endregion List <Point3d> pt = new List <Point3d>(pl.Count); #region 将观测点投影到地形网格上,并增加眼高 foreach (Point3d p0 in pl) { Point3d p = p0; Ray3d rayp = new Ray3d(new Point3d(p.X, p.Y, mb.Min.Z), Vector3d.ZAxis); double pmdp = Intersection.MeshRay(tm, rayp); if (RhinoMath.IsValidDouble(pmdp) && pmdp > 0.0) { p = rayp.PointAt(pmdp); } else { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"观测点{p}无法被Z向投影至地形网格上"); return; } p.Z += 1.5; //增加眼高 pt.Add(p); } //采样点 #endregion foreach (Mesh m in o) //将障碍物附加入网格 { tm.Append(m); } bool[] grib = new bool[grid.Count]; //采样点布尔数组 foreach (Point3d p in pt) { if (Environment.ProcessorCount > 2) { Parallel.For(0, grid.Count, j => //多线程处理每个采样点 { if (!grib[j]) //grib为否(尚未可见)时 判定当前是否为可见点,与网格上的点阵交点仅为1的即可见点 { grib[j] = Intersection.MeshLine(tm, new Line(p, grid[j]), out _).Length == 1; } }); } else { for (int j = 0; j < grid.Count; j++) { if (!grib[j]) //grib为否(尚未可见)时 判定当前是否为可见点,与网格上的点阵交点仅为1的即可见点 { grib[j] = Intersection.MeshLine(tm, new Line(p, grid[j]), out _).Length == 1; } } } } for (int i = grid.Count - 1; i >= 0; i--) //剔除不可见点 { if (!grib[i]) { grid.RemoveAt(i); } } DA.SetDataList(0, pt); DA.SetDataList(1, grid); }
public Point3d ClosestPoint(Point3d testPoint) { double t = ClosestParameter(testPoint); return(RhinoMath.IsValidDouble(t) ? PointAt(t) : Point3d.Unset); }
/// <summary> /// Test for a curve that is a polyline (or looks like a polyline). /// </summary> bool IsPolyline(Curve curve, ref int point_count, ref bool bClosed, ref bool bPlanar, ref bool bLength, ref bool bAngle, ref bool bIntersect) { if (null == curve) { return(false); } List <Point3d> points = new List <Point3d>(); // Is the curve a polyline curve? PolylineCurve polyline_curve = curve as PolylineCurve; if (null != polyline_curve) { if (polyline_curve.PointCount <= 2) { return(false); } for (int i = 0; i < polyline_curve.PointCount; i++) { points.Add(polyline_curve.Point(i)); } } // Is the curve a polycurve that looks like an polyline? PolyCurve poly_curve = curve as PolyCurve; if (null != poly_curve) { Polyline polyline; if (poly_curve.TryGetPolyline(out polyline)) { if (polyline.Count <= 2) { return(false); } for (int i = 0; i < polyline.Count; i++) { points.Add(polyline[i]); } } } // Is the curve a NURBS curve that looks like an polyline? NurbsCurve nurbs_curve = curve as NurbsCurve; if (null != nurbs_curve) { Polyline polyline; if (nurbs_curve.TryGetPolyline(out polyline)) { if (polyline.Count <= 2) { return(false); } for (int i = 0; i < polyline.Count; i++) { points.Add(polyline[i]); } } } if (0 == points.Count) { return(false); } // Is the curve closed? bClosed = curve.IsClosed; // Is the curve planar? bPlanar = curve.IsPlanar(); // Get the point (vertex) count. point_count = (bClosed ? points.Count - 1 : points.Count); // Test for self-intersection. CurveIntersections intesections = Intersection.CurveSelf(curve, m_tolerance); bIntersect = (intesections.Count > 0) ? true : false; // If the curve is not closed, no reason to continue... if (!bClosed) { return(true); } // Test if the distance between each point is identical. double distance = 0.0; for (int i = 1; i < points.Count; i++) { Point3d p0 = points[i - 1]; Point3d p1 = points[i]; Vector3d v = p0 - p1; double d = v.Length; if (i == 1) { distance = d; continue; } else if (Math.Abs(distance - d) < m_tolerance) { continue; } else { distance = RhinoMath.UnsetValue; break; } } // Set return value. bLength = RhinoMath.IsValidDouble(distance); // Test if the angle between each point is identical. double angle = 0.0; for (int i = 1; i < points.Count - 1; i++) { Point3d p0 = points[i - 1]; Point3d p1 = points[i]; Point3d p2 = points[i + 1]; Vector3d v0 = p1 - p0; Vector3d v1 = p1 - p2; v0.Unitize(); v1.Unitize(); double a = Vector3d.VectorAngle(v0, v1); if (i == 1) { angle = a; continue; } else if (Math.Abs(angle - a) < m_angle_tolerance) { continue; } else { angle = RhinoMath.UnsetValue; break; } } // Set return value. bAngle = RhinoMath.IsValidDouble(angle); return(true); }
SolveResults Compute(Curve crv, List <double> pattern) { var rc = new SolveResults(); if (pattern.Count == 0) { return(null); } var pattern_length = 0.0; for (var i = 0; i < pattern.Count; i++) { if (pattern[i] < 0.0) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Dash patterns cannot have negative length segments"); pattern[i] = 0.0; } pattern_length += pattern[i]; } if (pattern_length <= 1e-12) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Total pattern length is too short."); return(rc); } crv = crv.DuplicateCurve(); var dashes = new List <Curve>(); var gaps = new List <Curve>(); var index = -1; var dash = false; while (true) { //toggle gap/dash flag dash = !dash; //increment index++; //limit if (index >= pattern.Count) { index = 0; } //get pattern length if (Math.Abs(pattern[index]) < 1e-32) { if (dash) { dashes.Add(null); } else { gaps.Add(null); } } else { //measure length double length = crv.GetLength(); if (!RhinoMath.IsValidDouble(length)) { break; } //cut short if we're at the end of the curve if (length <= pattern[index]) { if (dash) { dashes.Add(crv); } else { gaps.Add(crv); } break; } //compute normalised arc-length parameter. if (!crv.LengthParameter(pattern[index], out var t)) { break; } var segment = crv.Trim(crv.Domain.Min, t); if (segment != null && segment.IsValid) { if (dash) { dashes.Add(segment); } else { gaps.Add(segment); } } crv = crv.Trim(t, crv.Domain.Max); if (crv == null) { break; } } } rc.Dashes = dashes; rc.Gaps = gaps; return(rc); }
public Curve[] AfterOffset(Curve destination, double naN, Plane unset, int num2) { if (!RhinoMath.IsValidDouble(naN)) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "不是有效的数字"); return(new Curve[] {}); } else if (!unset.IsValid) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "不是有效的平面"); return(new Curve[] { }); } else { double num3 = Math.Abs(naN); double tolerance = Math.Min(GH_Component.DocumentTolerance(), 0.1 * num3); GH_Component.DocumentAngleTolerance(); num2 = Math.Max(Math.Min(num2, 4), 0); if (naN == 0.0) { return(new Curve[] { destination }); } else { CurveOffsetCornerStyle none = CurveOffsetCornerStyle.None; switch (num2) { case 0: none = CurveOffsetCornerStyle.None; break; case 1: none = CurveOffsetCornerStyle.Sharp; break; case 2: none = CurveOffsetCornerStyle.Round; break; case 3: none = CurveOffsetCornerStyle.Smooth; break; case 4: none = CurveOffsetCornerStyle.Chamfer; break; } Curve[] inputCurves = null; inputCurves = destination.Offset(unset, naN, tolerance, none); if (inputCurves == null) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "不能偏移该曲线"); return(new Curve[] { }); } else { Curve[] data = Curve.JoinCurves(inputCurves); if (data == null) { return(inputCurves); } else { return(data); } } } } }
public void SetAsNumberInput(double minimum, double maximum) { OnlyNumbers = true; MinimumNumberValue = RhinoMath.IsValidDouble(minimum) ? minimum : RhinoMath.UnsetValue; MaximumNumberValue = RhinoMath.IsValidDouble(maximum) ? maximum : RhinoMath.UnsetValue; }
protected override void SolveInstance(IGH_DataAccess DA) { var plane = Plane.Unset; var x = RhinoMath.UnsetValue; var y = RhinoMath.UnsetValue; var r = RhinoMath.UnsetValue; if (!DA.GetData(0, ref plane)) { return; } if (!DA.GetData(1, ref x)) { return; } if (!DA.GetData(2, ref y)) { return; } if (!DA.GetData(3, ref r)) { return; } if (!plane.IsValid) { return; } if (!RhinoMath.IsValidDouble(x)) { return; } if (!RhinoMath.IsValidDouble(y)) { return; } if (!RhinoMath.IsValidDouble(r)) { return; } if ((Math.Abs(x) < 1e-12) || (Math.Abs(y) < 1e-12)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Rectangle diagonal cannot be zero length."); return; } var min = Math.Min(x, y); r = Math.Min(r, 0.5 * min); if (r <= 0.0) { var dx = x * 0.5; var dy = y * 0.5; var width = new Interval(-dx, dx); var height = new Interval(-dy, dy); var rect = new Rectangle3d(plane, width, height); DA.SetData(0, new GH_Rectangle(rect)); DA.SetData(1, rect.Circumference); return; } if ((x == y) && (r == (0.5 * x))) { var circle = new Circle(plane, r); DA.SetData(0, new GH_Circle(circle)); DA.SetData(1, circle.Circumference); return; } var curve = RoundedRectangle(plane, x, y, r); if (null == curve) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Rectangle construction failed."); return; } DA.SetData(0, curve); DA.SetData(1, curve.GetLength()); }
protected override Result RunCommand(RhinoDoc doc, RunMode mode) { // Select cutting surface var gc = new GetObject(); gc.SetCommandPrompt("Select cutting surface"); gc.GeometryFilter = ObjectType.Surface; gc.SubObjectSelect = false; gc.Get(); if (gc.CommandResult() != Result.Success) { return(gc.CommandResult()); } var splitter = gc.Object(0).Brep(); if (null == splitter) { return(Result.Failure); } // Select surface to trim var gs = new GetObject(); gs.SetCommandPrompt("Select surface to trim"); gs.GeometryFilter = ObjectType.Surface; gs.SubObjectSelect = false; gs.EnablePreSelect(false, true); gs.DeselectAllBeforePostSelect = false; gs.Get(); if (gs.CommandResult() != Result.Success) { return(gs.CommandResult()); } var brep_ref = gs.Object(0); var brep = brep_ref.Brep(); if (null == brep) { return(Result.Failure); } var pick_pt = brep_ref.SelectionPoint(); if (!pick_pt.IsValid) { // The user didn't "pick" the object, but rather // selected the object using the SelID command. // So, make up some pick location. var dom_u = brep.Faces[0].Domain(0); var dom_v = brep.Faces[0].Domain(1); pick_pt = brep.Faces[0].PointAt(dom_u.Min, dom_v.Min); } // Do the splitting var trims = brep.Split(splitter, doc.ModelAbsoluteTolerance); if (null == trims || 1 == trims.Length) { RhinoApp.WriteLine("Unable to trim surface."); return(Result.Failure); } // Figure out which piece the user wanted trimmed away var dist = RhinoMath.UnsetValue; int picked_index = -1; for (int i = 0; i < trims.Length; i++) { var pt = trims[i].ClosestPoint(pick_pt); if (pt.IsValid) { double d = pt.DistanceTo(pick_pt); if (!RhinoMath.IsValidDouble(dist) || d < dist) { dist = d; picked_index = i; } } } // Add the new pieces for (int i = 0; i < trims.Length; i++) { if (i != picked_index) { doc.Objects.AddBrep(trims[i]); } } // Delete the original doc.Objects.Delete(brep_ref, false); doc.Views.Redraw(); return(Result.Success); }
/// <summary> /// Calculates the u, v, n directions of a NURBS curve control point /// similar to the method used by the MoveUVN command. /// </summary> /// <param name="nurb">The NURBS curve to evaluate.</param> /// <param name="cvIndex">The index of the control point to evaluate.</param> /// <param name="uDir">The u direction.</param> /// <param name="vDir">The v direction.</param> /// <param name="nDir">The n direction.</param> /// <returns>true if successful, false otherwise</returns> public static bool GetNurbsCurveControlPointDirections( NurbsCurve nurb, int cvIndex, out Vector3d uDir, out Vector3d vDir, out Vector3d nDir ) { uDir = vDir = nDir = Vector3d.Unset; var rc = false; if (null != nurb && cvIndex >= 0 && cvIndex < nurb.Points.Count) { var t = nurb.GrevilleParameter(cvIndex); if (RhinoMath.IsValidDouble(t)) { if (t < nurb.Domain.Min) { t += nurb.Domain.Length; } uDir = nurb.TangentAt(t); var kappa = nurb.CurvatureAt(t); if (nurb.TryGetPlane(out Plane plane)) { nDir = plane.ZAxis; vDir = Vector3d.CrossProduct(nDir, uDir); vDir.Unitize(); } else if (kappa.Unitize()) { vDir = kappa; nDir = Vector3d.CrossProduct(uDir, vDir); nDir.Unitize(); } else { vDir.PerpendicularTo(uDir); vDir.Unitize(); nDir = Vector3d.CrossProduct(uDir, vDir); nDir.Unitize(); } const double tol = 1E-15; if (Math.Abs(uDir.X) <= tol) { uDir.X = 0.0; } if (Math.Abs(uDir.Y) <= tol) { uDir.Y = 0.0; } if (Math.Abs(uDir.Z) <= tol) { uDir.Z = 0.0; } if (Math.Abs(vDir.X) <= tol) { vDir.X = 0.0; } if (Math.Abs(vDir.Y) <= tol) { vDir.Y = 0.0; } if (Math.Abs(vDir.Z) <= tol) { vDir.Z = 0.0; } if (Math.Abs(nDir.X) <= tol) { nDir.X = 0.0; } if (Math.Abs(nDir.Y) <= tol) { nDir.Y = 0.0; } if (Math.Abs(nDir.Z) <= tol) { nDir.Z = 0.0; } rc = true; } } return(rc); }