Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi-line PROJ string export capability, and use it by default in projinfo (unless --single-line is specified) (fixes #1543) #2381

Merged
merged 4 commits into from
Oct 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/source/apps/projinfo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ The following control parameters can appear in any order:

.. option:: --single-line

Output WKT or PROJJSON strings on a single line, instead of multiple intended lines by
default.
Output PROJ, WKT or PROJJSON strings on a single line, instead of multiple
indented lines by default.

.. option:: --searchpaths

Expand Down
4 changes: 4 additions & 0 deletions include/proj/io.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,10 @@ class PROJ_GCC_DLL PROJStringFormatter {
PROJ_DLL ~PROJStringFormatter();
//! @endcond

PROJ_DLL PROJStringFormatter &setMultiLine(bool multiLine) noexcept;
PROJ_DLL PROJStringFormatter &setIndentationWidth(int width) noexcept;
PROJ_DLL PROJStringFormatter &setMaxLineLength(int maxLineLength) noexcept;

PROJ_DLL void setUseApproxTMerc(bool flag);

PROJ_DLL const std::string &toString() const;
Expand Down
3 changes: 3 additions & 0 deletions scripts/reference_exported_symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@ osgeo::proj::io::PROJStringFormatter::ingestPROJString(std::string const&)
osgeo::proj::io::PROJStringFormatter::~PROJStringFormatter()
osgeo::proj::io::PROJStringFormatter::setCRSExport(bool)
osgeo::proj::io::PROJStringFormatter::setCurrentStepInverted(bool)
osgeo::proj::io::PROJStringFormatter::setIndentationWidth(int)
osgeo::proj::io::PROJStringFormatter::setMaxLineLength(int)
osgeo::proj::io::PROJStringFormatter::setMultiLine(bool)
osgeo::proj::io::PROJStringFormatter::setUseApproxTMerc(bool)
osgeo::proj::io::PROJStringFormatter::startInversion()
osgeo::proj::io::PROJStringFormatter::stopInversion()
Expand Down
14 changes: 6 additions & 8 deletions src/apps/projinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,11 +350,11 @@ static void outputObject(
objToExport = projStringExportable;
}

std::cout << objToExport->exportToPROJString(
PROJStringFormatter::create(
PROJStringFormatter::Convention::PROJ_5,
dbContext)
.get())
auto formatter = PROJStringFormatter::create(
PROJStringFormatter::Convention::PROJ_5, dbContext);
formatter->setMultiLine(!outputOpt.singleLine &&
crs == nullptr);
std::cout << objToExport->exportToPROJString(formatter.get())
<< std::endl;
} catch (const std::exception &e) {
std::cerr << "Error when exporting to PROJ string: " << e.what()
Expand All @@ -376,9 +376,7 @@ static void outputObject(
}
auto formatter =
WKTFormatter::create(WKTFormatter::Convention::WKT2_2015);
if (outputOpt.singleLine) {
formatter->setMultiLine(false);
}
formatter->setMultiLine(!outputOpt.singleLine);
formatter->setStrict(outputOpt.strict);
auto wkt = wktExportable->exportToWKT(formatter.get());
if (outputOpt.c_ify) {
Expand Down
31 changes: 25 additions & 6 deletions src/iso19111/c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1504,9 +1504,16 @@ const char *proj_as_wkt(PJ_CONTEXT *ctx, const PJ *obj, PJ_WKT_TYPE type,
* @param obj Object (must not be NULL)
* @param type PROJ String version.
* @param options NULL-terminated list of strings with "KEY=VALUE" format. or
* NULL.
* The currently recognized option is USE_APPROX_TMERC=YES to add the +approx
* flag to +proj=tmerc or +proj=utm
* NULL. Currently supported options are:
* <ul>
* <li>USE_APPROX_TMERC=YES to add the +approx flag to +proj=tmerc or
* +proj=utm.</li>
* <li>MULTILINE=YES/NO. Defaults to NO</li>
* <li>INDENTATION_WIDTH=number. Defaults to 2 (when multiline output is
* on).</li>
* <li>MAX_LINE_LENGTH=number. Defaults to 80 (when multiline output is
* on).</li>
* </ul>
* @return a string, or NULL in case of error.
*/
const char *proj_as_proj_string(PJ_CONTEXT *ctx, const PJ *obj,
Expand Down Expand Up @@ -1542,9 +1549,21 @@ const char *proj_as_proj_string(PJ_CONTEXT *ctx, const PJ *obj,
auto dbContext = getDBcontextNoException(ctx, __FUNCTION__);
try {
auto formatter = PROJStringFormatter::create(convention, dbContext);
if (options != nullptr && options[0] != nullptr) {
if (ci_equal(options[0], "USE_APPROX_TMERC=YES")) {
formatter->setUseApproxTMerc(true);
for (auto iter = options; iter && iter[0]; ++iter) {
const char *value;
if ((value = getOptionValue(*iter, "MULTILINE="))) {
formatter->setMultiLine(ci_equal(value, "YES"));
} else if ((value = getOptionValue(*iter, "INDENTATION_WIDTH="))) {
formatter->setIndentationWidth(std::atoi(value));
} else if ((value = getOptionValue(*iter, "MAX_LINE_LENGTH="))) {
formatter->setMaxLineLength(std::atoi(value));
} else if ((value = getOptionValue(*iter, "USE_APPROX_TMERC="))) {
formatter->setUseApproxTMerc(ci_equal(value, "YES"));
} else {
std::string msg("Unknown option :");
msg += *iter;
proj_log_error(ctx, __FUNCTION__, msg.c_str());
return nullptr;
}
}
obj->lastPROJString = exportable->exportToPROJString(formatter.get());
Expand Down
78 changes: 70 additions & 8 deletions src/iso19111/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6722,6 +6722,10 @@ struct PROJStringFormatter::Private {
bool coordOperationOptimizations_ = false;
bool crsExport_ = false;
bool legacyCRSToCRSContext_ = false;
bool multiLine_ = false;
int indentWidth_ = 2;
int indentLevel_ = 0;
int maxLineLength_ = 80;

std::string result_{};

Expand Down Expand Up @@ -6780,6 +6784,36 @@ void PROJStringFormatter::setUseApproxTMerc(bool flag) {

// ---------------------------------------------------------------------------

/** \brief Whether to use multi line output or not. */
PROJStringFormatter &
PROJStringFormatter::setMultiLine(bool multiLine) noexcept {
d->multiLine_ = multiLine;
return *this;
}

// ---------------------------------------------------------------------------

/** \brief Set number of spaces for each indentation level (defaults to 2).
*/
PROJStringFormatter &
PROJStringFormatter::setIndentationWidth(int width) noexcept {
d->indentWidth_ = width;
return *this;
}

// ---------------------------------------------------------------------------

/** \brief Set the maximum size of a line (when multiline output is enable).
* Can be set to 0 for unlimited length.
*/
PROJStringFormatter &
PROJStringFormatter::setMaxLineLength(int maxLineLength) noexcept {
d->maxLineLength_ = maxLineLength;
return *this;
}

// ---------------------------------------------------------------------------

/** \brief Returns the PROJ string. */
const std::string &PROJStringFormatter::toString() const {

Expand Down Expand Up @@ -7308,28 +7342,56 @@ const std::string &PROJStringFormatter::toString() const {
pj_double_quote_string_param_if_needed(paramValue.value);
}
}

if (d->multiLine_) {
d->indentLevel_++;
}
}

for (const auto &step : d->steps_) {
std::string curLine;
if (!d->result_.empty()) {
d->appendToResult("+step");
if (d->multiLine_) {
curLine = std::string(d->indentLevel_ * d->indentWidth_, ' ');
curLine += "+step";
} else {
curLine = " +step";
}
}
if (step.inverted) {
d->appendToResult("+inv");
curLine += " +inv";
}
if (!step.name.empty()) {
d->appendToResult(step.isInit ? "+init=" : "+proj=");
d->result_ += step.name;
if (!curLine.empty())
curLine += ' ';
curLine += step.isInit ? "+init=" : "+proj=";
curLine += step.name;
}
for (const auto &paramValue : step.paramValues) {
d->appendToResult("+");
d->result_ += paramValue.key;
std::string newKV = "+";
newKV += paramValue.key;
if (!paramValue.value.empty()) {
d->result_ += '=';
d->result_ +=
newKV += '=';
newKV +=
pj_double_quote_string_param_if_needed(paramValue.value);
}
if (d->maxLineLength_ > 0 && d->multiLine_ &&
curLine.size() + newKV.size() >
static_cast<size_t>(d->maxLineLength_)) {
if (d->multiLine_ && !d->result_.empty())
d->result_ += '\n';
d->result_ += curLine;
curLine = std::string(
d->indentLevel_ * d->indentWidth_ + strlen("+step "), ' ');
} else {
if (!curLine.empty())
curLine += ' ';
}
curLine += newKV;
}
if (d->multiLine_ && !d->result_.empty())
d->result_ += '\n';
d->result_ += curLine;
}

if (d->result_.empty()) {
Expand Down
4 changes: 2 additions & 2 deletions test/cli/testprojinfo
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ echo "Testing projinfo -o ALL EPSG:4326" >> ${OUT}
$EXE -o ALL EPSG:4326 >>${OUT}
echo "" >>${OUT}

echo "Testing projinfo -s EPSG:4326 -t EPSG:32631" >> ${OUT}
$EXE -s EPSG:4326 -t EPSG:32631 >>${OUT}
echo "Testing projinfo -s EPSG:4326 -t EPSG:32631 --single-line" >> ${OUT}
$EXE -s EPSG:4326 -t EPSG:32631 --single-line >>${OUT}
echo "" >>${OUT}

echo "Testing projinfo -s NAD27 -t NAD83" >> ${OUT}
Expand Down
Loading