/// <summary> /// Solves the instance. /// </summary> /// <param name="DA">Da.</param> protected override void SolveInstance(IGH_DataAccess DA) { Mesh mesh = null; Curve startGeod = null; int Count = 0; double Angle = 0.0; int Iter = 0; if (!DA.GetData(0, ref mesh)) { return; } if (!DA.GetData(1, ref startGeod)) { return; } if (!DA.GetData(2, ref Count)) { return; } if (!DA.GetData(3, ref Angle)) { return; } if (!DA.GetData(4, ref Iter)) { return; } List <Curve> geodesicPattern = MeshGeodesicMethods.ComputeGeodesicPatternByParralelTransport(mesh, startGeod, Count, Angle, Iter); DA.SetDataList(0, geodesicPattern); }
// Find the best fitting geodesic curve for a set of public double ComputeError(int n, double[] x) { double alpha = x[0]; Curve curve = perpGeodesics[startIndex]; Point3d pt = curve.PointAt(perpParameters[startIndex]); Vector3d vector = curve.TangentAt(perpParameters[startIndex]); MeshPoint mPt = mesh.ClosestMeshPoint(pt, 0.0); Vector3d normal = mesh.NormalAt(mPt); Vector3d cP = Vector3d.CrossProduct(vector, normal); cP.Rotate(alpha, normal); Curve newG = MeshGeodesicMethods.getGeodesicCurveOnMesh(mesh, pt, cP, maxIter).ToNurbsCurve(); if (bothDir) { Curve newG2 = MeshGeodesicMethods.getGeodesicCurveOnMesh(mesh, pt, -cP, maxIter).ToNurbsCurve(); newG = Curve.JoinCurves(new List <Curve> { newG, newG2 })[0]; } // Assign resulting geodesic to global property for output. selectedGeodesic = newG; // Calculate error double error = 0; for (int i = 0; i < perpGeodesics.Count - 1; i++) { Curve g = perpGeodesics[i]; CurveIntersections cvInt = Intersection.CurveCurve(newG, g, 0.00001, 0.00001); if (cvInt.Count > 0) { // Compute distance if intersection is found double param = cvInt[0].ParameterB; Interval domain = new Interval(param, perpParameters[i]); double distance = g.GetLength(domain); // Add squared distance to error error += Math.Pow(distance, 2); } else { // Penalize if no intersection is found on this perp geodesic error += 10; } } return(error); }
protected override void SolveInstance(IGH_DataAccess DA) { Mesh mesh = null; Vector3d startDirection = Vector3d.Unset; List <Point3d> points = new List <Point3d>(); if (!DA.GetData(0, ref mesh)) { return; } if (!DA.GetData(1, ref startDirection)) { return; } if (!DA.GetDataList(2, points)) { return; } List <Vector3d> vectors = MeshGeodesicMethods.VectorParallelTransport(startDirection, points, mesh); DA.SetDataList(0, vectors); }
/// <summary> /// Solves the instance. /// </summary> /// <param name="DA">Da.</param> protected override void SolveInstance(IGH_DataAccess DA) { // Properties Mesh mesh = null; Curve initialCurve = null; double specifiedDistance = 0.0; int maxCount = 0; double threshold = 0.0; double perpStepSize = 0.0; bool bothDir = false; double minThreshold = 0.0; // Set the input data if (!DA.GetData(0, ref mesh)) { return; } if (!DA.GetData(1, ref initialCurve)) { return; } if (!DA.GetData(2, ref bothDir)) { return; } if (!DA.GetData(3, ref maxCount)) { return; } if (!DA.GetData(4, ref threshold)) { return; } if (!DA.GetData(5, ref specifiedDistance)) { return; } if (!DA.GetData(6, ref perpStepSize)) { return; } if (!DA.GetData(7, ref minThreshold)) { return; } // Data validation if (maxCount == 0) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Count cannot be 0"); } if (!mesh.IsValid) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Mesh is invalid"); } // Placeholder properties DataTree <Curve> pattern = new DataTree <Curve>(); Curve previousCurve = initialCurve; List <Curve> perpGeods = new List <Curve>(); List <double> perpParams = new List <double>(); // Start piecewise evolution process for (int i = 0; i < maxCount; i++) { Debug.WriteLine("Iter " + i); // Create placeholder lists perpGeods = new List <Curve>(); perpParams = new List <double>(); // Divide curve double[] geodParams = previousCurve.DivideByLength(perpStepSize, true); if (geodParams == null) { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "No points found on iter" + i); break; } if (geodParams.Length <= 2) { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Not enough points found on iter" + i); break; } // Generate perp geodesics for measurement foreach (double t in geodParams) { // Get curve tangent vector and mesh normal Point3d point = previousCurve.PointAt(t); Vector3d tangent = previousCurve.TangentAt(t); Vector3d normal = mesh.NormalAt(mesh.ClosestMeshPoint(point, 0.0)); // Rotate vector against normals 90 degrees tangent.Rotate(0.5 * Math.PI, normal); // Generate perp geodesic Curve perpGeodesic = MeshGeodesicMethods.getGeodesicCurveOnMesh(mesh, point, tangent, 100).ToNurbsCurve(); // Check for success if (perpGeodesic != null && perpGeodesic.GetLength() > specifiedDistance) { // Divide by specified length double perpT = 0.0; perpGeodesic.LengthParameter(specifiedDistance, out perpT); // Add data to lists perpGeods.Add(perpGeodesic); perpParams.Add(perpT); } } // Clean perp geods of intersections ocurring BEFORE the specified distance var result = CleanPerpGeodesics(perpGeods, perpParams, specifiedDistance); // Assign clean lists perpGeods = result.perpGeodesics; perpParams = result.perpParams; // Break if not enough perpGeods remain if (perpGeods.Count < 6) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Not enough perp geodesics where found for iter " + i); break; } //Generate the next piecewise geodesic List <Curve> iterCurves = GeneratePiecewiseGeodesicCurve(mesh, perpParams, perpGeods, 1000, bothDir, 0, threshold, Vector3d.Unset); // Add it to the pattern pattern.AddRange(iterCurves, new GH_Path(i)); // Assign as previous for the next round Curve[] joinedResult = Curve.JoinCurves(iterCurves); // Error check if (joinedResult.Length > 1) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "More than 1 curve after Join in iter " + i); break; } //Create points and bisectrix vectors for next round of perp geodesics Point3dList ptList = new Point3dList(); foreach (Curve c in iterCurves) { if (!ptList.Contains(c.PointAtStart)) { ptList.Add(c.PointAtStart); } if (!ptList.Contains(c.PointAtEnd)) { ptList.Add(c.PointAtEnd); } } Debug.WriteLine("ptList Count: " + ptList.Count); // Assign new curve to previous curve Curve joinedCurve = joinedResult[0]; previousCurve = joinedCurve; } // Assign data to output DA.SetDataTree(0, pattern); DA.SetDataList(2, perpGeods); }
// Find the best fitting geodesic curve for a set of public new double ComputeError(int n, double[] x) { double alpha = x[0]; bestFitInterval = new int[] { }; Curve curve = perpGeodesics[startIndex]; Point3d pt = curve.PointAt(perpParameters[startIndex]); Vector3d vector = curve.TangentAt(perpParameters[startIndex]); MeshPoint mPt = mesh.ClosestMeshPoint(pt, 0.0); Vector3d normal = mesh.NormalAt(mPt); Vector3d cP = Vector3d.CrossProduct(vector, normal); cP.Rotate(alpha, normal); if (refDir == Vector3d.Unset) { refDir = cP; } double angle = Vector3d.VectorAngle(cP, refDir); if (angle >= 0.1 * Math.PI) { cP = -cP; } Vector3d.VectorAngle(cP, refDir); Curve newG = MeshGeodesicMethods.getGeodesicCurveOnMesh(mesh, pt, cP, maxIter).ToNurbsCurve(); if (bothDir) { Curve newG2 = MeshGeodesicMethods.getGeodesicCurveOnMesh(mesh, pt, -cP, maxIter).ToNurbsCurve(); newG = Curve.JoinCurves(new List <Curve> { newG, newG2 })[0]; } // Assign resulting geodesic to global property for output. selectedGeodesic = newG; // Calculate error double error = 0; List <double> distances = new List <double>(); List <double> signedDistances = new List <double>(); for (int i = 0; i < perpGeodesics.Count - 1; i++) { Curve g = perpGeodesics[i]; CurveIntersections cvInt = Intersection.CurveCurve(newG, g, 0.00001, 0.00001); double signedDistance = g.GetLength(new Interval(0, perpParameters[i])); signedDistances.Add(signedDistance); if (cvInt.Count > 0) { // Compute distance if intersection is found double param = cvInt[0].ParameterB; double distance = g.GetLength(new Interval(0, param)); distances.Add(distance); // Add squared distance to error error += Math.Pow(signedDistance - distance, 2); } else { // Penalize if no intersection is found on this perp geodesic distances.Add(1000); error += 1000; } } //Calculate longest interval within threshold. for (int k = (distances.Count - 1); k >= 2; k--) { for (int i = 0; i < (distances.Count - k); i++) { //Check if interval i->k is within bounds bool flag = true; for (int j = i; j < i + k; j++) { double Lbound = signedDistances[j] * (1 - threshold); double Ubound = signedDistances[j] * (1 + threshold); if (Lbound > distances[j] || distances[j] > Ubound) { flag = false; break; } } if (flag && bestFitInterval.Length == 0) { bestFitInterval = new int[] { i, i + k }; } } } if (bestFitInterval.Length == 0) { error += 1000000; return(error); } error = error / (bestFitInterval[1] - bestFitInterval[0]); //if (invertDir) selectedGeodesic.Reverse(); return(error); }
protected override void SolveInstance(IGH_DataAccess DA) { // Input variables int iter = 0; Mesh mesh = new Mesh(); List <Point3d> startPoints = new List <Point3d>(); List <Vector3d> startDirections = new List <Vector3d>(); // Output holders List <Curve> polyList = new List <Curve>(); bool bothDir = false; // Value setting if (!DA.GetData(0, ref iter)) { return; } if (!DA.GetData(1, ref mesh)) { return; } if (!DA.GetDataList(2, startPoints)) { return; } if (!DA.GetDataList(3, startDirections)) { return; } if (!DA.GetData(4, ref bothDir)) { return; } // Value checks if (startPoints.Count != startDirections.Count) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Start point and vector list must be the same length"); } for (int i = 0; i < startPoints.Count; i++) { Curve crv; Polyline pl = MeshGeodesicMethods.getGeodesicCurveOnMesh(mesh, startPoints[i], startDirections[i], iter); if (bothDir) { Polyline pl2 = MeshGeodesicMethods.getGeodesicCurveOnMesh(mesh, startPoints[i], -startDirections[i], iter); crv = Curve.JoinCurves(new List <Curve> { pl.ToNurbsCurve(), pl2.ToNurbsCurve() })[0]; } else { crv = pl.ToNurbsCurve(); } polyList.Add(crv); } // Output results DA.SetDataList(0, polyList); }