Introduced support for multiple names for solar system objects. As with
stars and DSOs, names are separated by colons.ver1_6_1
parent
2623b098bb
commit
e7645a774f
|
@ -25,6 +25,8 @@
|
|||
using namespace std;
|
||||
|
||||
Body::Body(PlanetarySystem* _system, const string& _name) :
|
||||
names(1),
|
||||
localizedNameIndex(0),
|
||||
system(_system),
|
||||
satellites(NULL),
|
||||
timeline(NULL),
|
||||
|
@ -105,18 +107,71 @@ void Body::setDefaultProperties()
|
|||
}
|
||||
|
||||
|
||||
string Body::getName(bool i18n) const
|
||||
/*! Return the list of all names (non-localized) by which this
|
||||
* body is known.
|
||||
*/
|
||||
const vector<string>& Body::getNames() const
|
||||
{
|
||||
if (!i18n || i18nName == "") return name;
|
||||
return i18nName;
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
void Body::setName(const string _name)
|
||||
/*! Return the primary name for the body; if i18n, return the
|
||||
* localized name of the body.
|
||||
*/
|
||||
string Body::getName(bool i18n) const
|
||||
{
|
||||
name = _name;
|
||||
i18nName = _(_name.c_str());
|
||||
if (name == i18nName) i18nName = "";
|
||||
if (!i18n)
|
||||
return names[0];
|
||||
else
|
||||
return names[localizedNameIndex];
|
||||
}
|
||||
|
||||
|
||||
/*! Get the localized name for the body. If no localized name
|
||||
* has been set, the primary name is returned.
|
||||
*/
|
||||
string Body::getLocalizedName() const
|
||||
{
|
||||
return names[localizedNameIndex];
|
||||
}
|
||||
|
||||
|
||||
bool Body::hasLocalizedName() const
|
||||
{
|
||||
return localizedNameIndex != 0;
|
||||
}
|
||||
|
||||
|
||||
/*! Set the primary name of the body. The localized name is updated
|
||||
* automatically as well.
|
||||
* Note: setName() is private, and only called from the Body constructor.
|
||||
* It shouldn't be called elsewhere.
|
||||
*/
|
||||
void Body::setName(const string& name)
|
||||
{
|
||||
names[0] = name;
|
||||
string localizedName = _(name.c_str());
|
||||
if (name == localizedName)
|
||||
{
|
||||
// No localized name; set the localized name index to zero to
|
||||
// indicate this.
|
||||
localizedNameIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
names.push_back(localizedName);
|
||||
localizedNameIndex = names.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! Add a new name for this body. Aliases are non localized.
|
||||
*/
|
||||
void Body::addAlias(const string& alias)
|
||||
{
|
||||
names.push_back(alias);
|
||||
system->addAlias(this, alias);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1089,11 +1144,64 @@ PlanetarySystem::~PlanetarySystem()
|
|||
}
|
||||
|
||||
|
||||
/*! Add a new alias for an object. If an object with the specified
|
||||
* alias already exists in the planetary system, the old entry will
|
||||
* be replaced.
|
||||
*/
|
||||
void PlanetarySystem::addAlias(Body* body, const string& alias)
|
||||
{
|
||||
assert(body->getSystem() == this);
|
||||
|
||||
objectIndex.insert(make_pair(alias, body));
|
||||
}
|
||||
|
||||
|
||||
/*! Remove the an alias for an object. This method does nothing
|
||||
* if the alias is not present in the index, or if the alias
|
||||
* refers to a different object.
|
||||
*/
|
||||
void PlanetarySystem::removeAlias(const Body* body, const string& alias)
|
||||
{
|
||||
assert(body->getSystem() == this);
|
||||
|
||||
ObjectIndex::iterator iter = objectIndex.find(alias);
|
||||
if (iter != objectIndex.end())
|
||||
{
|
||||
if (iter->second == body)
|
||||
objectIndex.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PlanetarySystem::addBody(Body* body)
|
||||
{
|
||||
satellites.insert(satellites.end(), body);
|
||||
objectIndex.insert(make_pair(body->getName(), body));
|
||||
i18nObjectIndex.insert(make_pair(body->getName(true), body));
|
||||
addBodyToNameIndex(body);
|
||||
}
|
||||
|
||||
|
||||
// Add all aliases for the body to the name index
|
||||
void PlanetarySystem::addBodyToNameIndex(const Body* body)
|
||||
{
|
||||
const vector<string>& names = body->getNames();
|
||||
for (vector<string>::const_iterator iter = names.begin(); iter != names.end(); iter++)
|
||||
{
|
||||
objectIndex.insert(make_pair(*iter, body));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove all references to the body in the name index.
|
||||
void PlanetarySystem::removeBodyFromNameIndex(const Body* body)
|
||||
{
|
||||
assert(body->getSystem() == this);
|
||||
|
||||
// Erase the object from the object indices
|
||||
const vector<string>& names = body->getNames();
|
||||
for (vector<string>::const_iterator iter = names.begin(); iter != names.end(); iter++)
|
||||
{
|
||||
removeAlias(body, *iter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1108,28 +1216,8 @@ void PlanetarySystem::removeBody(Body* body)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Erase the object from the object indices
|
||||
for (ObjectIndex::iterator iter = objectIndex.begin();
|
||||
iter != objectIndex.end(); iter++)
|
||||
{
|
||||
if (iter->second == body)
|
||||
{
|
||||
objectIndex.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (ObjectIndex::iterator iter = i18nObjectIndex.begin();
|
||||
iter != i18nObjectIndex.end(); iter++)
|
||||
{
|
||||
if (iter->second == body)
|
||||
{
|
||||
i18nObjectIndex.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
removeBodyFromNameIndex(body);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1145,40 +1233,36 @@ void PlanetarySystem::replaceBody(Body* oldBody, Body* newBody)
|
|||
}
|
||||
}
|
||||
|
||||
// Erase the object from the object indices
|
||||
for (ObjectIndex::iterator iter = objectIndex.begin();
|
||||
iter != objectIndex.end(); iter++)
|
||||
{
|
||||
if (iter->second == oldBody)
|
||||
{
|
||||
objectIndex.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (ObjectIndex::iterator iter = i18nObjectIndex.begin();
|
||||
iter != i18nObjectIndex.end(); iter++)
|
||||
{
|
||||
if (iter->second == oldBody)
|
||||
{
|
||||
i18nObjectIndex.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the replacement to the object indices
|
||||
objectIndex.insert(make_pair(newBody->getName(), newBody));
|
||||
i18nObjectIndex.insert(make_pair(newBody->getName(true), newBody));
|
||||
removeBodyFromNameIndex(oldBody);
|
||||
addBodyToNameIndex(newBody);
|
||||
}
|
||||
|
||||
|
||||
/*! Find a body with the specified name within a planetary system.
|
||||
*
|
||||
* deepSearch: if true, recursively search the systems of child objects
|
||||
* i18n: if true, allow matching of localized body names. When responding
|
||||
* to a user query, this flag should be true. In other cases--such
|
||||
* as resolving an object name in an ssc file--it should be false. Otherwise,
|
||||
* object lookup will behave differently based on the locale.
|
||||
*/
|
||||
Body* PlanetarySystem::find(const string& _name, bool deepSearch, bool i18n) const
|
||||
{
|
||||
ObjectIndex index = i18n?i18nObjectIndex:objectIndex;
|
||||
ObjectIndex::const_iterator firstMatch = index.find(_name);
|
||||
if (firstMatch != index.end())
|
||||
ObjectIndex::const_iterator firstMatch = objectIndex.find(_name);
|
||||
if (firstMatch != objectIndex.end())
|
||||
{
|
||||
return firstMatch->second;
|
||||
Body* matchedBody = firstMatch->second;
|
||||
|
||||
if (i18n)
|
||||
{
|
||||
return matchedBody;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore localized names
|
||||
if (!matchedBody->hasLocalizedName() || _name != matchedBody->getLocalizedName())
|
||||
return matchedBody;
|
||||
}
|
||||
}
|
||||
|
||||
if (deepSearch)
|
||||
|
@ -1221,25 +1305,37 @@ bool PlanetarySystem::traverse(TraversalFunc func, void* info) const
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> PlanetarySystem::getCompletion(const std::string& _name, bool rec) const
|
||||
std::vector<std::string> PlanetarySystem::getCompletion(const std::string& _name, bool deepSearch) const
|
||||
{
|
||||
std::vector<std::string> completion;
|
||||
int _name_length = UTF8Length(_name);
|
||||
|
||||
for (vector<Body*>::const_iterator iter = satellites.begin();
|
||||
iter != satellites.end(); iter++)
|
||||
// Search through all names in this planetary system.
|
||||
for (ObjectIndex::const_iterator iter = objectIndex.begin();
|
||||
iter != objectIndex.end(); iter++)
|
||||
{
|
||||
if (UTF8StringCompare((*iter)->getName(true), _name, _name_length) == 0)
|
||||
const string& alias = iter->first;
|
||||
|
||||
if (UTF8StringCompare(alias, _name, _name_length) == 0)
|
||||
{
|
||||
completion.push_back((*iter)->getName(true));
|
||||
}
|
||||
if (rec && (*iter)->getSatellites() != NULL)
|
||||
{
|
||||
std::vector<std::string> bodies = (*iter)->getSatellites()->getCompletion(_name);
|
||||
completion.insert(completion.end(), bodies.begin(), bodies.end());
|
||||
completion.push_back(alias);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Scan child objects
|
||||
if (deepSearch)
|
||||
{
|
||||
for (vector<Body*>::const_iterator iter = satellites.begin();
|
||||
iter != satellites.end(); iter++)
|
||||
{
|
||||
if ((*iter)->getSatellites() != NULL)
|
||||
{
|
||||
vector<string> bodies = (*iter)->getSatellites()->getCompletion(_name);
|
||||
completion.insert(completion.end(), bodies.begin(), bodies.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return completion;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ class PlanetarySystem
|
|||
Body* getPrimaryBody() const { return primary; };
|
||||
int getSystemSize() const { return satellites.size(); };
|
||||
Body* getBody(int i) const { return satellites[i]; };
|
||||
|
||||
void addAlias(Body* body, const std::string& alias);
|
||||
void removeAlias(const Body* body, const std::string& alias);
|
||||
void addBody(Body* body);
|
||||
void removeBody(Body* body);
|
||||
void replaceBody(Body* oldBody, Body* newBody);
|
||||
|
@ -58,6 +61,10 @@ class PlanetarySystem
|
|||
Body* find(const std::string&, bool deepSearch = false, bool i18n = false) const;
|
||||
std::vector<std::string> getCompletion(const std::string& _name, bool rec = true) const;
|
||||
|
||||
private:
|
||||
void addBodyToNameIndex(const Body* body);
|
||||
void removeBodyFromNameIndex(const Body* body);
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, Body*, UTF8StringOrderingPredicate> ObjectIndex;
|
||||
|
||||
|
@ -66,7 +73,6 @@ class PlanetarySystem
|
|||
Body* primary;
|
||||
std::vector<Body*> satellites;
|
||||
ObjectIndex objectIndex; // index of bodies by name
|
||||
ObjectIndex i18nObjectIndex;
|
||||
};
|
||||
|
||||
|
||||
|
@ -176,8 +182,11 @@ class Body
|
|||
void setDefaultProperties();
|
||||
|
||||
PlanetarySystem* getSystem() const;
|
||||
const std::vector<std::string>& getNames() const;
|
||||
std::string getName(bool i18n = false) const;
|
||||
void setName(const std::string);
|
||||
std::string getLocalizedName() const;
|
||||
bool hasLocalizedName() const;
|
||||
void addAlias(const std::string& alias);
|
||||
|
||||
void setTimeline(Timeline* timeline);
|
||||
const Timeline* getTimeline() const;
|
||||
|
@ -320,11 +329,12 @@ class Body
|
|||
void markUpdated();
|
||||
|
||||
private:
|
||||
void setName(const std::string& _name);
|
||||
void recomputeCullingRadius();
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::string i18nName;
|
||||
std::vector<std::string> names;
|
||||
unsigned int localizedNameIndex;
|
||||
|
||||
// Parent in the name hierarchy
|
||||
PlanetarySystem* system;
|
||||
|
|
|
@ -1055,7 +1055,10 @@ bool LoadSolarSystemObjects(istream& in,
|
|||
sscError(tokenizer, "object name expected");
|
||||
return false;
|
||||
}
|
||||
string name = tokenizer.getStringValue().c_str();
|
||||
|
||||
// The name list is a string with zero more names. Multiple names are
|
||||
// delimited by colons.
|
||||
string nameList = tokenizer.getStringValue().c_str();
|
||||
|
||||
if (tokenizer.nextToken() != Tokenizer::TokenString)
|
||||
{
|
||||
|
@ -1081,6 +1084,31 @@ bool LoadSolarSystemObjects(istream& in,
|
|||
|
||||
Selection parent = universe.findPath(parentName, NULL, 0);
|
||||
PlanetarySystem* parentSystem = NULL;
|
||||
|
||||
vector<string> names;
|
||||
// Iterate through the string for names delimited
|
||||
// by ':', and insert them into the name list.
|
||||
if (nameList.empty())
|
||||
{
|
||||
names.push_back("");
|
||||
}
|
||||
else
|
||||
{
|
||||
string::size_type startPos = 0;
|
||||
while (startPos != string::npos)
|
||||
{
|
||||
string::size_type next = nameList.find(':', startPos);
|
||||
string::size_type length = string::npos;
|
||||
if (next != string::npos)
|
||||
{
|
||||
length = next - startPos;
|
||||
++next;
|
||||
}
|
||||
names.push_back(nameList.substr(startPos, length));
|
||||
startPos = next;
|
||||
}
|
||||
}
|
||||
string primaryName = names.front();
|
||||
|
||||
if (itemType == "Body" || itemType == "ReferencePoint")
|
||||
{
|
||||
|
@ -1112,19 +1140,19 @@ bool LoadSolarSystemObjects(istream& in,
|
|||
else
|
||||
{
|
||||
errorMessagePrelude(tokenizer);
|
||||
cerr << _("parent body '") << parentName << _("' of '") << name << _("' not found.\n");
|
||||
cerr << _("parent body '") << parentName << _("' of '") << primaryName << _("' not found.") << endl;
|
||||
}
|
||||
|
||||
if (parentSystem != NULL)
|
||||
{
|
||||
Body* existingBody = parentSystem->find(name);
|
||||
Body* existingBody = parentSystem->find(primaryName);
|
||||
if (existingBody)
|
||||
{
|
||||
if (disposition == AddObject)
|
||||
{
|
||||
errorMessagePrelude(tokenizer);
|
||||
cerr << _("warning duplicate definition of ") <<
|
||||
parentName << " " << name << '\n';
|
||||
parentName << " " << primaryName << '\n';
|
||||
}
|
||||
else if (disposition == ReplaceObject)
|
||||
{
|
||||
|
@ -1134,9 +1162,20 @@ bool LoadSolarSystemObjects(istream& in,
|
|||
|
||||
Body* body;
|
||||
if (itemType == "ReferencePoint")
|
||||
body = CreateReferencePoint(name, parentSystem, universe, existingBody, objectData, directory, disposition);
|
||||
body = CreateReferencePoint(primaryName, parentSystem, universe, existingBody, objectData, directory, disposition);
|
||||
else
|
||||
body = CreatePlanet(name, parentSystem, universe, existingBody, objectData, directory, disposition);
|
||||
body = CreatePlanet(primaryName, parentSystem, universe, existingBody, objectData, directory, disposition);
|
||||
|
||||
if (body != NULL && disposition == AddObject)
|
||||
{
|
||||
vector<string>::const_iterator iter = names.begin();
|
||||
iter++;
|
||||
while (iter != names.end())
|
||||
{
|
||||
body->addAlias(*iter);
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (itemType == "AltSurface")
|
||||
|
@ -1146,7 +1185,7 @@ bool LoadSolarSystemObjects(istream& in,
|
|||
surface->hazeColor = Color(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
FillinSurface(objectData, surface, directory);
|
||||
if (surface != NULL && parent.body() != NULL)
|
||||
parent.body()->addAlternateSurface(name, surface);
|
||||
parent.body()->addAlternateSurface(primaryName, surface);
|
||||
else
|
||||
sscError(tokenizer, _("bad alternate surface"));
|
||||
}
|
||||
|
@ -1157,7 +1196,7 @@ bool LoadSolarSystemObjects(istream& in,
|
|||
Location* location = CreateLocation(objectData, parent.body());
|
||||
if (location != NULL)
|
||||
{
|
||||
location->setName(name);
|
||||
location->setName(primaryName);
|
||||
parent.body()->addLocation(location);
|
||||
}
|
||||
else
|
||||
|
@ -1168,7 +1207,7 @@ bool LoadSolarSystemObjects(istream& in,
|
|||
else
|
||||
{
|
||||
errorMessagePrelude(tokenizer);
|
||||
cerr << _("parent body '") << parentName << _("' of '") << name << _("' not found.\n");
|
||||
cerr << _("parent body '") << parentName << _("' of '") << primaryName << _("' not found.\n");
|
||||
}
|
||||
}
|
||||
delete objectDataValue;
|
||||
|
|
Loading…
Reference in New Issue