static Frame *MakeFrameFor(SystemBody *sbody, Body *b, Frame *f) { if (!sbody->parent) { if (b) b->SetFrame(f); f->SetBodies(sbody, b); return f; } if (sbody->type == SystemBody::TYPE_GRAVPOINT) { Frame *orbFrame = new Frame(f, sbody->name.c_str()); orbFrame->SetBodies(sbody, b); orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1); return orbFrame; } SystemBody::BodySuperType supertype = sbody->GetSuperType(); if ((supertype == SystemBody::SUPERTYPE_GAS_GIANT) || (supertype == SystemBody::SUPERTYPE_ROCKY_PLANET)) { // for planets we want an non-rotating frame for a few radii // and a rotating frame with no radius to contain attached objects double frameRadius = std::max(4.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.05); Frame *orbFrame = new Frame(f, sbody->name.c_str(), Frame::FLAG_HAS_ROT); orbFrame->SetBodies(sbody, b); orbFrame->SetRadius(frameRadius); //printf("\t\t\t%s has frame size %.0fkm, body radius %.0fkm\n", sbody->name.c_str(), // (frameRadius ? frameRadius : 10*sbody->GetRadius())*0.001f, // sbody->GetRadius()*0.001f); assert(sbody->rotationPeriod != 0); Frame *rotFrame = new Frame(orbFrame, sbody->name.c_str(), Frame::FLAG_ROTATING); rotFrame->SetBodies(sbody, b); // rotating frame has atmosphere radius or feature height, whichever is larger rotFrame->SetRadius(b->GetPhysRadius()); matrix3x3d rotMatrix = matrix3x3d::RotateX(sbody->axialTilt.ToDouble()); double angSpeed = 2.0*M_PI/sbody->GetRotationPeriod(); rotFrame->SetAngSpeed(angSpeed); if (sbody->rotationalPhaseAtStart != fixed(0)) rotMatrix = rotMatrix * matrix3x3d::RotateY(sbody->rotationalPhaseAtStart.ToDouble()); rotFrame->SetOrient(rotMatrix); b->SetFrame(rotFrame); return orbFrame; } else if (supertype == SystemBody::SUPERTYPE_STAR) { // stars want a single small non-rotating frame // bigger than it's furtherest orbiting body. // if there are no orbiting bodies use a frame of several radii. Frame *orbFrame = new Frame(f, sbody->name.c_str()); orbFrame->SetBodies(sbody, b); orbFrame->SetRadius(std::max(10.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.1)); b->SetFrame(orbFrame); return orbFrame; } else if (sbody->type == SystemBody::TYPE_STARPORT_ORBITAL) { // space stations want non-rotating frame to some distance // and a zero-size rotating frame Frame *orbFrame = new Frame(f, sbody->name.c_str(), Frame::FLAG_HAS_ROT); orbFrame->SetBodies(sbody, b); // orbFrame->SetRadius(10*sbody->GetRadius()); orbFrame->SetRadius(20000.0); // 4x standard parking radius b->SetFrame(orbFrame); return orbFrame; // assert(sbody->rotationPeriod != 0); // rotFrame = new Frame(orbFrame, sbody->name.c_str(), Frame::FLAG_ROTATING); // rotFrame->SetBodies(sbody, b); // rotFrame->SetRadius(0.0); // rotFrame->SetAngVelocity(vector3d(0.0,double(static_cast<SpaceStation*>(b)->GetDesiredAngVel()),0.0)); // b->SetFrame(rotFrame); } else if (sbody->type == SystemBody::TYPE_STARPORT_SURFACE) { // just put body into rotating frame of planet, not in its own frame // (because collisions only happen between objects in same frame, // and we want collisions on starport and on planet itself) Frame *rotFrame = f->GetRotFrame(); b->SetFrame(rotFrame); assert(rotFrame->IsRotFrame()); assert(rotFrame->GetBody()->IsType(Object::PLANET)); matrix3x3d rot; vector3d pos; Planet *planet = static_cast<Planet*>(rotFrame->GetBody()); RelocateStarportIfUnderwaterOrBuried(sbody, rotFrame, planet, pos, rot); sbody->orbit.rotMatrix = rot; b->SetPosition(pos * planet->GetTerrainHeight(pos)); b->SetOrient(rot); return rotFrame; } else { assert(0); } return NULL; }
static Frame *MakeFrameFor(double at_time, SystemBody *sbody, Body *b, Frame *f) { if (!sbody->GetParent()) { if (b) b->SetFrame(f); f->SetBodies(sbody, b); return f; } if (sbody->GetType() == SystemBody::TYPE_GRAVPOINT) { Frame *orbFrame = new Frame(f, sbody->GetName().c_str()); orbFrame->SetBodies(sbody, b); orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1); return orbFrame; } SystemBody::BodySuperType supertype = sbody->GetSuperType(); if ((supertype == SystemBody::SUPERTYPE_GAS_GIANT) || (supertype == SystemBody::SUPERTYPE_ROCKY_PLANET)) { // for planets we want an non-rotating frame for a few radii // and a rotating frame with no radius to contain attached objects double frameRadius = std::max(4.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.05); Frame *orbFrame = new Frame(f, sbody->GetName().c_str(), Frame::FLAG_HAS_ROT); orbFrame->SetBodies(sbody, b); orbFrame->SetRadius(frameRadius); //Output("\t\t\t%s has frame size %.0fkm, body radius %.0fkm\n", sbody->name.c_str(), // (frameRadius ? frameRadius : 10*sbody->GetRadius())*0.001f, // sbody->GetRadius()*0.001f); assert(sbody->IsRotating() != 0); Frame *rotFrame = new Frame(orbFrame, sbody->GetName().c_str(), Frame::FLAG_ROTATING); rotFrame->SetBodies(sbody, b); // rotating frame has atmosphere radius or feature height, whichever is larger rotFrame->SetRadius(b->GetPhysRadius()); matrix3x3d rotMatrix = matrix3x3d::RotateX(sbody->GetAxialTilt()); double angSpeed = 2.0*M_PI/sbody->GetRotationPeriod(); rotFrame->SetAngSpeed(angSpeed); if (sbody->HasRotationPhase()) rotMatrix = rotMatrix * matrix3x3d::RotateY(sbody->GetRotationPhaseAtStart()); rotFrame->SetInitialOrient(rotMatrix, at_time); b->SetFrame(rotFrame); return orbFrame; } else if (supertype == SystemBody::SUPERTYPE_STAR) { // stars want a single small non-rotating frame // bigger than it's furtherest orbiting body. // if there are no orbiting bodies use a frame of several radii. Frame *orbFrame = new Frame(f, sbody->GetName().c_str()); orbFrame->SetBodies(sbody, b); double frameRadius = std::max(10.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.1); // Respect the frame of other stars in the multi-star system. We still make sure that the frame ends outside // the body. For a minimum separation of 1.236 radii, nothing will overlap (see StarSystem::StarSystem()). if (sbody->GetParent() && frameRadius > AU * 0.11 * sbody->GetOrbMin()) frameRadius = std::max(1.1*sbody->GetRadius(), AU * 0.11 * sbody->GetOrbMin()); orbFrame->SetRadius(frameRadius); b->SetFrame(orbFrame); return orbFrame; } else if (sbody->GetType() == SystemBody::TYPE_STARPORT_ORBITAL) { // space stations want non-rotating frame to some distance Frame *orbFrame = new Frame(f, sbody->GetName().c_str()); orbFrame->SetBodies(sbody, b); // orbFrame->SetRadius(10*sbody->GetRadius()); orbFrame->SetRadius(20000.0); // 4x standard parking radius b->SetFrame(orbFrame); return orbFrame; } else if (sbody->GetType() == SystemBody::TYPE_STARPORT_SURFACE) { // just put body into rotating frame of planet, not in its own frame // (because collisions only happen between objects in same frame, // and we want collisions on starport and on planet itself) Frame *rotFrame = f->GetRotFrame(); b->SetFrame(rotFrame); assert(rotFrame->IsRotFrame()); assert(rotFrame->GetBody()->IsType(Object::PLANET)); matrix3x3d rot; vector3d pos; Planet *planet = static_cast<Planet*>(rotFrame->GetBody()); RelocateStarportIfUnderwaterOrBuried(sbody, rotFrame, planet, pos, rot); sbody->SetOrbitPlane(rot); b->SetPosition(pos * planet->GetTerrainHeight(pos)); b->SetOrient(rot); return rotFrame; } else { assert(0); } return 0; }
static Frame *MakeFrameFor(SystemBody *sbody, Body *b, Frame *f) { Frame *orbFrame, *rotFrame; double frameRadius; if (!sbody->parent) { if (b) b->SetFrame(f); f->m_sbody = sbody; f->m_astroBody = b; return f; } if (sbody->type == SystemBody::TYPE_GRAVPOINT) { orbFrame = new Frame(f, sbody->name.c_str()); orbFrame->m_sbody = sbody; orbFrame->m_astroBody = b; orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1); return orbFrame; } SystemBody::BodySuperType supertype = sbody->GetSuperType(); if ((supertype == SystemBody::SUPERTYPE_GAS_GIANT) || (supertype == SystemBody::SUPERTYPE_ROCKY_PLANET)) { // for planets we want an non-rotating frame for a few radii // and a rotating frame in the same position but with maybe 1.05*radius, // which actually contains the object. frameRadius = std::max(4.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.05); orbFrame = new Frame(f, sbody->name.c_str()); orbFrame->m_sbody = sbody; orbFrame->SetRadius(frameRadius); //printf("\t\t\t%s has frame size %.0fkm, body radius %.0fkm\n", sbody->name.c_str(), // (frameRadius ? frameRadius : 10*sbody->GetRadius())*0.001f, // sbody->GetRadius()*0.001f); assert(sbody->rotationPeriod != 0); rotFrame = new Frame(orbFrame, sbody->name.c_str()); // rotating frame has size of GeoSphere terrain bounding sphere rotFrame->SetRadius(b->GetBoundingRadius()); matrix4x4d rotMatrix = matrix4x4d::RotateXMatrix(sbody->axialTilt.ToDouble()); vector3d angVel = vector3d(0.0, 2.0*M_PI/sbody->GetRotationPeriod(), 0.0); rotFrame->SetAngVelocity(angVel); if (sbody->rotationalPhaseAtStart != fixed(0)) rotMatrix = rotMatrix * matrix4x4d::RotateYMatrix(sbody->rotationalPhaseAtStart.ToDouble()); rotFrame->SetRotationOnly(rotMatrix); rotFrame->m_astroBody = b; b->SetFrame(rotFrame); return orbFrame; } else if (supertype == SystemBody::SUPERTYPE_STAR) { // stars want a single small non-rotating frame orbFrame = new Frame(f, sbody->name.c_str()); orbFrame->m_sbody = sbody; orbFrame->m_astroBody = b; orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1); b->SetFrame(orbFrame); return orbFrame; } else if (sbody->type == SystemBody::TYPE_STARPORT_ORBITAL) { // space stations want non-rotating frame to some distance // and a much closer rotating frame frameRadius = 1000000.0; // XXX NFI! orbFrame = new Frame(f, sbody->name.c_str()); orbFrame->m_sbody = sbody; // orbFrame->SetRadius(10*sbody->GetRadius()); orbFrame->SetRadius(frameRadius); assert(sbody->rotationPeriod != 0); rotFrame = new Frame(orbFrame, sbody->name.c_str()); rotFrame->SetRadius(1000.0); // rotFrame->SetRadius(1.1*sbody->GetRadius()); // enough for collisions? rotFrame->SetAngVelocity(vector3d(0.0,double(static_cast<SpaceStation*>(b)->GetDesiredAngVel()),0.0)); rotFrame->m_astroBody = b; // hope this doesn't break anything b->SetFrame(rotFrame); return orbFrame; } else if (sbody->type == SystemBody::TYPE_STARPORT_SURFACE) { // just put body into rotating frame of planet, not in its own frame // (because collisions only happen between objects in same frame, // and we want collisions on starport and on planet itself) Frame *frame = *f->m_children.begin(); b->SetFrame(frame); assert(frame->m_astroBody->IsType(Object::PLANET)); matrix4x4d rot; vector3d pos; Planet *planet = static_cast<Planet*>(frame->m_astroBody); RelocateStarportIfUnderwaterOrBuried(sbody, frame, planet, pos, rot); sbody->orbit.rotMatrix = rot; b->SetPosition(pos * planet->GetTerrainHeight(pos)); b->SetRotMatrix(rot); return frame; } else { assert(0); } return NULL; }
static Frame *MakeFrameFor(SBody *sbody, Body *b, Frame *f) { Frame *orbFrame, *rotFrame; double frameRadius; if (!sbody->parent) { if (b) b->SetFrame(f); f->m_sbody = sbody; f->m_astroBody = b; return f; } if (sbody->type == SBody::TYPE_GRAVPOINT) { orbFrame = new Frame(f, sbody->name.c_str()); orbFrame->m_sbody = sbody; orbFrame->m_astroBody = b; orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1); return orbFrame; } SBody::BodySuperType supertype = sbody->GetSuperType(); if ((supertype == SBody::SUPERTYPE_GAS_GIANT) || (supertype == SBody::SUPERTYPE_ROCKY_PLANET)) { // for planets we want an non-rotating frame for a few radii // and a rotating frame in the same position but with maybe 1.05*radius, // which actually contains the object. frameRadius = std::max(4.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.05); orbFrame = new Frame(f, sbody->name.c_str()); orbFrame->m_sbody = sbody; orbFrame->SetRadius(frameRadius); //printf("\t\t\t%s has frame size %.0fkm, body radius %.0fkm\n", sbody->name.c_str(), // (frameRadius ? frameRadius : 10*sbody->GetRadius())*0.001f, // sbody->GetRadius()*0.001f); assert(sbody->rotationPeriod != 0); rotFrame = new Frame(orbFrame, sbody->name.c_str()); // rotating frame has size of GeoSphere terrain bounding sphere rotFrame->SetRadius(b->GetBoundingRadius()); rotFrame->SetAngVelocity(vector3d(0,2*M_PI/sbody->GetRotationPeriod(),0)); rotFrame->m_astroBody = b; SetFrameOrientationFromSBodyAxialTilt(rotFrame, sbody); b->SetFrame(rotFrame); return orbFrame; } else if (supertype == SBody::SUPERTYPE_STAR) { // stars want a single small non-rotating frame orbFrame = new Frame(f, sbody->name.c_str()); orbFrame->m_sbody = sbody; orbFrame->m_astroBody = b; orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1); b->SetFrame(orbFrame); return orbFrame; } else if (sbody->type == SBody::TYPE_STARPORT_ORBITAL) { // space stations want non-rotating frame to some distance // and a much closer rotating frame frameRadius = 1000000.0; // XXX NFI! orbFrame = new Frame(f, sbody->name.c_str()); orbFrame->m_sbody = sbody; // orbFrame->SetRadius(10*sbody->GetRadius()); orbFrame->SetRadius(frameRadius); assert(sbody->rotationPeriod != 0); rotFrame = new Frame(orbFrame, sbody->name.c_str()); rotFrame->SetRadius(1000.0); // rotFrame->SetRadius(1.1*sbody->GetRadius()); // enough for collisions? rotFrame->SetAngVelocity(vector3d(0.0,double(static_cast<SpaceStation*>(b)->GetDesiredAngVel()),0.0)); rotFrame->m_astroBody = b; // hope this doesn't break anything b->SetFrame(rotFrame); return orbFrame; } else if (sbody->type == SBody::TYPE_STARPORT_SURFACE) { // just put body into rotating frame of planet, not in its own frame // (because collisions only happen between objects in same frame, // and we want collisions on starport and on planet itself) Frame *frame = *f->m_children.begin(); b->SetFrame(frame); assert(frame->m_astroBody->IsType(Object::PLANET)); Planet *planet = static_cast<Planet*>(frame->m_astroBody); /* position on planet surface */ double height; int tries; matrix4x4d rot; vector3d pos; // first try suggested position rot = sbody->orbit.rotMatrix; pos = rot * vector3d(0,1,0); if (planet->GetTerrainHeight(pos) - planet->GetSBody()->GetRadius() <= 0.0) { MTRand r(sbody->seed); // position is under water. try some random ones for (tries=0; tries<100; tries++) { // used for orientation on planet surface double r2 = r.Double(); // function parameter evaluation order is implementation-dependent double r1 = r.Double(); // can't put two rands in the same expression rot = matrix4x4d::RotateZMatrix(2*M_PI*r1) * matrix4x4d::RotateYMatrix(2*M_PI*r2); pos = rot * vector3d(0,1,0); height = planet->GetTerrainHeight(pos) - planet->GetSBody()->GetRadius(); // don't want to be under water if (height > 0.0) break; } } b->SetPosition(pos * planet->GetTerrainHeight(pos)); b->SetRotMatrix(rot); return frame; } else { assert(0); } return NULL; }