Skip to content

Export tools now accept "--frame enu" to generate XYZ data in ENU frame#43

Merged
jlblancoc merged 1 commit intodevelopfrom
feat/export-enu-frame
Feb 23, 2026
Merged

Export tools now accept "--frame enu" to generate XYZ data in ENU frame#43
jlblancoc merged 1 commit intodevelopfrom
feat/export-enu-frame

Conversation

@jlblancoc
Copy link
Copy Markdown
Member

@jlblancoc jlblancoc commented Feb 22, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added --frame command-line option to mm2las, mm2ply, and mm2txt applications, allowing users to export point clouds in either map or ENU (East-North-Up) coordinate frames.
    • ENU frame export requires georeferencing data in the input map; validation and error messages guide users when data is missing.
  • Documentation

    • Updated documentation for all three export applications with new --frame option specifications, usage examples, and coordinate frame transformation details.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 22, 2026

📝 Walkthrough

Walkthrough

Three point cloud export utilities (mm2las, mm2ply, mm2txt) gain a new --frame CLI option to export points in either the map frame (default) or ENU (East-North-Up) frame. On-the-fly coordinate transformation applies when ENU is selected, using georeferencing data from the input map. Export function signatures are updated to accept an optional transformation parameter, and documentation is revised accordingly.

Changes

Cohort / File(s) Summary
LAS Export with Frame Support
apps/mm2las/main.cpp
Added --frame CLI option with validation; extended saveToLas signature to accept optional T_enu_to_map parameter; implements coordinate transformation during point export when ENU frame is requested.
PLY Export with Frame Support
apps/mm2ply/main.cpp
Added --frame CLI option with validation; extended saveToPly signature to accept optional T_enu_to_map parameter; applies transformed coordinates (tx/ty/tz) when ENU mode is active for both header and per-field output.
TXT Export with Frame Support
apps/mm2txt/main.cpp
Added --frame CLI option with validation; extended saveToTxt signature to accept optional T_enu_to_map parameter; transforms and uses ENU coordinates for x/y/z fields when transformation is present.
Export Tool Documentation
docs/source/app_mm2las.rst, docs/source/app_mm2ply.rst, docs/source/app_mm2txt.rst
Added --frame option documentation, usage examples, and new Coordinate Frames sections describing map frame default and ENU transformation behavior with georeferencing requirements.

Sequence Diagram

sequenceDiagram
    participant User
    participant Tool as Export Tool
    participant Map as Input Map
    participant Transform as Transform Engine
    participant Output as Output File

    User->>Tool: Execute with --frame enu
    Tool->>Tool: Parse and validate --frame argument
    Tool->>Map: Load map and retrieve georeferencing data
    alt Georeferencing exists
        Map-->>Tool: Return georeferencing data
        Tool->>Transform: Construct T_enu_to_map from georeferencing
        Transform-->>Tool: Transformation ready
        loop For each point
            Tool->>Transform: Apply T_enu_to_map to point coordinates
            Transform-->>Tool: Return transformed (tx, ty, tz)
            Tool->>Output: Write transformed coordinates
        end
        Output-->>User: Export complete in ENU frame
    else Missing georeferencing
        Map-->>Tool: No georeferencing data
        Tool-->>User: Error: ENU frame requires georeferencing
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 From map to ENU, the coordinates dance,
Three tools in harmony take their stance,
Georeferencing guides the transformation true,
East-North-Up frame, a perspective anew! 🗺️

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: adding --frame enu support to export tools for generating XYZ data in ENU coordinate frame, which aligns with changes across all three export tools (mm2las, mm2ply, mm2txt) and documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/export-enu-frame

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/mm2txt/main.cpp (1)

407-436: ⚠️ Potential issue | 🟠 Major

--frame enu is silently ignored for legacy point cloud types.

When the layer contains a legacy type (CPointsMapXYZIRT, CPointsMapXYZI, or a plain CPointsMap in the else branch), the code falls through to native save methods (saveXYZIRT_to_text_file, saveXYZI_to_text_file, save3D_to_text_file) which don't accept a transformation parameter. If the user requests --frame enu, coordinates are exported in the map frame with no warning.

At minimum, emit a warning when T_enu_to_map.has_value() and the legacy path is taken. Ideally, error out since the user's request can't be honored.

