- dist1 = startpoint.distanceTo(coord);
- dist2 = endpoint.distanceTo(coord);
-
- if (dist2<dist1) {
- if (dist!=NULL) {
- *dist = dist2;
- }
- nearerPoint = endpoint;
- } else {
- if (dist!=NULL) {
- *dist = dist1;
- }
- nearerPoint = startpoint;
- }
-
- return nearerPoint;
-}
-
-
-
-Vector RS_Ellipse::getNearestPointOnEntity(const Vector& coord,
- bool onEntity, double* dist, RS_Entity** entity) {
-
- RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity");
-
- Vector ret(false);
-
- if (entity!=NULL) {
- *entity = this;
- }
- double ang = getAngle();
-
- Vector normalized = (coord - data.center).rotate(-ang);
-
- double dU = normalized.x;
- double dV = normalized.y;
- double dA = getMajorRadius();
- double dB = getMinorRadius();
- double dEpsilon = 1.0e-8;
- int iMax = 32;
- int riIFinal = 0;
- double rdX = 0.0;
- double rdY = 0.0;
- double dDistance;
- bool swap = false;
- bool majorSwap = false;
-
- if (dA<dB) {
- double dum = dA;
- dA = dB;
- dB = dum;
- dum = dU;
- dU = dV;
- dV = dum;
- majorSwap = true;
- }
-
- if (dV<0.0) {
- dV*=-1.0;
- swap = true;
- }
-
- // initial guess
- double dT = dB*(dV - dB);
-
- // Newton s method
- int i;
- for (i = 0; i < iMax; i++) {
- RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity: i: %d", i);
- double dTpASqr = dT + dA*dA;
- double dTpBSqr = dT + dB*dB;
- double dInvTpASqr = 1.0/dTpASqr;
- double dInvTpBSqr = 1.0/dTpBSqr;
- double dXDivA = dA*dU*dInvTpASqr;
- double dYDivB = dB*dV*dInvTpBSqr;
- double dXDivASqr = dXDivA*dXDivA;
- double dYDivBSqr = dYDivB*dYDivB;
- double dF = dXDivASqr + dYDivBSqr - 1.0;
- RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity: dF: %f", dF);
- if ( fabs(dF) < dEpsilon ) {
- // F(t0) is close enough to zero, terminate the iteration:
- rdX = dXDivA*dA;
- rdY = dYDivB*dB;
- riIFinal = i;
- RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity: rdX,rdY 1: %f,%f", rdX, rdY);
- break;
- }
- double dFDer = 2.0*(dXDivASqr*dInvTpASqr + dYDivBSqr*dInvTpBSqr);
- double dRatio = dF/dFDer;
- RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity: dRatio: %f", dRatio);
- if ( fabs(dRatio) < dEpsilon ) {
- // t1-t0 is close enough to zero, terminate the iteration:
- rdX = dXDivA*dA;
- rdY = dYDivB*dB;
- riIFinal = i;
- RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity: rdX,rdY 2: %f,%f", rdX, rdY);
- break;
- }
- dT += dRatio;
- }
- if ( i == iMax ) {
- // failed to converge:
- RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity: failed");
- dDistance = RS_MAXDOUBLE;
- }
- else {
- double dDelta0 = rdX - dU;
- double dDelta1 = rdY - dV;
- dDistance = sqrt(dDelta0*dDelta0 + dDelta1*dDelta1);
- ret = Vector(rdX, rdY);
- RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity: rdX,rdY 2: %f,%f", rdX, rdY);
- RS_DEBUG->print("RS_Ellipse::getNearestPointOnEntity: ret: %f,%f", ret.x, ret.y);
- }
-
- if (dist!=NULL) {
- if (ret.valid) {
- *dist = dDistance;
- } else {
- *dist = RS_MAXDOUBLE;
- }
- }
-
- if (ret.valid) {
- if (swap) {
- ret.y*=-1.0;
- }
- if (majorSwap) {
- double dum = ret.x;
- ret.x = ret.y;
- ret.y = dum;
- }
- ret = (ret.rotate(ang) + data.center);
-
- if (onEntity) {
- double a1 = data.center.angleTo(getStartpoint());
- double a2 = data.center.angleTo(getEndpoint());
- double a = data.center.angleTo(ret);
- if (!RS_Math::isAngleBetween(a, a1, a2, data.reversed)) {
- ret = Vector(false);
- }
- }
- }
-
- return ret;