BSONObj DocumentSourceLookUp::queryForInput(const Document& input, const FieldPath& localFieldPath, const std::string& foreignFieldName, const BSONObj& additionalFilter) { Value localFieldVal = input.getNestedField(localFieldPath); // Missing values are treated as null. if (localFieldVal.missing()) { localFieldVal = Value(BSONNULL); } // We are constructing a query of one of the following forms: // {$and: [{<foreignFieldName>: {$eq: <localFieldVal>}}, <additionalFilter>]} // {$and: [{<foreignFieldName>: {$in: [<value>, <value>, ...]}}, <additionalFilter>]} // {$and: [{$or: [{<foreignFieldName>: {$eq: <value>}}, // {<foreignFieldName>: {$eq: <value>}}, ...]}, // <additionalFilter>]} BSONObjBuilder query; BSONArrayBuilder andObj(query.subarrayStart("$and")); BSONObjBuilder joiningObj(andObj.subobjStart()); if (localFieldVal.isArray()) { // Assume an array value logically corresponds to many documents, rather than logically // corresponding to one document with an array value. const vector<Value>& localArray = localFieldVal.getArray(); const bool containsRegex = std::any_of( localArray.begin(), localArray.end(), [](Value val) { return val.getType() == RegEx; }); if (containsRegex) { // A regex inside of an $in will not be treated as an equality comparison, so use an // $or. BSONObj orQuery = buildEqualityOrQuery(foreignFieldName, localFieldVal.getArray()); joiningObj.appendElements(orQuery); } else { // { _foreignFieldFieldName : { "$in" : localFieldValue } } BSONObjBuilder subObj(joiningObj.subobjStart(foreignFieldName)); subObj << "$in" << localFieldVal; subObj.doneFast(); } } else { // { _foreignFieldFieldName : { "$eq" : localFieldValue } } BSONObjBuilder subObj(joiningObj.subobjStart(foreignFieldName)); subObj << "$eq" << localFieldVal; subObj.doneFast(); } joiningObj.doneFast(); BSONObjBuilder additionalFilterObj(andObj.subobjStart()); additionalFilterObj.appendElements(additionalFilter); additionalFilterObj.doneFast(); andObj.doneFast(); return query.obj(); }
/** * Retrieves a quaternion, scaled to an associated angle unit. * * The quaternion is specified in the catalog file in axis-angle format as follows: * \verbatim {PropertyName} [ angle axisX axisY axisZ ] \endverbatim * * @param[in] key Hash key for the rotation. * @param[out] val A quaternion representing the value if present, unaffected if not. * @return True if the key exists in the hash, false otherwise. */ bool AssociativeArray::getRotation(const string& key, Eigen::Quaternionf& val) const { Value* v = getValue(key); if (v == NULL || v->getType() != Value::ArrayType) return false; Array* arr = v->getArray(); if (arr->size() != 4) return false; Value* w = (*arr)[0]; Value* x = (*arr)[1]; Value* y = (*arr)[2]; Value* z = (*arr)[3]; if (w->getType() != Value::NumberType || x->getType() != Value::NumberType || y->getType() != Value::NumberType || z->getType() != Value::NumberType) return false; Vector3f axis((float) x->getNumber(), (float) y->getNumber(), (float) z->getNumber()); double ang = w->getNumber(); double angScale = 1.0; getAngleScale(key, angScale); float angle = degToRad((float) (ang * angScale)); val = Quaternionf(AngleAxisf(angle, axis.normalized())); return true; }
bool AssociativeArray::getRotation(const string& key, Quatf& val) const { Value* v = getValue(key); if (v == NULL || v->getType() != Value::ArrayType) return false; Array* arr = v->getArray(); if (arr->size() != 4) return false; Value* w = (*arr)[0]; Value* x = (*arr)[1]; Value* y = (*arr)[2]; Value* z = (*arr)[3]; if (w->getType() != Value::NumberType || x->getType() != Value::NumberType || y->getType() != Value::NumberType || z->getType() != Value::NumberType) return false; Vec3f axis((float) x->getNumber(), (float) y->getNumber(), (float) z->getNumber()); axis.normalize(); float angle = degToRad((float) w->getNumber()); val.setAxisAngle(axis, angle); return true; }
Value DocumentSourceRedact::redactValue(const Value& in) { const BSONType valueType = in.getType(); if (valueType == Object) { _variables->setValue(_currentId, in); const boost::optional<Document> result = redactObject(); if (result) { return Value(*result); } else { return Value(); } } else if (valueType == Array) { // TODO dont copy if possible vector<Value> newArr; const vector<Value>& arr = in.getArray(); for (size_t i = 0; i < arr.size(); i++) { if (arr[i].getType() == Object || arr[i].getType() == Array) { const Value toAdd = redactValue(arr[i]); if (!toAdd.missing()) { newArr.push_back(toAdd); } } else { newArr.push_back(arr[i]); } } return Value(std::move(newArr)); } else { return in; } }
Value DocumentSourceRedact::redactValue(const Variables& vars, const Value& in) { const BSONType valueType = in.getType(); if (valueType == Object) { Variables recurse = vars; recurse.current = in; const boost::optional<Document> result = redactObject(recurse); if (result) { return Value(*result); } else { return Value(); } } else if (valueType == Array) { // TODO dont copy if possible vector<Value> newArr; const vector<Value>& arr = in.getArray(); for (size_t i = 0; i < arr.size(); i++) { if (arr[i].getType() == Object || arr[i].getType() == Array) { const Value toAdd = redactValue(vars, arr[i]) ; if (!toAdd.missing()) { newArr.push_back(toAdd); } } } return Value::consume(newArr); } else { return in; } }
AsterismList* ReadAsterismList(istream& in, const StarDatabase& stardb) { AsterismList* asterisms = new AsterismList(); Tokenizer tokenizer(&in); Parser parser(&tokenizer); while (tokenizer.nextToken() != Tokenizer::TokenEnd) { if (tokenizer.getTokenType() != Tokenizer::TokenString) { DPRINTF(0, "Error parsing asterism file.\n"); for_each(asterisms->begin(), asterisms->end(), deleteFunc<Asterism*>()); delete asterisms; return NULL; } string name = tokenizer.getStringValue(); Asterism* ast = new Asterism(name); Value* chainsValue = parser.readValue(); if (chainsValue == NULL || chainsValue->getType() != Value::ArrayType) { DPRINTF(0, "Error parsing asterism %s\n", name.c_str()); for_each(asterisms->begin(), asterisms->end(), deleteFunc<Asterism*>()); delete asterisms; delete chainsValue; return NULL; } Array* chains = chainsValue->getArray(); for (int i = 0; i < (int) chains->size(); i++) { if ((*chains)[i]->getType() == Value::ArrayType) { Array* a = (*chains)[i]->getArray(); Asterism::Chain* chain = new Asterism::Chain(); for (Array::const_iterator iter = a->begin(); iter != a->end(); iter++) { if ((*iter)->getType() == Value::StringType) { Star* star = stardb.find((*iter)->getString()); if (star != NULL) chain->insert(chain->end(), star->getPosition()); } } ast->addChain(*chain); } } asterisms->insert(asterisms->end(), ast); delete chainsValue; } return asterisms; }
vector<string> Connection::listDatabases(){ Value val = comm.getData("/_all_dbs"); Array arr = val.getArray(); vector<string> dbs; Array::iterator db = arr.begin(); const Array::iterator &db_end = arr.end(); for(; db != db_end; ++db) dbs.push_back((*db).getString()); return dbs; }
TEST(ValueTest, SetValue) { Value b; b.set(true); EXPECT_EQ(true, b.getBoolean()); Value i1; i1.set(42); EXPECT_EQ(42, i1.getInteger()); Value i2; i2.set(42L); EXPECT_EQ(42, i2.getInteger()); Value f1; f1.set(0.42F); EXPECT_NEAR(0.42, f1.getFloat(), 0.000001); Value f2; f2.set(0.42); EXPECT_NEAR(0.42, f2.getFloat(), 0.000001); Value s1; s1.set("foobar"); EXPECT_EQ("foobar", s1.getString()); Value s2; s2.set(std::string("foobar")); EXPECT_EQ("foobar", s2.getString()); Value s3; s3.set(QString("foobar")); EXPECT_EQ("foobar", s3.getString()); Value::Array arr; arr.push_back(Value(42)); Value a; a.set(arr); EXPECT_EQ(arr, a.getArray()); Value::Object obj; obj["foobar"] = Value(42); Value o1; o1.set(obj); EXPECT_EQ(obj, o1.getObject()); Value o2; o2.set(o1); EXPECT_EQ(o1, o2); }
BSONObj DocumentSourceLookUp::queryForInput(const Document& input, const FieldPath& localFieldPath, const std::string& foreignFieldName) { Value localFieldVal = input.getNestedField(localFieldPath); // Missing values are treated as null. if (localFieldVal.missing()) { localFieldVal = Value(BSONNULL); } BSONObjBuilder query; BSONObjBuilder subObj(query.subobjStart(foreignFieldName)); if (localFieldVal.isArray()) { // Assume an array value logically corresponds to many documents, rather than logically // corresponding to one document with an array value. const vector<Value>& localArray = localFieldVal.getArray(); const bool containsRegex = std::any_of( localArray.begin(), localArray.end(), [](Value val) { return val.getType() == RegEx; }); if (containsRegex) { // A regex inside of an $in will not be treated as an equality comparison, so use an // $or. return buildEqualityOrQuery(foreignFieldName, localFieldVal.getArray()); } // { _foreignFieldFieldName : { "$in" : localFieldValue } } subObj << "$in" << localFieldVal; } else { // { _foreignFieldFieldName : { "$eq" : localFieldValue } } subObj << "$eq" << localFieldVal; } subObj.doneFast(); return query.obj(); }
bool DocumentSourceGraphLookUp::addToVisitedAndFrontier(BSONObj result, long long depth) { Value _id = Value(result.getField("_id")); if (_visited.find(_id) != _visited.end()) { // We've already seen this object, don't repeat any work. return false; } // We have not seen this node before. If '_depthField' was specified, add the field to the // object. BSONObj fullObject = _depthField ? addDepthFieldToObject(_depthField->fullPath(), depth, result) : result; // Add the object to our '_visited' list. _visited[_id] = fullObject; // Update the size of '_visited' appropriately. _visitedUsageBytes += _id.getApproximateSize(); _visitedUsageBytes += static_cast<size_t>(fullObject.objsize()); // Add the 'connectFrom' field of 'result' into '_frontier'. If the 'connectFrom' field is an // array, we treat it as connecting to multiple values, so we must add each element to // '_frontier'. BSONElementSet recurseOnValues; dps::extractAllElementsAlongPath(result, _connectFromField.fullPath(), recurseOnValues); for (auto&& elem : recurseOnValues) { Value recurseOn = Value(elem); if (recurseOn.isArray()) { for (auto&& subElem : recurseOn.getArray()) { _frontier->insert(subElem); _frontierUsageBytes += subElem.getApproximateSize(); } } else if (!recurseOn.missing()) { // Don't recurse on a missing value. _frontier->insert(recurseOn); _frontierUsageBytes += recurseOn.getApproximateSize(); } } // We inserted into _visited, so return true. return true; }
Value ExclusionNode::applyProjectionToValue(Value val) const { switch (val.getType()) { case BSONType::Object: return Value(applyProjection(val.getDocument())); case BSONType::Array: { // Apply exclusion to each element of the array. Note that numeric paths aren't treated // specially, and we will always apply the projection to each element in the array. // // For example, applying the projection {"a.1": 0} to the document // {a: [{b: 0, "1": 0}, {b: 1, "1": 1}]} will not result in {a: [{b: 0, "1": 0}]}, but // instead will result in {a: [{b: 0}, {b: 1}]}. std::vector<Value> values = val.getArray(); for (auto it = values.begin(); it != values.end(); it++) { *it = applyProjectionToValue(*it); } return Value(std::move(values)); } default: return val; } }
void AccumulatorPush::processInternal(const Value& input, bool merging) { if (!merging) { if (!input.missing()) { vpValue.push_back(input); _memUsageBytes += input.getApproximateSize(); } } else { // If we're merging, we need to take apart the arrays we // receive and put their elements into the array we are collecting. // If we didn't, then we'd get an array of arrays, with one array // from each merge source. verify(input.getType() == Array); const vector<Value>& vec = input.getArray(); vpValue.insert(vpValue.end(), vec.begin(), vec.end()); for (size_t i = 0; i < vec.size(); i++) { _memUsageBytes += vec[i].getApproximateSize(); } } }
void DocumentSourceGraphLookUp::performSearch() { // Make sure _input is set before calling performSearch(). invariant(_input); _variables->setRoot(*_input); Value startingValue = _startWith->evaluateInternal(_variables.get()); _variables->clearRoot(); // If _startWith evaluates to an array, treat each value as a separate starting point. if (startingValue.isArray()) { for (auto value : startingValue.getArray()) { _frontier->insert(value); _frontierUsageBytes += value.getApproximateSize(); } } else { _frontier->insert(startingValue); _frontierUsageBytes += startingValue.getApproximateSize(); } doBreadthFirstSearch(); }
Value ProjectionNode::applyProjectionsToValue(Value inputValue) const { if (inputValue.getType() == BSONType::Object) { MutableDocument outputSubDoc{initializeOutputDocument(inputValue.getDocument())}; applyProjections(inputValue.getDocument(), &outputSubDoc); return outputSubDoc.freezeToValue(); } else if (inputValue.getType() == BSONType::Array) { std::vector<Value> values = inputValue.getArray(); for (auto& value : values) { // If this is a nested array and our policy is to not recurse, skip the array. // Otherwise, descend into the array and project each element individually. const bool shouldSkip = value.isArray() && _policies.arrayRecursionPolicy == ArrayRecursionPolicy::kDoNotRecurseNestedArrays; value = (shouldSkip ? transformSkippedValueForOutput(value) : applyProjectionsToValue(value)); } return Value(std::move(values)); } else { // This represents the case where we are projecting children of a field which does not have // any children; for instance, applying the projection {"a.b": true} to the document {a: 2}. return transformSkippedValueForOutput(inputValue); } }
TEST(ValueTest, CreateValue) { Value b = true; EXPECT_EQ(true, b.getBoolean()); Value i1 = 42; EXPECT_EQ(42, i1.getInteger()); Value i2 = 42L; EXPECT_EQ(42, i2.getInteger()); Value f1 = 0.42F; EXPECT_NEAR(0.42, f1.getFloat(), 0.000001); Value f2 = 0.42; EXPECT_NEAR(0.42, f2.getFloat(), 0.000001); Value s1 = "foobar"; EXPECT_EQ("foobar", s1.getString()); Value s2 = std::string("foobar"); EXPECT_EQ("foobar", s2.getString()); Value s3 = QString("foobar"); EXPECT_EQ("foobar", s3.getString()); Value::Array arr; arr.push_back(Value(42)); Value a = arr; EXPECT_EQ(arr, a.getArray()); Value::Object obj; obj["foobar"] = Value(42); Value o1 = obj; EXPECT_EQ(obj, o1.getObject()); Value o2 = o1; EXPECT_EQ(o1, o2); }
bool AssociativeArray::getVector(const string& key, Vec3d& val) const { Value* v = getValue(key); if (v == NULL || v->getType() != Value::ArrayType) return false; Array* arr = v->getArray(); if (arr->size() != 3) return false; Value* x = (*arr)[0]; Value* y = (*arr)[1]; Value* z = (*arr)[2]; if (x->getType() != Value::NumberType || y->getType() != Value::NumberType || z->getType() != Value::NumberType) return false; val = Vec3d(x->getNumber(), y->getNumber(), z->getNumber()); return true; }
TEST(ValueTest, ValueMap) { boost::shared_ptr<Scalar> s(new Scalar(NTA_BasicType_Int32)); s->value.int32 = 10; boost::shared_ptr<Array> a(new Array(NTA_BasicType_Real32)); boost::shared_ptr<std::string> str(new std::string("hello world")); ValueMap vm; vm.add("scalar", s); vm.add("array", a); vm.add("string", str); ASSERT_ANY_THROW(vm.add("scalar", s)); ASSERT_TRUE(vm.contains("scalar")); ASSERT_TRUE(vm.contains("array")); ASSERT_TRUE(vm.contains("string")); ASSERT_TRUE(!vm.contains("foo")); ASSERT_TRUE(!vm.contains("scalar2")); ASSERT_TRUE(!vm.contains("xscalar")); boost::shared_ptr<Scalar> s1 = vm.getScalar("scalar"); ASSERT_TRUE(s1 == s); boost::shared_ptr<Array> a1 = vm.getArray("array"); ASSERT_TRUE(a1 == a); boost::shared_ptr<Scalar> def(new Scalar(NTA_BasicType_Int32)); Int32 x = vm.getScalarT("scalar", (Int32)20); ASSERT_EQ((Int32)10, x); x = vm.getScalarT("scalar2", (Int32)20); ASSERT_EQ((Int32)20, x); Value v = vm.getValue("array"); ASSERT_EQ(Value::arrayCategory, v.getCategory()); ASSERT_TRUE(v.getArray() == a); }
void AccumulatorAddToSet::processInternal(const Value& input, bool merging) { if (!merging) { if (!input.missing()) { bool inserted = set.insert(input).second; if (inserted) { _memUsageBytes += input.getApproximateSize(); } } } else { // If we're merging, we need to take apart the arrays we // receive and put their elements into the array we are collecting. // If we didn't, then we'd get an array of arrays, with one array // from each merge source. verify(input.getType() == Array); const vector<Value>& array = input.getArray(); for (size_t i = 0; i < array.size(); i++) { bool inserted = set.insert(array[i]).second; if (inserted) { _memUsageBytes += array[i].getApproximateSize(); } } } }
Value ProjectionNode::applyExpressionsToValue(const Document& root, Value inputValue) const { if (inputValue.getType() == BSONType::Object) { MutableDocument outputDoc(inputValue.getDocument()); applyExpressions(root, &outputDoc); return outputDoc.freezeToValue(); } else if (inputValue.getType() == BSONType::Array) { std::vector<Value> values = inputValue.getArray(); for (auto& value : values) { value = applyExpressionsToValue(root, value); } return Value(std::move(values)); } else { if (subtreeContainsComputedFields()) { // Our semantics in this case are to replace whatever existing value we find with a new // document of all the computed values. This case represents applying a projection like // {"a.b": {$literal: 1}} to the document {a: 1}. This should yield {a: {b: 1}}. MutableDocument outputDoc; applyExpressions(root, &outputDoc); return outputDoc.freezeToValue(); } // We didn't have any expressions, so just skip this value. return transformSkippedValueForOutput(inputValue); } }
int main () { string resposta; string codigoCupom; string productID; bool desejoAdicionarProduto = true; bool questionResolved = false; bool firstProductAdded = false; Shoppingcart* shoppingCart = new Shoppingcart; Value v; Value v2; Array ar; Array ar2; v.loadFromFile("product.json"); v2.loadFromFile("discounts.json"); ar = Array(v.getArray()); ar2 = Array(v2.getArray()); // Primeira parte do programa referente aa adicao de produtos ao carrinho while(desejoAdicionarProduto) { cout<<"Digite a ID do produto que deseja adicionar"<<endl; cin>>productID; // Toda a execucao de codigo referente aa adicao de um produto pelo ID somente tem sentido se o usuario tiver digitado corretamente if(shoppingCart->validateProductID(productID)) { // Este if de baixo serve para validar se a entrada e um inteiro sem sinal , o codigo so seque naturalmente se validarID = true cout<<"Esta certo disso (S/N) ?"<<endl; cin>>resposta; do { if(!(resposta == "S") && !(resposta == "s") && !(resposta == "n") && !(resposta == "N")) { cout<<"Voce so pode responder com (s/S/n/N)"<<endl; cout<<endl; cout<<"Esta certo disso (S/N) ?"<<endl; cin>>resposta; } } while(!(resposta == "S") && !(resposta == "s") && !(resposta == "n") && !(resposta == "N")); if(resposta == "S" || resposta == "s") if(shoppingCart->adicionarAoCarrinho(Atoi(productID),ar) == 0) if(resposta != "N" && resposta != "n") { cout<<"Deseja adicionar mais algum produto (S/N) ?"<<endl; cin>>resposta; // Este looping ai de baixo trata a possibilidade do usuario na responder som um caracter s/S/n/N do { if(resposta == "S" || resposta == "s"); else if(resposta == "N" || resposta == "n"); else { cout<<endl; cout<<"Voce so pode responder com (s/S/n/N)"<<endl; cout<<endl; cout<<"Deseja adicionar mais algum produto (S/N) ?"<<endl; cin>>resposta; } } while(!(resposta == "S") && !(resposta == "s") && !(resposta == "n") && !(resposta == "N")); do { if(resposta == "S" || resposta == "s") desejoAdicionarProduto = true; else if(resposta == "N" || resposta == "n") desejoAdicionarProduto = false; else { cout<<endl; cout<<"Voce so pode responder com (s/S/n/N)"<<endl; cout<<endl; cout<<"Deseja adicionar mais algum produto (S/N) ?"<<endl; cin>>resposta; } } while(!(resposta == "S") && !(resposta == "s") && !(resposta == "n") && !(resposta == "N")); } }
BSONObj DocumentSourceLookUp::makeMatchStageFromInput(const Document& input, const FieldPath& localFieldPath, const std::string& foreignFieldName, const BSONObj& additionalFilter) { Value localFieldVal = input.getNestedField(localFieldPath); // Missing values are treated as null. if (localFieldVal.missing()) { localFieldVal = Value(BSONNULL); } // We construct a query of one of the following forms, depending on the contents of // 'localFieldVal'. // // {$and: [{<foreignFieldName>: {$eq: <localFieldVal>}}, <additionalFilter>]} // if 'localFieldVal' isn't an array value. // // {$and: [{<foreignFieldName>: {$in: [<value>, <value>, ...]}}, <additionalFilter>]} // if 'localFieldVal' is an array value but doesn't contain any elements that are regular // expressions. // // {$and: [{$or: [{<foreignFieldName>: {$eq: <value>}}, // {<foreignFieldName>: {$eq: <value>}}, ...]}, // <additionalFilter>]} // if 'localFieldVal' is an array value and it contains at least one element that is a // regular expression. // We wrap the query in a $match so that it can be parsed into a DocumentSourceMatch when // constructing a pipeline to execute. BSONObjBuilder match; BSONObjBuilder query(match.subobjStart("$match")); BSONArrayBuilder andObj(query.subarrayStart("$and")); BSONObjBuilder joiningObj(andObj.subobjStart()); if (localFieldVal.isArray()) { // A $lookup on an array value corresponds to finding documents in the foreign collection // that have a value of any of the elements in the array value, rather than finding // documents that have a value equal to the entire array value. These semantics are // automatically provided to us by using the $in query operator. const vector<Value>& localArray = localFieldVal.getArray(); const bool containsRegex = std::any_of( localArray.begin(), localArray.end(), [](Value val) { return val.getType() == RegEx; }); if (containsRegex) { // A regular expression inside the $in query operator will perform pattern matching on // any string values. Since we want regular expressions to only match other RegEx types, // we write the query as a $or of equality comparisons instead. BSONObj orQuery = buildEqualityOrQuery(foreignFieldName, localFieldVal.getArray()); joiningObj.appendElements(orQuery); } else { // { <foreignFieldName> : { "$in" : <localFieldVal> } } BSONObjBuilder subObj(joiningObj.subobjStart(foreignFieldName)); subObj << "$in" << localFieldVal; subObj.doneFast(); } } else { // { <foreignFieldName> : { "$eq" : <localFieldVal> } } BSONObjBuilder subObj(joiningObj.subobjStart(foreignFieldName)); subObj << "$eq" << localFieldVal; subObj.doneFast(); } joiningObj.doneFast(); BSONObjBuilder additionalFilterObj(andObj.subobjStart()); additionalFilterObj.appendElements(additionalFilter); additionalFilterObj.doneFast(); andObj.doneFast(); query.doneFast(); return match.obj(); }
static bool CreateTimeline(Body* body, PlanetarySystem* system, Universe& universe, Hash* planetData, const string& path, Disposition disposition, BodyType bodyType) { FrameTree* parentFrameTree = NULL; Selection parentObject = GetParentObject(system); bool orbitsPlanet = false; if (parentObject.body()) { parentFrameTree = parentObject.body()->getOrCreateFrameTree(); orbitsPlanet = true; } else if (parentObject.star()) { SolarSystem* solarSystem = universe.getSolarSystem(parentObject.star()); if (solarSystem == NULL) solarSystem = universe.createSolarSystem(parentObject.star()); parentFrameTree = solarSystem->getFrameTree(); } else { // Bad orbit barycenter specified return false; } ReferenceFrame* defaultOrbitFrame = NULL; ReferenceFrame* defaultBodyFrame = NULL; if (bodyType == SurfaceObject) { defaultOrbitFrame = new BodyFixedFrame(parentObject, parentObject); defaultBodyFrame = CreateTopocentricFrame(parentObject, parentObject, Selection(body)); defaultOrbitFrame->addRef(); defaultBodyFrame->addRef(); } else { defaultOrbitFrame = parentFrameTree->getDefaultReferenceFrame(); defaultBodyFrame = parentFrameTree->getDefaultReferenceFrame(); } // If there's an explicit timeline definition, parse that. Otherwise, we'll do // things the old way. Value* value = planetData->getValue("Timeline"); if (value != NULL) { if (value->getType() != Value::ArrayType) { clog << "Error: Timeline must be an array\n"; return false; } Timeline* timeline = CreateTimelineFromArray(body, universe, value->getArray(), path, defaultOrbitFrame, defaultBodyFrame); if (timeline == NULL) { return false; } else { body->setTimeline(timeline); return true; } } // Information required for the object timeline. ReferenceFrame* orbitFrame = NULL; ReferenceFrame* bodyFrame = NULL; Orbit* orbit = NULL; RotationModel* rotationModel = NULL; double beginning = -numeric_limits<double>::infinity(); double ending = numeric_limits<double>::infinity(); // If any new timeline values are specified, we need to overrideOldTimeline will // be set to true. bool overrideOldTimeline = false; // The interaction of Modify with timelines is slightly complicated. If the timeline // is specified by putting the OrbitFrame, Orbit, BodyFrame, or RotationModel directly // in the object definition (i.e. not inside a Timeline structure), it will completely // replace the previous timeline if it contained more than one phase. Otherwise, the // properties of the single phase will be modified individually, for compatibility with // Celestia versions 1.5.0 and earlier. if (disposition == ModifyObject) { const Timeline* timeline = body->getTimeline(); if (timeline->phaseCount() == 1) { const TimelinePhase* phase = timeline->getPhase(0); orbitFrame = phase->orbitFrame(); bodyFrame = phase->bodyFrame(); orbit = phase->orbit(); rotationModel = phase->rotationModel(); beginning = phase->startTime(); ending = phase->endTime(); } } // Get the object's orbit reference frame. bool newOrbitFrame = false; Value* frameValue = planetData->getValue("OrbitFrame"); if (frameValue != NULL) { ReferenceFrame* frame = CreateReferenceFrame(universe, frameValue, parentObject, body); if (frame != NULL) { orbitFrame = frame; newOrbitFrame = true; overrideOldTimeline = true; } } // Get the object's body frame. bool newBodyFrame = false; Value* bodyFrameValue = planetData->getValue("BodyFrame"); if (bodyFrameValue != NULL) { ReferenceFrame* frame = CreateReferenceFrame(universe, bodyFrameValue, parentObject, body); if (frame != NULL) { bodyFrame = frame; newBodyFrame = true; overrideOldTimeline = true; } } // If no orbit or body frame was specified, use the default ones if (orbitFrame == NULL) orbitFrame = defaultOrbitFrame; if (bodyFrame == NULL) bodyFrame = defaultBodyFrame; // If the center of the is a star, orbital element units are // in AU; otherwise, use kilometers. if (orbitFrame->getCenter().star() != NULL) orbitsPlanet = false; else orbitsPlanet = true; Orbit* newOrbit = CreateOrbit(orbitFrame->getCenter(), planetData, path, !orbitsPlanet); if (newOrbit == NULL && orbit == NULL) { if (body->getTimeline() && disposition == ModifyObject) { // The object definition is modifying an existing object with a multiple phase // timeline, but no orbit definition was given. This can happen for completely // sensible reasons, such a Modify definition that just changes visual properties. // Or, the definition may try to change other timeline phase properties such as // the orbit frame, but without providing an orbit. In both cases, we'll just // leave the original timeline alone. return true; } else { clog << "No valid orbit specified for object '" << body->getName() << "'. Skipping.\n"; return false; } } // If a new orbit was given, override any old orbit if (newOrbit != NULL) { orbit = newOrbit; overrideOldTimeline = true; } // Get the rotation model for this body double syncRotationPeriod = orbit->getPeriod(); RotationModel* newRotationModel = CreateRotationModel(planetData, path, syncRotationPeriod); // If a new rotation model was given, override the old one if (newRotationModel != NULL) { rotationModel = newRotationModel; overrideOldTimeline = true; } // If there was no rotation model specified, nor a previous rotation model to // override, create the default one. if (rotationModel == NULL) { // If no rotation model is provided, use a default rotation model-- // a uniform rotation that's synchronous with the orbit (appropriate // for nearly all natural satellites in the solar system.) rotationModel = CreateDefaultRotationModel(syncRotationPeriod); } if (ParseDate(planetData, "Beginning", beginning)) overrideOldTimeline = true; if (ParseDate(planetData, "Ending", ending)) overrideOldTimeline = true; // Something went wrong if the disposition isn't modify and no timeline // is to be created. assert(disposition == ModifyObject || overrideOldTimeline); if (overrideOldTimeline) { if (beginning >= ending) { clog << "Beginning time must be before Ending time.\n"; return false; } // We finally have an orbit, rotation model, frames, and time range. Create // the object timeline. TimelinePhase* phase = TimelinePhase::CreateTimelinePhase(universe, body, beginning, ending, *orbitFrame, *orbit, *bodyFrame, *rotationModel); // We've already checked that beginning < ending; nothing else should go // wrong during the creation of a TimelinePhase. assert(phase != NULL); if (phase == NULL) { clog << "Internal error creating TimelinePhase.\n"; return false; } Timeline* timeline = new Timeline(); timeline->appendPhase(phase); body->setTimeline(timeline); // Check for circular references in frames; this can only be done once the timeline // has actually been set. // TIMELINE-TODO: This check is not comprehensive; it won't find recursion in // multiphase timelines. if (newOrbitFrame && isFrameCircular(*body->getOrbitFrame(0.0), ReferenceFrame::PositionFrame)) { clog << "Orbit frame for " << body->getName() << " is nested too deep (probably circular)\n"; return false; } if (newBodyFrame && isFrameCircular(*body->getBodyFrame(0.0), ReferenceFrame::OrientationFrame)) { clog << "Body frame for " << body->getName() << " is nested too deep (probably circular)\n"; return false; } } return true; }
void ValueTest::RunTests() { // scalar { boost::shared_ptr<Scalar> s(new Scalar(NTA_BasicType_Int32)); s->value.int32 = 10; Value v(s); TEST(v.isScalar()); TEST(! v.isString()); TEST(! v.isArray()); TESTEQUAL(Value::scalarCategory, v.getCategory()); TESTEQUAL(NTA_BasicType_Int32, v.getType()); boost::shared_ptr<Scalar> s1 = v.getScalar(); TEST(s1 == s); SHOULDFAIL(v.getArray()); SHOULDFAIL(v.getString()); TESTEQUAL("Scalar of type Int32", v.getDescription()); Int32 x = v.getScalarT<Int32>(); TESTEQUAL(10, x); SHOULDFAIL(v.getScalarT<UInt32>()); } // array { boost::shared_ptr<Array> s(new Array(NTA_BasicType_Int32)); s->allocateBuffer(10); Value v(s); TEST(v.isArray()); TEST(! v.isString()); TEST(! v.isScalar()); TESTEQUAL(Value::arrayCategory, v.getCategory()); TESTEQUAL(NTA_BasicType_Int32, v.getType()); boost::shared_ptr<Array> s1 = v.getArray(); TEST(s1 == s); SHOULDFAIL(v.getScalar()); SHOULDFAIL(v.getString()); SHOULDFAIL(v.getScalarT<Int32>()); TESTEQUAL("Array of type Int32", v.getDescription()); } // string { boost::shared_ptr<std::string> s(new std::string("hello world")); Value v(s); TEST(! v.isArray()); TEST(v.isString()); TEST(! v.isScalar()); TESTEQUAL(Value::stringCategory, v.getCategory()); TESTEQUAL(NTA_BasicType_Byte, v.getType()); boost::shared_ptr<std::string> s1 = v.getString(); TESTEQUAL("hello world", s1->c_str()); SHOULDFAIL(v.getScalar()); SHOULDFAIL(v.getArray()); SHOULDFAIL(v.getScalarT<Int32>()); TESTEQUAL("string (hello world)", v.getDescription()); } // ValueMap { boost::shared_ptr<Scalar> s(new Scalar(NTA_BasicType_Int32)); s->value.int32 = 10; boost::shared_ptr<Array> a(new Array(NTA_BasicType_Real32)); boost::shared_ptr<std::string> str(new std::string("hello world")); ValueMap vm; vm.add("scalar", s); vm.add("array", a); vm.add("string", str); SHOULDFAIL(vm.add("scalar", s)); TEST(vm.contains("scalar")); TEST(vm.contains("array")); TEST(vm.contains("string")); TEST(!vm.contains("foo")); TEST(!vm.contains("scalar2")); TEST(!vm.contains("xscalar")); boost::shared_ptr<Scalar> s1 = vm.getScalar("scalar"); TEST(s1 == s); boost::shared_ptr<Array> a1 = vm.getArray("array"); TEST(a1 == a); boost::shared_ptr<Scalar> def(new Scalar(NTA_BasicType_Int32)); Int32 x = vm.getScalarT("scalar", (Int32)20); TESTEQUAL((Int32)10, x); x = vm.getScalarT("scalar2", (Int32)20); TESTEQUAL((Int32)20, x); Value v = vm.getValue("array"); TESTEQUAL(Value::arrayCategory, v.getCategory()); TEST(v.getArray() == a); } }