Suggested fix
         else
         {
+            if (T_enu_to_map.has_value())
+            {
+                std::cerr << "Warning: --frame enu is not supported for legacy point map type '"
+                          << pts->GetRuntimeClass()->className
+                          << "' in layer '" << name << "'. Exporting in map frame.\n";
+            }
 `#pragma` GCC diagnostic push
 `#pragma` GCC diagnostic ignored "-Wdeprecated-declarations"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mm2txt/main.cpp` around lines 407 - 436, The legacy branch that calls
CPointsMapXYZIRT::saveXYZIRT_to_text_file, CPointsMapXYZI::saveXYZI_to_text_file
or pts->save3D_to_text_file ignores a requested ENU transform; update the else
branch so that if T_enu_to_map.has_value() is true you emit a clear warning (or
better: return an error/exit non‑zero) before calling the legacy save methods,
e.g. detect T_enu_to_map.has_value() at the start of the legacy-handling block
and then either call processLogger.warn(...) or print an error and exit,
referencing the legacy classes CPointsMapXYZIRT, CPointsMapXYZI and the
pts->save3D_to_text_file call so the user knows the ENU frame request cannot be
honored.
🧹 Nitpick comments (1)
apps/mm2ply/main.cpp (1)

343-350: Transformed ENU coordinates are truncated to float for PLY output.

The transformed coordinates are computed as double but cast to float on Line 347 before writing. The PLY header declares x/y/z as float (consistent with the non-ENU path), so this is format-correct. However, if ENU coordinates are large (e.g., hundreds of km), float precision (~7 significant digits) may introduce cm-level quantization. This may be acceptable given the PLY format constraint, but worth noting for users of the --frame enu feature.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mm2ply/main.cpp` around lines 343 - 350, The code casts ENU-transformed
coordinates (tx/ty/tz) to float before writing (in the block checking
T_enu_to_map and acc.name), which loses precision for large ENU values; to fix,
keep tx/ty/tz as double when writing and update the PLY header generation to
declare x/y/z as double when the ENU frame is used (so the PLY types match), and
call write_val with a double format (e.g., "%.16e") without static_cast<float>,
adjusting any downstream writers that rely on float-sized values; reference
symbols: T_enu_to_map, tx, ty, tz, acc.name, write_val and the PLY header
generation logic that emits x/y/z types.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/mm2las/main.cpp`:
- Around line 601-611: The code applies T_enu_to_map->composePoint(...) to
points that are already in the metric map frame, which is backwards; replace the
call to composePoint(...) with inverseComposePoint(...) so the transform
converts map->ENU (i.e. call T_enu_to_map->inverseComposePoint(xs[i], ys[i],
zs[i], px, py, pz) or the equivalent overload used elsewhere), and make the same
replacement for the identical usages in the other tools (mm2txt and mm2ply).
Ensure you update every occurrence where composePoint is used on xs/ys/zs ->
px/py/pz guarded by T_enu_to_map.has_value().

In `@apps/mm2ply/main.cpp`:
- Around line 307-312: The transform is applied in the wrong direction: when
converting points from ENU to map you must call inverseComposePoint, not
composePoint. In the block using T_enu_to_map (the code that currently calls
T_enu_to_map->composePoint(xs[i], ys[i], zs[i], tx, ty, tz)), replace that call
with T_enu_to_map->inverseComposePoint(xs[i], ys[i], zs[i], tx, ty, tz) so the
ENU coordinates (xs, ys, zs) are correctly transformed into map coordinates (tx,
ty, tz).

In `@apps/mm2txt/main.cpp`:
- Around line 152-157: The ENU->map on-the-fly transform is using
T_enu_to_map->composePoint but likely needs the inverse direction (use
inverseComposePoint) as in the mm2las fix; change the call in the loop that
currently invokes T_enu_to_map->composePoint(xs.at(i), ys.at(i), zs.at(i), tx,
ty, tz) to call T_enu_to_map->inverseComposePoint(...) so the input ENU
coordinates (xs.at(i), ys.at(i), zs.at(i)) are correctly mapped to tx, ty, tz,
and keep the same tx/ty/tz output variables and logic.

---

Outside diff comments:
In `@apps/mm2txt/main.cpp`:
- Around line 407-436: The legacy branch that calls
CPointsMapXYZIRT::saveXYZIRT_to_text_file, CPointsMapXYZI::saveXYZI_to_text_file
or pts->save3D_to_text_file ignores a requested ENU transform; update the else
branch so that if T_enu_to_map.has_value() is true you emit a clear warning (or
better: return an error/exit non‑zero) before calling the legacy save methods,
e.g. detect T_enu_to_map.has_value() at the start of the legacy-handling block
and then either call processLogger.warn(...) or print an error and exit,
referencing the legacy classes CPointsMapXYZIRT, CPointsMapXYZI and the
pts->save3D_to_text_file call so the user knows the ENU frame request cannot be
honored.

---

Nitpick comments:
In `@apps/mm2ply/main.cpp`:
- Around line 343-350: The code casts ENU-transformed coordinates (tx/ty/tz) to
float before writing (in the block checking T_enu_to_map and acc.name), which
loses precision for large ENU values; to fix, keep tx/ty/tz as double when
writing and update the PLY header generation to declare x/y/z as double when the
ENU frame is used (so the PLY types match), and call write_val with a double
format (e.g., "%.16e") without static_cast<float>, adjusting any downstream
writers that rely on float-sized values; reference symbols: T_enu_to_map, tx,
ty, tz, acc.name, write_val and the PLY header generation logic that emits x/y/z
types.

Comment thread apps/mm2las/main.cpp
Comment thread apps/mm2ply/main.cpp
Comment thread apps/mm2txt/main.cpp
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.49%. Comparing base (f1e9014) to head (d87959f).
⚠️ Report is 2 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           develop      #43   +/-   ##
========================================
  Coverage    77.49%   77.49%           
========================================
  Files          185      185           
  Lines         9883     9883           
  Branches       934      934           
========================================
  Hits          7659     7659           
  Misses        2224     2224           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jlblancoc jlblancoc merged commit ee94748 into develop Feb 23, 2026
15 checks passed
@jlblancoc jlblancoc deleted the feat/export-enu-frame branch February 23, 2026 00:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant