*
* @return Data that describes the arc.
*/
protected ArcData computeArc(DrawContext dc)
{
Globe globe = dc.getGlobe();
// The graphic looks like this:
//
// A \
// \
// Mid |______\
// | /
// /
// B /
Vec4 pA = globe.computePointFromPosition(this.position2);
Vec4 pB = globe.computePointFromPosition(this.position3);
Position baseMidpoint = new Position(LatLon.interpolate(0.5, this.position2, this.position3), 0);
Vec4 pMid = globe.computePointFromPosition(baseMidpoint);
// Compute a vector perpendicular to the segment AB and the normal vector
Vec4 vAB = pB.subtract3(pA);
Vec4 normal = globe.computeSurfaceNormalAtPoint(pMid);
Vec4 perpendicular = vAB.cross3(normal).normalize3();
ArcData arcData = new ArcData();
double chordLength = pA.distanceTo3(pB);
Angle arcAngle = this.getArcAngle();
// The arc is drawn as a segment of a circle defined by a chord and the arc angle. Control points 2 and 3 define
// the chord. Compute the radius of the circle, and the distance from the center of the circle to the chord from
// this information. See http://mathworld.wolfram.com/CircularSegment.html and
// http://en.wikipedia.org/wiki/Circular_segment for background on these formulas.
arcData.radius = chordLength / (2 * arcAngle.sinHalfAngle());
double dist = arcData.radius * arcAngle.cosHalfAngle();
// Determine which side of the line AB the arrow point falls on. We want the arc face away from the arrow, so
// set the direction of the perpendicular component according to the sign of the scalar triple product.
Vec4 vOrientation = globe.computePointFromPosition(this.position1).subtract3(pMid);
double tripleProduct = perpendicular.dot3(vOrientation);
double sign = (tripleProduct > 0) ? -1 : 1;
arcData.direction = perpendicular.multiply3(sign);
// Find the center point of the circle
Vec4 pCenter = pMid.add3(arcData.direction.multiply3(dist));
arcData.center = globe.computePositionFromPoint(pCenter);
// Compute the start and sweep angles for the arc
arcData.startAngle = LatLon.greatCircleAzimuth(arcData.center, this.position2);
Angle endAngle = LatLon.greatCircleAzimuth(arcData.center, this.position3);
// Compute the angle between the start and end points. Note that we cannot use Angle.angularDistance because
// we need a signed distance here.
double diffDegrees = endAngle.subtract(arcData.startAngle).degrees;
if (diffDegrees < -180)
diffDegrees += 360;
else if (diffDegrees > 180)
diffDegrees -= 360;
arcData.arcAngle = Angle.fromDegrees(diffDegrees);
// Find the midpoint of the arc
double globeRadius = globe.getRadiusAt(arcData.center.getLatitude(), arcData.center.getLongitude());
LatLon ll = LatLon.greatCircleEndPosition(arcData.center,
arcData.arcAngle.divide(2.0).radians + arcData.startAngle.radians, arcData.radius / globeRadius);
arcData.midpoint = new Position(ll, 0);
return arcData;