Skip to content

Commit

Permalink
add options to control output cj transform and metadata writing
Browse files Browse the repository at this point in the history
  • Loading branch information
Ylannl committed Nov 27, 2024
1 parent e031c8d commit 43495b4
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 33 deletions.
67 changes: 62 additions & 5 deletions apps/roofer-app/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ struct RooferConfig {

// crop output
bool split_cjseq = false;
bool omit_metadata = false;
std::optional<roofer::arr3d> cj_scale;
std::optional<roofer::arr3d> cj_translate;
std::string building_toml_file_spec =
"{path}/objects/{bid}/config_{pc_name}.toml";
std::string building_las_file_spec =
Expand Down Expand Up @@ -415,6 +418,15 @@ class ConfigParameterByReference : public ConfigParameter {
return fmt::format("[{},{},{},{}]", _value->pmin[0], _value->pmin[1],
_value->pmax[0], _value->pmax[1]);
}
} else if constexpr (std::is_same_v<T, roofer::arr2f>) {
return fmt::format("[{},{}]", _value[0], _value[1]);
} else if constexpr (std::is_same_v<T, std::optional<roofer::arr3d>>) {
if (!_value.has_value()) {
return "[]";
} else {
return fmt::format("[{},{},{}]", (*_value)[0], (*_value)[1],
(*_value)[2]);
}
} else {
return fmt::format("{}", _value);
}
Expand All @@ -423,11 +435,11 @@ class ConfigParameterByReference : public ConfigParameter {
std::list<std::string>::iterator set(
std::list<std::string>& args,
std::list<std::string>::iterator it) override {
if (it == args.end()) {
throw std::runtime_error("Missing argument for parameter.");
} else if constexpr (std::is_same_v<T, bool>) {
if constexpr (std::is_same_v<T, bool>) {
_value = !(_value);
return it;
} else if (it == args.end()) {
throw std::runtime_error("Missing argument for parameter");
} else if constexpr (std::is_same_v<T, int> ||
std::is_same_v<T, std::optional<int>>) {
_value = std::stoi(*it);
Expand Down Expand Up @@ -475,6 +487,20 @@ class ConfigParameterByReference : public ConfigParameter {
it = args.erase(it);
_value = arr;
return it;
} else if constexpr (std::is_same_v<T, std::optional<roofer::arr3d>>) {
roofer::arr3d arr;
// Check if there are enough arguments
if (std::distance(it, args.end()) < 3) {
throw std::runtime_error("Not enough arguments, need 3.");
}
arr[0] = std::stod(*it);
it = args.erase(it);
arr[1] = std::stod(*it);
it = args.erase(it);
arr[2] = std::stod(*it);
it = args.erase(it);
_value = arr;
return it;
} else {
static_assert(!std::is_same_v<T, T>,
"Unsupported type for ConfigParameterByReference::set()");
Expand All @@ -484,8 +510,31 @@ class ConfigParameterByReference : public ConfigParameter {
void set_from_toml(const toml::table& table,
const std::string& name) override {
if constexpr (std::is_same_v<T, std::array<float, 2>>) {
throw std::runtime_error("Failed to read value for " + name +
" from config file.");
if (const toml::array* a = table[name].as_array()) {
if (a->size() == 2 &&
(a->is_homogeneous(toml::node_type::floating_point) ||
a->is_homogeneous(toml::node_type::integer))) {
_value = roofer::arr2f{*a->get(0)->value<float>(),
*a->get(1)->value<float>()};
} else {
throw std::runtime_error("Failed to read value for " + name +
" from config file.");
}
}
} else if constexpr (std::is_same_v<T,
std::optional<std::array<double, 3>>>) {
if (const toml::array* a = table[name].as_array()) {
if (a->size() == 3 &&
(a->is_homogeneous(toml::node_type::floating_point) ||
a->is_homogeneous(toml::node_type::integer))) {
_value = roofer::arr3d{*a->get(0)->value<double>(),
*a->get(1)->value<double>(),
*a->get(2)->value<double>()};
} else {
throw std::runtime_error("Failed to read value for " + name +
" from config file.");
}
}
} else if constexpr (std::is_same_v<T,
std::optional<roofer::TBox<double>>>) {
if (const toml::array* a = table[name].as_array()) {
Expand Down Expand Up @@ -523,6 +572,8 @@ class ConfigParameterByReference : public ConfigParameter {
return "<xmin ymin xmax ymax>";
} else if constexpr (std::is_same_v<T, roofer::arr2f>) {
return "<x y>";
} else if constexpr (std::is_same_v<T, std::optional<roofer::arr3d>>) {
return "<x y z>";
} else {
static_assert(!std::is_same_v<T, T>,
"Unsupported type for "
Expand Down Expand Up @@ -623,6 +674,12 @@ struct RooferConfigHandler {
"Output CityJSONSequence file for each building [default: one file per "
"output tile]",
_cfg.split_cjseq, {});
add("omit-metadata", "Omit metadata in CityJSON output", _cfg.omit_metadata,
{});
add("cj-scale", "Scaling applied to CityJSON output vertices",
_cfg.cj_scale, {});
add("cj-translate", "Translation applied to CityJSON output vertices",
_cfg.cj_translate, {});
addr("plane-detect-k", "plane detect k", _cfg.rec.plane_detect_k,
{roofer::v::HigherThan<int>(0)});
addr("plane-detect-min-points", "plane detect min points",
Expand Down
6 changes: 6 additions & 0 deletions apps/roofer-app/example_full.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ lod = 22
## Output options
# Output CityJSONSequence file for each building [default: one file per output tile]
split-cjseq = false
# Omit metadata from output CityJSON
omit-metadata = true
# Manually override CityJSON transform translation
cj-translate = [171800.0,472700.0,0.0]
# Manually override CityJSON transform scale
cj-scale = [0.01,0.01,0.01]

output-directory = 'output-directory'

Expand Down
48 changes: 32 additions & 16 deletions apps/roofer-app/roofer-app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -998,7 +998,13 @@ int main(int argc, const char* argv[]) {
roofer::io::createCityJsonWriter(*building_tile.proj_helper);
CityJsonWriter->written_features_count = serialized_buildings_cnt;
CityJsonWriter->identifier_attribute = roofer_cfg.id_attribute;
if (building_tile.proj_helper->data_offset.has_value()) {
// user provided offset
if (roofer_cfg.cj_translate.has_value()) {
CityJsonWriter->translate_x_ = (*roofer_cfg.cj_translate)[0];
CityJsonWriter->translate_y_ = (*roofer_cfg.cj_translate)[1];
CityJsonWriter->translate_z_ = (*roofer_cfg.cj_translate)[2];
// auto offset from data
} else if (building_tile.proj_helper->data_offset.has_value()) {
CityJsonWriter->translate_x_ =
(*building_tile.proj_helper->data_offset)[0];
CityJsonWriter->translate_y_ =
Expand All @@ -1010,9 +1016,15 @@ int main(int argc, const char* argv[]) {
"Tile {} has no data offset, cannot write to cityjson",
building_tile.id));
}
CityJsonWriter->scale_x_ = 0.01;
CityJsonWriter->scale_y_ = 0.01;
CityJsonWriter->scale_z_ = 0.01;
if (roofer_cfg.cj_scale.has_value()) {
CityJsonWriter->scale_x_ = (*roofer_cfg.cj_scale)[0];
CityJsonWriter->scale_y_ = (*roofer_cfg.cj_scale)[1];
CityJsonWriter->scale_z_ = (*roofer_cfg.cj_scale)[2];
} else {
CityJsonWriter->scale_x_ = 0.01;
CityJsonWriter->scale_y_ = 0.01;
CityJsonWriter->scale_z_ = 0.01;
}

std::ofstream ofs;
if (!roofer_cfg.split_cjseq) {
Expand All @@ -1021,19 +1033,23 @@ int main(int argc, const char* argv[]) {
fmt::format("tile_{:05d}.city.jsonl", building_tile.id);
fs::create_directories(jsonl_tile_path.parent_path());
ofs.open(jsonl_tile_path);
CityJsonWriter->write_metadata(
ofs, project_srs.get(), building_tile.extent,
{.identifier = std::to_string(building_tile.id)});
if (!roofer_cfg.omit_metadata)
CityJsonWriter->write_metadata(
ofs, project_srs.get(), building_tile.extent,
{.identifier = std::to_string(building_tile.id)});
} else {
std::string metadata_json_file =
fmt::format(fmt::runtime(roofer_cfg.metadata_json_file_spec),
fmt::arg("path", roofer_cfg.output_path));
fs::create_directories(fs::path(metadata_json_file).parent_path());
ofs.open(metadata_json_file);
CityJsonWriter->write_metadata(
ofs, project_srs.get(), building_tile.extent,
{.identifier = std::to_string(building_tile.id)});
ofs.close();
if (!roofer_cfg.omit_metadata) {
std::string metadata_json_file =
fmt::format(fmt::runtime(roofer_cfg.metadata_json_file_spec),
fmt::arg("path", roofer_cfg.output_path));
fs::create_directories(
fs::path(metadata_json_file).parent_path());
ofs.open(metadata_json_file);
CityJsonWriter->write_metadata(
ofs, project_srs.get(), building_tile.extent,
{.identifier = std::to_string(building_tile.id)});
ofs.close();
}
}

for (auto& building : building_tile.buildings) {
Expand Down
12 changes: 12 additions & 0 deletions docs/cli_application.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,18 @@ Options

Output CityJSONSequence file for each building [default: one file per output tile]

.. option:: --cj-translate

Specify manually the translation applied to CityJSON output vertices

.. option:: --cj-scale

Specify manually the scaling applied to CityJSON output vertices

.. option:: --omit-metadata

Omit metadata from output CityJSON

.. option:: --filter <str>

Specify WHERE clause in OGR SQL to select specfic features from <polygon-source>
Expand Down
12 changes: 6 additions & 6 deletions include/roofer/io/CityJsonWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ namespace roofer::io {

vec1s key_options;

float translate_x_ = 0.;
float translate_y_ = 0.;
float translate_z_ = 0.;
float scale_x_ = 1.;
float scale_y_ = 1.;
float scale_z_ = 1.;
double translate_x_ = 0.;
double translate_y_ = 0.;
double translate_z_ = 0.;
double scale_x_ = 0.01;
double scale_y_ = 0.01;
double scale_z_ = 0.01;

roofer::misc::projHelperInterface& pjHelper;

Expand Down
9 changes: 3 additions & 6 deletions src/extra/io/CityJsonWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,10 @@ namespace roofer::io {
};

std::vector<std::array<int, 3>> vertices_int;
double _offset_x = translate_x_;
double _offset_y = translate_y_;
double _offset_z = translate_z_;
for (auto& vertex : vertex_vec) {
vertices_int.push_back({int((vertex[0] - _offset_x) / scale_x_),
int((vertex[1] - _offset_y) / scale_y_),
int((vertex[2] - _offset_z) / scale_z_)});
vertices_int.push_back({int((vertex[0] - translate_x_) / scale_x_),
int((vertex[1] - translate_y_) / scale_y_),
int((vertex[2] - translate_z_) / scale_z_)});
}
outputJSON["vertices"] = vertices_int;

Expand Down

0 comments on commit 43495b4

Please sign in to comment.