\brief Instantiate a sub-class of BaseObject from a PROJ string. * * The projString must contain +type=crs for the object to be detected as a * CRS instead of a CoordinateOperation. * * @throw ParsingException */
| 10054 | * @throw ParsingException |
| 10055 | */ |
| 10056 | BaseObjectNNPtr |
| 10057 | PROJStringParser::createFromPROJString(const std::string &projString) { |
| 10058 | |
| 10059 | // In some abnormal situations involving init=epsg:XXXX syntax, we could |
| 10060 | // have infinite loop |
| 10061 | if (d->ctx_ && |
| 10062 | d->ctx_->projStringParserCreateFromPROJStringRecursionCounter == 2) { |
| 10063 | throw ParsingException( |
| 10064 | "Infinite recursion in PROJStringParser::createFromPROJString()"); |
| 10065 | } |
| 10066 | |
| 10067 | d->steps_.clear(); |
| 10068 | d->title_.clear(); |
| 10069 | d->globalParamValues_.clear(); |
| 10070 | d->projString_ = projString; |
| 10071 | PROJStringSyntaxParser(projString, d->steps_, d->globalParamValues_, |
| 10072 | d->title_); |
| 10073 | |
| 10074 | if (d->steps_.empty()) { |
| 10075 | const auto &vunits = d->getGlobalParamValue("vunits"); |
| 10076 | const auto &vto_meter = d->getGlobalParamValue("vto_meter"); |
| 10077 | if (!vunits.empty() || !vto_meter.empty()) { |
| 10078 | Step fakeStep; |
| 10079 | if (!vunits.empty()) { |
| 10080 | fakeStep.paramValues.emplace_back( |
| 10081 | Step::KeyValue("vunits", vunits)); |
| 10082 | } |
| 10083 | if (!vto_meter.empty()) { |
| 10084 | fakeStep.paramValues.emplace_back( |
| 10085 | Step::KeyValue("vto_meter", vto_meter)); |
| 10086 | } |
| 10087 | auto vdatum = |
| 10088 | VerticalReferenceFrame::create(createMapWithUnknownName()); |
| 10089 | auto vcrs = VerticalCRS::create( |
| 10090 | createMapWithUnknownName(), vdatum, |
| 10091 | VerticalCS::createGravityRelatedHeight( |
| 10092 | d->buildUnit(fakeStep, "vunits", "vto_meter"))); |
| 10093 | return vcrs; |
| 10094 | } |
| 10095 | } |
| 10096 | |
| 10097 | const bool isGeocentricCRS = |
| 10098 | ((d->steps_.size() == 1 && |
| 10099 | d->getParamValue(d->steps_[0], "type") == "crs") || |
| 10100 | (d->steps_.size() == 2 && d->steps_[1].name == "unitconvert")) && |
| 10101 | !d->steps_[0].inverted && isGeocentricStep(d->steps_[0].name); |
| 10102 | |
| 10103 | // +init=xxxx:yyyy syntax |
| 10104 | if (d->steps_.size() == 1 && d->steps_[0].isInit && |
| 10105 | !d->steps_[0].inverted) { |
| 10106 | |
| 10107 | // Those used to come from a text init file |
| 10108 | // We only support them in compatibility mode |
| 10109 | const std::string &stepName = d->steps_[0].name; |
| 10110 | if (ci_starts_with(stepName, "epsg:") || |
| 10111 | ci_starts_with(stepName, "IGNF:")) { |
| 10112 | |
| 10113 | /* We create a new context so as to avoid messing up with the */ |
no test coverage detected