mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Style
This commit is contained in:
@@ -34,7 +34,7 @@ Stack
|
||||
primitives used in instrumentation.
|
||||
* **IfcOpenShell C++ libs** (IfcParse / IfcGeom) for IFC parsing and
|
||||
geometry generation, plus **helpers** for the schema-agnostic
|
||||
helpers (``Unit``, ``Geolocation``, ``Placement``).
|
||||
helpers (``unit``, ``geolocation``, ``placement``).
|
||||
* **Eigen3** for 4×4 matrices and small linear algebra.
|
||||
* **meshoptimizer** at sidecar-build time only — decimates each
|
||||
unique mesh into an LOD1 slice. Not pulled at runtime.
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
|
||||
#include "../../SessionState.h"
|
||||
#include "../../../ifcviewer/Federation.h"
|
||||
#include "../../../ifcutil/Geolocation.h"
|
||||
#include "../../../helpers/geolocation.h"
|
||||
#include "../../../ifcviewer/SceneLoader.h"
|
||||
#include "../../../ifcutil/Unit.h"
|
||||
#include "../../../helpers/unit.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@@ -89,8 +89,8 @@ QString formatNamedUnit(const express::Base& unit) {
|
||||
text += QString::fromStdString(prefix) + " ";
|
||||
}
|
||||
text += QString::fromStdString(name);
|
||||
auto symbol_it = kUnitSymbols.find(name);
|
||||
if (symbol_it != kUnitSymbols.end()) {
|
||||
auto symbol_it = UNIT_SYMBOLS.find(name);
|
||||
if (symbol_it != UNIT_SYMBOLS.end()) {
|
||||
text += " (" + QString::fromStdString(symbol_it->second) + ")";
|
||||
}
|
||||
return text;
|
||||
@@ -100,8 +100,8 @@ QString formatNamedUnit(const express::Base& unit) {
|
||||
if (name_attr.isNull()) return "—";
|
||||
const std::string name = static_cast<std::string>(name_attr);
|
||||
QString text = QString::fromStdString(name);
|
||||
auto symbol_it = kUnitSymbols.find(name);
|
||||
if (symbol_it != kUnitSymbols.end()) {
|
||||
auto symbol_it = UNIT_SYMBOLS.find(name);
|
||||
if (symbol_it != UNIT_SYMBOLS.end()) {
|
||||
text += " (" + QString::fromStdString(symbol_it->second) + ")";
|
||||
}
|
||||
return text;
|
||||
@@ -119,7 +119,7 @@ std::optional<QString> coordinateOperationType(ifcopenshell::file* ifc_file) {
|
||||
}
|
||||
|
||||
if (ifc_file->schema()->name() == "IFC2X3") {
|
||||
if (getHelmertTransformationParameters(ifc_file)) {
|
||||
if (get_helmert_transformation_parameters(ifc_file)) {
|
||||
return QStringLiteral("ePSet_MapConversion");
|
||||
}
|
||||
}
|
||||
@@ -129,10 +129,10 @@ std::optional<QString> coordinateOperationType(ifcopenshell::file* ifc_file) {
|
||||
SelectedModelGeorefState stateFromLiveFile(ifcopenshell::file* ifc_file) {
|
||||
if (!ifc_file) return unknownState("Not available yet", "No data source");
|
||||
|
||||
const auto params = getHelmertTransformationParameters(ifc_file);
|
||||
const auto params = get_helmert_transformation_parameters(ifc_file);
|
||||
const auto coordop_type = coordinateOperationType(ifc_file);
|
||||
const auto project_unit_value = getProjectUnit(ifc_file, "LENGTHUNIT");
|
||||
const auto map_unit_value = getMapUnit(ifc_file);
|
||||
const auto project_unit_value = get_project_unit(ifc_file, "LENGTHUNIT");
|
||||
const auto map_unit_value = get_map_unit(ifc_file);
|
||||
const QString project_unit = project_unit_value ? formatNamedUnit(*project_unit_value) : QString("—");
|
||||
const QString map_unit = map_unit_value ? formatNamedUnit(*map_unit_value) : project_unit;
|
||||
|
||||
@@ -143,7 +143,7 @@ SelectedModelGeorefState stateFromLiveFile(ifcopenshell::file* ifc_file) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const double rotation_dd = xaxis2angleDeg(params->xaa, params->xao);
|
||||
const double rotation_dd = x_axis_to_angle_deg(params->xaa, params->xao);
|
||||
return {
|
||||
"Yes",
|
||||
coordop_type.value_or("Unknown"),
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
message("Running CMakeLists.txt in /src/ifcutil")
|
||||
message("Running CMakeLists.txt in /src/helpers")
|
||||
|
||||
# Schema-agnostic IFC helpers ported from ifcopenshell.util.*. Pure
|
||||
# IfcParse + Eigen, no Qt, no IfcGeom, no viewer/renderer deps — so unit
|
||||
@@ -44,8 +44,8 @@ set_target_properties(helpers PROPERTIES
|
||||
)
|
||||
|
||||
# PUBLIC: callers (IfcViewer, test_federation, future tools) get
|
||||
# `#include "Unit.h"` etc. via this directory automatically, no
|
||||
# `#include "../helpers/Unit.h"` ugliness at call sites.
|
||||
# `#include "unit.h"` etc. via this directory automatically, no
|
||||
# `#include "../helpers/unit.h"` ugliness at call sites.
|
||||
target_include_directories(helpers PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(helpers PUBLIC
|
||||
|
||||
+21
-21
@@ -17,8 +17,8 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "Geolocation.h"
|
||||
#include "Placement.h"
|
||||
#include "geolocation.h"
|
||||
#include "placement.h"
|
||||
|
||||
#include "../ifcparse/express.h"
|
||||
#include "../ifcparse/file.h"
|
||||
@@ -35,7 +35,7 @@ namespace {
|
||||
// ePSet_MapConversion stores eastings/northings/scale as IfcLengthMeasure or
|
||||
// IfcReal wrapped inside IfcValue (a SELECT) — get_attribute_value(0) peels
|
||||
// the wrapper. Returns nullopt if the value is missing or non-numeric.
|
||||
std::optional<double> readPropertyValueDouble(const express::Base& property) {
|
||||
std::optional<double> read_property_value_double(const express::Base& property) {
|
||||
if (!property.declaration().is("IfcPropertySingleValue")) return std::nullopt;
|
||||
auto pe = property.as<express::Entity>();
|
||||
auto nv = pe.get("NominalValue");
|
||||
@@ -53,7 +53,7 @@ std::optional<double> readPropertyValueDouble(const express::Base& property) {
|
||||
} // namespace
|
||||
|
||||
std::optional<HelmertTransformation>
|
||||
getHelmertTransformationParameters(ifcopenshell::file* ifc_file) {
|
||||
get_helmert_transformation_parameters(ifcopenshell::file* ifc_file) {
|
||||
HelmertTransformation p;
|
||||
const std::string schema_name = ifc_file->schema()->name();
|
||||
|
||||
@@ -81,7 +81,7 @@ getHelmertTransformationParameters(ifcopenshell::file* ifc_file) {
|
||||
auto pname_attr = pe.get("Name");
|
||||
if (pname_attr.isNull()) continue;
|
||||
std::string pname = pname_attr;
|
||||
auto value = readPropertyValueDouble(prop);
|
||||
auto value = read_property_value_double(prop);
|
||||
if (!value) continue;
|
||||
if (pname == "Eastings") p.e = *value;
|
||||
else if (pname == "Northings") p.n = *value;
|
||||
@@ -153,7 +153,7 @@ getHelmertTransformationParameters(ifcopenshell::file* ifc_file) {
|
||||
return p;
|
||||
}
|
||||
|
||||
std::optional<Eigen::Matrix4d> getWcs(ifcopenshell::file* ifc_file) {
|
||||
std::optional<Eigen::Matrix4d> get_wcs(ifcopenshell::file* ifc_file) {
|
||||
auto contexts = ifc_file->instances_by_type_excl_subtypes(
|
||||
"IfcGeometricRepresentationContext");
|
||||
express::Base wcs;
|
||||
@@ -175,11 +175,11 @@ std::optional<Eigen::Matrix4d> getWcs(ifcopenshell::file* ifc_file) {
|
||||
if (!(decl.is("IfcAxis2Placement3D") || decl.is("IfcAxis2PlacementLinear"))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return getAxis2Placement(wcs);
|
||||
return get_axis2_placement(wcs);
|
||||
}
|
||||
|
||||
Eigen::Matrix4d local2global(const Eigen::Matrix4d& matrix,
|
||||
const HelmertTransformation& p) {
|
||||
Eigen::Matrix4d local_to_global(const Eigen::Matrix4d& matrix,
|
||||
const HelmertTransformation& p) {
|
||||
const double theta = std::atan2(p.xao, p.xaa);
|
||||
const double c = std::cos(theta);
|
||||
const double s = std::sin(theta);
|
||||
@@ -208,17 +208,17 @@ Eigen::Matrix4d local2global(const Eigen::Matrix4d& matrix,
|
||||
return result;
|
||||
}
|
||||
|
||||
Eigen::Matrix4d autoLocal2Global(ifcopenshell::file* ifc_file,
|
||||
const Eigen::Matrix4d& matrix,
|
||||
bool should_return_in_map_units) {
|
||||
auto params = getHelmertTransformationParameters(ifc_file);
|
||||
Eigen::Matrix4d auto_local_to_global(ifcopenshell::file* ifc_file,
|
||||
const Eigen::Matrix4d& matrix,
|
||||
bool should_return_in_map_units) {
|
||||
auto params = get_helmert_transformation_parameters(ifc_file);
|
||||
if (!params) return matrix;
|
||||
|
||||
Eigen::Matrix4d m = matrix;
|
||||
if (auto wcs = getWcs(ifc_file)) {
|
||||
if (auto wcs = get_wcs(ifc_file)) {
|
||||
m = wcs->inverse() * m;
|
||||
}
|
||||
Eigen::Matrix4d result = local2global(m, *params);
|
||||
Eigen::Matrix4d result = local_to_global(m, *params);
|
||||
if (!should_return_in_map_units) {
|
||||
result(0, 3) /= params->scale;
|
||||
result(1, 3) /= params->scale;
|
||||
@@ -227,8 +227,8 @@ Eigen::Matrix4d autoLocal2Global(ifcopenshell::file* ifc_file,
|
||||
return result;
|
||||
}
|
||||
|
||||
Eigen::Matrix4d helmertMetersFromParameters(const HelmertTransformation& p,
|
||||
double map_unit_to_meters) {
|
||||
Eigen::Matrix4d helmert_meters_from_parameters(const HelmertTransformation& p,
|
||||
double map_unit_to_meters) {
|
||||
const double theta = std::atan2(p.xao, p.xaa);
|
||||
const double c = std::cos(theta);
|
||||
const double s = std::sin(theta);
|
||||
@@ -247,7 +247,7 @@ Eigen::Matrix4d helmertMetersFromParameters(const HelmertTransformation& p,
|
||||
return M;
|
||||
}
|
||||
|
||||
std::optional<express::Base> getMapUnit(ifcopenshell::file* ifc_file) {
|
||||
std::optional<express::Base> get_map_unit(ifcopenshell::file* ifc_file) {
|
||||
std::vector<express::Base> coordops;
|
||||
try {
|
||||
coordops = ifc_file->instances_by_type("IfcCoordinateOperation");
|
||||
@@ -264,7 +264,7 @@ std::optional<express::Base> getMapUnit(ifcopenshell::file* ifc_file) {
|
||||
return (express::Base) mu_attr;
|
||||
}
|
||||
|
||||
double xaxis2angleDeg(double xaa, double xao) {
|
||||
constexpr double kPi = 3.14159265358979323846;
|
||||
return -std::atan2(xao, xaa) * (180.0 / kPi);
|
||||
double x_axis_to_angle_deg(double xaa, double xao) {
|
||||
constexpr double PI = 3.14159265358979323846;
|
||||
return -std::atan2(xao, xaa) * (180.0 / PI);
|
||||
}
|
||||
|
||||
+16
-16
@@ -19,7 +19,7 @@
|
||||
|
||||
// Port of selected helpers from
|
||||
// src/ifcopenshell-python/ifcopenshell/util/geolocation.py — primarily
|
||||
// auto_local2global, which builds a 4x4 matrix that lifts an element's local
|
||||
// auto_local_to_global, which builds a 4x4 matrix that lifts an element's local
|
||||
// transform into the model's global (georeferenced) frame. The python utils
|
||||
// are expected to be ported to C++ in their own module later; this file is
|
||||
// the temporary home until that lands.
|
||||
@@ -52,28 +52,28 @@ struct HelmertTransformation {
|
||||
// IfcProject.ePSet_MapConversion property set in IFC2X3. Returns nullopt
|
||||
// when the model has no map conversion.
|
||||
std::optional<HelmertTransformation>
|
||||
getHelmertTransformationParameters(ifcopenshell::file* ifc_file);
|
||||
get_helmert_transformation_parameters(ifcopenshell::file* ifc_file);
|
||||
|
||||
// Read the IfcGeometricRepresentationContext.WorldCoordinateSystem (preferring
|
||||
// the "Model" context) as a 4x4 matrix. Returns nullopt when the model has
|
||||
// no parseable WCS.
|
||||
std::optional<Eigen::Matrix4d> getWcs(ifcopenshell::file* ifc_file);
|
||||
std::optional<Eigen::Matrix4d> get_wcs(ifcopenshell::file* ifc_file);
|
||||
|
||||
// Apply a Helmert transformation to a 4x4 local matrix.
|
||||
Eigen::Matrix4d local2global(const Eigen::Matrix4d& matrix,
|
||||
const HelmertTransformation& params);
|
||||
Eigen::Matrix4d local_to_global(const Eigen::Matrix4d& matrix,
|
||||
const HelmertTransformation& params);
|
||||
|
||||
// Lift a 4x4 local matrix into global (map) coordinates using the IFC model's
|
||||
// georeferencing data. When no map conversion is present the matrix is
|
||||
// returned unchanged. When should_return_in_map_units is false, the
|
||||
// translation column is divided by the map scale so the result is expressed
|
||||
// in project length units.
|
||||
Eigen::Matrix4d autoLocal2Global(ifcopenshell::file* ifc_file,
|
||||
const Eigen::Matrix4d& matrix,
|
||||
bool should_return_in_map_units = true);
|
||||
Eigen::Matrix4d auto_local_to_global(ifcopenshell::file* ifc_file,
|
||||
const Eigen::Matrix4d& matrix,
|
||||
bool should_return_in_map_units = true);
|
||||
|
||||
// Build the Helmert transformation as a meter-input / meter-output 4x4 matrix
|
||||
// directly from parsed parameters, bypassing autoLocal2Global's normalisation
|
||||
// directly from parsed parameters, bypassing auto_local_to_global's normalisation
|
||||
// step. Used by callers that want a single per-model georef matrix to compose
|
||||
// with placement matrices at upload time.
|
||||
//
|
||||
@@ -86,26 +86,26 @@ Eigen::Matrix4d autoLocal2Global(ifcopenshell::file* ifc_file,
|
||||
// meter inputs from the geometry iterator, Scale is represented by that unit
|
||||
// conversion and is not applied again in the linear block. The caller composes
|
||||
// any IfcGeometricRepresentationContext WCS on the right:
|
||||
// G = helmertMetersFromParameters(...) · inv(wcs_meters)
|
||||
// G = helmert_meters_from_parameters(...) · inv(wcs_meters)
|
||||
// (where wcs_meters has its translation column converted from project units
|
||||
// to meters via calculateUnitScale).
|
||||
// to meters via calculate_unit_scale).
|
||||
//
|
||||
// Unlike autoLocal2Global, this preserves IfcMapConversionScaled.FactorX/Y/Z
|
||||
// Unlike auto_local_to_global, this preserves IfcMapConversionScaled.FactorX/Y/Z
|
||||
// in the rotation block, so they apply correctly to placement translations
|
||||
// when composing per-model.
|
||||
Eigen::Matrix4d helmertMetersFromParameters(const HelmertTransformation& params,
|
||||
double map_unit_to_meters);
|
||||
Eigen::Matrix4d helmert_meters_from_parameters(const HelmertTransformation& params,
|
||||
double map_unit_to_meters);
|
||||
|
||||
// IfcCoordinateOperation.TargetCRS.MapUnit (the IfcNamedUnit), if present.
|
||||
// Returns nullopt for IFC2X3, models without an IfcCoordinateOperation, or
|
||||
// when MapUnit is absent on the IfcProjectedCRS. This is retained for UI /
|
||||
// metadata inspection; transform composition derives map unit scale from
|
||||
// IfcMapConversion.Scale instead.
|
||||
std::optional<express::Base> getMapUnit(ifcopenshell::file* ifc_file);
|
||||
std::optional<express::Base> get_map_unit(ifcopenshell::file* ifc_file);
|
||||
|
||||
// "How do I rotate project east to get to grid east?" — i.e. -atan2(xao, xaa)
|
||||
// converted to degrees, anticlockwise positive. Mirrors
|
||||
// ifcopenshell.util.geolocation.xaxis2angle.
|
||||
double xaxis2angleDeg(double xaa, double xao);
|
||||
double x_axis_to_angle_deg(double xaa, double xao);
|
||||
|
||||
#endif // GEOLOCATION_H
|
||||
|
||||
+20
-20
@@ -17,7 +17,7 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "Placement.h"
|
||||
#include "placement.h"
|
||||
|
||||
#include "../ifcparse/instance_data.h"
|
||||
#include "../ifcparse/schema.h"
|
||||
@@ -26,13 +26,13 @@
|
||||
|
||||
namespace {
|
||||
|
||||
Eigen::Vector3d safeNormalize(const Eigen::Vector3d& v,
|
||||
const Eigen::Vector3d& fallback) {
|
||||
Eigen::Vector3d safe_normalize(const Eigen::Vector3d& v,
|
||||
const Eigen::Vector3d& fallback) {
|
||||
const double n = v.norm();
|
||||
return (n > 0.0) ? Eigen::Vector3d(v / n) : fallback;
|
||||
}
|
||||
|
||||
std::vector<double> readDirectionRatios(const express::Base& dir) {
|
||||
std::vector<double> read_direction_ratios(const express::Base& dir) {
|
||||
if (!dir) return {};
|
||||
auto attr = dir.as<express::Entity>().get("DirectionRatios");
|
||||
if (attr.isNull()) return {};
|
||||
@@ -41,12 +41,12 @@ std::vector<double> readDirectionRatios(const express::Base& dir) {
|
||||
|
||||
} // namespace
|
||||
|
||||
Eigen::Matrix4d a2p(const Eigen::Vector3d& origin,
|
||||
const Eigen::Vector3d& z,
|
||||
const Eigen::Vector3d& x) {
|
||||
const Eigen::Vector3d xn = safeNormalize(x, Eigen::Vector3d::UnitX());
|
||||
const Eigen::Vector3d zn = safeNormalize(z, Eigen::Vector3d::UnitZ());
|
||||
const Eigen::Vector3d yn = safeNormalize(zn.cross(xn), Eigen::Vector3d::UnitY());
|
||||
Eigen::Matrix4d axes_to_placement(const Eigen::Vector3d& origin,
|
||||
const Eigen::Vector3d& z,
|
||||
const Eigen::Vector3d& x) {
|
||||
const Eigen::Vector3d xn = safe_normalize(x, Eigen::Vector3d::UnitX());
|
||||
const Eigen::Vector3d zn = safe_normalize(z, Eigen::Vector3d::UnitZ());
|
||||
const Eigen::Vector3d yn = safe_normalize(zn.cross(xn), Eigen::Vector3d::UnitY());
|
||||
|
||||
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
|
||||
m.block<3, 1>(0, 0) = xn;
|
||||
@@ -56,7 +56,7 @@ Eigen::Matrix4d a2p(const Eigen::Vector3d& origin,
|
||||
return m;
|
||||
}
|
||||
|
||||
Eigen::Matrix4d getAxis2Placement(const express::Base& placement) {
|
||||
Eigen::Matrix4d get_axis2_placement(const express::Base& placement) {
|
||||
if (!placement) return Eigen::Matrix4d::Identity();
|
||||
const auto& decl = placement.declaration();
|
||||
auto entity = placement.as<express::Entity>();
|
||||
@@ -68,12 +68,12 @@ Eigen::Matrix4d getAxis2Placement(const express::Base& placement) {
|
||||
if (decl.is("IfcAxis2Placement3D") || decl.is("IfcAxis2PlacementLinear")) {
|
||||
auto axis_attr = entity.get("Axis");
|
||||
if (!axis_attr.isNull()) {
|
||||
auto dr = readDirectionRatios((express::Base) axis_attr);
|
||||
auto dr = read_direction_ratios((express::Base) axis_attr);
|
||||
if (dr.size() >= 3) z = Eigen::Vector3d(dr[0], dr[1], dr[2]);
|
||||
}
|
||||
auto refdir_attr = entity.get("RefDirection");
|
||||
if (!refdir_attr.isNull()) {
|
||||
auto dr = readDirectionRatios((express::Base) refdir_attr);
|
||||
auto dr = read_direction_ratios((express::Base) refdir_attr);
|
||||
if (dr.size() >= 3) x = Eigen::Vector3d(dr[0], dr[1], dr[2]);
|
||||
}
|
||||
auto loc_attr = entity.get("Location");
|
||||
@@ -86,7 +86,7 @@ Eigen::Matrix4d getAxis2Placement(const express::Base& placement) {
|
||||
} else if (decl.is("IfcAxis2Placement2D")) {
|
||||
auto refdir_attr = entity.get("RefDirection");
|
||||
if (!refdir_attr.isNull()) {
|
||||
auto dr = readDirectionRatios((express::Base) refdir_attr);
|
||||
auto dr = read_direction_ratios((express::Base) refdir_attr);
|
||||
if (dr.size() >= 1) {
|
||||
x = Eigen::Vector3d(dr.size() > 0 ? dr[0] : 1.0,
|
||||
dr.size() > 1 ? dr[1] : 0.0,
|
||||
@@ -106,7 +106,7 @@ Eigen::Matrix4d getAxis2Placement(const express::Base& placement) {
|
||||
} else if (decl.is("IfcAxis1Placement")) {
|
||||
auto axis_attr = entity.get("Axis");
|
||||
if (!axis_attr.isNull()) {
|
||||
auto dr = readDirectionRatios((express::Base) axis_attr);
|
||||
auto dr = read_direction_ratios((express::Base) axis_attr);
|
||||
if (dr.size() >= 3) z = Eigen::Vector3d(dr[0], dr[1], dr[2]);
|
||||
}
|
||||
auto loc_attr = entity.get("Location");
|
||||
@@ -120,10 +120,10 @@ Eigen::Matrix4d getAxis2Placement(const express::Base& placement) {
|
||||
return Eigen::Matrix4d::Identity();
|
||||
}
|
||||
|
||||
return a2p(o, z, x);
|
||||
return axes_to_placement(o, z, x);
|
||||
}
|
||||
|
||||
Eigen::Matrix4d getLocalPlacement(const express::Base& placement) {
|
||||
Eigen::Matrix4d get_local_placement(const express::Base& placement) {
|
||||
if (!placement) return Eigen::Matrix4d::Identity();
|
||||
const auto& decl = placement.declaration();
|
||||
|
||||
@@ -132,13 +132,13 @@ Eigen::Matrix4d getLocalPlacement(const express::Base& placement) {
|
||||
Eigen::Matrix4d parent = Eigen::Matrix4d::Identity();
|
||||
auto rel_attr = entity.get("PlacementRelTo");
|
||||
if (!rel_attr.isNull()) {
|
||||
parent = getLocalPlacement((express::Base) rel_attr);
|
||||
parent = get_local_placement((express::Base) rel_attr);
|
||||
}
|
||||
auto rp_attr = entity.get("RelativePlacement");
|
||||
if (rp_attr.isNull()) return parent;
|
||||
return parent * getAxis2Placement((express::Base) rp_attr);
|
||||
return parent * get_axis2_placement((express::Base) rp_attr);
|
||||
}
|
||||
|
||||
// IfcAxis2Placement* / IfcAxis1Placement passed in directly.
|
||||
return getAxis2Placement(placement);
|
||||
return get_axis2_placement(placement);
|
||||
}
|
||||
|
||||
@@ -32,19 +32,19 @@
|
||||
// Build a 4x4 placement matrix from an origin + Z + X axis triple, mirroring
|
||||
// ifcopenshell.util.placement.a2p. The Y axis is derived as Z × X. Inputs
|
||||
// don't need to be unit; vectors are renormalised internally.
|
||||
Eigen::Matrix4d a2p(const Eigen::Vector3d& origin,
|
||||
const Eigen::Vector3d& z,
|
||||
const Eigen::Vector3d& x);
|
||||
Eigen::Matrix4d axes_to_placement(const Eigen::Vector3d& origin,
|
||||
const Eigen::Vector3d& z,
|
||||
const Eigen::Vector3d& x);
|
||||
|
||||
// IfcAxis2Placement{2D,3D,Linear} / IfcAxis1Placement -> 4x4 matrix. Mirrors
|
||||
// ifcopenshell.util.placement.get_axis2placement. Returns identity for null
|
||||
// or unparseable inputs. Translation is in the IFC's project length unit.
|
||||
Eigen::Matrix4d getAxis2Placement(const express::Base& placement);
|
||||
Eigen::Matrix4d get_axis2_placement(const express::Base& placement);
|
||||
|
||||
// Resolve an IfcLocalPlacement (or an IfcAxis2Placement* directly) into a
|
||||
// 4x4 matrix in the IFC project's length unit, walking the PlacementRelTo
|
||||
// chain. Mirrors ifcopenshell.util.placement.get_local_placement. Returns
|
||||
// identity for a null input.
|
||||
Eigen::Matrix4d getLocalPlacement(const express::Base& placement);
|
||||
Eigen::Matrix4d get_local_placement(const express::Base& placement);
|
||||
|
||||
#endif // PLACEMENT_H
|
||||
|
||||
+44
-44
@@ -17,7 +17,7 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "Unit.h"
|
||||
#include "unit.h"
|
||||
|
||||
#include "../ifcparse/file.h"
|
||||
#include "../ifcparse/instance_data.h"
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
const std::unordered_map<std::string, double> kSiPrefixes = {
|
||||
const std::unordered_map<std::string, double> SI_PREFIXES = {
|
||||
{ "EXA", 1e18 },
|
||||
{ "PETA", 1e15 },
|
||||
{ "TERA", 1e12 },
|
||||
@@ -45,7 +45,7 @@ const std::unordered_map<std::string, double> kSiPrefixes = {
|
||||
{ "ATTO", 1e-18 },
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string, std::string> kSiPrefixSymbols = {
|
||||
const std::unordered_map<std::string, std::string> SI_PREFIX_SYMBOLS = {
|
||||
{ "EXA", "E" },
|
||||
{ "PETA", "P" },
|
||||
{ "TERA", "T" },
|
||||
@@ -64,7 +64,7 @@ const std::unordered_map<std::string, std::string> kSiPrefixSymbols = {
|
||||
{ "ATTO", "a" },
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string, double> kSiConversions = {
|
||||
const std::unordered_map<std::string, double> SI_CONVERSIONS = {
|
||||
{ "thou", 0.0000254 },
|
||||
{ "inch", 0.0254 },
|
||||
{ "foot", 0.3048 },
|
||||
@@ -105,7 +105,7 @@ const std::unordered_map<std::string, double> kSiConversions = {
|
||||
{ "fahrenheit", 1.8 },
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string, std::string> kImperialTypes = {
|
||||
const std::unordered_map<std::string, std::string> IMPERIAL_TYPES = {
|
||||
{ "thou", "LENGTHUNIT" }, { "inch", "LENGTHUNIT" }, { "foot", "LENGTHUNIT" },
|
||||
{ "yard", "LENGTHUNIT" }, { "mile", "LENGTHUNIT" },
|
||||
{ "square thou", "AREAUNIT" }, { "square inch", "AREAUNIT" },
|
||||
@@ -127,7 +127,7 @@ const std::unordered_map<std::string, std::string> kImperialTypes = {
|
||||
{ "fahrenheit", "THERMODYNAMICTEMPERATUREUNIT" },
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string, std::string> kUnitSymbols = {
|
||||
const std::unordered_map<std::string, std::string> UNIT_SYMBOLS = {
|
||||
// SI base / derived
|
||||
{ "CUBIC_METRE", "m3" },
|
||||
{ "GRAM", "g" },
|
||||
@@ -162,7 +162,7 @@ const std::unordered_map<std::string, std::string> kUnitSymbols = {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string toLower(const std::string& s) {
|
||||
std::string to_lower(const std::string& s) {
|
||||
std::string r;
|
||||
r.resize(s.size());
|
||||
std::transform(s.begin(), s.end(), r.begin(),
|
||||
@@ -171,7 +171,7 @@ std::string toLower(const std::string& s) {
|
||||
}
|
||||
|
||||
// Pull an enumeration string off an attribute_value, or "" if null/invalid.
|
||||
std::string enumString(const attribute_value& av) {
|
||||
std::string enum_string(const attribute_value& av) {
|
||||
if (av.isNull()) return {};
|
||||
if (av.type() != ifcopenshell::Argument_ENUMERATION) return {};
|
||||
enumeration_reference er = av;
|
||||
@@ -180,13 +180,13 @@ std::string enumString(const attribute_value& av) {
|
||||
|
||||
} // namespace
|
||||
|
||||
double getPrefixMultiplier(const std::string& prefix) {
|
||||
double get_prefix_multiplier(const std::string& prefix) {
|
||||
if (prefix.empty()) return 1.0;
|
||||
auto it = kSiPrefixes.find(prefix);
|
||||
return (it == kSiPrefixes.end()) ? 1.0 : it->second;
|
||||
auto it = SI_PREFIXES.find(prefix);
|
||||
return (it == SI_PREFIXES.end()) ? 1.0 : it->second;
|
||||
}
|
||||
|
||||
std::optional<double> siScaleFromNamedUnit(express::Base unit) {
|
||||
std::optional<double> si_scale_from_named_unit(express::Base unit) {
|
||||
double scale = 1.0;
|
||||
while (unit && unit.declaration().is("IfcConversionBasedUnit")) {
|
||||
auto e = unit.as<express::Entity>();
|
||||
@@ -195,8 +195,8 @@ std::optional<double> siScaleFromNamedUnit(express::Base unit) {
|
||||
std::string name;
|
||||
auto name_attr = e.get("Name");
|
||||
if (!name_attr.isNull()) name = (std::string) name_attr;
|
||||
if (auto it = kSiConversions.find(toLower(name));
|
||||
it != kSiConversions.end()) {
|
||||
if (auto it = SI_CONVERSIONS.find(to_lower(name));
|
||||
it != SI_CONVERSIONS.end()) {
|
||||
return scale * it->second;
|
||||
}
|
||||
|
||||
@@ -217,15 +217,15 @@ std::optional<double> siScaleFromNamedUnit(express::Base unit) {
|
||||
|
||||
if (unit && unit.declaration().is("IfcSIUnit")) {
|
||||
auto e = unit.as<express::Entity>();
|
||||
const std::string prefix = enumString(e.get("Prefix"));
|
||||
const std::string name = enumString(e.get("Name"));
|
||||
double m = getPrefixMultiplier(prefix);
|
||||
const std::string prefix = enum_string(e.get("Prefix"));
|
||||
const std::string name = enum_string(e.get("Name"));
|
||||
double m = get_prefix_multiplier(prefix);
|
||||
// SQUARE_/CUBIC_-prefixed SI names: prefix multiplier squared/cubed.
|
||||
if (name.find("SQUARE") != std::string::npos) {
|
||||
m *= getPrefixMultiplier(prefix);
|
||||
m *= get_prefix_multiplier(prefix);
|
||||
} else if (name.find("CUBIC") != std::string::npos) {
|
||||
m *= getPrefixMultiplier(prefix);
|
||||
m *= getPrefixMultiplier(prefix);
|
||||
m *= get_prefix_multiplier(prefix);
|
||||
m *= get_prefix_multiplier(prefix);
|
||||
}
|
||||
return scale * m;
|
||||
}
|
||||
@@ -238,7 +238,7 @@ std::optional<double> siScaleFromNamedUnit(express::Base unit) {
|
||||
return scale;
|
||||
}
|
||||
|
||||
std::optional<express::Base> getUnitAssignment(ifcopenshell::file* ifc_file) {
|
||||
std::optional<express::Base> get_unit_assignment(ifcopenshell::file* ifc_file) {
|
||||
auto projects = ifc_file->instances_by_type("IfcProject");
|
||||
if (projects.empty()) return std::nullopt;
|
||||
auto ua_attr = projects[0].as<express::Entity>().get("UnitsInContext");
|
||||
@@ -246,9 +246,9 @@ std::optional<express::Base> getUnitAssignment(ifcopenshell::file* ifc_file) {
|
||||
return (express::Base) ua_attr;
|
||||
}
|
||||
|
||||
std::optional<express::Base> getProjectUnit(ifcopenshell::file* ifc_file,
|
||||
const std::string& unit_type) {
|
||||
auto ua = getUnitAssignment(ifc_file);
|
||||
std::optional<express::Base> get_project_unit(ifcopenshell::file* ifc_file,
|
||||
const std::string& unit_type) {
|
||||
auto ua = get_unit_assignment(ifc_file);
|
||||
if (!ua) return std::nullopt;
|
||||
auto units_attr = ua->as<express::Entity>().get("Units");
|
||||
if (units_attr.isNull()) return std::nullopt;
|
||||
@@ -260,60 +260,60 @@ std::optional<express::Base> getProjectUnit(ifcopenshell::file* ifc_file,
|
||||
continue;
|
||||
}
|
||||
auto ut = unit.as<express::Entity>().get("UnitType");
|
||||
if (enumString(ut) == unit_type) return unit;
|
||||
if (enum_string(ut) == unit_type) return unit;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
double calculateUnitScale(ifcopenshell::file* ifc_file,
|
||||
const std::string& unit_type) {
|
||||
auto unit = getProjectUnit(ifc_file, unit_type);
|
||||
double calculate_unit_scale(ifcopenshell::file* ifc_file,
|
||||
const std::string& unit_type) {
|
||||
auto unit = get_project_unit(ifc_file, unit_type);
|
||||
if (!unit) return 1.0;
|
||||
auto scale = siScaleFromNamedUnit(*unit);
|
||||
auto scale = si_scale_from_named_unit(*unit);
|
||||
return scale.value_or(1.0);
|
||||
}
|
||||
|
||||
double convert(double value,
|
||||
const std::string& from_prefix, const std::string& from_unit,
|
||||
const std::string& to_prefix, const std::string& to_unit) {
|
||||
const std::string fl = toLower(from_unit);
|
||||
const std::string tl = toLower(to_unit);
|
||||
const std::string fl = to_lower(from_unit);
|
||||
const std::string tl = to_lower(to_unit);
|
||||
|
||||
if (auto it = kSiConversions.find(fl); it != kSiConversions.end()) {
|
||||
if (auto it = SI_CONVERSIONS.find(fl); it != SI_CONVERSIONS.end()) {
|
||||
value *= it->second;
|
||||
} else if (!from_prefix.empty()) {
|
||||
value *= getPrefixMultiplier(from_prefix);
|
||||
value *= get_prefix_multiplier(from_prefix);
|
||||
if (from_unit.find("SQUARE") != std::string::npos) {
|
||||
value *= getPrefixMultiplier(from_prefix);
|
||||
value *= get_prefix_multiplier(from_prefix);
|
||||
} else if (from_unit.find("CUBIC") != std::string::npos) {
|
||||
value *= getPrefixMultiplier(from_prefix);
|
||||
value *= getPrefixMultiplier(from_prefix);
|
||||
value *= get_prefix_multiplier(from_prefix);
|
||||
value *= get_prefix_multiplier(from_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto it = kSiConversions.find(tl); it != kSiConversions.end()) {
|
||||
if (auto it = SI_CONVERSIONS.find(tl); it != SI_CONVERSIONS.end()) {
|
||||
return value * (1.0 / it->second);
|
||||
} else if (!to_prefix.empty()) {
|
||||
value *= 1.0 / getPrefixMultiplier(to_prefix);
|
||||
value *= 1.0 / get_prefix_multiplier(to_prefix);
|
||||
// NB: python ifcopenshell.util.unit.convert checks `from_unit` (not
|
||||
// `to_unit`) here. Mirrored for parity — from_unit and to_unit are
|
||||
// always the same dimension in valid calls, so behaviour is the same.
|
||||
if (from_unit.find("SQUARE") != std::string::npos) {
|
||||
value *= 1.0 / getPrefixMultiplier(to_prefix);
|
||||
value *= 1.0 / get_prefix_multiplier(to_prefix);
|
||||
} else if (from_unit.find("CUBIC") != std::string::npos) {
|
||||
value *= 1.0 / getPrefixMultiplier(to_prefix);
|
||||
value *= 1.0 / getPrefixMultiplier(to_prefix);
|
||||
value *= 1.0 / get_prefix_multiplier(to_prefix);
|
||||
value *= 1.0 / get_prefix_multiplier(to_prefix);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
double convertUnit(double value, express::Base from_unit, express::Base to_unit) {
|
||||
double convert_unit(double value, express::Base from_unit, express::Base to_unit) {
|
||||
auto pull = [](express::Base u, std::string& prefix, std::string& name) {
|
||||
auto e = u.as<express::Entity>();
|
||||
if (u.declaration().is("IfcSIUnit")) {
|
||||
prefix = enumString(e.get("Prefix"));
|
||||
name = enumString(e.get("Name"));
|
||||
prefix = enum_string(e.get("Prefix"));
|
||||
name = enum_string(e.get("Name"));
|
||||
} else {
|
||||
// IfcConversionBasedUnit / IfcContextDependentUnit: no Prefix,
|
||||
// Name is a string attribute.
|
||||
|
||||
+14
-14
@@ -35,44 +35,44 @@ namespace ifcopenshell { class file; }
|
||||
|
||||
// SI prefix multipliers, e.g. "MILLI" -> 1e-3. Empty key not present;
|
||||
// callers should pass an empty prefix string for "no prefix".
|
||||
extern const std::unordered_map<std::string, double> kSiPrefixes;
|
||||
extern const std::unordered_map<std::string, double> SI_PREFIXES;
|
||||
|
||||
// SI prefix display symbols, e.g. "MILLI" -> "m".
|
||||
extern const std::unordered_map<std::string, std::string> kSiPrefixSymbols;
|
||||
extern const std::unordered_map<std::string, std::string> SI_PREFIX_SYMBOLS;
|
||||
|
||||
// Conversion-based unit name (lowercase, IFC convention) -> SI base scale.
|
||||
// e.g. "foot" -> 0.3048, "square foot" -> 0.09290304.
|
||||
extern const std::unordered_map<std::string, double> kSiConversions;
|
||||
extern const std::unordered_map<std::string, double> SI_CONVERSIONS;
|
||||
|
||||
// Conversion-based unit name -> IFC unit type, e.g. "foot" -> "LENGTHUNIT".
|
||||
extern const std::unordered_map<std::string, std::string> kImperialTypes;
|
||||
extern const std::unordered_map<std::string, std::string> IMPERIAL_TYPES;
|
||||
|
||||
// Display symbol per unit name. Covers IfcSIUnit names ("METRE" -> "m") and
|
||||
// IfcConversionBasedUnit names ("foot" -> "ft").
|
||||
extern const std::unordered_map<std::string, std::string> kUnitSymbols;
|
||||
extern const std::unordered_map<std::string, std::string> UNIT_SYMBOLS;
|
||||
|
||||
// Returns the multiplier for an SI prefix. Empty string returns 1.0.
|
||||
double getPrefixMultiplier(const std::string& prefix);
|
||||
double get_prefix_multiplier(const std::string& prefix);
|
||||
|
||||
// Returns the SI scale for an IfcNamedUnit such that
|
||||
// value_in_unit * scale == value_in_si_base
|
||||
// Walks IfcConversionBasedUnit chains down to IfcSIUnit. Returns nullopt
|
||||
// when the chain bottoms out in IfcContextDependentUnit (cannot convert).
|
||||
std::optional<double> siScaleFromNamedUnit(express::Base named_unit);
|
||||
std::optional<double> si_scale_from_named_unit(express::Base named_unit);
|
||||
|
||||
// IfcProject.UnitsInContext (the IfcUnitAssignment). Returns nullopt if
|
||||
// the file has no project or no assignment.
|
||||
std::optional<express::Base> getUnitAssignment(ifcopenshell::file* ifc_file);
|
||||
std::optional<express::Base> get_unit_assignment(ifcopenshell::file* ifc_file);
|
||||
|
||||
// First unit in the project's IfcUnitAssignment matching `unit_type`
|
||||
// (e.g. "LENGTHUNIT"). Returns nullopt if not found.
|
||||
std::optional<express::Base> getProjectUnit(ifcopenshell::file* ifc_file,
|
||||
const std::string& unit_type);
|
||||
std::optional<express::Base> get_project_unit(ifcopenshell::file* ifc_file,
|
||||
const std::string& unit_type);
|
||||
|
||||
// Project unit -> SI base scale (e.g. project in mm => 0.001). Defaults
|
||||
// to 1.0 when no project unit of the requested type is set.
|
||||
double calculateUnitScale(ifcopenshell::file* ifc_file,
|
||||
const std::string& unit_type = "LENGTHUNIT");
|
||||
double calculate_unit_scale(ifcopenshell::file* ifc_file,
|
||||
const std::string& unit_type = "LENGTHUNIT");
|
||||
|
||||
// Convert between two units identified by name + optional SI prefix.
|
||||
// SQUARE_/CUBIC_ prefixed SI names get the prefix multiplier squared/cubed
|
||||
@@ -83,7 +83,7 @@ double convert(double value,
|
||||
|
||||
// Convert between two IfcNamedUnit entities. Pulls Name and Prefix off each
|
||||
// and delegates to convert(). IfcConversionBasedUnit names that don't appear
|
||||
// in kSiConversions return the value unchanged.
|
||||
double convertUnit(double value, express::Base from_unit, express::Base to_unit);
|
||||
// in SI_CONVERSIONS return the value unchanged.
|
||||
double convert_unit(double value, express::Base from_unit, express::Base to_unit);
|
||||
|
||||
#endif // UNIT_H
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "Federation.h"
|
||||
#include "Geolocation.h"
|
||||
#include "Unit.h"
|
||||
#include "geolocation.h"
|
||||
#include "unit.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
@@ -103,18 +103,18 @@ ModelGeoref computeModelGeoref(ifcopenshell::file* ifc_file) {
|
||||
if (!ifc_file) return out;
|
||||
|
||||
out.units.project_length_to_meters =
|
||||
calculateUnitScale(ifc_file, "LENGTHUNIT");
|
||||
calculate_unit_scale(ifc_file, "LENGTHUNIT");
|
||||
|
||||
auto params = getHelmertTransformationParameters(ifc_file);
|
||||
auto params = get_helmert_transformation_parameters(ifc_file);
|
||||
const double scale = (params && params->scale != 0.0) ? params->scale : 1.0;
|
||||
out.units.map_unit_to_meters = out.units.project_length_to_meters / scale;
|
||||
if (!params) return out;
|
||||
|
||||
Eigen::Matrix4d helmert =
|
||||
helmertMetersFromParameters(*params, out.units.map_unit_to_meters);
|
||||
helmert_meters_from_parameters(*params, out.units.map_unit_to_meters);
|
||||
|
||||
if (auto wcs = getWcs(ifc_file)) {
|
||||
// getWcs returns the WCS in project units (translation in project
|
||||
if (auto wcs = get_wcs(ifc_file)) {
|
||||
// get_wcs returns the WCS in project units (translation in project
|
||||
// length units). Convert translation to metres before inverting.
|
||||
Eigen::Matrix4d wcs_m = *wcs;
|
||||
wcs_m(0, 3) *= out.units.project_length_to_meters;
|
||||
@@ -147,11 +147,11 @@ guessFederatedFalseOrigin(const Eigen::Vector3d& first_geometry_point_m,
|
||||
out.xyz = t_m * u_fed_inv;
|
||||
|
||||
// Rotation: helmert grid-north baked into coordinate_operation_meters.
|
||||
// helmertMetersFromParameters built that block as R_z(theta)·diag(fx,fy,fz)
|
||||
// with theta = atan2(xao, xaa); xaxis2angle is `-theta` in degrees.
|
||||
// helmert_meters_from_parameters built that block as R_z(theta)·diag(fx,fy,fz)
|
||||
// with theta = atan2(xao, xaa); x_axis_to_angle_deg is `-theta` in degrees.
|
||||
if (use_coord_op) {
|
||||
const Eigen::Matrix4d& M = georef.coordinate_operation_meters;
|
||||
out.rz_deg = xaxis2angleDeg(M(0, 0), M(1, 0));
|
||||
out.rz_deg = x_axis_to_angle_deg(M(0, 0), M(1, 0));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ struct ModelTransformation {
|
||||
};
|
||||
|
||||
// Per-model unit scales captured at load time. project_length_to_meters comes
|
||||
// from calculateUnitScale(file, "LENGTHUNIT"). map_unit_to_meters is derived
|
||||
// from calculate_unit_scale(file, "LENGTHUNIT"). map_unit_to_meters is derived
|
||||
// from IfcMapConversion.Scale as project_length_to_meters / Scale; the
|
||||
// IfcProjectedCRS.MapUnit named unit is metadata and does not affect the
|
||||
// transform composition.
|
||||
@@ -161,7 +161,7 @@ Eigen::Matrix4d composeFederatedFalseOrigin(const FederatedFalseOrigin&,
|
||||
|
||||
// Compose ModelTransformation into a 4x4 matrix in metres.
|
||||
// `coordinate_operation_meters` is the model's CoordinateOperation matrix
|
||||
// (e.g. helmertMetersFromParameters · inv(wcs_meters)) — needed to lift
|
||||
// (e.g. helmert_meters_from_parameters · inv(wcs_meters)) — needed to lift
|
||||
// `a` into metres when a_frame == ModelLocal. Pass identity when the
|
||||
// CoordinateOperation is disabled or absent.
|
||||
Eigen::Matrix4d composeModelTransformation(const ModelTransformation&,
|
||||
|
||||
@@ -158,9 +158,9 @@ target_link_libraries(test_federation PRIVATE
|
||||
Qt${QT_VERSION}::Gui # Federation::HomeView uses QVector3D from QtGui
|
||||
Qt${QT_VERSION}::Test # QSignalSpy
|
||||
Eigen3::Eigen # Federation.h: composed matrices use Eigen
|
||||
# helpers provides Unit::convert + Geolocation helpers
|
||||
# (helmertMetersFromParameters, getWcs, getMapUnit) + Placement
|
||||
# (getAxis2Placement, called from Geolocation::getWcs). Linking the
|
||||
# helpers provides unit conversion and geolocation helpers
|
||||
# (helmert_meters_from_parameters, get_wcs, get_map_unit) + Placement
|
||||
# (get_axis2_placement, called from geolocation::get_wcs). Linking the
|
||||
# static lib avoids re-compiling those .cpp files here and pulls
|
||||
# the src/helpers include dir + IfcParse transitively.
|
||||
helpers
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "Federation.h"
|
||||
#include "Geolocation.h"
|
||||
#include "geolocation.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
@@ -467,7 +467,7 @@ TEST_CASE("helmert metres transform consumes Scale through map unit scale",
|
||||
|
||||
const double project_length_to_meters = 0.001;
|
||||
const double map_unit_to_meters = project_length_to_meters / params.scale;
|
||||
Eigen::Matrix4d M = helmertMetersFromParameters(params, map_unit_to_meters);
|
||||
Eigen::Matrix4d M = helmert_meters_from_parameters(params, map_unit_to_meters);
|
||||
|
||||
Eigen::Vector4d local_m(10.0, 20.0, 0.0, 1.0);
|
||||
Eigen::Vector4d global_m = M * local_m;
|
||||
|
||||
Reference in New Issue
Block a user