/* * NearestPointOnCurve : * Compute the parameter value of the point on a Bezier * curve segment closest to some arbtitrary, user-input point. * Return the point on the curve at that parameter value. * Geom::Point P; The user-supplied point Geom::Point *V; Control points of cubic Bezier */ double NearestPointOnCurve(Geom::Point P, Geom::Point *V) { double t_candidate[W_DEGREE]; /* Possible roots */ /* Convert problem to 5th-degree Bezier form */ Geom::Point *w = ConvertToBezierForm(P, V); /* Find all possible roots of 5th-degree equation */ int n_solutions = FindRoots(w, W_DEGREE, t_candidate, 0); std::free((char *)w); /* Check distance to end of the curve, where t = 1 */ double dist = SquaredLength(P - V[DEGREE]); double t = 1.0; /* Find distances for candidate points */ for (int i = 0; i < n_solutions; i++) { Geom::Point p = Bez(V, DEGREE, t_candidate[i], NULL, NULL); double new_dist = SquaredLength(P - p); if (new_dist < dist) { dist = new_dist; t = t_candidate[i]; } } /* Return the parameter value t */ return t; }
double Measurement::NearestPointOnCurve(QPointF P, vector<QPointF> V) { QPointF *w; /* Ctl pts for 5th-degree eqn */ double t_candidate[W_DEGREE]; /* Possible roots */ int n_solutions; /* Number of roots found */ double t; /* Parameter value of closest pt*/ QPointF v_arr[4]; for(int i=0; i<4; i++) v_arr[i]=V[i]; /* Convert problem to 5th-degree Bezier form */ w = ConvertToBezierForm(P, v_arr); /* Find all possible roots of 5th-degree equation */ n_solutions = FindRoots(w, W_DEGREE, t_candidate, 0); free((char *)w); /* Compare distances of P to all candidates, and to t=0, and t=1 */ { double dist, new_dist; QPointF p; QPointF v; int i; /* Check distance to beginning of curve, where t = 0 */ dist = V2SquaredLength(V2Sub(&P, &v_arr[0], &v)); t = 0.0; /* Find distances for candidate points */ for (i = 0; i < n_solutions; i++) { p = Bezier(v_arr, DEGREE, t_candidate[i], (QPointF *)NULL, (QPointF *)NULL); new_dist = V2SquaredLength(V2Sub(&P, &p, &v)); if (new_dist < dist) { dist = new_dist; t = t_candidate[i]; } } /* Finally, look at distance to end point, where t = 1.0 */ new_dist = V2SquaredLength(V2Sub(&P, &V[DEGREE], &v)); if (new_dist < dist) { dist = new_dist; t = 1.0; } } /* Return the point on the curve at parameter value t */ // printf("t : %4.12f\n", t); QPointF b=Bezier(v_arr, DEGREE, t, (QPointF *)NULL, (QPointF *)NULL); return V2DistanceBetween2Points(&P,&b); }
// 计算一点到三次贝塞尔曲线段上的最近点 // Parameters : // pt: The user-supplied point // pts: Control points of cubic Bezier // nearpt: output the point on the curve at that parameter value // GEOMAPI void mgNearestOnBezier( const Point2d& pt, const Point2d* pts, Point2d& nearpt) { Point2d w[W_DEGREE+1]; // Ctl pts for 5th-degree eqn float t_candidate[W_DEGREE]; // Possible roots int n_solutions; // Number of roots found float t; // Parameter value of closest pt // Convert problem to 5th-degree Bezier form ConvertToBezierForm(pt, pts, w); // Find all possible roots of 5th-degree equation n_solutions = FindRoots(w, W_DEGREE, t_candidate, 0); // Compare distances of pt to all candidates, and to t=0, and t=1 { float dist, new_dist; Point2d p; int i; // Check distance to beginning of curve, where t = 0 dist = (pt - pts[0]).lengthSqrd(); t = 0.0; // Find distances for candidate points for (i = 0; i < n_solutions; i++) { p = BezierPoint(pts, DEGREE, t_candidate[i], (Point2d *)NULL, (Point2d *)NULL); new_dist = (pt - p).lengthSqrd(); if (new_dist < dist) { dist = new_dist; t = t_candidate[i]; } } // Finally, look at distance to end point, where t = 1.0 new_dist = (pt - pts[DEGREE]).lengthSqrd(); if (new_dist < dist) { dist = new_dist; t = 1.0; } } // Return the point on the curve at parameter value t // printf("t : %4.12f\n", t); nearpt = (BezierPoint(pts, DEGREE, t, (Point2d *)NULL, (Point2d *)NULL)); }