472 |
} |
} |
473 |
}; |
}; |
474 |
|
|
475 |
|
|
476 |
|
/** Project a point through another point to a circle. |
477 |
|
* @param pt the point to project |
478 |
|
* @param p the projection center |
479 |
|
* @param ctr The center of the circle |
480 |
|
* @param rad The radius of the circle |
481 |
|
* @return The projected point, or if not possible, the original pt. |
482 |
|
*/ |
483 |
|
Vec project2circle(Vec pt, Vec p, Vec ctr, float rad) { |
484 |
|
Vec ao = pt - ctr; |
485 |
|
Vec ap = pt - p; |
486 |
|
|
487 |
|
// Coefficients of the 2nd degree equation |
488 |
|
float a = dot(ap, ap); |
489 |
|
float b = 2*dot(ap, ao); |
490 |
|
float c = dot(ao, ao) - rad * rad; |
491 |
|
|
492 |
|
// determinant of the equation |
493 |
|
float det = b*b - 4*a*c; |
494 |
|
|
495 |
|
float ans = (det > 0 ? (-b + sqrt(det)) / (2*a) : 0); |
496 |
|
|
497 |
|
return pt + ans * ap; |
498 |
|
|
499 |
|
} |
500 |
|
|
501 |
|
|
502 |
/** Buoy coordinates. |
/** Buoy coordinates. |
503 |
* <p> |
* <p> |
504 |
* The depth is between -1 (center) and 0 (edge) |
* The depth is between -1 (center) and 0 (edge) |
505 |
* <p> |
* <p> |
506 |
* Parameter layout: |
* Parameter layout: |
507 |
* x_circle, y_circle, radius, x_projpoint, y_projpoint, pointdir |
* x_circle, y_circle, radius, x_projpoint, y_projpoint, shiftamount |
508 |
* <p> |
* <p> |
|
* Pointdir = 0 -> place at center, pointdir = 1, place |
|
|
* normally, -1, place with projpoint = center+(center-projpoint) |
|
509 |
* Linear interp between 0..1, 0..-1 |
* Linear interp between 0..1, 0..-1 |
510 |
*/ |
*/ |
511 |
class BuoyOnCircleCoords { |
class BuoyOnCircleCoords { |
|
bool valid; |
|
512 |
public: |
public: |
513 |
typedef AffineXYCoords BaseTransform; |
typedef AffineXYCoords BaseTransform; |
514 |
enum { NParams = 6, NDetermining = 1 }; |
enum { NParams = 6, NDetermining = 1 }; |
517 |
|
|
518 |
CoordSys *anchor = *anchorp; |
CoordSys *anchor = *anchorp; |
519 |
|
|
520 |
float pointdir = params[5]; |
Pt ctr(params[0], params[1]); |
521 |
ZVec ctr(params[0], params[1], 0); |
Pt proj(params[3], params[4]); |
|
ZVec proj(params[3], params[4], 0); |
|
522 |
float radius = params[2]; |
float radius = params[2]; |
523 |
|
float shiftamount = params[5]; |
524 |
|
|
|
if(pointdir < 0) { |
|
|
proj = ctr + (ctr - proj); |
|
|
pointdir = -pointdir; |
|
|
} |
|
525 |
|
|
526 |
// Get the anchor of the buoy |
// Get the anchor of the buoy |
527 |
ZPt anchorPt = anchor->transform(ZPt(0,0,0)); |
ZPt anchorZPt(anchor->transform(ZPt(0,0,0))); |
528 |
// Now that we have the anchor, project |
Pt anchorPt(anchorZPt); |
|
// from it to the circle. |
|
|
ZVec amc = proj - ctr; amc.z = 0; |
|
|
ZVec v = anchorPt - proj; v.z = 0; |
|
|
// coeffs of 2nd degree eq |
|
|
float a = v.dot(v); |
|
|
float b = 2*v.dot(amc); |
|
|
float c = amc.dot(amc) - radius*radius; |
|
|
|
|
|
float rdist = (anchorPt-ctr).length() / radius; |
|
|
|
|
|
float det = b*b - 4*a*c; |
|
|
|
|
|
DBG(dbg_buoy) << "eq: "<<anchorPt<<" "<<amc<<" "<<v<<" "<<a<<" "<<b<<" "<<c<<"\n"; |
|
|
|
|
|
ZPt pt; |
|
|
if(det <= 0) { |
|
|
pt = ZVec(0,0,0); |
|
|
DBG(dbg_buoy) << "No solution - zero\n"; |
|
|
} else { |
|
|
float ans = (-b + sqrt(det)) / (2*a); |
|
|
pt = proj + ans * v; |
|
|
DBG(dbg_buoy) << "solution: "<<pt<<"\n"; |
|
|
} |
|
529 |
|
|
530 |
|
// shifted point: default buoy location |
531 |
|
Pt shifted = anchorPt + (ctr - proj) * shiftamount; |
532 |
|
|
533 |
ZPt tr = ctr + pointdir * (pt-ctr); |
float shiftrad = (shifted - ctr).length(); |
534 |
|
float anchorrad = (anchorPt - ctr).length(); |
535 |
|
|
536 |
|
Pt buoy; |
537 |
|
if(shiftrad >= radius) { |
538 |
|
// if shifted point is outside circle, our work is done |
539 |
|
buoy = shifted; |
540 |
|
} else { |
541 |
|
if(anchorrad >= radius) |
542 |
|
// otherwise, kludge it by placing it on the anchor. |
543 |
|
// There's a small jump here; we should do it differently. |
544 |
|
buoy = anchorPt; // XXX ??? |
545 |
|
else |
546 |
|
// If both anchor and shifted point are inside circle, |
547 |
|
// project. |
548 |
|
buoy = project2circle(anchorPt, proj, ctr, radius); |
549 |
|
} |
550 |
|
|
551 |
valid = 1; |
float scale = 1-anchorrad / radius ; |
|
float scale = 1-rdist; |
|
552 |
|
|
553 |
if(scale <.0001) { |
if(scale <shiftamount) { |
554 |
valid = 0; |
scale = shiftamount; |
|
scale = 1; |
|
555 |
} |
} |
556 |
DBG(dbg_buoy) << "final: "<<tr<<" "<<valid<<" "<<scale<<" "<<rdist<<"\n"; |
DBG(dbg_buoy) << "final: "<<buoy << " "<<" "<<scale<<" "<<"\n"; |
557 |
|
|
558 |
newparams[0] = tr.x; |
newparams[0] = buoy.x; |
559 |
newparams[1] = tr.y; |
newparams[1] = buoy.y; |
560 |
newparams[2] = tr.z - scale; |
newparams[2] = anchorZPt.z - scale; |
561 |
newparams[3] = scale; |
newparams[3] = scale; |
562 |
newparams[4] = 0; |
newparams[4] = 0; |
563 |
newparams[5] = 0; |
newparams[5] = 0; |
564 |
newparams[6] = scale; |
newparams[6] = scale; |
565 |
} |
} |
566 |
virtual bool shouldBeDrawn() { |
bool shouldBeDrawn() { return true; } |
|
return valid; |
|
|
} |
|
567 |
}; |
}; |
568 |
|
|
569 |
/** Rotation around 3D vector. |
/** Rotation around 3D vector. |