Example #1
0
        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);
        }
Example #2
0
        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);
        }