// Create a body (planet, moon, spacecraft, etc.) using the values from a // property list. The usePlanetsUnits flags specifies whether period and // semi-major axis are in years and AU rather than days and kilometers. static Body* CreateBody(const string& name, PlanetarySystem* system, Universe& universe, Body* existingBody, Hash* planetData, const string& path, Disposition disposition, BodyType bodyType) { Body* body = NULL; if (disposition == ModifyObject || disposition == ReplaceObject) { body = existingBody; } if (body == NULL) { body = new Body(system, name); // If the body doesn't exist, always treat the disposition as 'Add' disposition = AddObject; // Set the default classification for new objects based on the body type. // This may be overridden by the Class property. if (bodyType == SurfaceObject) { body->setClassification(Body::SurfaceFeature); } } if (!CreateTimeline(body, system, universe, planetData, path, disposition, bodyType)) { // No valid timeline given; give up. if (body != existingBody) delete body; return NULL; } // Three values control the shape and size of an ellipsoidal object: // semiAxes, radius, and oblateness. It is an error if neither the // radius nor semiaxes are set. If both are set, the radius is // multipled by each of the specified semiaxis to give the shape of // the body ellipsoid. Oblateness is ignored if semiaxes are provided; // otherwise, the ellipsoid has semiaxes: ( radius, radius, 1-radius ). // These rather complex rules exist to maintain backward compatibility. // // If the body also has a mesh, it is always scaled in x, y, and z by // the maximum semiaxis, never anisotropically. double radius = (double) body->getRadius(); bool radiusSpecified = false; if (planetData->getLength("Radius", radius)) { body->setSemiAxes(Vector3f::Constant((float) radius)); radiusSpecified = true; } Vector3d semiAxes = Vector3d::Ones(); if (planetData->getVector("SemiAxes", semiAxes)) { if (radiusSpecified) { // if the radius has been specified, treat SemiAxes as dimensionless // (i.e. ignore units) and multiply the radius by the SemiAxes semiAxes *= radius; } else { double semiAxesScale = 1.0; planetData->getLengthScale("SemiAxes", semiAxesScale); semiAxes *= semiAxesScale; } // Swap y and z to match internal coordinate system body->setSemiAxes(Vector3f((float) semiAxes.x(), (float) semiAxes.z(), (float) semiAxes.y())); } else { double oblateness = 0.0; if (planetData->getNumber("Oblateness", oblateness)) { body->setSemiAxes((float) body->getRadius() * Vector3f(1.0f, 1.0f - (float) oblateness, 1.0f)); } } int classification = body->getClassification(); string classificationName; if (planetData->getString("Class", classificationName)) classification = GetClassificationId(classificationName); if (classification == Body::Unknown) { // Try to guess the type if (system->getPrimaryBody() != NULL) { if(radius > 0.1) classification = Body::Moon; else classification = Body::Spacecraft; } else { if (radius < 1000.0) classification = Body::Asteroid; else classification = Body::Planet; } } body->setClassification(classification); if (classification == Body::Invisible) body->setVisible(false); // Set default properties for the object based on its classification if (classification & CLASSES_INVISIBLE_AS_POINT) body->setVisibleAsPoint(false); if ((classification & CLASSES_SECONDARY_ILLUMINATOR) == 0) body->setSecondaryIlluminator(false); if (classification & CLASSES_UNCLICKABLE) body->setClickable(false); string infoURL; if (planetData->getString("InfoURL", infoURL)) { if (infoURL.find(':') == string::npos) { // Relative URL, the base directory is the current one, // not the main installation directory if (path[1] == ':') // Absolute Windows path, file:/// is required infoURL = "file:///" + path + "/" + infoURL; else if (!path.empty()) infoURL = path + "/" + infoURL; } body->setInfoURL(infoURL); } double albedo = 0.5; if (planetData->getNumber("Albedo", albedo)) body->setAlbedo((float) albedo); // TODO - add mass units double mass = 0.0; if (planetData->getNumber("Mass", mass)) body->setMass((float) mass); Quaternionf orientation = Quaternionf::Identity(); if (planetData->getRotation("Orientation", orientation)) { body->setGeometryOrientation(orientation); } Surface surface; if (disposition == ModifyObject) { surface = body->getSurface(); } else { surface.color = Color(1.0f, 1.0f, 1.0f); surface.hazeColor = Color(0.0f, 0.0f, 0.0f, 0.0f); } FillinSurface(planetData, &surface, path); body->setSurface(surface); { string geometry(""); if (planetData->getString("Mesh", geometry)) { Vector3f geometryCenter(Vector3f::Zero()); if (planetData->getVector("MeshCenter", geometryCenter)) { // TODO: Adjust bounding radius if model center isn't // (0.0f, 0.0f, 0.0f) } bool isNormalized = true; planetData->getBoolean("NormalizeMesh", isNormalized); float geometryScale = 1.0f; planetData->getLength("MeshScale", geometryScale); ResourceHandle geometryHandle = GetGeometryManager()->getHandle(GeometryInfo(geometry, path, geometryCenter, 1.0f, isNormalized)); body->setGeometry(geometryHandle); body->setGeometryScale(geometryScale); } } // Read the atmosphere { Value* atmosDataValue = planetData->getValue("Atmosphere"); if (atmosDataValue != NULL) { if (atmosDataValue->getType() != Value::HashType) { cout << "ReadSolarSystem: Atmosphere must be an assoc array.\n"; } else { Hash* atmosData = atmosDataValue->getHash(); assert(atmosData != NULL); Atmosphere* atmosphere = NULL; if (disposition == ModifyObject) { atmosphere = body->getAtmosphere(); if (atmosphere == NULL) { Atmosphere atm; body->setAtmosphere(atm); atmosphere = body->getAtmosphere(); } } else { atmosphere = new Atmosphere(); } atmosData->getLength("Height", atmosphere->height); atmosData->getColor("Lower", atmosphere->lowerColor); atmosData->getColor("Upper", atmosphere->upperColor); atmosData->getColor("Sky", atmosphere->skyColor); atmosData->getColor("Sunset", atmosphere->sunsetColor); atmosData->getNumber("Mie", atmosphere->mieCoeff); atmosData->getLength("MieScaleHeight", atmosphere->mieScaleHeight); atmosData->getNumber("MieAsymmetry", atmosphere->miePhaseAsymmetry); atmosData->getVector("Rayleigh", atmosphere->rayleighCoeff); //atmosData->getNumber("RayleighScaleHeight", atmosphere->rayleighScaleHeight); atmosData->getVector("Absorption", atmosphere->absorptionCoeff); // Get the cloud map settings atmosData->getLength("CloudHeight", atmosphere->cloudHeight); if (atmosData->getNumber("CloudSpeed", atmosphere->cloudSpeed)) atmosphere->cloudSpeed = degToRad(atmosphere->cloudSpeed); string cloudTexture; if (atmosData->getString("CloudMap", cloudTexture)) { atmosphere->cloudTexture.setTexture(cloudTexture, path, TextureInfo::WrapTexture); } string cloudNormalMap; if (atmosData->getString("CloudNormalMap", cloudNormalMap)) { atmosphere->cloudNormalMap.setTexture(cloudNormalMap, path, TextureInfo::WrapTexture); } double cloudShadowDepth = 0.0; if (atmosData->getNumber("CloudShadowDepth", cloudShadowDepth)) { cloudShadowDepth = max(0.0, min(1.0, cloudShadowDepth)); // clamp to [0, 1] atmosphere->cloudShadowDepth = (float) cloudShadowDepth; } body->setAtmosphere(*atmosphere); if (disposition != ModifyObject) delete atmosphere; } } } // Read the ring system { Value* ringsDataValue = planetData->getValue("Rings"); if (ringsDataValue != NULL) { if (ringsDataValue->getType() != Value::HashType) { cout << "ReadSolarSystem: Rings must be an assoc array.\n"; } else { Hash* ringsData = ringsDataValue->getHash(); // ASSERT(ringsData != NULL); RingSystem rings(0.0f, 0.0f); if (body->getRings() != NULL) rings = *body->getRings(); double inner = 0.0, outer = 0.0; if (ringsData->getLength("Inner", inner)) rings.innerRadius = (float) inner; if (ringsData->getLength("Outer", outer)) rings.outerRadius = (float) outer; Color color(1.0f, 1.0f, 1.0f); if (ringsData->getColor("Color", color)) rings.color = color; string textureName; if (ringsData->getString("Texture", textureName)) rings.texture = MultiResTexture(textureName, path); body->setRings(rings); } } } bool clickable = true; if (planetData->getBoolean("Clickable", clickable)) { body->setClickable(clickable); } bool visible = true; if (planetData->getBoolean("Visible", visible)) { body->setVisible(visible); } Color orbitColor; if (planetData->getColor("OrbitColor", orbitColor)) { body->setOrbitColorOverridden(true); body->setOrbitColor(orbitColor); } return body; }
FavoritesList* ReadFavoritesList(istream& in) { FavoritesList* favorites = new FavoritesList(); Tokenizer tokenizer(&in); Parser parser(&tokenizer); while (tokenizer.nextToken() != Tokenizer::TokenEnd) { if (tokenizer.getTokenType() != Tokenizer::TokenString) { DPRINTF(0, "Error parsing favorites file.\n"); for_each(favorites->begin(), favorites->end(), deleteFunc<FavoritesEntry*>()); delete favorites; return NULL; } FavoritesEntry* fav = new FavoritesEntry(); fav->name = tokenizer.getStringValue(); Value* favParamsValue = parser.readValue(); if (favParamsValue == NULL || favParamsValue->getType() != Value::HashType) { DPRINTF(0, "Error parsing favorites entry %s\n", fav->name.c_str()); for_each(favorites->begin(), favorites->end(), deleteFunc<FavoritesEntry*>()); delete favorites; if (favParamsValue != NULL) delete favParamsValue; return NULL; } Hash* favParams = favParamsValue->getHash(); //If this is a folder, don't get any other params. if(!favParams->getBoolean("isFolder", fav->isFolder)) fav->isFolder = false; if(fav->isFolder) { favorites->insert(favorites->end(), fav); continue; } // Get parentFolder favParams->getString("parentFolder", fav->parentFolder); // Get position Vec3d base(0.0, 0.0, 0.0); Vec3d offset(0.0, 0.0, 0.0); favParams->getVector("base", base); favParams->getVector("offset", offset); base *= 1e6; fav->position = UniversalCoord(Point3d(base.x, base.y, base.z)) + offset; // Get orientation Vec3d axis(1.0, 0.0, 0.0); double angle = 0.0; favParams->getVector("axis", axis); favParams->getNumber("angle", angle); fav->orientation.setAxisAngle(Vec3f((float) axis.x, (float) axis.y, (float) axis.z), (float) angle); // Get time fav->jd = 0.0; favParams->getNumber("time", fav->jd); // Get the selected object favParams->getString("selection", fav->selectionName); string coordSysName; favParams->getString("coordsys", coordSysName); if (coordSysName == "ecliptical") fav->coordSys = ObserverFrame::Ecliptical; else if (coordSysName == "equatorial") fav->coordSys = ObserverFrame::Equatorial; else if (coordSysName == "geographic") fav->coordSys = ObserverFrame::BodyFixed; else fav->coordSys = ObserverFrame::Universal; favorites->insert(favorites->end(), fav); } return favorites; }