public List <Curve> GenerateSubCurves(double[] _startData, double[] _xl, double[] _xu) { // Generate Initial values and variable Bounds for the optimization problem. // Only using first variable for now, the extra variable is just to make it work. double[] startData = _startData; double[] xl = _xl; double[] xu = _xu; List <Curve> pieceWiseList = new List <Curve>(); pieceWiseList.Add(selectedGeodesic); if (bestFitInterval.Length != 0) { pieceWiseList[0] = CutCurveBetweenPerpIndexes(pieceWiseList[0], perpGeodesics, bestFitInterval[0], bestFitInterval[1]); if (bestFitInterval[1] < (perpGeodesics.Count - 1)) { List <Curve> tempGeodesics = perpGeodesics.GetRange(bestFitInterval[1], (perpGeodesics.Count - bestFitInterval[1])); List <double> tempParameters = perpParameters.GetRange(bestFitInterval[1], (perpGeodesics.Count - bestFitInterval[1])); Vector3d tangent = pieceWiseList[0].TangentAtEnd; double t; tempGeodesics[0].ClosestPoint(pieceWiseList[0].PointAtEnd, out t); tempParameters[0] = t; BestFitPieceWiseGeodesic tempBestFit = new BestFitPieceWiseGeodesic(mesh, tempGeodesics, tempParameters, maxIter / 2, false, 0, threshold, tangent); var tempOptimizer = new Bobyqa(2, tempBestFit.ComputeError, xl, xu); var tempResult = tempOptimizer.FindMinimum(startData); pieceWiseList.AddRange(tempBestFit.GenerateSubCurves(startData, xl, xu)); } if (bestFitInterval[0] > 0) { List <Curve> tempGeodesics = perpGeodesics.GetRange(0, bestFitInterval[0] + 1); List <double> tempParameters = perpParameters.GetRange(0, bestFitInterval[0] + 1); double t; Vector3d tangent = pieceWiseList[0].TangentAtStart; tempGeodesics[tempGeodesics.Count - 1].ClosestPoint(pieceWiseList[0].PointAtStart, out t); tempParameters[tempGeodesics.Count - 1] = t; BestFitPieceWiseGeodesic tempBestFit = new BestFitPieceWiseGeodesic(mesh, tempGeodesics, tempParameters, maxIter / 2, false, tempGeodesics.Count - 1, threshold, -tangent); var tempOptimizer = new Bobyqa(2, tempBestFit.ComputeError, xl, xu); var tempResult = tempOptimizer.FindMinimum(startData); pieceWiseList.AddRange(tempBestFit.GenerateSubCurves(startData, xl, xu)); } } return(pieceWiseList); }
public List <Curve> GeneratePiecewiseGeodesicCurve(Mesh mesh, List <double> perpParameters, List <Curve> perpGeodesics, int maxIter, bool bothDir, int startIndex, double threshold, Vector3d dir) { // Generate Initial values and variable Bounds for the optimization problem. // Only using first variable for now, the extra variable is just to make it work. Random rnd = new Random(); double limit = 0.35; double start = (rnd.NextDouble() * limit) - (limit / 2); double[] startData = { start, 0 }; double[] xl = new double[] { -limit * Math.PI, -1 }; double[] xu = new double[] { limit *Math.PI, 1 }; // Generate bestfit G BestFitPieceWiseGeodesic bestFitG = new BestFitPieceWiseGeodesic(mesh, perpGeodesics, perpParameters, maxIter, bothDir, startIndex, threshold, dir); // Run optimization var optimizer = new Bobyqa(2, bestFitG.ComputeError, xl, xu); var result = optimizer.FindMinimum(startData); // If no best fit is found, gradually increase angle if (bestFitG.bestFitInterval.Length == 0 || result.F > 0.1) { do { limit += 0.05; Debug.WriteLine("Limit increased :" + limit); start = (rnd.NextDouble() * limit) - (limit / 2); startData[0] = start; xl = new double[] { -limit * Math.PI, -1 }; xu = new double[] { limit *Math.PI, 1 }; optimizer = new Bobyqa(2, bestFitG.ComputeError, xl, xu); result = optimizer.FindMinimum(startData); //Debug.WriteLine("Result: " + result.F + " Interval: " + bestFitG.bestFitInterval[0] + "-" + bestFitG.bestFitInterval[1]); } while (limit < 0.35); AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "No best interval found?!"); if (bestFitG.bestFitInterval.Length == 0) { return new List <Curve>() { bestFitG.selectedGeodesic } } ; } //Debug.WriteLine("Result: " + result.F + " Interval: " + bestFitG.bestFitInterval[0] + "-" + bestFitG.bestFitInterval[1]); // Split the curve double domainLength = bestFitG.bestFitInterval[1] - bestFitG.bestFitInterval[0]; Curve splitC = bestFitG.selectedGeodesic; splitC.Domain = new Interval(0, 1); List <Curve> pieceWiseList = new List <Curve>(); if (domainLength < perpGeodesics.Count - 4) { // Generate piecewise at end if (bestFitG.bestFitInterval[1] < perpGeodesics.Count - 3) { // Get reference point for splitting //var refInt = Intersection.CurveCurve(splitC, perpGeodesics[(bestFitG.bestFitInterval[1] - 1)], 0.0, 0.0); //double refT = refInt[0].ParameterA; // Get intersection with end point var endInt = Intersection.CurveCurve(splitC, perpGeodesics[(bestFitG.bestFitInterval[1])], 0.0, 0.0); var endParam = endInt[0].ParameterA; Point3d refPoint = splitC.PointAt(endParam / 2); // Split the curve Curve[] splitGs = splitC.Split(endParam); // Select the correct curve foreach (Curve g in splitGs) { double t; g.ClosestPoint(refPoint, out t); double distance = refPoint.DistanceTo(g.PointAt(t)); if (distance < 0.01) { splitC = g; break; } } List <double> paramsAtEnd = new List <double>(perpParameters); paramsAtEnd.RemoveRange(0, bestFitG.bestFitInterval[1]); List <Curve> geodsAtEnd = new List <Curve>(perpGeodesics); geodsAtEnd.RemoveRange(0, bestFitG.bestFitInterval[1]); // Replace first parameter with the parameter of the piecewise curve endpoint at the perpGeod. var events = Intersection.CurveCurve(geodsAtEnd[0], bestFitG.selectedGeodesic, 0.0, 0.0); paramsAtEnd[0] = events[0].ParameterA; // Get the best next best fit geodesic at end pieceWiseList.AddRange(GeneratePiecewiseAtEnd(mesh, paramsAtEnd, geodsAtEnd, maxIter, 0, threshold)); } //// Generate piecewise at start //if (bestFitG.bestFitInterval[0] > 3) //{ // var refInt = Intersection.CurveCurve(splitC, perpGeodesics[(bestFitG.bestFitInterval[0] + 2)], 0.0, 0.0); // Point3d refPoint = refInt[0].PointB; // // Get intersection with end point // var startInt = Intersection.CurveCurve(splitC, perpGeodesics[(bestFitG.bestFitInterval[0])], 0.0, 0.0); // var startParam = startInt[0].ParameterA; // // Split the curve // Curve[] splitGs = splitC.Split(startParam); // // Select the correct curve // foreach (Curve g in splitGs) // { // double t; // g.ClosestPoint(refPoint, out t); // double distance = refPoint.DistanceTo(g.PointAt(t)); // if (distance < 0.01) // { // splitC = g; // break; // } // } // List<double> paramsAtStart = new List<double>(perpParameters); // paramsAtStart.RemoveRange(bestFitG.bestFitInterval[0], (perpParameters.Count - 1) - bestFitG.bestFitInterval[0] - 1); // List<Curve> geodsAtStart = new List<Curve>(perpGeodesics); // geodsAtStart.RemoveRange(bestFitG.bestFitInterval[0], (perpGeodesics.Count - 1) - bestFitG.bestFitInterval[0] - 1); // // Replace first parameter with the parameter of the piecewise curve endpoint at the perpGeod. // paramsAtStart.Reverse(); // geodsAtStart.Reverse(); // var events = Intersection.CurveCurve(geodsAtStart[0], bestFitG.selectedGeodesic, 0.0, 0.0); // paramsAtStart[0] = events[0].ParameterA; // Vector3d vector = -splitC.TangentAtStart; // // This would be the same as at end, but with a first step flipping the direction of the perpGeodesics list. // /pieceWiseList.AddRange(GeneratePiecewiseAtStart(mesh, paramsAtStart, geodsAtStart, maxIter, 0, threshold, vector)); //} pieceWiseList.Add(splitC); } else { pieceWiseList.Add(bestFitG.selectedGeodesic); } //pieceWiseList = bestFitG.GenerateSubCurves(startData, xl, xu, 0); return(pieceWiseList); }
/// <summary> /// Generates the sub curves. /// </summary> /// <returns>The sub curves.</returns> /// <param name="_startData">Start data.</param> /// <param name="_xl">Xl.</param> /// <param name="_xu">Xu.</param> /// <param name="type">Generation type: 0 for doubleside, 1 for end side, -1 for start side of curve</param> public List <Curve> GenerateSubCurves(double[] _startData, double[] _xl, double[] _xu, int type) { // Generate Initial values and variable Bounds for the optimization problem. // Only using first variable for now, the extra variable is just to make it work. double[] startData = _startData; double[] xl = _xl; double[] xu = _xu; List <Curve> pieceWiseList = new List <Curve>(); pieceWiseList.Add(selectedGeodesic); if (bestFitInterval.Length != 0) { switch (type) { // End point case 1: pieceWiseList[0] = CutCurveBetweenPerpIndexes(pieceWiseList[0], perpGeodesics, 0, bestFitInterval[1]); break; // Start point case -1: pieceWiseList[0] = CutCurveBetweenPerpIndexes(pieceWiseList[0], perpGeodesics, bestFitInterval[0], perpGeodesics.Count - 1); break; default: pieceWiseList[0] = CutCurveBetweenPerpIndexes(pieceWiseList[0], perpGeodesics, bestFitInterval[0], bestFitInterval[1]); break; } if ((bestFitInterval[1] < (perpGeodesics.Count - 1)) && (type == 0 || type == 1)) { List <Curve> tempGeodesics = perpGeodesics.GetRange(bestFitInterval[1], (perpGeodesics.Count - bestFitInterval[1])); List <double> tempParameters = perpParameters.GetRange(bestFitInterval[1], (perpGeodesics.Count - bestFitInterval[1])); Vector3d tangent = pieceWiseList[0].TangentAtEnd; double t; tempGeodesics[0].ClosestPoint(pieceWiseList[0].PointAtEnd, out t); tempParameters[0] = t; BestFitPieceWiseGeodesic tempBestFit = new BestFitPieceWiseGeodesic(mesh, tempGeodesics, tempParameters, maxIter, false, 0, threshold, tangent); var tempOptimizer = new Bobyqa(2, tempBestFit.ComputeError, xl, xu); var tempResult = tempOptimizer.FindMinimum(startData); if (tempBestFit.bestFitInterval.Length == 0) { pieceWiseList[0] = selectedGeodesic; //No best fit found } else { pieceWiseList.AddRange(tempBestFit.GenerateSubCurves(startData, xl, xu, 1)); } } //if (bestFitInterval[0] > 0 && (type == 0 || type == -1)) //{ // List<Curve> tempGeodesics = perpGeodesics.GetRange(0, bestFitInterval[0] + 1); // List<double> tempParameters = perpParameters.GetRange(0, bestFitInterval[0] + 1); // double t; // Vector3d tangent = pieceWiseList[0].TangentAtStart; // //tangent.Rotate(Math.PI, mesh.NormalAt(mesh.ClosestMeshPoint(pieceWiseList[0].PointAtStart, 0.0))); // tempGeodesics[tempGeodesics.Count - 1].ClosestPoint(pieceWiseList[0].PointAtStart, out t); // tempParameters[tempGeodesics.Count - 1] = t; // BestFitPieceWiseGeodesic tempBestFit = new BestFitPieceWiseGeodesic(mesh, tempGeodesics, tempParameters, maxIter, false, tempGeodesics.Count - 1, threshold, -tangent); // var tempOptimizer = new Bobyqa(2, tempBestFit.ComputeError, xl, xu); // var tempResult = tempOptimizer.FindMinimum(startData); // if (tempBestFit.bestFitInterval.Length == 0) // { // pieceWiseList.Add(tempBestFit.selectedGeodesic); // No best fit found; // } // else // { // tempBestFit.selectedGeodesic.Reverse(); // pieceWiseList.AddRange(tempBestFit.GenerateSubCurves(startData, xl, xu, -1)); // } //} } return(pieceWiseList); }
protected override void SolveInstance(IGH_DataAccess DA) { // Properties Mesh mesh = null; List <Curve> perpGeodesics = new List <Curve>(); List <double> perpParameters = new List <double>(); int maxIter = 0; bool bothDir = false; int startIndex = 0; mesh = null; perpGeodesics = new List <Curve>(); perpParameters = new List <double>(); double threshold = 0.0; // Set the input data if (!DA.GetData(0, ref mesh)) { return; } if (!DA.GetDataList(1, perpGeodesics)) { return; } if (!DA.GetDataList(2, perpParameters)) { return; } if (!DA.GetData(3, ref maxIter)) { return; } if (!DA.GetData(4, ref bothDir)) { return; } if (!DA.GetData(5, ref startIndex)) { return; } if (!DA.GetData(6, ref threshold)) { return; } // Data validation if (maxIter == 0) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "MaxIter cannot be 0"); } if (!mesh.IsValid) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Mesh is invalid"); } if (perpGeodesics.Count < 2) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "There must be at least 2 perpendicular geodesics"); } if (perpParameters.Count != perpGeodesics.Count) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Curves and Params list must have the same number of items"); } // Generate Initial values and variable Bounds for the optimization problem. // Only using first variable for now, the extra variable is just to make it work. double[] startData = { 0.010, 0 }; double[] xl = new double[] { -0.15, -1 }; double[] xu = new double[] { 0.15, 1 }; BestFitPieceWiseGeodesic bestFitG = new BestFitPieceWiseGeodesic(mesh, perpGeodesics, perpParameters, maxIter, bothDir, startIndex, threshold, Vector3d.Unset); var optimizer = new Bobyqa(2, bestFitG.ComputeError, xl, xu); var result = optimizer.FindMinimum(startData); if (bestFitG.bestFitInterval.Length == 0) { AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "No best interval found?!"); return; } // Sub curves methods go here List <Curve> pieceWiseList = new List <Curve>(); pieceWiseList = bestFitG.GenerateSubCurves(startData, xl, xu); DA.SetDataList(0, pieceWiseList); DA.SetDataList(1, result.X); }