Fixed planet picking to actually compute ray-sphere intersections.
parent
97d39ad87a
commit
1cf7e96de1
|
@ -405,13 +405,14 @@ void Simulation::setSelection(const Selection& sel)
|
||||||
struct PlanetPickInfo
|
struct PlanetPickInfo
|
||||||
{
|
{
|
||||||
float cosClosestAngle;
|
float cosClosestAngle;
|
||||||
|
double closestDistance;
|
||||||
Body* closestBody;
|
Body* closestBody;
|
||||||
Vec3d direction;
|
Vec3d direction;
|
||||||
Point3d origin;
|
Point3d origin;
|
||||||
double jd;
|
double jd;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool PlanetPickTraversal(Body* body, void* info)
|
bool ApproxPlanetPickTraversal(Body* body, void* info)
|
||||||
{
|
{
|
||||||
PlanetPickInfo* pickInfo = (PlanetPickInfo*) info;
|
PlanetPickInfo* pickInfo = (PlanetPickInfo*) info;
|
||||||
|
|
||||||
|
@ -429,6 +430,32 @@ bool PlanetPickTraversal(Body* body, void* info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Perform an intersection test between the pick ray and a body
|
||||||
|
bool ExactPlanetPickTraversal(Body* body, void* info)
|
||||||
|
{
|
||||||
|
PlanetPickInfo* pickInfo = (PlanetPickInfo*) info;
|
||||||
|
|
||||||
|
Point3d bpos = body->getHeliocentricPosition(pickInfo->jd);
|
||||||
|
Vec3d bodyDir = bpos - pickInfo->origin;
|
||||||
|
|
||||||
|
// This intersection test naively assumes that the body is spherical.
|
||||||
|
double v = bodyDir * pickInfo->direction;
|
||||||
|
double disc = square(body->getRadius()) - ((bodyDir * bodyDir) - square(v));
|
||||||
|
|
||||||
|
if (disc > 0.0)
|
||||||
|
{
|
||||||
|
double distance = v - sqrt(disc);
|
||||||
|
if (distance > 0.0 && distance < pickInfo->closestDistance)
|
||||||
|
{
|
||||||
|
pickInfo->closestDistance = distance;
|
||||||
|
pickInfo->closestBody = body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Selection Simulation::pickPlanet(Observer& observer,
|
Selection Simulation::pickPlanet(Observer& observer,
|
||||||
Star& sun,
|
Star& sun,
|
||||||
SolarSystem& solarSystem,
|
SolarSystem& solarSystem,
|
||||||
|
@ -444,10 +471,28 @@ Selection Simulation::pickPlanet(Observer& observer,
|
||||||
pickInfo.origin = astro::heliocentricPosition(observer.getPosition(),
|
pickInfo.origin = astro::heliocentricPosition(observer.getPosition(),
|
||||||
sun.getPosition());
|
sun.getPosition());
|
||||||
pickInfo.cosClosestAngle = -1.0f;
|
pickInfo.cosClosestAngle = -1.0f;
|
||||||
|
pickInfo.closestDistance = 1.0e50;
|
||||||
pickInfo.closestBody = NULL;
|
pickInfo.closestBody = NULL;
|
||||||
pickInfo.jd = simTime / 86400.0f;
|
pickInfo.jd = simTime / 86400.0f;
|
||||||
|
|
||||||
solarSystem.getPlanets()->traverse(PlanetPickTraversal, (void*) &pickInfo);
|
// First see if there's a planet that the pick ray intersects.
|
||||||
|
// Select the closest planet intersected.
|
||||||
|
solarSystem.getPlanets()->traverse(ExactPlanetPickTraversal,
|
||||||
|
(void*) &pickInfo);
|
||||||
|
if (pickInfo.closestBody != NULL)
|
||||||
|
{
|
||||||
|
selection = Selection(pickInfo.closestBody);
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no planet was intersected by the pick ray, choose the planet
|
||||||
|
// with the smallest angular separation from the pick ray. Very distant
|
||||||
|
// planets are likley to fail the intersection test even if the user
|
||||||
|
// clicks on a pixel where the planet's disc has been rendered--in order
|
||||||
|
// to make distant planets visible on the screen at all, their apparent size
|
||||||
|
// has to be greater than their actual disc size.
|
||||||
|
solarSystem.getPlanets()->traverse(ApproxPlanetPickTraversal,
|
||||||
|
(void*) &pickInfo);
|
||||||
if (pickInfo.cosClosestAngle > cos(degToRad(0.5f)))
|
if (pickInfo.cosClosestAngle > cos(degToRad(0.5f)))
|
||||||
selection = Selection(pickInfo.closestBody);
|
selection = Selection(pickInfo.closestBody);
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue