Skip to content
Open
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
19 changes: 14 additions & 5 deletions volume-cartographer/apps/src/vc_obj2tifxyz.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "vc/core/util/Surface.hpp"
#include "vc/core/util/QuadSurface.hpp"
#include "vc/core/util/Slicing.hpp"
#include "vc/core/util/TifxyzIdentity.hpp"
#include <cctype>

#include <iostream>
Expand Down Expand Up @@ -518,7 +519,7 @@ int main(int argc, char *argv[])
std::cout << "usage: " << argv[0]
<< " <input.obj> <output_directory> [stretch_factor] [mesh_units]"
<< " [--uv-metric] [--uv-to-obj=<ratio>] [--uv-downsample=<f>]"
<< " [--grid-cap=<pixels>]" << std::endl;
<< " [--grid-cap=<pixels>] [--uuid=<id>]" << std::endl;
std::cout << "Converts an OBJ file to tifxyz format" << std::endl;
std::cout << std::endl;
std::cout << "Parameters:" << std::endl;
Expand All @@ -530,6 +531,7 @@ int main(int argc, char *argv[])
std::cout << " --uv-to-obj=<ratio> : OBJ units per 1 UV unit (default: 1.0). Only used with --uv-metric." << std::endl;
std::cout << " --uv-downsample=<f> : Uniform UV decimation factor (>=1.0). Reduces grid by ~f^2." << std::endl;
std::cout << " --grid-cap=<pixels> : Upper bound on total grid pixels. Implies extra decimation if needed." << std::endl;
std::cout << " --uuid=<id> : Metadata UUID. Defaults to the output-directory basename." << std::endl;
std::cout << " --tifxyz-source=<dir>: Original tifxyz being flattened. Its meta.json scale sizes the" << std::endl;
std::cout << " output grid to the input sampling density (output scale == input" << std::endl;
std::cout << " scale). If <dir>/approval.tif exists, it is resampled onto the new" << std::endl;
Expand All @@ -552,6 +554,7 @@ int main(int argc, char *argv[])
float uv_downsample = 1.0f;
uint64_t grid_cap = 0;
std::string tifxyz_source; // original tifxyz dir: provides scale + approval mask
std::string uuid_override;

// Backward-compatible parsing:
// positional numbers: stretch_factor, mesh_units
Expand Down Expand Up @@ -599,6 +602,14 @@ int main(int argc, char *argv[])
tifxyz_source = a.substr(std::string("--tifxyz-source=").size());
continue;
}
if (starts_with(a, "--uuid=")) {
uuid_override = a.substr(std::string("--uuid=").size());
if (uuid_override.empty()) {
std::cerr << "Invalid value for --uuid (must be non-empty)\n";
return EXIT_FAILURE;
}
continue;
}
// numbers (legacy positional)
if (consumed_numbers == 0) {
stretch_factor = std::atof(a.c_str());
Expand Down Expand Up @@ -707,10 +718,8 @@ int main(int argc, char *argv[])
}

// Generate a UUID for the surface
std::string uuid = output_dir.filename().string();
if (uuid.empty()) {
uuid = obj_path.stem().string();
}
const std::string uuid =
vc::util::resolveTifxyzUuid(output_dir, obj_path, uuid_override);

std::cout << "Saving to tifxyz format..." << std::endl;

Expand Down
36 changes: 26 additions & 10 deletions volume-cartographer/apps/src/vc_obj2tifxyz_legacy.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "vc/core/util/QuadSurface.hpp"
#include "vc/core/util/TifxyzIdentity.hpp"

#include <iostream>
#include <fstream>
Expand Down Expand Up @@ -304,13 +305,14 @@ class ObjToTifxyzConverter {

int main(int argc, char *argv[])
{
if (argc < 3 || argc > 4) {
std::cout << "usage: " << argv[0] << " <input.obj> <output_directory> [step_size]" << std::endl;
if (argc < 3) {
std::cout << "usage: " << argv[0] << " <input.obj> <output_directory> [step_size] [--uuid=<id>]" << std::endl;
std::cout << "Converts an OBJ file to tifxyz format" << std::endl;
std::cout << std::endl;
std::cout << "Parameters:" << std::endl;
std::cout << " step_size: UV units per grid cell (default: 20)" << std::endl;
std::cout << " Scale will be 1/step_size (default: 0.05)" << std::endl;
std::cout << " --uuid=<id>: Metadata UUID. Defaults to the output-directory basename." << std::endl;
std::cout << std::endl;
std::cout << "Example: " << argv[0] << " mesh.obj output_dir" << std::endl;
std::cout << "Example: " << argv[0] << " mesh.obj output_dir 10" << std::endl;
Expand All @@ -320,13 +322,29 @@ int main(int argc, char *argv[])
std::filesystem::path obj_path = argv[1];
std::filesystem::path output_dir = argv[2];
float step_size = 20.0f;

if (argc >= 4) {
step_size = std::atof(argv[3]);
std::string uuid_override;

bool consumed_step_size = false;
for (int i = 3; i < argc; ++i) {
const std::string arg = argv[i];
if (arg.rfind("--uuid=", 0) == 0) {
uuid_override = arg.substr(std::string("--uuid=").size());
if (uuid_override.empty()) {
std::cerr << "Invalid value for --uuid (must be non-empty)" << std::endl;
return EXIT_FAILURE;
}
continue;
}
if (consumed_step_size) {
std::cerr << "Unknown argument: " << arg << std::endl;
return EXIT_FAILURE;
}
step_size = std::atof(arg.c_str());
if (step_size <= 0) {
std::cerr << "Invalid step size: " << step_size << std::endl;
std::cerr << "Invalid step size: " << arg << std::endl;
return EXIT_FAILURE;
}
consumed_step_size = true;
}

if (!std::filesystem::exists(obj_path)) {
Expand Down Expand Up @@ -358,10 +376,8 @@ int main(int argc, char *argv[])
}

// Generate a UUID for the surface
std::string uuid = output_dir.filename().string();
if (uuid.empty()) {
uuid = obj_path.stem().string();
}
const std::string uuid =
vc::util::resolveTifxyzUuid(output_dir, obj_path, uuid_override);

std::cout << "Saving to tifxyz format..." << std::endl;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include <filesystem>
#include <stdexcept>
#include <string>

namespace vc::util {

/** Resolve the UUID written to a TIFXYZ meta.json.
*
* An explicit UUID lets production pipelines keep artifact directories named
* after a processing role (for example, "output_tifxyz") without giving
* unrelated surfaces the same collection identity. With no override, retain
* the historical output-directory-basename behavior.
*/
inline std::string resolveTifxyzUuid(
const std::filesystem::path& outputDirectory,
const std::filesystem::path& inputPath,
const std::string& explicitUuid = {})
{
if (!explicitUuid.empty()) {
return explicitUuid;
}

std::string uuid = outputDirectory.filename().string();
if (uuid.empty()) {
uuid = inputPath.stem().string();
}
if (uuid.empty()) {
throw std::invalid_argument(
"cannot derive TIFXYZ UUID from an empty output directory and input path");
}
return uuid;
}

} // namespace vc::util
2 changes: 2 additions & 0 deletions volume-cartographer/core/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ endfunction()

vc_add_test(NAME test_smoke LIBS doctest::doctest)

vc_add_test(NAME test_tifxyz_identity)

vc_add_test(NAME test_appendmask_render)

vc_add_test(NAME test_chunked_plane_sampler_fallback)
Expand Down
31 changes: 31 additions & 0 deletions volume-cartographer/core/test/test_tifxyz_identity.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>

#include "vc/core/util/TifxyzIdentity.hpp"

TEST_CASE("explicit TIFXYZ UUID overrides a generic output directory")
{
CHECK(vc::util::resolveTifxyzUuid(
"/tmp/output_tifxyz", "/tmp/mesh.obj", "PHerc1447-segment") ==
"PHerc1447-segment");
}

TEST_CASE("TIFXYZ UUID keeps the historical output-directory default")
{
CHECK(vc::util::resolveTifxyzUuid(
"/tmp/output_tifxyz", "/tmp/mesh.obj") == "output_tifxyz");
}

TEST_CASE("TIFXYZ UUID falls back to the input stem for a trailing output path")
{
CHECK(vc::util::resolveTifxyzUuid(
std::filesystem::path("/tmp/output/"), "/tmp/source-mesh.obj") ==
"source-mesh");
}

TEST_CASE("TIFXYZ UUID rejects completely empty identity inputs")
{
CHECK_THROWS_AS(
vc::util::resolveTifxyzUuid(std::filesystem::path{}, std::filesystem::path{}),
std::invalid_argument);
}
Loading