コード例 #1
0
// Add children to item, but group objects of certain classes
// into subtrees to avoid clutter. Stars, planets, and moons
// are shown as direct children of the parent. Small moons,
// asteroids, and spacecraft a grouped together, as there tend to be
// large collections of such objects.
void
SolarSystemTreeModel::addTreeItemChildrenGrouped(TreeItem* item,
                                                 PlanetarySystem* sys,
                                                 const vector<Star*>* orbitingStars,
                                                 Selection parent)
{
    vector<Body*> asteroids;
    vector<Body*> spacecraft;
    vector<Body*> minorMoons;
	vector<Body*> surfaceFeatures;
	vector<Body*> components;
    vector<Body*> other;
    vector<Body*> normal;

    bool groupAsteroids = true;
    bool groupSpacecraft = true;
	bool groupComponents = true;
	bool groupSurfaceFeatures = true;
    if (parent.body())
    {
        // Don't put asteroid moons in the asteroid group; make them
        // immediate children of the parent.
        if (parent.body()->getClassification() == Body::Asteroid)
            groupAsteroids = false;

        if (parent.body()->getClassification() == Body::Spacecraft)
            groupSpacecraft = false;
    }

    for (int i = 0; i < sys->getSystemSize(); i++)
    {
        Body* body = sys->getBody(i);
        switch (body->getClassification())
        {
        case Body::Planet:
        case Body::DwarfPlanet:
        case Body::Invisible:
            normal.push_back(body);
            break;
        case Body::Moon:
            normal.push_back(body);
            break;
        case Body::MinorMoon:
            minorMoons.push_back(body);
            break;
        case Body::Asteroid:
        case Body::Comet:
            if (groupAsteroids)
                asteroids.push_back(body);
            else
                normal.push_back(body);
            break;
        case Body::Spacecraft:
            if (groupSpacecraft)
                spacecraft.push_back(body);
            else
                normal.push_back(body);
            break;
		case Body::Component:
			if (groupComponents)
				components.push_back(body);
			else
				normal.push_back(body);
			break;
		case Body::SurfaceFeature:
			if (groupSurfaceFeatures)
				surfaceFeatures.push_back(body);
			else
				normal.push_back(body);
			break;
        default:
            other.push_back(body);
            break;
        }
    }

    // Calculate the total number of children
    item->nChildren = 0;
    if (orbitingStars != NULL)
        item->nChildren += orbitingStars->size();

    item->nChildren += normal.size();
    if (!asteroids.empty())
        item->nChildren++;
    if (!spacecraft.empty())
        item->nChildren++;
    if (!minorMoons.empty())
        item->nChildren++;
	if (!surfaceFeatures.empty())
		item->nChildren++;
	if (!components.empty())
		item->nChildren++;
    if (!other.empty())
        item->nChildren++;

    if (item->nChildren != 0)
    {
        int childIndex = 0;
        item->children = new TreeItem*[item->nChildren];
        {
            // Add the stars
            if (orbitingStars != NULL)
            {
                for (unsigned int i = 0; i < orbitingStars->size(); i++)
                {
                    Selection child(orbitingStars->at(i));
                    item->children[childIndex] = createTreeItem(child, item, childIndex);
                    childIndex++;
                }
            }

            // Add the direct children
            for (int i = 0; i < (int) normal.size(); i++)
            {
                item->children[childIndex] = createTreeItem(normal[i], item, childIndex);
                childIndex++;
            }

            // Add the groups
            if (!minorMoons.empty())
            {
                item->children[childIndex] = createGroupTreeItem(Body::MinorMoon,
                                                                 minorMoons,
                                                                 item, childIndex);
                childIndex++;
            }

            if (!asteroids.empty())
            {
                item->children[childIndex] = createGroupTreeItem(Body::Asteroid,
                                                                 asteroids,
                                                                 item, childIndex);
                childIndex++;
            }

            if (!spacecraft.empty())
            {
                item->children[childIndex] = createGroupTreeItem(Body::Spacecraft,
                                                                 spacecraft,
                                                                 item, childIndex);
                childIndex++;
            }

			if (!surfaceFeatures.empty())
			{
                item->children[childIndex] = createGroupTreeItem(Body::SurfaceFeature,
                                                                 surfaceFeatures,
                                                                 item, childIndex);
                childIndex++;
			}

			if (!components.empty())
			{
                item->children[childIndex] = createGroupTreeItem(Body::Component,
                                                                 components,
                                                                 item, childIndex);
                childIndex++;
			}

            if (!other.empty())
            {
                item->children[childIndex] = createGroupTreeItem(Body::Unknown,
                                                                 other,
                                                                 item, childIndex);
                childIndex++;
            }
        }
    }
}
コード例 #2
0
ファイル: solarsys.cpp プロジェクト: nisselarsson/Celestia
// 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;
}