diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 47c6472..6280df1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -144,3 +144,11 @@ jobs: with: files: ${{ matrix.artifact_name }}.zip token: ${{ secrets.GITHUB_TOKEN }} + + swift-package: + name: Swift Package (macOS) + runs-on: macos-15 + steps: + - uses: actions/checkout@v5 + - name: Run package tests + run: swift test diff --git a/.gitignore b/.gitignore index 43cc93c..9938c61 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,12 @@ Makefile # Object files *.o *.obj +# ...but Wavefront OBJ test fixtures are not object files +!Tests/MeshDenoiserKitTests/Fixtures/*.obj # macOS .DS_Store + +# Swift Package Manager +.build/ +.swiftpm/ diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..adc00c1 --- /dev/null +++ b/Package.swift @@ -0,0 +1,47 @@ +// swift-tools-version:5.9 +import PackageDescription + +let package = Package( + name: "MeshDenoiserKit", + platforms: [.iOS(.v17), .macOS(.v14)], + products: [ + .library(name: "MeshDenoiserKit", targets: ["MeshDenoiserKit"]), + ], + targets: [ + // OpenMesh headers deliberately live in "Headers", not the SPM default + // "include": they must stay textual includes, not a Clang module — + // some of them #include each other inside open namespaces, which + // breaks when clang maps the #include to a module import. + .target( + name: "OpenMeshCore", + path: "Sources/OpenMeshCore", + cxxSettings: [ + .define("OM_STATIC_BUILD"), + .headerSearchPath("Headers"), + ] + ), + .target( + name: "CMeshDenoiserCore", + dependencies: ["OpenMeshCore"], + path: "Sources/CMeshDenoiserCore", + publicHeadersPath: "include", + cxxSettings: [ + .headerSearchPath("../../src"), + .headerSearchPath("../../Vendor/eigen"), + .headerSearchPath("../OpenMeshCore/Headers"), + ] + ), + .target( + name: "MeshDenoiserKit", + dependencies: ["CMeshDenoiserCore"], + path: "Sources/MeshDenoiserKit" + ), + .testTarget( + name: "MeshDenoiserKitTests", + dependencies: ["MeshDenoiserKit"], + path: "Tests/MeshDenoiserKitTests", + resources: [.copy("Fixtures")] + ), + ], + cxxLanguageStandard: .cxx17 +) diff --git a/README.md b/README.md index 92bf28f..11bd7c0 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,34 @@ MeshDenoiser --help | `--deterministic` | Force single-threaded execution for reproducible output | | `--write-default-options PATH` | Write the default options template to a file and exit | +## Using from Swift (iOS / macOS) + +This repo is also a Swift Package (`MeshDenoiserKit`) targeting iOS 17+ / macOS 14+. +It exposes the denoiser as a buffers-in/buffers-out API — file I/O stays in your app +(ModelIO/SceneKit read USDZ natively). Vertex count and order are preserved, so UVs +and materials on the original asset remain valid; recompute normals after denoising. + +```swift +import MeshDenoiserKit + +var params = MeshDenoiseParameters() // tuned defaults +params.outerIterations = 2 // more smoothing + +let denoised = try await MeshDenoiser.denoise( + positions: positions, // [SIMD3] + indices: indices, // [UInt32], 3 per triangle + parameters: params +) { progress in + print("Progress: \(progress)") +} +``` + +Cancellation: cancel the surrounding `Task`; the call throws `CancellationError` +(checked after each outer iteration). For very large meshes (>~500k vertices) set +`params.linearSolver = .conjugateGradient` to reduce memory use. + +Vendored dependencies (Eigen, OpenMesh Core) are pinned by `scripts/vendor_dependencies.sh`. + ## Denoising Parameters The defaults are tuned for detail-preserving cleanup. Generate a commented template with diff --git a/Sources/CMeshDenoiserCore/CMeshDenoiserCore.cpp b/Sources/CMeshDenoiserCore/CMeshDenoiserCore.cpp new file mode 100644 index 0000000..3d1edb9 --- /dev/null +++ b/Sources/CMeshDenoiserCore/CMeshDenoiserCore.cpp @@ -0,0 +1,117 @@ +#include "CMeshDenoiserCore.h" + +#include "MeshTypes.h" +#include "MeshNormalDenoising.h" + +#include +#include +#include + +void md_params_init_defaults(md_params *params) +{ + params->lambda = 0.15; + params->eta = 2.2; + params->mu = 0.2; + params->nu = 0.25; + params->mesh_update_closeness_weight = 0.001; + params->mesh_update_iterations = 20; + params->mesh_update_displacement_eps = 0.1; + params->outer_iterations = 1; + params->linear_solver_type = 1; + params->deterministic = 0; +} + +md_status md_denoise(const float *vertices, size_t vertex_count, + const uint32_t *indices, size_t triangle_count, + const md_params *params, + float *out_vertices, + md_progress_fn progress, void *ctx) +{ + if(vertices == nullptr || indices == nullptr || params == nullptr || out_vertices == nullptr || + vertex_count == 0 || triangle_count == 0){ + return MD_ERR_INVALID_INPUT; + } + + for(size_t i = 0; i < vertex_count * 3; ++i){ + if(!std::isfinite(vertices[i])){ + return MD_ERR_INVALID_INPUT; + } + } + for(size_t i = 0; i < triangle_count * 3; ++i){ + if(indices[i] >= vertex_count){ + return MD_ERR_INVALID_INPUT; + } + } + + SDFilter::MeshDenoisingParameters param; + param.lambda = params->lambda; + param.eta = params->eta; + param.mu = params->mu; + param.nu = params->nu; + param.mesh_update_closeness_weight = params->mesh_update_closeness_weight; + param.mesh_update_iter = params->mesh_update_iterations; + param.mesh_update_disp_eps = params->mesh_update_displacement_eps; + param.outer_iterations = params->outer_iterations; + param.deterministic_mode = (params->deterministic != 0); + switch(params->linear_solver_type){ + case 0: param.linear_solver_type = SDFilter::Parameters::CG; break; + case 1: param.linear_solver_type = SDFilter::Parameters::LDLT; break; + default: return MD_ERR_INVALID_PARAMS; + } + if(!param.valid_parameters()){ + return MD_ERR_INVALID_PARAMS; + } + + if(param.deterministic_mode){ + Eigen::setNbThreads(1); + } + + TriMesh mesh; + std::vector vhandles; + vhandles.reserve(vertex_count); + for(size_t i = 0; i < vertex_count; ++i){ + vhandles.push_back(mesh.add_vertex(TriMesh::Point( + static_cast(vertices[3 * i]), + static_cast(vertices[3 * i + 1]), + static_cast(vertices[3 * i + 2])))); + } + for(size_t i = 0; i < triangle_count; ++i){ + TriMesh::FaceHandle fh = mesh.add_face( + vhandles[indices[3 * i]], + vhandles[indices[3 * i + 1]], + vhandles[indices[3 * i + 2]]); + if(!fh.is_valid()){ + return MD_ERR_INVALID_INPUT; // degenerate or non-manifold face + } + } + + // Same pipeline as the CLI: normalize -> denoise -> restore. + Eigen::Vector3d original_center; + double original_scale = 0.0; + SDFilter::normalize_mesh(mesh, original_center, original_scale); + + SDFilter::MeshNormalDenoising denoiser(mesh); + if(progress != nullptr){ + denoiser.set_progress_callback([progress, ctx](int completed, int total) -> bool { + return progress(completed, total, ctx); + }); + } + + TriMesh output_mesh; + if(!denoiser.denoise(param, output_mesh)){ + return denoiser.cancelled() ? MD_CANCELLED : MD_ERR_SOLVER_FAILED; + } + + SDFilter::restore_mesh(output_mesh, original_center, original_scale); + + for(TriMesh::ConstVertexIter cv_it = output_mesh.vertices_begin(); + cv_it != output_mesh.vertices_end(); ++cv_it){ + const TriMesh::Point &pt = output_mesh.point(*cv_it); + const int idx = cv_it->idx(); + out_vertices[3 * idx] = static_cast(pt[0]); + out_vertices[3 * idx + 1] = static_cast(pt[1]); + out_vertices[3 * idx + 2] = static_cast(pt[2]); + } + + return MD_OK; +} diff --git a/Sources/CMeshDenoiserCore/include/CMeshDenoiserCore.h b/Sources/CMeshDenoiserCore/include/CMeshDenoiserCore.h new file mode 100644 index 0000000..974cb0f --- /dev/null +++ b/Sources/CMeshDenoiserCore/include/CMeshDenoiserCore.h @@ -0,0 +1,55 @@ +// C API for the SD-filter mesh denoiser (algorithm: Zhang et al., arXiv:1712.03574). +// Buffers in / buffers out; vertex count and order are preserved. +#ifndef CMESHDENOISERCORE_H +#define CMESHDENOISERCORE_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + double lambda; // regularization weight (> 0) + double eta; // spatial Gaussian sigma, scaled by avg face-centroid distance (> 0) + double mu; // guidance normal difference weight (> 0) + double nu; // signal normal difference weight (> 0) + double mesh_update_closeness_weight; // vertex position fidelity (>= 0) + int mesh_update_iterations; // max vertex-update iterations per outer iteration (> 0) + double mesh_update_displacement_eps; // early-stop RMS displacement threshold (<= 0 disables) + int outer_iterations; // full filtering passes (> 0) + int linear_solver_type; // 0 = conjugate gradient, 1 = LDLT (default) + int deterministic; // nonzero forces single-threaded Eigen for reproducible output +} md_params; + +typedef enum { + MD_OK = 0, + MD_ERR_INVALID_INPUT = 1, // NULL/empty buffers, NaN/Inf coords, bad indices, non-manifold face + MD_ERR_INVALID_PARAMS = 2, + MD_ERR_SOLVER_FAILED = 3, + MD_CANCELLED = 4 +} md_status; + +// Called after each completed outer iteration. Return false to cancel. +typedef bool (*md_progress_fn)(int completed_outer, int total_outer, void *ctx); + +// Fills params with the tuned defaults from MeshDenoiserDefaults.txt. +void md_params_init_defaults(md_params *params); + +// vertices: xyz triples, vertex_count points. +// indices: 3 per triangle, triangle_count triangles, each index < vertex_count. +// out_vertices: caller-allocated, 3 * vertex_count floats. Written only on MD_OK. +// progress may be NULL; ctx is passed through to it. +md_status md_denoise(const float *vertices, size_t vertex_count, + const uint32_t *indices, size_t triangle_count, + const md_params *params, + float *out_vertices, + md_progress_fn progress, void *ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Sources/MeshDenoiserKit/MeshDenoiseError.swift b/Sources/MeshDenoiserKit/MeshDenoiseError.swift new file mode 100644 index 0000000..5d54c93 --- /dev/null +++ b/Sources/MeshDenoiserKit/MeshDenoiseError.swift @@ -0,0 +1,10 @@ +/// Errors thrown by ``MeshDenoiser/denoise(positions:indices:parameters:progress:)``. +/// Cancellation is reported as `CancellationError`, not through this enum. +public enum MeshDenoiseError: Error, Equatable { + /// Empty buffers, NaN/Inf coordinates, out-of-range indices, or a degenerate/non-manifold face. + case invalidInput + /// A parameter is out of its documented range. + case invalidParameters + /// The sparse solver failed to factorize or converge. + case solverFailed +} diff --git a/Sources/MeshDenoiserKit/MeshDenoiseParameters.swift b/Sources/MeshDenoiserKit/MeshDenoiseParameters.swift new file mode 100644 index 0000000..47ebd8d --- /dev/null +++ b/Sources/MeshDenoiserKit/MeshDenoiseParameters.swift @@ -0,0 +1,50 @@ +import CMeshDenoiserCore + +/// SD-filter denoising parameters. Defaults are the tuned values from MeshDenoiserDefaults.txt. +public struct MeshDenoiseParameters: Sendable, Equatable { + + public enum LinearSolver: Int32, Sendable { + /// Iterative conjugate gradient — lower memory, use for very large meshes (>~500k vertices). + case conjugateGradient = 0 + /// Direct sparse Cholesky (default) — fastest for typical mesh sizes. + case ldlt = 1 + } + + /// Regularization weight. Higher = more smoothing per iteration. Must be > 0. + public var lambda: Double = 0.15 + /// Spatial Gaussian sigma, scaled by average face-centroid distance. Must be > 0. + public var eta: Double = 2.2 + /// Guidance normal difference weight. Must be > 0. + public var mu: Double = 0.2 + /// Signal normal difference weight. Must be > 0. + public var nu: Double = 0.25 + /// Vertex position fidelity during mesh update. Must be >= 0. + public var meshUpdateClosenessWeight: Double = 0.001 + /// Max vertex-update iterations per outer iteration. Must be > 0. + public var meshUpdateIterations: Int = 20 + /// Early-stop RMS displacement threshold for mesh update; <= 0 disables. + public var meshUpdateDisplacementEps: Double = 0.1 + /// Number of full filtering passes. More = more smoothing. Must be > 0. + public var outerIterations: Int = 1 + public var linearSolver: LinearSolver = .ldlt + /// Forces single-threaded execution for bit-reproducible output. + public var deterministic: Bool = false + + public init() {} + + var cParams: md_params { + var c = md_params() + md_params_init_defaults(&c) + c.lambda = lambda + c.eta = eta + c.mu = mu + c.nu = nu + c.mesh_update_closeness_weight = meshUpdateClosenessWeight + c.mesh_update_iterations = Int32(meshUpdateIterations) + c.mesh_update_displacement_eps = meshUpdateDisplacementEps + c.outer_iterations = Int32(outerIterations) + c.linear_solver_type = linearSolver.rawValue + c.deterministic = deterministic ? 1 : 0 + return c + } +} diff --git a/Sources/MeshDenoiserKit/MeshDenoiser.swift b/Sources/MeshDenoiserKit/MeshDenoiser.swift new file mode 100644 index 0000000..9fc6da5 --- /dev/null +++ b/Sources/MeshDenoiserKit/MeshDenoiser.swift @@ -0,0 +1,91 @@ +import CMeshDenoiserCore +import Dispatch +import Foundation +import os + +/// Bridges Task cancellation and progress callbacks across the C boundary. +private final class DenoiseSession: @unchecked Sendable { + let progressHandler: (@Sendable (Double) -> Void)? + private let cancelledLock = OSAllocatedUnfairLock(initialState: false) + + init(progressHandler: (@Sendable (Double) -> Void)?) { + self.progressHandler = progressHandler + } + + func cancel() { cancelledLock.withLock { $0 = true } } + var isCancelled: Bool { cancelledLock.withLock { $0 } } +} + +public enum MeshDenoiser { + + /// Denoises a triangle mesh, preserving vertex count and order. + /// + /// Runs the synchronous C++ filter on a global queue; supports Task cancellation + /// (checked after each outer iteration) and reports fractional progress. + /// - Returns: Denoised vertex positions, same count and order as `positions`. + public static func denoise( + positions: [SIMD3], + indices: [UInt32], + parameters: MeshDenoiseParameters = MeshDenoiseParameters(), + progress: (@Sendable (Double) -> Void)? = nil + ) async throws -> [SIMD3] { + let session = DenoiseSession(progressHandler: progress) + return try await withTaskCancellationHandler { + try await withCheckedThrowingContinuation { continuation in + DispatchQueue.global(qos: .userInitiated).async { + continuation.resume(with: Result { + try runSync(positions: positions, indices: indices, + parameters: parameters, session: session) + }) + } + } + } onCancel: { + session.cancel() + } + } + + private static func runSync( + positions: [SIMD3], + indices: [UInt32], + parameters: MeshDenoiseParameters, + session: DenoiseSession + ) throws -> [SIMD3] { + var flat = [Float](repeating: 0, count: positions.count * 3) + for (i, p) in positions.enumerated() { + flat[3 * i] = p.x + flat[3 * i + 1] = p.y + flat[3 * i + 2] = p.z + } + var out = [Float](repeating: 0, count: flat.count) + var cParams = parameters.cParams + + let callback: md_progress_fn = { completed, total, rawCtx in + let session = Unmanaged.fromOpaque(rawCtx!).takeUnretainedValue() + if session.isCancelled { return false } + session.progressHandler?(Double(completed) / Double(total)) + return true + } + + let status = withExtendedLifetime(session) { + md_denoise(flat, positions.count, + indices, indices.count / 3, + &cParams, &out, + callback, Unmanaged.passUnretained(session).toOpaque()) + } + + switch status { + case MD_OK: + return (0..(out[3 * $0], out[3 * $0 + 1], out[3 * $0 + 2]) + } + case MD_CANCELLED: + throw CancellationError() + case MD_ERR_INVALID_INPUT: + throw MeshDenoiseError.invalidInput + case MD_ERR_INVALID_PARAMS: + throw MeshDenoiseError.invalidParameters + default: + throw MeshDenoiseError.solverFailed + } + } +} diff --git a/Sources/OpenMeshCore/Core/CMakeLists.txt b/Sources/OpenMeshCore/Core/CMakeLists.txt new file mode 100644 index 0000000..48f5547 --- /dev/null +++ b/Sources/OpenMeshCore/Core/CMakeLists.txt @@ -0,0 +1,246 @@ +include (VCICommon) + +set ( headers +Geometry/Config.hh +Geometry/EigenVectorT.hh +Geometry/LoopSchemeMaskT.hh +Geometry/MathDefs.hh +Geometry/NormalConeT.hh +Geometry/NormalConeT_impl.hh +Geometry/Plane3d.hh +Geometry/QuadricT.hh +Geometry/Vector11T.hh +Geometry/VectorT.hh +Geometry/VectorT_inc.hh +IO/BinaryHelper.hh +IO/IOInstances.hh +IO/IOManager.hh +IO/MeshIO.hh +IO/OFFFormat.hh +IO/OMFormat.hh +IO/OMFormatT_impl.hh +IO/Options.hh +IO/SR_binary.hh +IO/SR_binary_spec.hh +IO/SR_binary_vector_of_bool.hh +IO/SR_rbo.hh +IO/SR_store.hh +IO/SR_types.hh +IO/StoreRestore.hh +IO/exporter/BaseExporter.hh +IO/exporter/ExporterT.hh +IO/importer/BaseImporter.hh +IO/importer/ImporterT.hh +IO/reader/BaseReader.hh +IO/reader/OBJReader.hh +IO/reader/OFFReader.hh +IO/reader/OMReader.hh +IO/reader/PLYReader.hh +IO/reader/STLReader.hh +IO/writer/BaseWriter.hh +IO/writer/OBJWriter.hh +IO/writer/OFFWriter.hh +IO/writer/OMWriter.hh +IO/writer/PLYWriter.hh +IO/writer/STLWriter.hh +IO/writer/VTKWriter.hh +Mesh/ArrayItems.hh +Mesh/ArrayKernel.hh +Mesh/ArrayKernelT_impl.hh +Mesh/AttribKernelT.hh +Mesh/Attributes.hh +Mesh/BaseKernel.hh +Mesh/BaseMesh.hh +Mesh/Casts.hh +Mesh/CirculatorsT.hh +Mesh/DefaultPolyMesh.hh +Mesh/DefaultTriMesh.hh +Mesh/FinalMeshItemsT.hh +Mesh/Handles.hh +Mesh/IteratorsT.hh +Mesh/PolyConnectivity.hh +Mesh/PolyConnectivity_inline_impl.hh +Mesh/PolyMeshT.hh +Mesh/PolyMeshT_impl.hh +Mesh/PolyMesh_ArrayKernelT.hh +Mesh/SmartHandles.hh +Mesh/SmartRange.hh +Mesh/Status.hh +Mesh/Tags.hh +Mesh/Traits.hh +Mesh/TriConnectivity.hh +Mesh/TriMeshT.hh +Mesh/TriMeshT_impl.hh +Mesh/TriMesh_ArrayKernelT.hh +Mesh/gen/circulators_header.hh +Mesh/gen/circulators_template.hh +Mesh/gen/footer.hh +Mesh/gen/iterators_header.hh +Mesh/gen/iterators_template.hh +System/OpenMeshDLLMacros.hh +System/compiler.hh +System/config.hh +System/mostream.hh +System/omstream.hh +Utils/AutoPropertyHandleT.hh +Utils/BaseProperty.hh +Utils/Endian.hh +Utils/GenProg.hh +Utils/HandleToPropHandle.hh +Utils/Noncopyable.hh +Utils/Predicates.hh +Utils/Property.hh +Utils/PropertyContainer.hh +Utils/PropertyCreator.hh +Utils/PropertyManager.hh +Utils/RandomNumberGenerator.hh +Utils/SingletonT.hh +Utils/SingletonT_impl.hh +Utils/color_cast.hh +Utils/typename.hh +Utils/vector_cast.hh +Utils/vector_traits.hh +) + +set ( sources +IO/BinaryHelper.cc +IO/IOManager.cc +IO/OMFormat.cc +IO/reader/BaseReader.cc +IO/reader/OBJReader.cc +IO/reader/OFFReader.cc +IO/reader/OMReader.cc +IO/reader/PLYReader.cc +IO/reader/STLReader.cc +IO/writer/BaseWriter.cc +IO/writer/OBJWriter.cc +IO/writer/OFFWriter.cc +IO/writer/OMWriter.cc +IO/writer/PLYWriter.cc +IO/writer/STLWriter.cc +IO/writer/VTKWriter.cc +Mesh/ArrayKernel.cc +Mesh/BaseKernel.cc +Mesh/PolyConnectivity.cc +Mesh/TriConnectivity.cc +System/omstream.cc +Utils/BaseProperty.cc +Utils/Endian.cc +Utils/PropertyCreator.cc +Utils/RandomNumberGenerator.cc +) + +# Disable Library installation when not building OpenMesh on its own but as part of another project! +if ( NOT ${CMAKE_PROJECT_NAME} MATCHES "OpenMesh") + set(VCI_NO_LIBRARY_INSTALL true) +endif() + + +if (WIN32) + + if ( OPENMESH_BUILD_SHARED ) + add_definitions( -DOPENMESHDLL -DBUILDOPENMESHDLL) + vci_add_library (OpenMeshCore SHARED ${sources} ${headers}) + else() + vci_add_library (OpenMeshCore STATIC ${sources} ${headers}) + endif() + + target_include_directories(OpenMeshCore PUBLIC + $ + $) + + +else () + vci_add_library (OpenMeshCore SHAREDANDSTATIC ${sources} ${headers}) + + target_include_directories(OpenMeshCore PUBLIC + $ + $) + + target_include_directories(OpenMeshCoreStatic PUBLIC + $ + $) + + set_target_properties (OpenMeshCore PROPERTIES VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} ) +endif () + +if (MSVC) + target_compile_options(OpenMeshCore PUBLIC /bigobj) +endif () + +# Add core as dependency before fixbundle +if ( (${CMAKE_PROJECT_NAME} MATCHES "OpenMesh") AND BUILD_APPS ) + + if ( APPLE OR (WIN32 AND NOT "${CMAKE_GENERATOR}" MATCHES "MinGW Makefiles" ) ) + add_dependencies (fixbundle OpenMeshCore) + endif() + +endif() + +# if we build debug and release in the same dir, we want to install both! +if ( ${CMAKE_PROJECT_NAME} MATCHES "OpenMesh") + if ( WIN32 ) + FILE(GLOB files_install_libs "${CMAKE_BINARY_DIR}/Build/lib/*.lib" ) + FILE(GLOB files_install_dlls "${CMAKE_BINARY_DIR}/Build/*.dll" ) + INSTALL(FILES ${files_install_libs} DESTINATION lib ) + INSTALL(FILES ${files_install_dlls} DESTINATION . ) + endif() +endif() + + +# Install Header Files (Apple) +if ( NOT VCI_PROJECT_MACOS_BUNDLE AND APPLE ) + FILE(GLOB files_install_Geometry "${CMAKE_CURRENT_SOURCE_DIR}/Geometry/*.hh" ) + FILE(GLOB files_install_IO "${CMAKE_CURRENT_SOURCE_DIR}/IO/*.hh" "${CMAKE_CURRENT_SOURCE_DIR}/IO/*.inl" ) + FILE(GLOB files_install_IO_importer "${CMAKE_CURRENT_SOURCE_DIR}/IO/importer/*.hh" ) + FILE(GLOB files_install_IO_exporter "${CMAKE_CURRENT_SOURCE_DIR}/IO/exporter/*.hh" ) + FILE(GLOB files_install_IO_reader "${CMAKE_CURRENT_SOURCE_DIR}/IO/reader/*.hh" ) + FILE(GLOB files_install_IO_writer "${CMAKE_CURRENT_SOURCE_DIR}/IO/writer/*.hh" ) + FILE(GLOB files_install_Mesh "${CMAKE_CURRENT_SOURCE_DIR}/Mesh/*.hh" ) + FILE(GLOB files_install_Mesh_Gen "${CMAKE_CURRENT_SOURCE_DIR}/Mesh/gen/*.hh" ) + FILE(GLOB files_install_System "${CMAKE_CURRENT_SOURCE_DIR}/System/*.hh" "${CMAKE_CURRENT_SOURCE_DIR}/System/config.h" ) + FILE(GLOB files_install_Utils "${CMAKE_CURRENT_SOURCE_DIR}/Utils/*.hh" ) + INSTALL(FILES ${files_install_Geometry} DESTINATION include/OpenMesh/Core/Geometry ) + INSTALL(FILES ${files_install_IO} DESTINATION include/OpenMesh/Core/IO ) + INSTALL(FILES ${files_install_IO_importer} DESTINATION include/OpenMesh/Core/IO/importer ) + INSTALL(FILES ${files_install_IO_exporter} DESTINATION include/OpenMesh/Core/IO/exporter ) + INSTALL(FILES ${files_install_IO_reader} DESTINATION include/OpenMesh/Core/IO/reader ) + INSTALL(FILES ${files_install_IO_writer} DESTINATION include/OpenMesh/Core/IO/writer ) + INSTALL(FILES ${files_install_Mesh} DESTINATION include/OpenMesh/Core/Mesh ) + INSTALL(FILES ${files_install_Mesh_Gen} DESTINATION include/OpenMesh/Core/Mesh/gen ) + INSTALL(FILES ${files_install_System} DESTINATION include/OpenMesh/Core/System ) + INSTALL(FILES ${files_install_Utils} DESTINATION include/OpenMesh/Core/Utils ) +endif() + + +# Only install if the project name matches OpenMesh. +if (${CMAKE_PROJECT_NAME} MATCHES "OpenMesh") + set (OPENMESH_NO_INSTALL_HEADERS FALSE CACHE BOOL "Should OpenMesh skip installing headers?") +else() + set (OPENMESH_NO_INSTALL_HEADERS TRUE CACHE BOOL "Should OpenMesh skip installing headers?") +endif() + +if (NOT APPLE AND NOT ${OPENMESH_NO_INSTALL_HEADERS}) + +# Install Header Files) +install(DIRECTORY . + DESTINATION include/OpenMesh/Core + FILES_MATCHING + PATTERN "*.hh" + PATTERN "CVS" EXCLUDE + PATTERN ".svn" EXCLUDE + PATTERN "tmp" EXCLUDE + PATTERN "Templates" EXCLUDE + PATTERN "Debian*" EXCLUDE) + +#install the config file +install(FILES System/config.h DESTINATION include/OpenMesh/Core/System) + +endif () + +install(TARGETS OpenMeshCore EXPORT OpenMeshConfig + ARCHIVE DESTINATION ${VCI_PROJECT_LIBDIR} + LIBRARY DESTINATION ${VCI_PROJECT_LIBDIR} + RUNTIME DESTINATION ${VCI_PROJECT_BINDIR}) + diff --git a/Sources/OpenMeshCore/Core/Geometry/Config.hh b/Sources/OpenMeshCore/Core/Geometry/Config.hh new file mode 100644 index 0000000..772a9df --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/Config.hh @@ -0,0 +1,70 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + + +//============================================================================= +// +// Defines +// +//============================================================================= + +#ifndef OPENMESH_GEOMETRY_CONFIG_HH +#define OPENMESH_GEOMETRY_CONFIG_HH + + +//== INCLUDES ================================================================= + +// OpenMesh Namespace Defines +#include + + +//== NAMESPACES =============================================================== + +#define BEGIN_NS_GEOMETRY namespace geometry { +#define END_NS_GEOMETRY } + + +//============================================================================= +#endif // OPENMESH_GEOMETRY_CONFIG_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Geometry/EigenVectorT.hh b/Sources/OpenMeshCore/Core/Geometry/EigenVectorT.hh new file mode 100644 index 0000000..5ae86e9 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/EigenVectorT.hh @@ -0,0 +1,104 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/** This file contains all code required to use Eigen3 vectors as Mesh + * vectors + */ +#pragma once + +#include +#include +#include + + +namespace OpenMesh { + template + struct vector_traits> { + static_assert(_Rows != Eigen::Dynamic && _Cols != Eigen::Dynamic, + "Should not use dynamic vectors."); + static_assert(_Rows == 1 || _Cols == 1, "Should not use matrices."); + + using vector_type = Eigen::Matrix<_Scalar, _Rows, _Cols, _Options>; + using value_type = _Scalar; + static const size_t size_ = _Rows * _Cols; + static size_t size() { return size_; } +}; + +} // namespace OpenMesh + +namespace Eigen { + + template + typename Derived::Scalar dot(const MatrixBase &x, + const MatrixBase &y) { + return x.dot(y); + } + + template + typename MatrixBase< Derived >::PlainObject cross(const MatrixBase &x, const MatrixBase &y) { + return x.cross(y); + } + + template + typename Derived::Scalar norm(const MatrixBase &x) { + return x.norm(); + } + + template + typename Derived::Scalar sqrnorm(const MatrixBase &x) { + return x.dot(x); + } + + template + MatrixBase &normalize(MatrixBase &x) { + x /= x.norm(); + return x; + } + + template + MatrixBase &vectorize(MatrixBase &x, + typename Derived::Scalar const &val) { + x.fill(val); + return x; + } + +} // namespace Eigen + diff --git a/Sources/OpenMeshCore/Core/Geometry/LoopSchemeMaskT.hh b/Sources/OpenMeshCore/Core/Geometry/LoopSchemeMaskT.hh new file mode 100644 index 0000000..329365b --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/LoopSchemeMaskT.hh @@ -0,0 +1,191 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef LOOPSCHEMEMASKT_HH +#define LOOPSCHEMEMASKT_HH + +#include +#include + +#include +#include + +namespace OpenMesh +{ + +/** implements cache for the weights of the original Loop scheme + supported: + - vertex projection rule on the next level + - vertex projection rule on the limit surface + - vertex projection rule on the k-th (level) step (Barthe, Kobbelt'2003) + - vertex tangents on the limit surface +*/ + +template +class LoopSchemeMaskT +{ +public: + enum { cache_size = cache_size_ }; + typedef T_ Scalar; + +protected: + + Scalar proj_weights_[cache_size]; + Scalar limit_weights_[cache_size]; + Scalar step_weights_[cache_size]; + std::vector tang0_weights_[cache_size]; + std::vector tang1_weights_[cache_size]; + +protected: + + inline static Scalar compute_proj_weight(uint _valence) + { + //return pow(3.0 / 2.0 + cos(2.0 * M_PI / _valence), 2) / 2.0 - 1.0; + double denom = (3.0 + 2.0*cos(2.0*M_PI/(double)_valence)); + double weight = (64.0*_valence)/(40.0 - denom*denom) - _valence; + return (Scalar) weight; + } + + inline static Scalar compute_limit_weight(uint _valence) + { + double proj_weight_value = compute_proj_weight(_valence); + proj_weight_value = proj_weight_value/(proj_weight_value + _valence);//normalize the proj_weight + double weight = (3.0/8.0)/(1.0 - proj_weight_value + (3.0/8.0)); + return (Scalar)weight; + } + + inline static Scalar compute_step_weight(uint _valence) + { + double proj_weight_value = compute_proj_weight(_valence); + proj_weight_value = proj_weight_value/(proj_weight_value + _valence);//normalize the proj_weight + double weight = proj_weight_value - (3.0/8.0); + return (Scalar)weight; + } + + inline static Scalar compute_tang0_weight(uint _valence, uint _ver_id) + { + return (Scalar)cos(2.0*M_PI*(double)_ver_id/(double)_valence); + } + + inline static Scalar compute_tang1_weight(uint _valence, uint _ver_id) + { + return (Scalar)sin(2.0*M_PI*(double)_ver_id/(double)_valence); + } + + void cache_weights() + { + proj_weights_[0] = 1; + for (uint k = 1; k < cache_size; ++k) + { + proj_weights_[k] = compute_proj_weight(k); + limit_weights_[k] = compute_limit_weight(k); + step_weights_[k] = compute_step_weight(k); + tang0_weights_[k].resize(k); + tang1_weights_[k].resize(k); + for (uint i = 0; i < k; ++i) + { + tang0_weights_[k][i] = compute_tang0_weight(k,i); + tang1_weights_[k][i] = compute_tang1_weight(k,i); + } + } + } + +public: + + LoopSchemeMaskT() + { + cache_weights(); + } + + inline Scalar proj_weight(uint _valence) const + { + assert(_valence < cache_size ); + return proj_weights_[_valence]; + } + + inline Scalar limit_weight(uint _valence) const + { + assert(_valence < cache_size ); + return limit_weights_[_valence]; + } + + inline Scalar step_weight(uint _valence, uint _step) const + { + assert(_valence < cache_size); + return pow(step_weights_[_valence], (int)_step);//can be precomputed + } + + inline Scalar tang0_weight(uint _valence, uint _ver_id) const + { + assert(_valence < cache_size ); + assert(_ver_id < _valence); + return tang0_weights_[_valence][_ver_id]; + } + + inline Scalar tang1_weight(uint _valence, uint _ver_id) const + { + assert(_valence < cache_size ); + assert(_ver_id < _valence); + return tang1_weights_[_valence][_ver_id]; + } + + void dump(uint _max_valency = cache_size - 1) const + { + assert(_max_valency <= cache_size - 1); + //CConsole::printf("(k : pw_k, lw_k): "); + for (uint i = 0; i <= _max_valency; ++i) + { + //CConsole::stream() << "(" << i << " : " << proj_weight(i) << ", " << limit_weight(i) << ", " << step_weight(i,1) << "), "; + } + //CConsole::printf("\n"); + } +}; + +typedef LoopSchemeMaskT LoopSchemeMaskDouble; +typedef SingletonT LoopSchemeMaskDoubleSingleton; + +}//namespace OpenMesh + +#endif//LOOPSCHEMEMASKT_HH + diff --git a/Sources/OpenMeshCore/Core/Geometry/MathDefs.hh b/Sources/OpenMeshCore/Core/Geometry/MathDefs.hh new file mode 100644 index 0000000..c7a77fc --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/MathDefs.hh @@ -0,0 +1,167 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef MATHDEFS_HH +#define MATHDEFS_HH + +#include +#include + +#ifndef M_PI + #define M_PI 3.14159265359 +#endif + +namespace OpenMesh +{ + +/** comparison operators with user-selected precision control +*/ +template +inline bool is_zero(const T& _a, Real _eps) +{ return fabs(_a) < _eps; } + +template +inline bool is_eq(const T1& a, const T2& b, Real _eps) +{ return is_zero(a-b, _eps); } + +template +inline bool is_gt(const T1& a, const T2& b, Real _eps) +{ return (a > b) && !is_eq(a,b,_eps); } + +template +inline bool is_ge(const T1& a, const T2& b, Real _eps) +{ return (a > b) || is_eq(a,b,_eps); } + +template +inline bool is_lt(const T1& a, const T2& b, Real _eps) +{ return (a < b) && !is_eq(a,b,_eps); } + +template +inline bool is_le(const T1& a, const T2& b, Real _eps) +{ return (a < b) || is_eq(a,b,_eps); } + +/*const float flt_eps__ = 10*FLT_EPSILON; +const double dbl_eps__ = 10*DBL_EPSILON;*/ +const float flt_eps__ = (float)1e-05; +const double dbl_eps__ = 1e-09; + +inline float eps__(float) +{ return flt_eps__; } + +inline double eps__(double) +{ return dbl_eps__; } + +template +inline bool is_zero(const T& a) +{ return is_zero(a, eps__(a)); } + +template +inline bool is_eq(const T1& a, const T2& b) +{ return is_zero(a-b); } + +template +inline bool is_gt(const T1& a, const T2& b) +{ return (a > b) && !is_eq(a,b); } + +template +inline bool is_ge(const T1& a, const T2& b) +{ return (a > b) || is_eq(a,b); } + +template +inline bool is_lt(const T1& a, const T2& b) +{ return (a < b) && !is_eq(a,b); } + +template +inline bool is_le(const T1& a, const T2& b) +{ return (a < b) || is_eq(a,b); } + +/// Trigonometry/angles - related + +template +inline T sane_aarg(T _aarg) +{ + if (_aarg < -1) + { + _aarg = -1; + } + else if (_aarg > 1) + { + _aarg = 1; + } + return _aarg; +} + +/** returns the angle determined by its cos and the sign of its sin + result is positive if the angle is in [0:pi] + and negative if it is in [pi:2pi] +*/ +template +T angle(T _cos_angle, T _sin_angle) +{//sanity checks - otherwise acos will return nan + _cos_angle = sane_aarg(_cos_angle); + return (T) _sin_angle >= 0 ? acos(_cos_angle) : -acos(_cos_angle); +} + +template +inline T positive_angle(T _angle) +{ return _angle < 0 ? (2*M_PI + _angle) : _angle; } + +template +inline T positive_angle(T _cos_angle, T _sin_angle) +{ return positive_angle(angle(_cos_angle, _sin_angle)); } + +template +inline T deg_to_rad(const T& _angle) +{ return M_PI*(_angle/180); } + +template +inline T rad_to_deg(const T& _angle) +{ return 180*(_angle/M_PI); } + +inline double log_(double _value) +{ return log(_value); } + +}//namespace OpenMesh + +#endif//MATHDEFS_HH diff --git a/Sources/OpenMeshCore/Core/Geometry/NormalConeT.hh b/Sources/OpenMeshCore/Core/Geometry/NormalConeT.hh new file mode 100644 index 0000000..c146c59 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/NormalConeT.hh @@ -0,0 +1,124 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +//============================================================================= +// +// CLASS NormalCone +// +//============================================================================= + + +#ifndef OPENMESH_NORMALCONE_HH +#define OPENMESH_NORMALCONE_HH + + +//== INCLUDES ================================================================= + + +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** /class NormalCone NormalCone.hh + + NormalCone that can be merged with other normal cones. Provides + the center normal and the opening angle. +**/ + +template +class NormalConeT +{ +public: + + // typedefs + typedef typename vector_traits::value_type Scalar; + typedef Vector Vec3; + + + //! default constructor (not initialized) + NormalConeT() : angle_(0.0) {} + + //! Initialize cone with center (unit vector) and angle (radius in radians) + explicit NormalConeT(const Vec3& _center_normal, Scalar _angle=0.0); + + //! return max. distance (radians) unit vector to cone (distant side) + Scalar max_angle(const Vec3&) const; + + //! return max. distance (radians) cone to cone (distant sides) + Scalar max_angle(const NormalConeT&) const; + + //! merge _cone; this instance will then enclose both former cones + void merge(const NormalConeT&); + + //! returns center normal + const Vec3& center_normal() const { return center_normal_; } + + //! returns size of cone (radius in radians) + inline Scalar angle() const { return angle_; } + +private: + + Vec3 center_normal_; + Scalar angle_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_NORMALCONE_C) +#define OPENMESH_NORMALCONE_TEMPLATES +#include "NormalConeT_impl.hh" +#endif +//============================================================================= +#endif // OPENMESH_NORMALCONE_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/Geometry/NormalConeT_impl.hh b/Sources/OpenMeshCore/Core/Geometry/NormalConeT_impl.hh new file mode 100644 index 0000000..d09fc42 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/NormalConeT_impl.hh @@ -0,0 +1,151 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +//============================================================================= +// +// CLASS NormalConeT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_NORMALCONE_C + +//== INCLUDES ================================================================= + +#include +#include "NormalConeT.hh" + +#ifdef max +# undef max +#endif + +#ifdef min +# undef min +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + +template +NormalConeT:: +NormalConeT(const Vec3& _center_normal, Scalar _angle) + : center_normal_(_center_normal), angle_(_angle) +{ +} + + +//---------------------------------------------------------------------------- + + +template +typename NormalConeT::Scalar +NormalConeT:: +max_angle(const Vec3& _norm) const +{ + Scalar dotp = (center_normal_ | _norm); + return (dotp >= 1.0 ? 0.0 : (dotp <= -1.0 ? M_PI : acos(dotp))) + + angle_; +} + + +//---------------------------------------------------------------------------- + + +template +typename NormalConeT::Scalar +NormalConeT:: +max_angle(const NormalConeT& _cone) const +{ + Scalar dotp = (center_normal_ | _cone.center_normal_); + Scalar centerAngle = dotp >= 1.0 ? 0.0 : (dotp <= -1.0 ? M_PI : acos(dotp)); + Scalar sideAngle0 = std::max(angle_-centerAngle, _cone.angle_); + Scalar sideAngle1 = std::max(_cone.angle_-centerAngle, angle_); + + return centerAngle + sideAngle0 + sideAngle1; +} + + +//---------------------------------------------------------------------------- + + +template +void +NormalConeT:: +merge(const NormalConeT& _cone) +{ + Scalar dotp = dot(center_normal_, _cone.center_normal_); + + if (fabs(dotp) < 0.99999f) + { + // new angle + Scalar centerAngle = acos(dotp); + Scalar minAngle = std::min(-angle(), centerAngle - _cone.angle()); + Scalar maxAngle = std::max( angle(), centerAngle + _cone.angle()); + angle_ = (maxAngle - minAngle) * Scalar(0.5f); + + // axis by SLERP + Scalar axisAngle = Scalar(0.5f) * (minAngle + maxAngle); + center_normal_ = ((center_normal_ * sin(centerAngle-axisAngle) + + _cone.center_normal_ * sin(axisAngle)) + / sin(centerAngle)); + } + else + { + // axes point in same direction + if (dotp > 0.0f) + angle_ = std::max(angle_, _cone.angle_); + + // axes point in opposite directions + else + angle_ = Scalar(2.0f * M_PI); + } +} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Geometry/Plane3d.hh b/Sources/OpenMeshCore/Core/Geometry/Plane3d.hh new file mode 100644 index 0000000..42e4c4a --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/Plane3d.hh @@ -0,0 +1,119 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + + +//============================================================================= +// +// CLASS Plane3D +// +//============================================================================= + + +#ifndef OPENMESH_PLANE3D_HH +#define OPENMESH_PLANE3D_HH + + +//== INCLUDES ================================================================= + +#include + + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** \class Plane3d Plane3d.hh + + ax + by + cz + d = 0 +*/ + + +class OPENMESHDLLEXPORT Plane3d +{ +public: + + typedef OpenMesh::Vec3f vector_type; + typedef vector_type::value_type value_type; + +public: + + Plane3d() + : d_(0) + { } + + Plane3d(const vector_type &_dir, const vector_type &_pnt) + : n_(_dir), d_(0) + { + n_.normalize(); + d_ = -dot(n_,_pnt); + } + + value_type signed_distance(const OpenMesh::Vec3f &_p) + { + return dot(n_ , _p) + d_; + } + + // back compatibility + value_type singed_distance(const OpenMesh::Vec3f &point) + { return signed_distance( point ); } + +public: + + vector_type n_; + value_type d_; + +}; + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_PLANE3D_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Geometry/QuadricT.hh b/Sources/OpenMeshCore/Core/Geometry/QuadricT.hh new file mode 100644 index 0000000..7e21257 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/QuadricT.hh @@ -0,0 +1,286 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + + +/** \file Core/Geometry/QuadricT.hh + + */ + +//============================================================================= +// +// CLASS QuadricT +// +//============================================================================= + +#ifndef OPENMESH_GEOMETRY_QUADRIC_HH +#define OPENMESH_GEOMETRY_QUADRIC_HH + + +//== INCLUDES ================================================================= + +#include "Config.hh" +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { //BEGIN_NS_OPENMESH +namespace Geometry { //BEGIN_NS_GEOMETRY + + +//== CLASS DEFINITION ========================================================= + + +/** /class QuadricT Geometry/QuadricT.hh + + Stores a quadric as a 4x4 symmetrix matrix. Used by the + error quadric based mesh decimation algorithms. +**/ + +template +class QuadricT +{ +public: + typedef Scalar value_type; + typedef QuadricT type; + typedef QuadricT Self; + // typedef VectorInterface > Vec3; + // typedef VectorInterface > Vec4; + //typedef Vector3Elem Vec3; + //typedef Vector4Elem Vec4; + + /// construct with upper triangle of symmetrix 4x4 matrix + QuadricT(Scalar _a, Scalar _b, Scalar _c, Scalar _d, + Scalar _e, Scalar _f, Scalar _g, + Scalar _h, Scalar _i, + Scalar _j) + : a_(_a), b_(_b), c_(_c), d_(_d), + e_(_e), f_(_f), g_(_g), + h_(_h), i_(_i), + j_(_j) + { + } + + + /// constructor from given plane equation: ax+by+cz+d_=0 + QuadricT( Scalar _a=0.0, Scalar _b=0.0, Scalar _c=0.0, Scalar _d=0.0 ) + : a_(_a*_a), b_(_a*_b), c_(_a*_c), d_(_a*_d), + e_(_b*_b), f_(_b*_c), g_(_b*_d), + h_(_c*_c), i_(_c*_d), + j_(_d*_d) + {} + + template + explicit QuadricT(const _Point& _pt) + { + set_distance_to_point(_pt); + } + + template + QuadricT(const _Normal& _n, const _Point& _p) + { + set_distance_to_plane(_n,_p); + } + + //set operator + void set(Scalar _a, Scalar _b, Scalar _c, Scalar _d, + Scalar _e, Scalar _f, Scalar _g, + Scalar _h, Scalar _i, + Scalar _j) + { + a_ = _a; b_ = _b; c_ = _c; d_ = _d; + e_ = _e; f_ = _f; g_ = _g; + h_ = _h; i_ = _i; + j_ = _j; + } + + //sets the quadric representing the squared distance to _pt + template + void set_distance_to_point(const _Point& _pt) + { + set(1, 0, 0, -_pt[0], + 1, 0, -_pt[1], + 1, -_pt[2], + dot(_pt,_pt)); + } + + //sets the quadric representing the squared distance to the plane [_a,_b,_c,_d] + void set_distance_to_plane(Scalar _a, Scalar _b, Scalar _c, Scalar _d) + { + a_ = _a*_a; b_ = _a*_b; c_ = _a*_c; d_ = _a*_d; + e_ = _b*_b; f_ = _b*_c; g_ = _b*_d; + h_ = _c*_c; i_ = _c*_d; + j_ = _d*_d; + } + + //sets the quadric representing the squared distance to the plane + //determined by the normal _n and the point _p + template + void set_distance_to_plane(const _Normal& _n, const _Point& _p) + { + set_distance_to_plane(_n[0], _n[1], _n[2], -dot(_n,_p)); + } + + /// set all entries to zero + void clear() { a_ = b_ = c_ = d_ = e_ = f_ = g_ = h_ = i_ = j_ = 0.0; } + + /// add quadrics + QuadricT& operator+=( const QuadricT& _q ) + { + a_ += _q.a_; b_ += _q.b_; c_ += _q.c_; d_ += _q.d_; + e_ += _q.e_; f_ += _q.f_; g_ += _q.g_; + h_ += _q.h_; i_ += _q.i_; + j_ += _q.j_; + return *this; + } + + QuadricT operator+(const QuadricT& _other ) const + { + QuadricT result = *this; + return result += _other; + } + + + /// multiply by scalar + QuadricT& operator*=( Scalar _s) + { + a_ *= _s; b_ *= _s; c_ *= _s; d_ *= _s; + e_ *= _s; f_ *= _s; g_ *= _s; + h_ *= _s; i_ *= _s; + j_ *= _s; + return *this; + } + + QuadricT operator*(Scalar _s) const + { + QuadricT result = *this; + return result *= _s; + } + + /// multiply 4D vector from right: Q*v + template + _Vec4 operator*(const _Vec4& _v) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]), w(_v[3]); + return _Vec4(x*a_ + y*b_ + z*c_ + w*d_, + x*b_ + y*e_ + z*f_ + w*g_, + x*c_ + y*f_ + z*h_ + w*i_, + x*d_ + y*g_ + z*i_ + w*j_); + } + + /// evaluate quadric Q at (3D or 4D) vector v: v*Q*v + template + Scalar operator()(const _Vec& _v) const + { + return evaluate(_v, GenProg::Int2Type::size_>()); + } + + Scalar a() const { return a_; } + Scalar b() const { return b_; } + Scalar c() const { return c_; } + Scalar d() const { return d_; } + Scalar e() const { return e_; } + Scalar f() const { return f_; } + Scalar g() const { return g_; } + Scalar h() const { return h_; } + Scalar i() const { return i_; } + Scalar j() const { return j_; } + + Scalar xx() const { return a_; } + Scalar xy() const { return b_; } + Scalar xz() const { return c_; } + Scalar xw() const { return d_; } + Scalar yy() const { return e_; } + Scalar yz() const { return f_; } + Scalar yw() const { return g_; } + Scalar zz() const { return h_; } + Scalar zw() const { return i_; } + Scalar ww() const { return j_; } + +protected: + + /// evaluate quadric Q at 3D vector v: v*Q*v + template + Scalar evaluate(const _Vec3& _v, GenProg::Int2Type<3>/*_dimension*/) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]); + return a_*x*x + 2.0*b_*x*y + 2.0*c_*x*z + 2.0*d_*x + + e_*y*y + 2.0*f_*y*z + 2.0*g_*y + + h_*z*z + 2.0*i_*z + + j_; + } + + /// evaluate quadric Q at 4D vector v: v*Q*v + template + Scalar evaluate(const _Vec4& _v, GenProg::Int2Type<4>/*_dimension*/) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]), w(_v[3]); + return a_*x*x + 2.0*b_*x*y + 2.0*c_*x*z + 2.0*d_*x*w + + e_*y*y + 2.0*f_*y*z + 2.0*g_*y*w + + h_*z*z + 2.0*i_*z*w + + j_*w*w; + } + +private: + + Scalar a_, b_, c_, d_, + e_, f_, g_, + h_, i_, + j_; +}; + + +/// Quadric using floats +typedef QuadricT Quadricf; + +/// Quadric using double +typedef QuadricT Quadricd; + + +//============================================================================= +} // END_NS_GEOMETRY +} // END_NS_OPENMESH +//============================================================================ +#endif // OPENMESH_GEOMETRY_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Geometry/Vector11T.hh b/Sources/OpenMeshCore/Core/Geometry/Vector11T.hh new file mode 100644 index 0000000..7a6c93b --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/Vector11T.hh @@ -0,0 +1,926 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#ifndef OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ +#define OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// This header is not needed by this file but expected by others including +// this file. +#include + + +/* + * Helpers for VectorT + */ +namespace { + +template +struct are_convertible_to; + +template +struct are_convertible_to { + static constexpr bool value = std::is_convertible::value + && are_convertible_to::value; +}; + +template +struct are_convertible_to : public std::is_convertible { +}; +} + +namespace OpenMesh { + +template +class VectorT { + + static_assert(DIM >= 1, "VectorT requires positive dimensionality."); + + private: + using container = std::array; + container values_; + + public: + + //---------------------------------------------------------------- class info + + /// the type of the scalar used in this template + typedef Scalar value_type; + + /// type of this vector + typedef VectorT vector_type; + + /// returns dimension of the vector (deprecated) + static constexpr int dim() { + return DIM; + } + + /// returns dimension of the vector + static constexpr size_t size() { + return DIM; + } + + static constexpr const size_t size_ = DIM; + + //-------------------------------------------------------------- constructors + + // Converting constructor: Constructs the vector from DIM values (of + // potentially heterogenous types) which are all convertible to Scalar. + template::type, + typename = typename std::enable_if< + are_convertible_to::value>::type> + constexpr VectorT(T v, Ts... vs) : values_ { {static_cast(v), static_cast(vs)...} } { + static_assert(sizeof...(Ts)+1 == DIM, + "Invalid number of components specified in constructor."); + static_assert(are_convertible_to::value, + "Not all components are convertible to Scalar."); + } + + /// default constructor creates uninitialized values. + constexpr VectorT() {} + + /** + * Creates a vector with all components set to v. + */ + explicit VectorT(const Scalar &v) { + vectorize(v); + } + + VectorT(const VectorT &rhs) = default; + VectorT(VectorT &&rhs) = default; + VectorT &operator=(const VectorT &rhs) = default; + VectorT &operator=(VectorT &&rhs) = default; + + /** + * Only for 4-component vectors with division operator on their + * Scalar: Dehomogenization. + */ + template + auto homogenized() const -> + typename std::enable_if()/std::declval()), DIM>>::type { + static_assert(D == DIM, "D and DIM need to be identical. (Never " + "override the default template arguments.)"); + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return VectorT( + values_[0]/values_[3], + values_[1]/values_[3], + values_[2]/values_[3], + 1); + } + + /// construct from a value array or any other iterator + template(), void(), + ++std::declval(), void())> + explicit VectorT(Iterator it) { + std::copy_n(it, DIM, values_.begin()); + } + + /// construct from an array + explicit VectorT(container&& _array) : + values_(_array) + { + } + + /// copy & cast constructor (explicit) + template::value>> + explicit VectorT(const VectorT& _rhs) { + operator=(_rhs); + } + + //--------------------------------------------------------------------- casts + + /// cast from vector with a different scalar type + template::value>> + vector_type& operator=(const VectorT& _rhs) { + std::transform(_rhs.cbegin(), _rhs.cend(), + this->begin(), [](OtherScalar rhs) { + return static_cast(std::move(rhs)); + }); + return *this; + } + + /// access to Scalar array + Scalar* data() { return values_.data(); } + + /// access to const Scalar array + const Scalar* data() const { return values_.data(); } + + //----------------------------------------------------------- element access + + /// get i'th element read-write + Scalar& operator[](size_t _i) { + assert(_i < DIM); + return values_[_i]; + } + + /// get i'th element read-only + const Scalar& operator[](size_t _i) const { + assert(_i < DIM); + return values_[_i]; + } + + //---------------------------------------------------------------- comparsion + + /// component-wise comparison + bool operator==(const vector_type& _rhs) const { + return std::equal(_rhs.values_.cbegin(), _rhs.values_.cend(), values_.cbegin()); + } + + /// component-wise comparison + bool operator!=(const vector_type& _rhs) const { + return !std::equal(_rhs.values_.cbegin(), _rhs.values_.cend(), values_.cbegin()); + } + + //---------------------------------------------------------- scalar operators + + /// component-wise self-multiplication with scalar + template + auto operator*=(const OtherScalar& _s) -> + typename std::enable_ifvalues_[0] * _s), Scalar>::value, + VectorT&>::type { + for (auto& e : *this) { + e *= _s; + } + return *this; + } + + /// component-wise self-division by scalar + template + auto operator/=(const OtherScalar& _s) -> + typename std::enable_ifvalues_[0] / _s), Scalar>::value, + VectorT&>::type { + for (auto& e : *this) { + e /= _s; + } + return *this; + } + + /// component-wise multiplication with scalar + template + typename std::enable_if() * std::declval()), + Scalar>::value, + VectorT>::type + operator*(const OtherScalar& _s) const { + return vector_type(*this) *= _s; + } + + /// component-wise division by with scalar + template + typename std::enable_if() / std::declval()), + Scalar>::value, + VectorT>::type + operator/(const OtherScalar& _s) const { + return vector_type(*this) /= _s; + } + + //---------------------------------------------------------- vector operators + + /// component-wise self-multiplication + template + auto operator*=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] *= _rhs.data()[i]; + } + return *this; + } + + /// component-wise self-division + template + auto operator/=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] /= _rhs.data()[i]; + } + return *this; + } + + /// vector difference from this + template + auto operator-=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] -= _rhs.data()[i]; + } + return *this; + } + + /// vector self-addition + template + auto operator+=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] += _rhs.data()[i]; + } + return *this; + } + + /// component-wise vector multiplication + template + auto operator*(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) *= _rhs; + } + + /// component-wise vector division + template + auto operator/(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) /= _rhs; + } + + /// component-wise vector addition + template + auto operator+(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) += _rhs; + } + + /// component-wise vector difference + template + auto operator-(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) -= _rhs; + } + + /// unary minus + vector_type operator-(void) const { + vector_type v; + std::transform(values_.begin(), values_.end(), v.values_.begin(), + [](const Scalar &s) { return -s; }); + return v; + } + + /// cross product: only defined for Vec3* as specialization + /// \see OpenMesh::cross and .cross() + template + auto operator% (const VectorT &_rhs) const -> + typename std::enable_if>::type { + return { + values_[1] * _rhs[2] - values_[2] * _rhs[1], + values_[2] * _rhs[0] - values_[0] * _rhs[2], + values_[0] * _rhs[1] - values_[1] * _rhs[0] + }; + } + + /// cross product: only defined for Vec3* as specialization + /// \see OpenMesh::cross and .operator% + template + auto cross (const VectorT &_rhs) const -> + decltype(*this % _rhs) + { + return *this % _rhs; + } + + + /// compute scalar product + /// \see OpenMesh::dot and .dot() + template + auto operator|(const VectorT& _rhs) const -> + decltype(*this->data() * *_rhs.data()) { + + return std::inner_product(begin() + 1, begin() + DIM, _rhs.begin() + 1, + *begin() * *_rhs.begin()); + } + + /// compute scalar product + /// \see OpenMesh::dot and .operator| + template + auto dot(const VectorT& _rhs) const -> + decltype(*this | _rhs) + { + return *this | _rhs; + } + + //------------------------------------------------------------ euclidean norm + + /// \name Euclidean norm calculations + //@{ + + /// compute squared euclidean norm + template + decltype(std::declval() * std::declval()) sqrnorm() const { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + typedef decltype(values_[0] * values_[0]) RESULT; + return std::accumulate(values_.cbegin() + 1, values_.cend(), + values_[0] * values_[0], + [](const RESULT &l, const Scalar &r) { return l + r * r; }); + } + + /// compute euclidean norm + template + auto norm() const -> + decltype(std::sqrt(std::declval>().sqrnorm())) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return std::sqrt(sqrnorm()); + } + + template + auto length() const -> + decltype(std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return norm(); + } + + /** normalize vector, return normalized vector + */ + template + auto normalize() -> + decltype(*this /= std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return *this /= norm(); + } + + /** return normalized vector + */ + template + auto normalized() const -> + decltype(*this / std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return *this / norm(); + } + + /** normalize vector, return normalized vector and avoids div by zero + */ + template + typename std::enable_if< + sizeof(decltype( + static_cast(0), + std::declval>().norm())) >= 0, + vector_type&>::type + normalize_cond() { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + auto n = norm(); + if (n != static_cast(0)) { + *this /= n; + } + return *this; + } + + //@} + + //------------------------------------------------------------ euclidean norm + + /// \name Non-Euclidean norm calculations + //@{ + + /// compute L1 (Manhattan) norm + Scalar l1_norm() const { + return std::accumulate( + values_.cbegin() + 1, values_.cend(), values_[0]); + } + + /// compute l8_norm + Scalar l8_norm() const { + return max_abs(); + } + + //@} + + //------------------------------------------------------------ max, min, mean + + /// \name Minimum maximum and mean + //@{ + + /// return the maximal component + Scalar max() const { + return *std::max_element(values_.cbegin(), values_.cend()); + } + + /// return the maximal absolute component + Scalar max_abs() const { + return std::abs( + *std::max_element(values_.cbegin(), values_.cend(), + [](const Scalar &a, const Scalar &b) { + return std::abs(a) < std::abs(b); + })); + } + + /// return the minimal component + Scalar min() const { + return *std::min_element(values_.cbegin(), values_.cend()); + } + + /// return the minimal absolute component + Scalar min_abs() const { + return std::abs( + *std::min_element(values_.cbegin(), values_.cend(), + [](const Scalar &a, const Scalar &b) { + return std::abs(a) < std::abs(b); + })); + } + + /// return arithmetic mean + Scalar mean() const { + return l1_norm()/DIM; + } + + /// return absolute arithmetic mean + Scalar mean_abs() const { + return std::accumulate(values_.cbegin() + 1, values_.cend(), + std::abs(values_[0]), + [](const Scalar &l, const Scalar &r) { + return l + std::abs(r); + }) / DIM; + } + + /// minimize values: same as *this = min(*this, _rhs), but faster + vector_type& minimize(const vector_type& _rhs) { + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [](const Scalar &l, const Scalar &r) { + return std::min(l, r); + }); + return *this; + } + + /// minimize values and signalize coordinate minimization + bool minimized(const vector_type& _rhs) { + bool result = false; + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [&result](const Scalar &l, const Scalar &r) { + if (l < r) { + return l; + } else { + result = true; + return r; + } + }); + return result; + } + + /// maximize values: same as *this = max(*this, _rhs), but faster + vector_type& maximize(const vector_type& _rhs) { + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [](const Scalar &l, const Scalar &r) { + return std::max(l, r); + }); + return *this; + } + + /// maximize values and signalize coordinate maximization + bool maximized(const vector_type& _rhs) { + bool result = false; + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [&result](const Scalar &l, const Scalar &r) { + if (l > r) { + return l; + } else { + result = true; + return r; + } + }); + return result; + } + + /// component-wise min + inline vector_type min(const vector_type& _rhs) const { + return vector_type(*this).minimize(_rhs); + } + + /// component-wise max + inline vector_type max(const vector_type& _rhs) const { + return vector_type(*this).maximize(_rhs); + } + + //@} + + //------------------------------------------------------------ misc functions + + /// component-wise apply function object with Scalar operator()(Scalar). + template + inline vector_type apply(const Functor& _func) const { + vector_type result; + std::transform(result.values_.cbegin(), result.values_.cend(), + result.values_.begin(), _func); + return result; + } + + /// store the same value in each component (e.g. to clear all entries) + vector_type& vectorize(const Scalar& _s) { + std::fill(values_.begin(), values_.end(), _s); + return *this; + } + + /// store the same value in each component + static vector_type vectorized(const Scalar& _s) { + return vector_type().vectorize(_s); + } + + /// lexicographical comparison + bool operator<(const vector_type& _rhs) const { + return std::lexicographical_compare( + values_.begin(), values_.end(), + _rhs.values_.begin(), _rhs.values_.end()); + } + + /// swap with another vector + void swap(VectorT& _other) + noexcept(noexcept(std::swap(values_, _other.values_))) { + std::swap(values_, _other.values_); + } + + //------------------------------------------------------------ component iterators + + /// \name Component iterators + //@{ + + using iterator = typename container::iterator; + using const_iterator = typename container::const_iterator; + using reverse_iterator = typename container::reverse_iterator; + using const_reverse_iterator = typename container::const_reverse_iterator; + + iterator begin() noexcept { return values_.begin(); } + const_iterator begin() const noexcept { return values_.cbegin(); } + const_iterator cbegin() const noexcept { return values_.cbegin(); } + + iterator end() noexcept { return values_.end(); } + const_iterator end() const noexcept { return values_.cend(); } + const_iterator cend() const noexcept { return values_.cend(); } + + reverse_iterator rbegin() noexcept { return values_.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return values_.crbegin(); } + const_reverse_iterator crbegin() const noexcept { return values_.crbegin(); } + + reverse_iterator rend() noexcept { return values_.rend(); } + const_reverse_iterator rend() const noexcept { return values_.crend(); } + const_reverse_iterator crend() const noexcept { return values_.crend(); } + + //@} +}; + +/// Component wise multiplication from the left +template +auto operator*(const OtherScalar& _s, const VectorT &rhs) -> + decltype(rhs.operator*(_s)) { + + return rhs * _s; +} + +/// output a vector by printing its space-separated compontens +template +auto operator<<(std::ostream& os, const VectorT &_vec) -> + typename std::enable_if< + sizeof(decltype(os << _vec[0])) >= 0, std::ostream&>::type { + + os << _vec[0]; + for (int i = 1; i < DIM; ++i) { + os << " " << _vec[i]; + } + return os; +} + +/// read the space-separated components of a vector from a stream +template +auto operator>> (std::istream& is, VectorT &_vec) -> + typename std::enable_if< + sizeof(decltype(is >> _vec[0])) >= 0, std::istream &>::type { + for (int i = 0; i < DIM; ++i) + is >> _vec[i]; + return is; +} + +/// \relates OpenMesh::VectorT +/// symmetric version of the dot product +template +Scalar dot(const VectorT& _v1, const VectorT& _v2) { + return (_v1 | _v2); +} + +/// \relates OpenMesh::VectorT +/// symmetric version of the cross product +template +auto +cross(const VectorT& _v1, const VectorT& _v2) -> + decltype(_v1 % _v2) { + return (_v1 % _v2); +} + +/// \relates OpenMesh::VectorT +/// non-member swap +template +void swap(VectorT& _v1, VectorT& _v2) +noexcept(noexcept(_v1.swap(_v2))) { + _v1.swap(_v2); +} + +/// \relates OpenMesh::VectorT +/// non-member norm +template +Scalar norm(const VectorT& _v) { + return _v.norm(); +} + +/// \relates OpenMesh::VectorT +/// non-member sqrnorm +template +Scalar sqrnorm(const VectorT& _v) { + return _v.sqrnorm(); +} +/// \relates OpenMesh::VectorT +/// non-member vectorize +template +VectorT& vectorize(VectorT& _v, OtherScalar const& _val) { + return _v.vectorize(_val); +} + +/// \relates OpenMesh::VectorT +/// non-member normalize +template +VectorT& normalize(VectorT& _v) { + return _v.normalize(); +} + +/// \relates OpenMesh::VectorT +/// non-member maximize +template +VectorT& maximize(VectorT& _v1, VectorT& _v2) { + return _v1.maximize(_v2); +} + +/// \relates OpenMesh::VectorT +/// non-member minimize +template +VectorT& minimize(VectorT& _v1, VectorT& _v2) { + return _v1.minimize(_v2); +} + +/// \relates OpenMesh::VectorT +/// non-member max +template +VectorT max(const VectorT& _v1, const VectorT& _v2) { + return _v1.max(_v2); +} + +/// \relates OpenMesh::VectorT +/// non-member min +template +VectorT min(const VectorT& _v1, const VectorT& _v2) { + return _v1.min(_v2); +} + + +//== TYPEDEFS ================================================================= + +/** 1-byte signed vector */ +typedef VectorT Vec1c; +/** 1-byte unsigned vector */ +typedef VectorT Vec1uc; +/** 1-short signed vector */ +typedef VectorT Vec1s; +/** 1-short unsigned vector */ +typedef VectorT Vec1us; +/** 1-int signed vector */ +typedef VectorT Vec1i; +/** 1-int unsigned vector */ +typedef VectorT Vec1ui; +/** 1-float vector */ +typedef VectorT Vec1f; +/** 1-double vector */ +typedef VectorT Vec1d; + +/** 2-byte signed vector */ +typedef VectorT Vec2c; +/** 2-byte unsigned vector */ +typedef VectorT Vec2uc; +/** 2-short signed vector */ +typedef VectorT Vec2s; +/** 2-short unsigned vector */ +typedef VectorT Vec2us; +/** 2-int signed vector */ +typedef VectorT Vec2i; +/** 2-int unsigned vector */ +typedef VectorT Vec2ui; +/** 2-float vector */ +typedef VectorT Vec2f; +/** 2-double vector */ +typedef VectorT Vec2d; + +/** 3-byte signed vector */ +typedef VectorT Vec3c; +/** 3-byte unsigned vector */ +typedef VectorT Vec3uc; +/** 3-short signed vector */ +typedef VectorT Vec3s; +/** 3-short unsigned vector */ +typedef VectorT Vec3us; +/** 3-int signed vector */ +typedef VectorT Vec3i; +/** 3-int unsigned vector */ +typedef VectorT Vec3ui; +/** 3-float vector */ +typedef VectorT Vec3f; +/** 3-double vector */ +typedef VectorT Vec3d; +/** 3-bool vector */ +typedef VectorT Vec3b; + +/** 4-byte signed vector */ +typedef VectorT Vec4c; +/** 4-byte unsigned vector */ +typedef VectorT Vec4uc; +/** 4-short signed vector */ +typedef VectorT Vec4s; +/** 4-short unsigned vector */ +typedef VectorT Vec4us; +/** 4-int signed vector */ +typedef VectorT Vec4i; +/** 4-int unsigned vector */ +typedef VectorT Vec4ui; +/** 4-float vector */ +typedef VectorT Vec4f; +/** 4-double vector */ +typedef VectorT Vec4d; + +/** 5-byte signed vector */ +typedef VectorT Vec5c; +/** 5-byte unsigned vector */ +typedef VectorT Vec5uc; +/** 5-short signed vector */ +typedef VectorT Vec5s; +/** 5-short unsigned vector */ +typedef VectorT Vec5us; +/** 5-int signed vector */ +typedef VectorT Vec5i; +/** 5-int unsigned vector */ +typedef VectorT Vec5ui; +/** 5-float vector */ +typedef VectorT Vec5f; +/** 5-double vector */ +typedef VectorT Vec5d; + +/** 6-byte signed vector */ +typedef VectorT Vec6c; +/** 6-byte unsigned vector */ +typedef VectorT Vec6uc; +/** 6-short signed vector */ +typedef VectorT Vec6s; +/** 6-short unsigned vector */ +typedef VectorT Vec6us; +/** 6-int signed vector */ +typedef VectorT Vec6i; +/** 6-int unsigned vector */ +typedef VectorT Vec6ui; +/** 6-float vector */ +typedef VectorT Vec6f; +/** 6-double vector */ +typedef VectorT Vec6d; + +} // namespace OpenMesh + +/** + * Literal operator for inline specification of colors in HTML syntax. + * + * Example: + * \code{.cpp} + * OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor; + * \endcode + */ +constexpr OpenMesh::Vec4f operator"" _htmlColor(unsigned long long raw_color) { + return OpenMesh::Vec4f( + ((raw_color >> 24) & 0xFF) / 255.0f, + ((raw_color >> 16) & 0xFF) / 255.0f, + ((raw_color >> 8) & 0xFF) / 255.0f, + ((raw_color >> 0) & 0xFF) / 255.0f); +} + +#endif /* OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ */ diff --git a/Sources/OpenMeshCore/Core/Geometry/VectorT.hh b/Sources/OpenMeshCore/Core/Geometry/VectorT.hh new file mode 100644 index 0000000..c2676c7 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/VectorT.hh @@ -0,0 +1,451 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + + +//============================================================================= +// +// CLASS VectorT +// +//============================================================================= + +// Don't parse this header file with doxygen since +// for some reason (obviously due to a bug in doxygen, +// bugreport: https://bugzilla.gnome.org/show_bug.cgi?id=629182) +// macro expansion and preprocessor defines +// don't work properly. + +#if ((defined(_MSC_VER) && (_MSC_VER >= 1900)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) +#include "Vector11T.hh" +#else +#ifndef DOXYGEN + +#ifndef OPENMESH_VECTOR_HH +#define OPENMESH_VECTOR_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + +#if defined(__GNUC__) && defined(__SSE__) +#include +#endif + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** The N values of the template Scalar type are the only data members + of the class VectorT. This guarantees 100% compatibility + with arrays of type Scalar and size N, allowing us to define the + cast operators to and from arrays and array pointers. + + In addition, this class will be specialized for Vec4f to be 16 bit + aligned, so that aligned SSE instructions can be used on these + vectors. +*/ +template class VectorDataT { + public: + Scalar values_[N]; +}; + + +#if defined(__GNUC__) && defined(__SSE__) + +/// This specialization enables us to use aligned SSE instructions. +template<> class VectorDataT { + public: + union { + __m128 m128; + float values_[4]; + }; +}; + +#endif + + + + +//== CLASS DEFINITION ========================================================= + + +#define DIM N +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT +#define unroll(expr) for (int i=0; i + A vector is an array of \ values of type \. + The actual data is stored in an VectorDataT, this class just adds + the necessary operators. +*/ +#include "VectorT_inc.hh" + +#undef DIM +#undef TEMPLATE_HEADER +#undef CLASSNAME +#undef DERIVED +#undef unroll + + + + +//== PARTIAL TEMPLATE SPECIALIZATIONS ========================================= +#if OM_PARTIAL_SPECIALIZATION + + +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT + + +#define DIM 2 +#define unroll(expr) expr(0) expr(1) +#define unroll_comb(expr, op) expr(0) op expr(1) +#define unroll_csv(expr) expr(0), expr(1) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#define DIM 3 +#define unroll(expr) expr(0) expr(1) expr(2) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) +#define unroll_csv(expr) expr(0), expr(1), expr(2) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#define DIM 4 +#define unroll(expr) expr(0) expr(1) expr(2) expr(3) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) op expr(3) +#define unroll_csv(expr) expr(0), expr(1), expr(2), expr(3) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + +#define DIM 5 +#define unroll(expr) expr(0) expr(1) expr(2) expr(3) expr(4) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) op expr(3) op expr(4) +#define unroll_csv(expr) expr(0), expr(1), expr(2), expr(3), expr(4) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + +#define DIM 6 +#define unroll(expr) expr(0) expr(1) expr(2) expr(3) expr(4) expr(5) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) op expr(3) op expr(4) op expr(5) +#define unroll_csv(expr) expr(0), expr(1), expr(2), expr(3), expr(4), expr(5) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#undef TEMPLATE_HEADER +#undef CLASSNAME +#undef DERIVED + + + + +//== FULL TEMPLATE SPECIALIZATIONS ============================================ +#else + +/// cross product for Vec3f +template<> +inline VectorT +VectorT::operator%(const VectorT& _rhs) const +{ + return + VectorT(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1], + values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2], + values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]); +} + + +/// cross product for Vec3d +template<> +inline VectorT +VectorT::operator%(const VectorT& _rhs) const +{ + return + VectorT(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1], + values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2], + values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]); +} + +#endif + + + +//== GLOBAL FUNCTIONS ========================================================= + + +/// \relates OpenMesh::VectorT +/// scalar * vector +template +inline VectorT operator*(Scalar2 _s, const VectorT& _v) { + return _v*_s; +} + + +/// \relates OpenMesh::VectorT +/// symmetric version of the dot product +template +inline Scalar +dot(const VectorT& _v1, const VectorT& _v2) { + return (_v1 | _v2); +} + + +/// \relates OpenMesh::VectorT +/// symmetric version of the cross product +template +inline VectorT +cross(const VectorT& _v1, const VectorT& _v2) { + return (_v1 % _v2); +} + + +/// \relates OpenMesh::VectorT +/// non-member norm +template +Scalar norm(const VectorT& _v) { + return _v.norm(); +} + + +/// \relates OpenMesh::VectorT +/// non-member sqrnorm +template +Scalar sqrnorm(const VectorT& _v) { + return _v.sqrnorm(); +} + + +/// \relates OpenMesh::VectorT +/// non-member vectorize +template +VectorT& vectorize(VectorT& _v, OtherScalar const& _val) { + return _v.vectorize(_val); +} + + +/// \relates OpenMesh::VectorT +/// non-member normalize +template +VectorT& normalize(VectorT& _v) { + return _v.normalize(); +} + + +/// \relates OpenMesh::VectorT +/// non-member maximize +template +VectorT& maximize(VectorT& _v1, VectorT& _v2) { + return _v1.maximize(_v2); +} + + +/// \relates OpenMesh::VectorT +/// non-member minimize +template +VectorT& minimize(VectorT& _v1, VectorT& _v2) { + return _v1.minimize(_v2); +} + + +/// \relates OpenMesh::VectorT +/// non-member max +template +VectorT max(const VectorT& _v1, const VectorT& _v2) { + return VectorT(_v1).maximize(_v2); +} + + +/// \relates OpenMesh::VectorT +/// non-member min +template +VectorT min(const VectorT& _v1, const VectorT& _v2) { + return VectorT(_v1).minimize(_v2); +} + + +//== TYPEDEFS ================================================================= + +/** 1-byte signed vector */ +typedef VectorT Vec1c; +/** 1-byte unsigned vector */ +typedef VectorT Vec1uc; +/** 1-short signed vector */ +typedef VectorT Vec1s; +/** 1-short unsigned vector */ +typedef VectorT Vec1us; +/** 1-int signed vector */ +typedef VectorT Vec1i; +/** 1-int unsigned vector */ +typedef VectorT Vec1ui; +/** 1-float vector */ +typedef VectorT Vec1f; +/** 1-double vector */ +typedef VectorT Vec1d; + +/** 2-byte signed vector */ +typedef VectorT Vec2c; +/** 2-byte unsigned vector */ +typedef VectorT Vec2uc; +/** 2-short signed vector */ +typedef VectorT Vec2s; +/** 2-short unsigned vector */ +typedef VectorT Vec2us; +/** 2-int signed vector */ +typedef VectorT Vec2i; +/** 2-int unsigned vector */ +typedef VectorT Vec2ui; +/** 2-float vector */ +typedef VectorT Vec2f; +/** 2-double vector */ +typedef VectorT Vec2d; + +/** 3-byte signed vector */ +typedef VectorT Vec3c; +/** 3-byte unsigned vector */ +typedef VectorT Vec3uc; +/** 3-short signed vector */ +typedef VectorT Vec3s; +/** 3-short unsigned vector */ +typedef VectorT Vec3us; +/** 3-int signed vector */ +typedef VectorT Vec3i; +/** 3-int unsigned vector */ +typedef VectorT Vec3ui; +/** 3-float vector */ +typedef VectorT Vec3f; +/** 3-double vector */ +typedef VectorT Vec3d; +/** 3-bool vector */ +typedef VectorT Vec3b; + +/** 4-byte signed vector */ +typedef VectorT Vec4c; +/** 4-byte unsigned vector */ +typedef VectorT Vec4uc; +/** 4-short signed vector */ +typedef VectorT Vec4s; +/** 4-short unsigned vector */ +typedef VectorT Vec4us; +/** 4-int signed vector */ +typedef VectorT Vec4i; +/** 4-int unsigned vector */ +typedef VectorT Vec4ui; +/** 4-float vector */ +typedef VectorT Vec4f; +/** 4-double vector */ +typedef VectorT Vec4d; + +/** 5-byte signed vector */ +typedef VectorT Vec5c; +/** 5-byte unsigned vector */ +typedef VectorT Vec5uc; +/** 5-short signed vector */ +typedef VectorT Vec5s; +/** 5-short unsigned vector */ +typedef VectorT Vec5us; +/** 5-int signed vector */ +typedef VectorT Vec5i; +/** 5-int unsigned vector */ +typedef VectorT Vec5ui; +/** 5-float vector */ +typedef VectorT Vec5f; +/** 5-double vector */ +typedef VectorT Vec5d; + +/** 6-byte signed vector */ +typedef VectorT Vec6c; +/** 6-byte unsigned vector */ +typedef VectorT Vec6uc; +/** 6-short signed vector */ +typedef VectorT Vec6s; +/** 6-short unsigned vector */ +typedef VectorT Vec6us; +/** 6-int signed vector */ +typedef VectorT Vec6i; +/** 6-int unsigned vector */ +typedef VectorT Vec6ui; +/** 6-float vector */ +typedef VectorT Vec6f; +/** 6-double vector */ +typedef VectorT Vec6d; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + + +#endif // OPENMESH_VECTOR_HH defined +//============================================================================= +#endif // DOXYGEN +#endif // C++11 diff --git a/Sources/OpenMeshCore/Core/Geometry/VectorT_inc.hh b/Sources/OpenMeshCore/Core/Geometry/VectorT_inc.hh new file mode 100644 index 0000000..de7680b --- /dev/null +++ b/Sources/OpenMeshCore/Core/Geometry/VectorT_inc.hh @@ -0,0 +1,663 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + + +// Set template keywords and class names properly when +// parsing with doxygen. This only seems to work this way since +// the scope of preprocessor defines is limited to one file in doxy. +#ifdef DOXYGEN + +// Only used for correct doxygen parsing +#define OPENMESH_VECTOR_HH + +#define DIM N +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT +#define unroll(expr) for (int i=0; i vector_type; + + /// returns dimension of the vector (deprecated) + static inline int dim() { return DIM; } + + /// returns dimension of the vector + static inline size_t size() { return DIM; } + + static const size_t size_ = DIM; + + + //-------------------------------------------------------------- constructors + + /// default constructor creates uninitialized values. + inline VectorT() {} + + /// special constructor for 1D vectors + explicit inline VectorT(const Scalar& v) { +// assert(DIM==1); +// values_[0] = v0; + vectorize(v); + } + +#if DIM == 2 + /// special constructor for 2D vectors + inline VectorT(const Scalar v0, const Scalar v1) { + Base::values_[0] = v0; Base::values_[1] = v1; + } +#endif + +#if DIM == 3 + /// special constructor for 3D vectors + inline VectorT(const Scalar v0, const Scalar v1, const Scalar v2) { + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; + } +#endif + +#if DIM == 4 + /// special constructor for 4D vectors + inline VectorT(const Scalar v0, const Scalar v1, + const Scalar v2, const Scalar v3) { + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; Base::values_[3]=v3; + } + + VectorT homogenized() const { return VectorT(Base::values_[0]/Base::values_[3], Base::values_[1]/Base::values_[3], Base::values_[2]/Base::values_[3], 1); } +#endif + +#if DIM == 5 + /// special constructor for 5D vectors + inline VectorT(const Scalar v0, const Scalar v1, const Scalar v2, + const Scalar v3, const Scalar v4) { + Base::values_[0]=v0; Base::values_[1]=v1;Base::values_[2]=v2; Base::values_[3]=v3; Base::values_[4]=v4; + } +#endif + +#if DIM == 6 + /// special constructor for 6D vectors + inline VectorT(const Scalar v0, const Scalar v1, const Scalar v2, + const Scalar v3, const Scalar v4, const Scalar v5) { + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; + Base::values_[3]=v3; Base::values_[4]=v4; Base::values_[5]=v5; + } +#endif + + /// construct from a value array (explicit) + explicit inline VectorT(const Scalar _values[DIM]) { + memcpy(data(), _values, DIM*sizeof(Scalar)); + } + + +#ifdef OM_CC_MIPS + /// assignment from a vector of the same kind + // mipspro need this method + inline vector_type& operator=(const vector_type& _rhs) { + memcpy(Base::values_, _rhs.Base::values_, DIM*sizeof(Scalar)); + return *this; + } +#endif + + + /// copy & cast constructor (explicit) + template + explicit inline VectorT(const VectorT& _rhs) { + operator=(_rhs); + } + + + + + //--------------------------------------------------------------------- casts + + /// cast from vector with a different scalar type + template + inline vector_type& operator=(const VectorT& _rhs) { +#define expr(i) Base::values_[i] = (Scalar)_rhs[i]; + unroll(expr); +#undef expr + return *this; + } + +// /// cast to Scalar array +// inline operator Scalar*() { return Base::values_; } + +// /// cast to const Scalar array +// inline operator const Scalar*() const { return Base::values_; } + + /// access to Scalar array + inline Scalar* data() { return Base::values_; } + + /// access to const Scalar array + inline const Scalar*data() const { return Base::values_; } + + + //----------------------------------------------------------- element access + +// /// get i'th element read-write +// inline Scalar& operator[](int _i) { +// assert(_i>=0 && _i=0 && _i operator%(const VectorT& _rhs) const +#if DIM==3 + { + return + VectorT(Base::values_[1]*_rhs.Base::values_[2]-Base::values_[2]*_rhs.Base::values_[1], + Base::values_[2]*_rhs.Base::values_[0]-Base::values_[0]*_rhs.Base::values_[2], + Base::values_[0]*_rhs.Base::values_[1]-Base::values_[1]*_rhs.Base::values_[0]); + } +#else + ; +#endif + + + /// compute scalar product + /// \see OpenMesh::dot + inline Scalar operator|(const vector_type& _rhs) const { + Scalar p(0); +#define expr(i) p += Base::values_[i] * _rhs.Base::values_[i]; + unroll(expr); +#undef expr + return p; + } + + + + + + //------------------------------------------------------------ euclidean norm + + /// \name Euclidean norm calculations + //@{ + /// compute euclidean norm + inline Scalar norm() const { return (Scalar)sqrt(sqrnorm()); } + inline Scalar length() const { return norm(); } // OpenSG interface + + /// compute squared euclidean norm + inline Scalar sqrnorm() const + { +#if DIM==N + Scalar s(0); +#define expr(i) s += Base::values_[i] * Base::values_[i]; + unroll(expr); +#undef expr + return s; +#else +#define expr(i) Base::values_[i]*Base::values_[i] + return (unroll_comb(expr, +)); +#undef expr +#endif + } + + /** normalize vector, return normalized vector + */ + + inline vector_type& normalize() + { + *this /= norm(); + return *this; + } + + /** return normalized vector + */ + + inline const vector_type normalized() const + { + return *this / norm(); + } + + /** normalize vector, return normalized vector and avoids div by zero + */ + inline vector_type& normalize_cond() + { + Scalar n = norm(); + if (n != (Scalar)0.0) + { + *this /= n; + } + return *this; + } + + //@} + + //------------------------------------------------------------ euclidean norm + + /// \name Non-Euclidean norm calculations + //@{ + + /// compute L1 (Manhattan) norm + inline Scalar l1_norm() const + { +#if DIM==N + Scalar s(0); +#define expr(i) s += std::abs(Base::values_[i]); + unroll(expr); +#undef expr + return s; +#else +#define expr(i) std::abs(Base::values_[i]) + return (unroll_comb(expr, +)); +#undef expr +#endif + } + + /// compute l8_norm + inline Scalar l8_norm() const + { + return max_abs(); + } + + //@} + + //------------------------------------------------------------ max, min, mean + + /// \name Minimum maximum and mean + //@{ + + /// return the maximal component + inline Scalar max() const + { + Scalar m(Base::values_[0]); + for(int i=1; im) m=Base::values_[i]; + return m; + } + + /// return the maximal absolute component + inline Scalar max_abs() const + { + Scalar m(std::abs(Base::values_[0])); + for(int i=1; im) + m=std::abs(Base::values_[i]); + return m; + } + + + /// return the minimal component + inline Scalar min() const + { + Scalar m(Base::values_[0]); + for(int i=1; i Base::values_[i]) Base::values_[i] = _rhs[i]; + unroll(expr); +#undef expr + return *this; + } + + /// maximize values and signalize coordinate maximization + inline bool maximized(const vector_type& _rhs) { + bool result(false); +#define expr(i) if (_rhs[i] > Base::values_[i]) { Base::values_[i] =_rhs[i]; result = true; } + unroll(expr); +#undef expr + return result; + } + + /// component-wise min + inline vector_type min(const vector_type& _rhs) const { + return vector_type(*this).minimize(_rhs); + } + + /// component-wise max + inline vector_type max(const vector_type& _rhs) const { + return vector_type(*this).maximize(_rhs); + } + + //@} + + //------------------------------------------------------------ misc functions + + /// component-wise apply function object with Scalar operator()(Scalar). + template + inline vector_type apply(const Functor& _func) const { + vector_type result; +#define expr(i) result[i] = _func(Base::values_[i]); + unroll(expr); +#undef expr + return result; + } + + /// store the same value in each component (e.g. to clear all entries) + vector_type& vectorize(const Scalar& _s) { +#define expr(i) Base::values_[i] = _s; + unroll(expr); +#undef expr + return *this; + } + + + /// store the same value in each component + static vector_type vectorized(const Scalar& _s) { + return vector_type().vectorize(_s); + } + + + /// lexicographical comparison + bool operator<(const vector_type& _rhs) const { +#define expr(i) if (Base::values_[i] != _rhs.Base::values_[i]) \ + return (Base::values_[i] < _rhs.Base::values_[i]); + unroll(expr); +#undef expr + return false; + } +}; + + + +/// read the space-separated components of a vector from a stream +TEMPLATE_HEADER +inline std::istream& +operator>>(std::istream& is, VectorT& vec) +{ +#define expr(i) is >> vec[i]; + unroll(expr); +#undef expr + return is; +} + + +/// output a vector by printing its space-separated compontens +TEMPLATE_HEADER +inline std::ostream& +operator<<(std::ostream& os, const VectorT& vec) +{ +#if DIM==N + for(int i=0; i +#include +// -------------------- OpenMesh +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +#ifndef DOXY_IGNORE_THIS + +//== IMPLEMENTATION =========================================================== + +//----------------------------------------------------------------------------- + +short int read_short(FILE* _in, bool _swap) +{ + union u1 { short int s; unsigned char c[2]; } sc; + fread(reinterpret_cast(sc.c), 1, 2, _in); + if (_swap) std::swap(sc.c[0], sc.c[1]); + return sc.s; +} + + +//----------------------------------------------------------------------------- + + +int read_int(FILE* _in, bool _swap) +{ + union u2 { int i; unsigned char c[4]; } ic; + fread(reinterpret_cast(ic.c), 1, 4, _in); + if (_swap) { + std::swap(ic.c[0], ic.c[3]); + std::swap(ic.c[1], ic.c[2]); + } + return ic.i; +} + + +//----------------------------------------------------------------------------- + + +float read_float(FILE* _in, bool _swap) +{ + union u3 { float f; unsigned char c[4]; } fc; + fread(reinterpret_cast(fc.c), 1, 4, _in); + if (_swap) { + std::swap(fc.c[0], fc.c[3]); + std::swap(fc.c[1], fc.c[2]); + } + return fc.f; +} + + +//----------------------------------------------------------------------------- + + +double read_double(FILE* _in, bool _swap) +{ + union u4 { double d; unsigned char c[8]; } dc; + fread(reinterpret_cast(dc.c), 1, 8, _in); + if (_swap) { + std::swap(dc.c[0], dc.c[7]); + std::swap(dc.c[1], dc.c[6]); + std::swap(dc.c[2], dc.c[5]); + std::swap(dc.c[3], dc.c[4]); + } + return dc.d; +} + +//----------------------------------------------------------------------------- + +short int read_short(std::istream& _in, bool _swap) +{ + union u1 { short int s; unsigned char c[2]; } sc; + _in.read(reinterpret_cast(sc.c), 2); + if (_swap) std::swap(sc.c[0], sc.c[1]); + return sc.s; +} + + +//----------------------------------------------------------------------------- + + +int read_int(std::istream& _in, bool _swap) +{ + union u2 { int i; unsigned char c[4]; } ic; + _in.read(reinterpret_cast(ic.c), 4); + if (_swap) { + std::swap(ic.c[0], ic.c[3]); + std::swap(ic.c[1], ic.c[2]); + } + return ic.i; +} + + +//----------------------------------------------------------------------------- + + +float read_float(std::istream& _in, bool _swap) +{ + union u3 { float f; unsigned char c[4]; } fc; + _in.read(reinterpret_cast(fc.c), 4); + if (_swap) { + std::swap(fc.c[0], fc.c[3]); + std::swap(fc.c[1], fc.c[2]); + } + return fc.f; +} + + +//----------------------------------------------------------------------------- + + +double read_double(std::istream& _in, bool _swap) +{ + union u4 { double d; unsigned char c[8]; } dc; + _in.read(reinterpret_cast(dc.c), 8); + if (_swap) { + std::swap(dc.c[0], dc.c[7]); + std::swap(dc.c[1], dc.c[6]); + std::swap(dc.c[2], dc.c[5]); + std::swap(dc.c[3], dc.c[4]); + } + return dc.d; +} + + +//----------------------------------------------------------------------------- + + +void write_short(short int _i, FILE* _out, bool _swap) +{ + union u1 { short int s; unsigned char c[2]; } sc; + sc.s = _i; + if (_swap) std::swap(sc.c[0], sc.c[1]); + fwrite(reinterpret_cast(sc.c), 1, 2, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_int(int _i, FILE* _out, bool _swap) +{ + union u2 { int i; unsigned char c[4]; } ic; + ic.i = _i; + if (_swap) { + std::swap(ic.c[0], ic.c[3]); + std::swap(ic.c[1], ic.c[2]); + } + fwrite(reinterpret_cast(ic.c), 1, 4, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_float(float _f, FILE* _out, bool _swap) +{ + union u3 { float f; unsigned char c[4]; } fc; + fc.f = _f; + if (_swap) { + std::swap(fc.c[0], fc.c[3]); + std::swap(fc.c[1], fc.c[2]); + } + fwrite(reinterpret_cast(fc.c), 1, 4, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_double(double _d, FILE* _out, bool _swap) +{ + union u4 { double d; unsigned char c[8]; } dc; + dc.d = _d; + if (_swap) { + std::swap(dc.c[0], dc.c[7]); + std::swap(dc.c[1], dc.c[6]); + std::swap(dc.c[2], dc.c[5]); + std::swap(dc.c[3], dc.c[4]); + } + fwrite(reinterpret_cast(dc.c), 1, 8, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_short(short int _i, std::ostream& _out, bool _swap) +{ + union u1 { short int s; unsigned char c[2]; } sc; + sc.s = _i; + if (_swap) std::swap(sc.c[0], sc.c[1]); + _out.write(reinterpret_cast(sc.c), 2); +} + + +//----------------------------------------------------------------------------- + + +void write_int(int _i, std::ostream& _out, bool _swap) +{ + union u2 { int i; unsigned char c[4]; } ic; + ic.i = _i; + if (_swap) { + std::swap(ic.c[0], ic.c[3]); + std::swap(ic.c[1], ic.c[2]); + } + _out.write(reinterpret_cast(ic.c), 4); +} + + +//----------------------------------------------------------------------------- + + +void write_float(float _f, std::ostream& _out, bool _swap) +{ + union u3 { float f; unsigned char c[4]; } fc; + fc.f = _f; + if (_swap) { + std::swap(fc.c[0], fc.c[3]); + std::swap(fc.c[1], fc.c[2]); + } + _out.write(reinterpret_cast(fc.c), 4); +} + + +//----------------------------------------------------------------------------- + + +void write_double(double _d, std::ostream& _out, bool _swap) +{ + union u4 { double d; unsigned char c[8]; } dc; + dc.d = _d; + if (_swap) { + std::swap(dc.c[0], dc.c[7]); + std::swap(dc.c[1], dc.c[6]); + std::swap(dc.c[2], dc.c[5]); + std::swap(dc.c[3], dc.c[4]); + } + _out.write(reinterpret_cast(dc.c), 8); +} + + +#endif + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/BinaryHelper.hh b/Sources/OpenMeshCore/Core/IO/BinaryHelper.hh new file mode 100644 index 0000000..3cbf895 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/BinaryHelper.hh @@ -0,0 +1,159 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_BINARY_HELPER_HH +#define OPENMESH_BINARY_HELPER_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#if defined( OM_CC_MIPS ) +# include +#else +# include +#endif +#include +// -------------------- OpenMesh + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + +//----------------------------------------------------------------------------- + + +/** Binary read a \c short from \c _is and perform byte swapping if + \c _swap is true */ +short int read_short(FILE* _in, bool _swap=false); + +/** Binary read an \c int from \c _is and perform byte swapping if + \c _swap is true */ +int read_int(FILE* _in, bool _swap=false); + +/** Binary read a \c float from \c _is and perform byte swapping if + \c _swap is true */ +float read_float(FILE* _in, bool _swap=false); + +/** Binary read a \c double from \c _is and perform byte swapping if + \c _swap is true */ +double read_double(FILE* _in, bool _swap=false); + +/** Binary read a \c short from \c _is and perform byte swapping if + \c _swap is true */ +short int read_short(std::istream& _in, bool _swap=false); + +/** Binary read an \c int from \c _is and perform byte swapping if + \c _swap is true */ +int read_int(std::istream& _in, bool _swap=false); + +/** Binary read a \c float from \c _is and perform byte swapping if + \c _swap is true */ +float read_float(std::istream& _in, bool _swap=false); + +/** Binary read a \c double from \c _is and perform byte swapping if + \c _swap is true */ +double read_double(std::istream& _in, bool _swap=false); + + +/** Binary write a \c short to \c _os and perform byte swapping if + \c _swap is true */ +void write_short(short int _i, FILE* _out, bool _swap=false); + +/** Binary write an \c int to \c _os and perform byte swapping if + \c _swap is true */ +void write_int(int _i, FILE* _out, bool _swap=false); + +/** Binary write a \c float to \c _os and perform byte swapping if + \c _swap is true */ +void write_float(float _f, FILE* _out, bool _swap=false); + +/** Binary write a \c double to \c _os and perform byte swapping if + \c _swap is true */ +void write_double(double _d, FILE* _out, bool _swap=false); + +/** Binary write a \c short to \c _os and perform byte swapping if + \c _swap is true */ +void write_short(short int _i, std::ostream& _out, bool _swap=false); + +/** Binary write an \c int to \c _os and perform byte swapping if + \c _swap is true */ +void write_int(int _i, std::ostream& _out, bool _swap=false); + +/** Binary write a \c float to \c _os and perform byte swapping if + \c _swap is true */ +void write_float(float _f, std::ostream& _out, bool _swap=false); + +/** Binary write a \c double to \c _os and perform byte swapping if + \c _swap is true */ +void write_double(double _d, std::ostream& _out, bool _swap=false); + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/IO/IOInstances.hh b/Sources/OpenMeshCore/Core/IO/IOInstances.hh new file mode 100644 index 0000000..6e0b085 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/IOInstances.hh @@ -0,0 +1,112 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper file for static builds +// +// In opposite to dynamic builds where the instance of every reader module +// is generated within the OpenMesh library, static builds only instanciate +// objects that are at least referenced once. As all reader modules are +// never used directly, they will not be part of a static build, hence +// this file. +// +//============================================================================= + + +#ifndef __IOINSTANCES_HH__ +#define __IOINSTANCES_HH__ + +#if defined(OM_STATIC_BUILD) || defined(ARCH_DARWIN) + +//============================================================================= + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + +//============================================================================= + + +// Instanciate every Reader module +static BaseReader* OFFReaderInstance = &OFFReader(); +static BaseReader* OBJReaderInstance = &OBJReader(); +static BaseReader* PLYReaderInstance = &PLYReader(); +static BaseReader* STLReaderInstance = &STLReader(); +static BaseReader* OMReaderInstance = &OMReader(); + +// Instanciate every writer module +static BaseWriter* OBJWriterInstance = &OBJWriter(); +static BaseWriter* OFFWriterInstance = &OFFWriter(); +static BaseWriter* STLWriterInstance = &STLWriter(); +static BaseWriter* OMWriterInstance = &OMWriter(); +static BaseWriter* PLYWriterInstance = &PLYWriter(); +static BaseWriter* VTKWriterInstance = &VTKWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // static ? +#endif //__IOINSTANCES_HH__ +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/IOManager.cc b/Sources/OpenMeshCore/Core/IO/IOManager.cc new file mode 100644 index 0000000..f109c37 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/IOManager.cc @@ -0,0 +1,336 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the OpenMesh IOManager singleton +// +//============================================================================= + + +//== INCLUDES ================================================================= + + +#include + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + +// Destructor never called. Moved into singleton getter function +// _IOManager_ *__IOManager_instance = 0; + +_IOManager_& IOManager() +{ + + static _IOManager_ __IOManager_instance; + + //if (!__IOManager_instance) + // __IOManager_instance = new _IOManager_(); + + return __IOManager_instance; +} + +//----------------------------------------------------------------------------- + +bool +_IOManager_:: +read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + std::set::const_iterator it = reader_modules_.begin(); + std::set::const_iterator it_end = reader_modules_.end(); + + if( it == it_end ) + { + omerr() << "[OpenMesh::IO::_IOManager_] No reading modules available!\n"; + return false; + } + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->can_u_read(_filename)) + { + _bi.prepare(); + bool ok = (*it)->read(_filename, _bi, _opt); + _bi.finish(); + return ok; + } + + // All modules failed to read + return false; +} + + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +read(std::istream& _is, const std::string& _ext, BaseImporter& _bi, Options& _opt) +{ + std::set::const_iterator it = reader_modules_.begin(); + std::set::const_iterator it_end = reader_modules_.end(); + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->BaseReader::can_u_read(_ext)) //Use the extension check only (no file existence) + { + _bi.prepare(); + bool ok = (*it)->read(_is, _bi, _opt); + _bi.finish(); + return ok; + } + + // All modules failed to read + return false; +} + + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) +{ + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + + if ( it == it_end ) + { + omerr() << "[OpenMesh::IO::_IOManager_] No writing modules available!\n"; + return false; + } + + // Try all registered modules + for(; it != it_end; ++it) + { + if ((*it)->can_u_write(_filename)) + { + return (*it)->write(_filename, _be, _opt, _precision); + } + } + + // All modules failed to save + return false; +} + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +write(std::ostream& _os,const std::string &_ext, BaseExporter& _be, Options _opt, std::streamsize _precision) +{ + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + + if ( it == it_end ) + { + omerr() << "[OpenMesh::IO::_IOManager_] No writing modules available!\n"; + return false; + } + + // Try all registered modules + for(; it != it_end; ++it) + { + if ((*it)->BaseWriter::can_u_write(_ext)) //Restrict test to the extension check + { + return (*it)->write(_os, _be, _opt, _precision); + } + } + + // All modules failed to save + return false; +} + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +can_read( const std::string& _format ) const +{ + std::set::const_iterator it = reader_modules_.begin(); + std::set::const_iterator it_end = reader_modules_.end(); + std::string filename = "dummy." + _format; + + for(; it != it_end; ++it) + if ((*it)->can_u_read(filename)) + return true; + + return false; +} + + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +can_write( const std::string& _format ) const +{ + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + std::string filename = "dummy." + _format; + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->can_u_write(filename)) + return true; + + return false; +} + + +//----------------------------------------------------------------------------- + + +const BaseWriter* +_IOManager_:: +find_writer(const std::string& _format) +{ + using std::string; + + string::size_type dotpos = _format.rfind('.'); + + string ext; + if (dotpos == string::npos) + ext = _format; + else + ext = _format.substr(dotpos+1,_format.length()-(dotpos+1)); + + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + std::string filename = "dummy." + ext; + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->can_u_write(filename)) + return *it; + + return nullptr; +} + + +//----------------------------------------------------------------------------- + + +void +_IOManager_:: +update_read_filters() +{ + std::set::const_iterator it = reader_modules_.begin(), + it_end = reader_modules_.end(); + std::string all = ""; + std::string filters = ""; + + for(; it != it_end; ++it) + { + // Initialized with space, as a workaround for debug build with clang on mac + // which crashes if tmp is initialized with an empty string ?! + std::string tmp = " "; + + filters += (*it)->get_description() + " ("; + + std::istringstream iss((*it)->get_extensions()); + + while (iss && !iss.eof() && (iss >> tmp) ) + { + tmp = " *." + tmp; filters += tmp; all += tmp; + } + + filters += " );;"; + } + + all = "All files ( " + all + " );;"; + + read_filters_ = all + filters; +} + + +//----------------------------------------------------------------------------- + + +void +_IOManager_:: +update_write_filters() +{ + std::set::const_iterator it = writer_modules_.begin(), + it_end = writer_modules_.end(); + std::string all; + std::string filters; + + for(; it != it_end; ++it) + { + // Initialized with space, as a workaround for debug build with clang on mac + // which crashes if tmp is initialized with an empty string ?! + std::string s = " "; + + filters += (*it)->get_description() + " ("; + + std::istringstream iss((*it)->get_extensions()); + while (iss && !iss.eof() && (iss >> s)) + { s = " *." + s; filters += s; all += s; } + + filters += " );;"; + } + all = "All files ( " + all + " );;"; + + write_filters_ = all + filters; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/IOManager.hh b/Sources/OpenMeshCore/Core/IO/IOManager.hh new file mode 100644 index 0000000..6fa823a --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/IOManager.hh @@ -0,0 +1,267 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// Implements the OpenMesh IOManager singleton +// +//============================================================================= + +#ifndef __IOMANAGER_HH__ +#define __IOMANAGER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include +#include +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** This is the real IOManager class that is later encapsulated by + SingletonT to enforce its uniqueness. _IOManager_ is not meant to be used + directly by the programmer - the IOManager alias exists for this task. + + All reader/writer modules register themselves at this class. For + reading or writing data all modules are asked to do the job. If no + suitable module is found, an error is returned. + + For the sake of reading, the target data structure is hidden + behind the BaseImporter interface that takes care of adding + vertices or faces. + + Writing from a source structure is encapsulate similarly behind a + BaseExporter interface, providing iterators over vertices/faces to + the writer modules. + + \see \ref mesh_io +*/ + +class OPENMESHDLLEXPORT _IOManager_ +{ +private: + + /// Constructor has nothing todo for the Manager + _IOManager_() {} + + /// Destructor has nothing todo for the Manager + ~_IOManager_() {}; + + /** Declare the singleton getter function as friend to access the private constructor + and destructor + */ + friend OPENMESHDLLEXPORT _IOManager_& IOManager(); + +public: + + /** + Read a mesh from file _filename. The target data structure is specified + by the given BaseImporter. The \c read method consecutively queries all + of its reader modules. True is returned upon success, false if all + reader modules failed to interprete _filename. + */ + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + +/** + Read a mesh from open std::istream _is. The target data structure is specified + by the given BaseImporter. The \c sread method consecutively queries all + of its reader modules. True is returned upon success, false if all + reader modules failed to use _is. + */ + bool read(std::istream& _filename, + const std::string& _ext, + BaseImporter& _bi, + Options& _opt); + + + /** Write a mesh to file _filename. The source data structure is specified + by the given BaseExporter. The \c save method consecutively queries all + of its writer modules. True is returned upon success, false if all + writer modules failed to write the requested format. + Options is determined by _filename's extension. + */ + bool write(const std::string& _filename, + BaseExporter& _be, + Options _opt=Options::Default, + std::streamsize _precision = 6); + +/** Write a mesh to open std::ostream _os. The source data structure is specified + by the given BaseExporter. The \c save method consecutively queries all + of its writer modules. True is returned upon success, false if all + writer modules failed to write the requested format. + Options is determined by _filename's extension. + */ + bool write(std::ostream& _filename, + const std::string& _ext, + BaseExporter& _be, + Options _opt=Options::Default, + std::streamsize _precision = 6); + + + /// Returns true if the format is supported by one of the reader modules. + bool can_read( const std::string& _format ) const; + + /// Returns true if the format is supported by one of the writer modules. + bool can_write( const std::string& _format ) const; + + + size_t binary_size(const std::string& _format, + BaseExporter& _be, + Options _opt = Options::Default) + { + const BaseWriter *bw = find_writer(_format); + return bw ? bw->binary_size(_be,_opt) : 0; + } + + + +public: //-- QT convenience function ------------------------------------------ + + + /** Returns all readable file extension + descriptions in one string. + File formats are separated by ;;. + Convenience function for Qt file dialogs. + */ + const std::string& qt_read_filters() const { return read_filters_; } + + + /** Returns all writeable file extension + descriptions in one string. + File formats are separated by ;;. + Convenience function for Qt file dialogs. + */ + const std::string& qt_write_filters() const { return write_filters_; } + + + +private: + + // collect all readable file extensions + void update_read_filters(); + + + // collect all writeable file extensions + void update_write_filters(); + + + +public: //-- SYSTEM PART------------------------------------------------------ + + + /** Registers a new reader module. A call to this function should be + implemented in the constructor of all classes derived from BaseReader. + */ + bool register_module(BaseReader* _bl) + { + reader_modules_.insert(_bl); + update_read_filters(); + return true; + } + + + + /** Registers a new writer module. A call to this function should be + implemented in the constructor of all classed derived from BaseWriter. + */ + bool register_module(BaseWriter* _bw) + { + writer_modules_.insert(_bw); + update_write_filters(); + return true; + } + + +private: + + const BaseWriter *find_writer(const std::string& _format); + + // stores registered reader modules + std::set reader_modules_; + + // stores registered writer modules + std::set writer_modules_; + + // input filters (e.g. for Qt file dialog) + std::string read_filters_; + + // output filters (e.g. for Qt file dialog) + std::string write_filters_; +}; + + +//============================================================================= + + +//_IOManager_* __IOManager_instance; Causes memory leak, as destructor is never called + +OPENMESHDLLEXPORT _IOManager_& IOManager(); + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/MeshIO.hh b/Sources/OpenMeshCore/Core/IO/MeshIO.hh new file mode 100644 index 0000000..66c0819 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/MeshIO.hh @@ -0,0 +1,274 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef OM_MESHIO_HH +#define OM_MESHIO_HH + + +//=== INCLUDES ================================================================ + +// -------------------- system settings +#include + +// -------------------- OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Convenience functions the map to IOManager functions. + \see OpenMesh::IO::_IOManager_ +*/ +//@{ + + +//----------------------------------------------------------------------------- + + +/** \brief Read a mesh from file _filename. + + The file format is determined by the file extension. + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The target mesh that will be filled with the read data + @param _filename fill to load + + @return Successful? + */ +template +bool +read_mesh(Mesh& _mesh, + const std::string& _filename) +{ + Options opt; + return read_mesh(_mesh, _filename, opt, true); +} + + +/** \brief Read a mesh from file _filename. + + The file format is determined by the file extension. + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The target mesh that will be filled with the read data + @param _filename fill to load + @param _opt Reader options (e.g. skip loading of normals ... depends + on the reader capabilities). Note that simply passing an + Options::Flag enum is not sufficient. + @param _clear Clear the target data before filling it (allows to + load multiple files into one Mesh). If you only want to read a mesh + without clearing set _clear to false. Providing a default Options + object is sufficient in this case. + + @return Successful? +*/ +template +bool +read_mesh(Mesh& _mesh, + const std::string& _filename, + Options& _opt, + bool _clear = true) +{ + if (_clear) _mesh.clear(); + ImporterT importer(_mesh); + return IOManager().read(_filename, importer, _opt); +} + + +/** \brief Read a mesh from file open std::istream. + + The file format is determined by parameter _ext. _ext has to include + ".[format]" in order to work properly (e.g. ".OFF") + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The target mesh that will be filled with the read data + @param _is stream to load the data from + @param _ext The file format that is written to the stream + @param _opt Reader options (e.g. skip loading of normals ... depends + on the reader capabilities) + @param _clear Clear the target data before filling it (allows to + load multiple files into one Mesh) + + @return Successful? +*/ +template +bool +read_mesh(Mesh& _mesh, + std::istream& _is, + const std::string& _ext, + Options& _opt, + bool _clear = true) +{ + if (_clear) _mesh.clear(); + ImporterT importer(_mesh); + return IOManager().read(_is,_ext, importer, _opt); +} + + + +//----------------------------------------------------------------------------- + + +/** \brief Write a mesh to the file _filename. + + The file format is determined by _filename's extension. + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The mesh that will be written to file + @param _filename output filename + @param _opt Writer options (e.g. writing of normals ... depends + on the writer capabilities) + @param _precision specifies stream precision for ascii files + + @return Successful? +*/ +template +bool write_mesh(const Mesh& _mesh, + const std::string& _filename, + Options _opt = Options::Default, + std::streamsize _precision = 6) +{ + ExporterT exporter(_mesh); + return IOManager().write(_filename, exporter, _opt, _precision); +} + + +//----------------------------------------------------------------------------- + + +/** Write a mesh to an open std::ostream. + + The file format is determined by parameter _ext. _ext has to include + ".[format]" in order to work properly (e.g. ".OFF") + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The mesh that will be written to file + @param _os output stream to write into + @param _ext extension defining the type of output + @param _opt Writer options (e.g. writing of normals ... depends + on the writer capabilities) + @param _precision specifies stream precision for ascii files + + @return Successful? +*/ +template +bool write_mesh(const Mesh& _mesh, + std::ostream& _os, + const std::string& _ext, + Options _opt = Options::Default, + std::streamsize _precision = 6) +{ + ExporterT exporter(_mesh); + return IOManager().write(_os,_ext, exporter, _opt, _precision); +} + + +//----------------------------------------------------------------------------- + +/** \brief Get binary size of data + + This function calls the corresponding writer which calculates the size + of the data that would be written to a binary file + + The file format is determined by parameter _ext. _ext has to include + ".[format]" in order to work properly (e.g. ".OFF") + + @param _mesh Mesh to write + @param _ext extension of the file (used to determine the writing module) + @param _opt Writer options (e.g. writing of normals ... depends + on the writer capabilities) + + @return Binary size in bytes used when writing the data +*/ +template +size_t binary_size(const Mesh& _mesh, + const std::string& _ext, + Options _opt = Options::Default) +{ + ExporterT exporter(_mesh); + return IOManager().binary_size(_ext, exporter, _opt); +} + + +//----------------------------------------------------------------------------- + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#if defined(OM_STATIC_BUILD) || defined(ARCH_DARWIN) +# include +#endif +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/OFFFormat.hh b/Sources/OpenMeshCore/Core/IO/OFFFormat.hh new file mode 100644 index 0000000..79ab28d --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/OFFFormat.hh @@ -0,0 +1,94 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef OPENMESH_IO_OFFFORMAT_HH +#define OPENMESH_IO_OFFFORMAT_HH + + +//=== INCLUDES ================================================================ + + +// OpenMesh +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Option for writer modules. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +#ifndef DOXY_IGNORE_THIS + +struct OPENMESHDLLEXPORT OFFFormat +{ + typedef int integer_type; + typedef float float_type; +}; + +#endif + + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/OMFormat.cc b/Sources/OpenMeshCore/Core/IO/OMFormat.cc new file mode 100644 index 0000000..bf75692 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/OMFormat.cc @@ -0,0 +1,258 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { +namespace OMFormat { + +//== IMPLEMENTATION =========================================================== + + Chunk::Integer_Size needed_bits( size_t s ) + { + if (s <= 0x000100) return Chunk::Integer_8; + if (s <= 0x010000) return Chunk::Integer_16; + +#if 0 + // !Not tested yet! This most probably won't work! + // NEED a 64bit system! + if ( (sizeof( size_t ) == 8) && (s >= 0x100000000) ) + return Chunk::Integer_64; +#endif + + return Chunk::Integer_32; + } + +//----------------------------------------------------------------------------- + + uint16& + operator << (uint16& val, const Chunk::Header& hdr) + { + val = 0; + val |= hdr.name_ << OMFormat::Chunk::OFF_NAME; + val |= hdr.entity_ << OMFormat::Chunk::OFF_ENTITY; + val |= hdr.type_ << OMFormat::Chunk::OFF_TYPE; + val |= hdr.signed_ << OMFormat::Chunk::OFF_SIGNED; + val |= hdr.float_ << OMFormat::Chunk::OFF_FLOAT; + val |= hdr.dim_ << OMFormat::Chunk::OFF_DIM; + val |= hdr.bits_ << OMFormat::Chunk::OFF_BITS; + return val; + } + + +//----------------------------------------------------------------------------- + + Chunk::Header& + operator << (Chunk::Header& hdr, const uint16 val) + { + hdr.reserved_ = 0; + hdr.name_ = val >> OMFormat::Chunk::OFF_NAME; + hdr.entity_ = val >> OMFormat::Chunk::OFF_ENTITY; + hdr.type_ = val >> OMFormat::Chunk::OFF_TYPE; + hdr.signed_ = val >> OMFormat::Chunk::OFF_SIGNED; + hdr.float_ = val >> OMFormat::Chunk::OFF_FLOAT; + hdr.dim_ = val >> OMFormat::Chunk::OFF_DIM; + hdr.bits_ = val >> OMFormat::Chunk::OFF_BITS; + return hdr; + } + +//----------------------------------------------------------------------------- + + + std::string as_string(uint8 version) + { + std::stringstream ss; + ss << major_version(version); + ss << "."; + ss << minor_version(version); + return ss.str(); + } + + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Entity e) + { + switch(e) + { + case Chunk::Entity_Vertex: return "Vertex"; + case Chunk::Entity_Mesh: return "Mesh"; + case Chunk::Entity_Edge: return "Edge"; + case Chunk::Entity_Halfedge: return "Halfedge"; + case Chunk::Entity_Face: return "Face"; + default: + std::clog << "as_string(Chunk::Entity): Invalid value!"; + } + return nullptr; + } + + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Type t) + { + switch(t) + { + case Chunk::Type_Pos: return "Pos"; + case Chunk::Type_Normal: return "Normal"; + case Chunk::Type_Texcoord: return "Texcoord"; + case Chunk::Type_Status: return "Status"; + case Chunk::Type_Color: return "Color"; + case Chunk::Type_Custom: return "Custom"; + case Chunk::Type_Topology: return "Topology"; + } + return nullptr; + } + + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Dim d) + { + switch(d) + { + case Chunk::Dim_1D: return "1D"; + case Chunk::Dim_2D: return "2D"; + case Chunk::Dim_3D: return "3D"; + case Chunk::Dim_4D: return "4D"; + case Chunk::Dim_5D: return "5D"; + case Chunk::Dim_6D: return "6D"; + case Chunk::Dim_7D: return "7D"; + case Chunk::Dim_8D: return "8D"; + } + return nullptr; + } + + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Integer_Size d) + { + switch(d) + { + case Chunk::Integer_8 : return "8"; + case Chunk::Integer_16 : return "16"; + case Chunk::Integer_32 : return "32"; + case Chunk::Integer_64 : return "64"; + } + return nullptr; + } + + const char *as_string(Chunk::Float_Size d) + { + switch(d) + { + case Chunk::Float_32 : return "32"; + case Chunk::Float_64 : return "64"; + case Chunk::Float_128: return "128"; + } + return nullptr; + } + + +//----------------------------------------------------------------------------- + + std::ostream& operator << ( std::ostream& _os, const Chunk::Header& _c ) + { + _os << "Chunk Header : 0x" << std::setw(4) + << std::hex << (*(uint16*)(&_c)) << std::dec << '\n'; + _os << "entity = " + << as_string(Chunk::Entity(_c.entity_)) << '\n'; + _os << "type = " + << as_string(Chunk::Type(_c.type_)); + if ( Chunk::Type(_c.type_)!=Chunk::Type_Custom) + { + _os << '\n' + << "signed = " + << _c.signed_ << '\n'; + _os << "float = " + << _c.float_ << '\n'; + _os << "dim = " + << as_string(Chunk::Dim(_c.dim_)) << '\n'; + _os << "bits = " + << (_c.float_ + ? as_string(Chunk::Float_Size(_c.bits_)) + : as_string(Chunk::Integer_Size(_c.bits_))); + } + return _os; + } + + +//----------------------------------------------------------------------------- + + std::ostream& operator << ( std::ostream& _os, const Header& _h ) + { + _os << "magic = '" << _h.magic_[0] << _h.magic_[1] << "'\n" + << "mesh = '" << _h.mesh_ << "'\n" + << "version = 0x" << std::hex << (uint16)_h.version_ << std::dec + << " (" << major_version(_h.version_) + << "." << minor_version(_h.version_) << ")\n" + << "#V = " << _h.n_vertices_ << '\n' + << "#F = " << _h.n_faces_ << '\n' + << "#E = " << _h.n_edges_; + return _os; + } + + + //----------------------------------------------------------------------------- + + +} // namespace OMFormat + // -------------------------------------------------------------------------- + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/OMFormat.hh b/Sources/OpenMeshCore/Core/IO/OMFormat.hh new file mode 100644 index 0000000..4ba0dc7 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/OMFormat.hh @@ -0,0 +1,758 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef OPENMESH_IO_OMFORMAT_HH +#define OPENMESH_IO_OMFORMAT_HH + + +//=== INCLUDES ================================================================ + +#include +#include +#include +#include +#include +#include +// -------------------- +#include +#if defined(OM_CC_GCC) && (OM_GCC_VERSION < 30000) +# include +# define OM_MISSING_HEADER_LIMITS 1 +#else +# include +#endif + + +//== NAMESPACES ============================================================== + +#ifndef DOXY_IGNORE_THIS +namespace OpenMesh { +namespace IO { +namespace OMFormat { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing +*/ +//@{ + +//----------------------------------------------------------------------------- + + // <:Header> + // <:Comment> + // Chunk 0 + // <:ChunkHeader> + // <:Comment> + // data + // Chunk 1 + // <:ChunkHeader> + // <:Comment> + // data + // . + // . + // . + // Chunk N + + // + // NOTICE! + // + // The usage of data types who differ in size + // on different pc architectures (32/64 bit) and/or + // operating systems, e.g. (unsigned) long, size_t, + // is not recommended because of inconsistencies + // in case of cross writing and reading. + // + // Basic types that are supported are: + + + typedef unsigned char uchar; + typedef uint8_t uint8; + typedef uint16_t uint16; + typedef uint32_t uint32; + typedef uint64_t uint64; + typedef int8_t int8; + typedef int16_t int16; + typedef int32_t int32; + typedef int64_t int64; + typedef float32_t float32; + typedef float64_t float64; + + struct Header + { + uchar magic_[2]; // OM + uchar mesh_; // [T]riangles, [Q]uads, [P]olygonals + uint8 version_; + uint32 n_vertices_; + uint32 n_faces_; + uint32 n_edges_; + + size_t store( std::ostream& _os, bool _swap ) const + { + _os.write( (char*)this, 4); // magic_, mesh_, version_ + size_t bytes = 4; + bytes += binary::store( _os, n_vertices_, _swap ); + bytes += binary::store( _os, n_faces_, _swap ); + bytes += binary::store( _os, n_edges_, _swap ); + return bytes; + } + + size_t restore( std::istream& _is, bool _swap ) + { + if (_is.read( reinterpret_cast(this) , 4 ).eof()) + return 0; + + size_t bytes = 4; + bytes += binary::restore( _is, n_vertices_, _swap ); + bytes += binary::restore( _is, n_faces_, _swap ); + bytes += binary::restore( _is, n_edges_, _swap ); + return bytes; + } + + }; + + struct Chunk + { + // Hardcoded this size to an uint32 to make the system 32/64 bit compatible. + // Needs further investigation! + typedef uint32 esize_t; // element size, used for custom properties + + enum Type { + Type_Pos = 0x00, + Type_Normal = 0x01, + Type_Texcoord = 0x02, + Type_Status = 0x03, + Type_Color = 0x04, + Type_Custom = 0x06, + Type_Topology = 0x07 + }; + + enum Entity { + Entity_Vertex = 0x00, + Entity_Mesh = 0x01, + Entity_Face = 0x02, + Entity_Edge = 0x04, + Entity_Halfedge = 0x06, + Entity_Sentinel = 0x07 + }; + + enum Dim { + Dim_1D = 0x00, + Dim_2D = 0x01, + Dim_3D = 0x02, + Dim_4D = 0x03, + Dim_5D = 0x04, + Dim_6D = 0x05, + Dim_7D = 0x06, + Dim_8D = 0x07 + }; + + enum Integer_Size { + Integer_8 = 0x00, // 1 byte for (unsigned) char + Integer_16 = 0x01, // 2 bytes for short + Integer_32 = 0x02, // 4 bytes for long + Integer_64 = 0x03 // 8 bytes for long long + }; + + enum Float_Size { + Float_32 = 0x00, // 4 bytes for float + Float_64 = 0x01, // 8 bytes for double + Float_128 = 0x02 // 16 bytes for long double (an assumption!) + }; + + static const int SIZE_RESERVED = 1; // 1 + static const int SIZE_NAME = 1; // 2 + static const int SIZE_ENTITY = 3; // 5 + static const int SIZE_TYPE = 4; // 9 + + static const int SIZE_SIGNED = 1; // 10 + static const int SIZE_FLOAT = 1; // 11 + static const int SIZE_DIM = 3; // 14 + static const int SIZE_BITS = 2; // 16 + + static const int OFF_RESERVED = 0; // 0 + static const int OFF_NAME = SIZE_RESERVED + OFF_RESERVED; // 2 + static const int OFF_ENTITY = SIZE_NAME + OFF_NAME; // 3 + static const int OFF_TYPE = SIZE_ENTITY + OFF_ENTITY; // 5 + static const int OFF_SIGNED = SIZE_TYPE + OFF_TYPE; // 9 + static const int OFF_FLOAT = SIZE_SIGNED + OFF_SIGNED; // 10 + static const int OFF_DIM = SIZE_FLOAT + OFF_FLOAT; // 11 + static const int OFF_BITS = SIZE_DIM + OFF_DIM; // 14 + + // !Attention! When changing the bit size, the operators + // << (uint16, Header) and << (Header, uint16) must be changed as well + // + // Entries signed_, float_, dim_, bits_ are not used when type_ + // equals Type_Custom + // + struct Header // 16 bits long + { + unsigned reserved_: SIZE_RESERVED; + unsigned name_ : SIZE_NAME; // 1 named property, 0 anonymous + unsigned entity_ : SIZE_ENTITY; // 0 vertex, 1 mesh, 2 edge, + // 4 halfedge, 6 face + unsigned type_ : SIZE_TYPE; // 0 pos, 1 normal, 2 texcoord, + // 3 status, 4 color 6 custom 7 topology + unsigned signed_ : SIZE_SIGNED; // bool + unsigned float_ : SIZE_FLOAT; // bool + unsigned dim_ : SIZE_DIM; // 0 1D, 1 2D, 2 3D, .., 7 8D + unsigned bits_ : SIZE_BITS; // {8, 16, 32, 64} | {32, 64, 128} + // (integer) (float) + unsigned unused_ : 16; // fill up to 32 bits + }; // struct Header + + + class PropertyName : public std::string + { + public: + + static const size_t size_max = 256; + + PropertyName( ) { } + + explicit PropertyName( const std::string& _name ) { *this = _name; } + + bool is_valid() const { return is_valid( size() ); } + + static bool is_valid( size_t _s ) { return _s <= size_max; } + + PropertyName& operator = ( const std::string& _rhs ) + { + assert( is_valid( _rhs.size() ) ); + + if ( is_valid( _rhs.size() ) ) + std::string::operator = ( _rhs ); + else + { + omerr() << "Warning! Property name too long. Will be shortened!\n"; + this->std::string::operator = ( _rhs.substr(0, size_max) ); + } + + return *this; + } + + }; + + }; // Chunk + + // ------------------------------------------------------------ Helper + // -------------------- get size information + + /// Return size of header in bytes. + inline size_t header_size(void) { return sizeof(Header); } + + + /// Return size of chunk header in bytes. + inline size_t chunk_header_size( void ) { return sizeof(uint16); } + + + /// Return the size of a scaler in bytes. + inline size_t scalar_size( const Chunk::Header& _hdr ) + { + return _hdr.float_ ? (0x01 << _hdr.bits_) : (0x04 << _hdr.bits_); + } + + + /// Return the dimension of the vector in a chunk + inline size_t dimensions(const Chunk::Header& _chdr) { return _chdr.dim_+1; } + + + /// Return the size of a vector in bytes. + inline size_t vector_size( const Chunk::Header& _chdr ) + { + return dimensions(_chdr)*scalar_size(_chdr); + } + + + /// Return the size of chunk data in bytes + inline size_t chunk_data_size( const Header& _hdr, const Chunk::Header& _chunk_hdr ) + { + size_t C; + switch( _chunk_hdr.entity_ ) + { + case Chunk::Entity_Vertex: C = _hdr.n_vertices_; break; + case Chunk::Entity_Face: C = _hdr.n_faces_; break; + case Chunk::Entity_Halfedge: C = _hdr.n_edges_*2; break; + case Chunk::Entity_Edge: C = _hdr.n_edges_; break; + case Chunk::Entity_Mesh: C = 1; break; + default: + C = 0; + std::cerr << "Invalid value in _chunk_hdr.entity_\n"; + assert( false ); + break; + } + + return C * vector_size( _chunk_hdr ); + } + + inline size_t chunk_size( const Header& _hdr, const Chunk::Header& _chunk_hdr ) + { + return chunk_header_size() + chunk_data_size( _hdr, _chunk_hdr ); + } + + // -------------------- convert from Chunk::Header to storage type + + uint16& operator << (uint16& val, const Chunk::Header& hdr); + Chunk::Header& operator << (Chunk::Header& hdr, const uint16 val); + + + // -------------------- type information + + template bool is_float(const T&) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return !Utils::NumLimitsT::is_integer(); +#else + return !std::numeric_limits::is_integer; +#endif + } + + template bool is_double(const T&) + { + return false; + } + + template <> inline bool is_double(const double&) + { + return true; + } + + template bool is_integer(const T) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return Utils::NumLimitsT::is_integer(); +#else + return std::numeric_limits::is_integer; +#endif + } + + template bool is_signed(const T&) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return Utils::NumLimitsT::is_signed(); +#else + return std::numeric_limits::is_signed; +#endif + } + + // -------------------- conversions (format type <- type/value) + + template + inline + Chunk::Dim dim( VecType ) + { + assert( vector_traits< VecType >::size() < 9 ); + return static_cast(vector_traits< VecType >::size() - 1); + } + + template + inline + Chunk::Dim dim( const Chunk::Header& _hdr ) + { + return static_cast( _hdr.dim_ ); + } + + // calc minimum (power-of-2) number of bits needed + Chunk::Integer_Size needed_bits( size_t s ); + + // Convert size of type to Integer_Size +#ifdef NDEBUG + template Chunk::Integer_Size integer_size(const T&) +#else + template Chunk::Integer_Size integer_size(const T& d) +#endif + { +#ifndef NDEBUG + assert( is_integer(d) ); +#endif + + switch( sizeof(T) ) + { + case 1: return OMFormat::Chunk::Integer_8; + case 2: return OMFormat::Chunk::Integer_16; + case 4: return OMFormat::Chunk::Integer_32; + case 8: return OMFormat::Chunk::Integer_64; + default: + std::cerr << "Invalid value in integer_size\n"; + assert( false ); + break; + } + return Chunk::Integer_Size(0); + } + + + // Convert size of type to FLoat_Size +#ifdef NDEBUG + template Chunk::Float_Size float_size(const T&) +#else + template Chunk::Float_Size float_size(const T& d) +#endif + { +#ifndef NDEBUG + assert( is_float(d) ); +#endif + + switch( sizeof(T) ) + { + case 4: return OMFormat::Chunk::Float_32; + case 8: return OMFormat::Chunk::Float_64; + case 16: return OMFormat::Chunk::Float_128; + default: + std::cerr << "Invalid value in float_size\n"; + assert( false ); + break; + } + return Chunk::Float_Size(0); + } + + // Return the storage type (Chunk::Header::bits_) + template + inline + unsigned int bits(const T& val) + { + return is_integer(val) + ? (static_cast(integer_size(val))) + : (static_cast(float_size(val))); + } + + // -------------------- create/read version + + inline uint8 mk_version(const uint16 major, const uint16 minor) + { return (major & 0x07) << 5 | (minor & 0x1f); } + + + inline uint16 major_version(const uint8 version) + { return (version >> 5) & 0x07; } + + + inline uint16 minor_version(const uint8 version) + { return (version & 0x001f); } + + + // ---------------------------------------- convenience functions + + std::string as_string(uint8 version); + + const char *as_string(Chunk::Type t); + const char *as_string(Chunk::Entity e); + const char *as_string(Chunk::Dim d); + const char *as_string(Chunk::Integer_Size d); + const char *as_string(Chunk::Float_Size d); + + std::ostream& operator << ( std::ostream& _os, const Header& _h ); + std::ostream& operator << ( std::ostream& _os, const Chunk::Header& _c ); + +//@} +} // namespace OMFormat + + // -------------------- (re-)store header + + template <> inline + size_t store( std::ostream& _os, const OMFormat::Header& _hdr, bool _swap) + { return _hdr.store( _os, _swap ); } + + template <> inline + size_t restore( std::istream& _is, OMFormat::Header& _hdr, bool _swap ) + { return _hdr.restore( _is, _swap ); } + + + // -------------------- (re-)store chunk header + + template <> inline + size_t + store( std::ostream& _os, const OMFormat::Chunk::Header& _hdr, bool _swap) + { + OMFormat::uint16 val; + val << _hdr; + return binary::store( _os, val, _swap ); + } + + template <> inline + size_t + restore( std::istream& _is, OMFormat::Chunk::Header& _hdr, bool _swap ) + { + OMFormat::uint16 val; + size_t bytes = binary::restore( _is, val, _swap ); + + _hdr << val; + + return bytes; + } + + // -------------------- (re-)store integer with wanted number of bits (bytes) + + typedef GenProg::TrueType t_signed; + typedef GenProg::FalseType t_unsigned; + + // helper to store a an integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed); + + // helper to store a an unsigned integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned); + + /// Store an integer with a wanted number of bits + template< typename T > + inline + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap) + { + assert( OMFormat::is_integer( _val ) ); + + if ( OMFormat::is_signed( _val ) ) + return store( _os, _val, _b, _swap, t_signed() ); + return store( _os, _val, _b, _swap, t_unsigned() ); + } + + // helper to store a an integer + template< typename T > inline + size_t restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed); + + // helper to store a an unsigned integer + template< typename T > inline + size_t restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned); + + /// Restore an integer with a wanted number of bits + template< typename T > + inline + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap) + { + assert( OMFormat::is_integer( _val ) ); + + if ( OMFormat::is_signed( _val ) ) + return restore( _is, _val, _b, _swap, t_signed() ); + return restore( _is, _val, _b, _swap, t_unsigned() ); + } + + + // + // ---------------------------------------- storing vectors + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<2>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<3>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + bytes += store( _os, _vec[2], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<4>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + bytes += store( _os, _vec[2], _swap ); + bytes += store( _os, _vec[3], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<1>, + bool _swap ) + { + return store( _os, _vec[0], _swap ); + } + + /// storing a vector type + template inline + size_t vector_store( std::ostream& _os, const VecT& _vec, bool _swap ) + { + return store( _os, _vec, + GenProg::Int2Type< vector_traits::size_ >(), + _swap ); + } + + // ---------------------------------------- restoring vectors + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<2>, + bool _swap ) + { + size_t bytes = restore( _is, _vec[0], _swap ); + bytes += restore( _is, _vec[1], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<3>, + bool _swap ) + { + typedef typename vector_traits::value_type scalar_type; + size_t bytes; + + bytes = binary::restore( _is, _vec[0], _swap ); + bytes += binary::restore( _is, _vec[1], _swap ); + bytes += binary::restore( _is, _vec[2], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<4>, + bool _swap ) + { + typedef typename vector_traits::value_type scalar_type; + size_t bytes; + + bytes = binary::restore( _is, _vec[0], _swap ); + bytes += binary::restore( _is, _vec[1], _swap ); + bytes += binary::restore( _is, _vec[2], _swap ); + bytes += binary::restore( _is, _vec[3], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<1>, + bool _swap ) + { + return restore( _is, _vec[0], _swap ); + } + + /// Restoring a vector type + template + inline + size_t + vector_restore( std::istream& _is, VecT& _vec, bool _swap ) + { + return restore( _is, _vec, + GenProg::Int2Type< vector_traits::size_ >(), + _swap ); + } + + + // ---------------------------------------- storing property names + + template <> + inline + size_t store( std::ostream& _os, const OMFormat::Chunk::PropertyName& _pn, + bool _swap ) + { + store( _os, _pn.size(), OMFormat::Chunk::Integer_8, _swap ); // 1 byte + if ( _pn.size() ) + _os.write( _pn.c_str(), _pn.size() ); // size bytes + return _pn.size() + 1; + } + + template <> + inline + size_t restore( std::istream& _is, OMFormat::Chunk::PropertyName& _pn, + bool _swap ) + { + size_t size; + + restore( _is, size, OMFormat::Chunk::Integer_8, _swap); // 1 byte + + assert( OMFormat::Chunk::PropertyName::is_valid( size ) ); + + if ( size > 0 ) + { + char buf[256]; + _is.read( buf, size ); // size bytes + buf[size] = '\0'; + _pn.resize(size); + _pn = buf; + } + return size+1; + } + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +#endif +//============================================================================= +#if defined(OM_MISSING_HEADER_LIMITS) +# undef OM_MISSING_HEADER_LIMITS +#endif +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_IO_OMFORMAT_CC) +# define OPENMESH_IO_OMFORMAT_TEMPLATES +# include "OMFormatT_impl.hh" +#endif +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/OMFormatT_impl.hh b/Sources/OpenMeshCore/Core/IO/OMFormatT_impl.hh new file mode 100644 index 0000000..e512ba9 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/OMFormatT_impl.hh @@ -0,0 +1,240 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#define OPENMESH_IO_OMFORMAT_CC + + +//== INCLUDES ================================================================= + +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + // helper to store a an integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed) + { + assert( OMFormat::is_integer( _val ) ); + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::int8 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::int16 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::int32 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_64: + { + OMFormat::int64 v = static_cast(_val); + return store( _os, v, _swap ); + } + } + return 0; + } + + + // helper to store a an unsigned integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned) + { + assert( OMFormat::is_integer( _val ) ); + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::uint8 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::uint16 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::uint32 v = static_cast(_val); + return store( _os, v, _swap ); + } + + case OMFormat::Chunk::Integer_64: + { + OMFormat::uint64 v = static_cast(_val); + return store( _os, v, _swap ); + } + } + return 0; + } + + + // helper to restore a an integer + template< typename T > + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed) + { + assert( OMFormat::is_integer( _val ) ); + size_t bytes = 0; + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::int8 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::int16 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::int32 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_64: + { + OMFormat::int64 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + } + return bytes; + } + + + // helper to restore a an unsigned integer + template< typename T > + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned) + { + assert( OMFormat::is_integer( _val ) ); + size_t bytes = 0; + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::uint8 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::uint16 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::uint32 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + + case OMFormat::Chunk::Integer_64: + { + OMFormat::uint64 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + } + return bytes; + } + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/Options.hh b/Sources/OpenMeshCore/Core/IO/Options.hh new file mode 100644 index 0000000..74c54d4 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/Options.hh @@ -0,0 +1,239 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef OPENMESH_IO_OPTIONS_HH +#define OPENMESH_IO_OPTIONS_HH + + +//=== INCLUDES ================================================================ + + +// OpenMesh +#include +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Option for reader and writer modules. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +/** \brief Set options for reader/writer modules. + * + * The class is used in a twofold way. + * -# In combination with reader modules the class is used + * - to pass hints to the reading module, whether the input is + * binary and what byte ordering the binary data has + * - to retrieve information about the file contents after + * succesful reading. + * -# In combination with write modules the class gives directions to + * the writer module, whether to + * - use binary mode or not and what byte order to use + * - store one of the standard properties. + * + * The option are defined in \c Options::Flag as bit values and stored in + * an \c int value as a bitset. + */ +class Options +{ +public: + typedef int enum_type; + typedef enum_type value_type; + + /// Definitions of %Options for reading and writing. The options can be + /// or'ed. + enum Flag { + None = 0x0000, ///< No options + Binary = 0x0001, ///< Set binary mode for r/w + MSB = 0x0002, ///< Assume big endian byte ordering + LSB = 0x0004, ///< Assume little endian byte ordering + Swap = 0x0008, ///< Swap byte order in binary mode + VertexNormal = 0x0010, ///< Has (r) / store (w) vertex normals + VertexColor = 0x0020, ///< Has (r) / store (w) vertex colors + VertexTexCoord = 0x0040, ///< Has (r) / store (w) texture coordinates + EdgeColor = 0x0080, ///< Has (r) / store (w) edge colors + FaceNormal = 0x0100, ///< Has (r) / store (w) face normals + FaceColor = 0x0200, ///< Has (r) / store (w) face colors + FaceTexCoord = 0x0400, ///< Has (r) / store (w) face texture coordinates + ColorAlpha = 0x0800, ///< Has (r) / store (w) alpha values for colors + ColorFloat = 0x1000, ///< Has (r) / store (w) float values for colors (currently only implemented for PLY and OFF files) + Custom = 0x2000, ///< Has (r) / store (w) custom properties marked persistent (currently PLY only supports reading and only ASCII version. OM supports reading and writing) + Status = 0x4000, ///< Has (r) / store (w) status properties + TexCoordST = 0x8000, ///< Write texture coordinates as ST instead of UV + Default = Custom, ///< By default write persistent custom properties + }; + + /// Texture filename. This will be written as + /// map_Kd in the OBJ writer into the material file. + std::string texture_file ; + + /// Filename extension for material files when writing OBJs + /// default is currently .mat + std::string material_file_extension; + +public: + + /// Default constructor + Options() : texture_file(""), material_file_extension(".mat"), flags_( Default ) + { } + + /// Initializing constructor setting multiple options + Options(const value_type _flgs) : flags_( _flgs) + { } + + /// Restore state after default constructor. + void cleanup(void) + { flags_ = Default; } + + /// Clear all bits. + void clear(void) + { flags_ = 0; } + + /// Returns true if all bits are zero. + bool is_empty(void) const { return !flags_; } + +public: + + + Options& operator = ( const value_type _rhs ) + { flags_ = _rhs; return *this; } + + + //@{ + /// Unset options defined in _rhs. + + Options& operator -= ( const value_type _rhs ) + { flags_ &= ~_rhs; return *this; } + + Options& unset( const value_type _rhs) + { return (*this -= _rhs); } + + //@} + + + + //@{ + /// Set options defined in _rhs + + Options& operator += ( const value_type _rhs ) + { flags_ |= _rhs; return *this; } + + Options& set( const value_type _rhs) + { return (*this += _rhs); } + + //@} + +public: + + + // Check if an option or several options are set. + bool check(const value_type _rhs) const + { + return (flags_ & _rhs)==_rhs; + } + + bool is_binary() const { return check(Binary); } + bool vertex_has_normal() const { return check(VertexNormal); } + bool vertex_has_color() const { return check(VertexColor); } + bool vertex_has_texcoord() const { return check(VertexTexCoord); } + bool vertex_has_status() const { return check(Status); } + bool edge_has_color() const { return check(EdgeColor); } + bool edge_has_status() const { return check(Status); } + bool halfedge_has_status() const { return check(Status); } + bool face_has_normal() const { return check(FaceNormal); } + bool face_has_color() const { return check(FaceColor); } + bool face_has_texcoord() const { return check(FaceTexCoord); } + bool face_has_status() const { return check(Status); } + bool color_has_alpha() const { return check(ColorAlpha); } + bool color_is_float() const { return check(ColorFloat); } + bool use_st_coordinates() const { return check(TexCoordST); } + + + /// Returns true if _rhs has the same options enabled. + bool operator == (const value_type _rhs) const + { return flags_ == _rhs; } + + + /// Returns true if _rhs does not have the same options enabled. + bool operator != (const value_type _rhs) const + { return flags_ != _rhs; } + + + /// Returns the option set. + operator value_type () const { return flags_; } + +private: + + bool operator && (const value_type _rhs) const; + + value_type flags_; +}; + +//----------------------------------------------------------------------------- + + + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/SR_binary.hh b/Sources/OpenMeshCore/Core/IO/SR_binary.hh new file mode 100644 index 0000000..65f4ac0 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/SR_binary.hh @@ -0,0 +1,145 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_BINARY_HH +#define OPENMESH_SR_BINARY_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#include +#include +#include +#include // accumulate +// -------------------- OpenMesh + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +//----------------------------------------------------------------------------- + + const static size_t UnknownSize(size_t(-1)); + + +//----------------------------------------------------------------------------- +// struct binary, helper for storing/restoring + +/// \struct binary SR_binary.hh +/// +/// The struct defines how to store and restore the type T. +/// It's used by the OM reader/writer modules. +/// +/// The following specialization are provided: +/// - Fundamental types except \c long +/// - %OpenMesh vector types +/// - %OpenMesh::StatusInfo +/// - std::string (max. length 65535) +/// - std::vector (requires a specialization for T) +/// +/// \todo Complete documentation of members +template < typename T, typename = void > struct binary +{ + typedef T value_type; + + /// Can we store T? Set this to true in your specialization. + static const bool is_streamable = false; + + /// What's the size of T? If it depends on the actual value (e.g. for vectors) return UnknownSize + static size_t size_of(void) { return UnknownSize; } + /// What't the size of a specific value of type T. + static size_t size_of(const value_type&) { return UnknownSize; } + + /// A string that identifies the type of T. + static std::string type_identifier (void) { return "UnknownType"; } + + /// Store a value of T and return the number of bytes written + static + size_t store( std::ostream& /* _os */, + const value_type& /* _v */, + bool /* _swap */ = false , + bool /* store_size */ = true ) // for vectors + { + std::ostringstream msg; + msg << "Type not supported: " << typeid(value_type).name(); + throw std::logic_error(msg.str()); + } + + /// Restore a value of T and return the number of bytes read + static + size_t restore( std::istream& /* _is */, + value_type& /* _v */, + bool /* _swap */ = false , + bool /* store_size */ = true ) // for vectors + { + std::ostringstream msg; + msg << "Type not supported: " << typeid(value_type).name(); + throw std::logic_error(msg.str()); + } +}; + +#undef X + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_RBO_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/IO/SR_binary_spec.hh b/Sources/OpenMeshCore/Core/IO/SR_binary_spec.hh new file mode 100644 index 0000000..0343ad9 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/SR_binary_spec.hh @@ -0,0 +1,439 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_BINARY_SPEC_HH +#define OPENMESH_SR_BINARY_SPEC_HH + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#include +#include +#if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000) +# include +#else +# include +#endif +#include +#include // logic_error +#include // accumulate +// -------------------- OpenMesh +#include +#include +#include +#include +#include + + +#include + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + +#ifndef DOXY_IGNORE_THIS + +//----------------------------------------------------------------------------- +// struct binary, helper for storing/restoring + +#define SIMPLE_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(const value_type&) { return sizeof(value_type); } \ + static size_t size_of(void) { return sizeof(value_type); } \ + static std::string type_identifier(void) { return #T; } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + if (_swap) reverse_byte_order(tmp); \ + _os.write( (const char*)&tmp, sizeof(value_type) ); \ + return _os.good() ? sizeof(value_type) : 0; \ + } \ + \ + static size_t restore( std::istream& _is, value_type& _val, \ + bool _swap=false) { \ + _is.read( (char*)&_val, sizeof(value_type) ); \ + if (_swap) reverse_byte_order(_val); \ + return _is.good() ? sizeof(value_type) : 0; \ + } \ + } + +SIMPLE_BINARY(bool); +//SIMPLE_BINARY(int); + +// Why is this needed? Should not be used as not 32 bit compatible +//SIMPLE_BINARY(unsigned long); +SIMPLE_BINARY(float); +SIMPLE_BINARY(double); +SIMPLE_BINARY(long double); +SIMPLE_BINARY(char); + +SIMPLE_BINARY(int8_t); +SIMPLE_BINARY(int16_t); +SIMPLE_BINARY(int32_t); +//SIMPLE_BINARY(int64_t); // TODO: This does not work. Find out why. +SIMPLE_BINARY(uint8_t); +SIMPLE_BINARY(uint16_t); +SIMPLE_BINARY(uint32_t); +SIMPLE_BINARY(uint64_t); + +//handles +SIMPLE_BINARY(FaceHandle); +SIMPLE_BINARY(EdgeHandle); +SIMPLE_BINARY(HalfedgeHandle); +SIMPLE_BINARY(VertexHandle); +SIMPLE_BINARY(MeshHandle); + +#undef SIMPLE_BINARY + +// For unsigned long which is of size 64 bit on 64 bit +// architectures: convert into 32 bit unsigned integer value +// in order to stay compatible between 32/64 bit architectures. +// This allows cross reading BUT forbids storing unsigned longs +// as data type since higher order word (4 bytes) will be truncated. +// Does not work in case the data type that is to be stored +// exceeds the value range of unsigned int in size, which is improbable... + +#define SIMPLE_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(const value_type&) { return sizeof(value_type); } \ + static size_t size_of(void) { return sizeof(value_type); } \ + static std::string type_identifier(void) { return #T; } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + if (_swap) reverse_byte_order(tmp); \ + /* Convert unsigned long to unsigned int for compatibility reasons */ \ + unsigned int t1 = static_cast(tmp); \ + _os.write( (const char*)&t1, sizeof(unsigned int) ); \ + return _os.good() ? sizeof(unsigned int) : 0; \ + } \ + \ + static size_t restore( std::istream& _is, value_type& _val, \ + bool _swap=false) { \ + unsigned int t1; \ + _is.read( (char*)&t1, sizeof(unsigned int) ); \ + _val = t1; \ + if (_swap) reverse_byte_order(_val); \ + return _is.good() ? sizeof(unsigned int) : 0; \ + } \ + } + +SIMPLE_BINARY(unsigned long); + +#undef SIMPLE_BINARY + +#define VECTORT_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(void) { return sizeof(value_type); } \ + static size_t size_of(const value_type&) { return size_of(); } \ + static std::string type_identifier(void) { return #T; } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + size_t b = size_of(_val), N = value_type::size_; \ + if (_swap) \ + for (size_t i=0; i struct binary< std::string > { + typedef std::string value_type; + typedef uint16_t length_t; + + static const bool is_streamable = true; + + static size_t size_of() { return UnknownSize; } + static size_t size_of(const value_type &_v) + { return sizeof(length_t) + _v.size(); } + static std::string type_identifier(void) { return "std::string"; } + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { +#if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000) + if (_v.size() < Utils::NumLimitsT::max() ) +#else + if (_v.size() < std::numeric_limits::max() ) +#endif + { + length_t len = length_t(_v.size()); + + size_t bytes = binary::store( _os, len, _swap ); + _os.write( _v.data(), len ); + return _os.good() ? len+bytes : 0; + } + throw std::runtime_error("Cannot store string longer than 64Kb"); + } + + static + size_t restore(std::istream& _is, value_type& _val, bool _swap=false) + { + length_t len; + size_t bytes = binary::restore( _is, len, _swap ); + _val.resize(len); + _is.read( const_cast(_val.data()), len ); + + return _is.good() ? (len+bytes) : 0; + } +}; + +template <> struct binary +{ + typedef OpenMesh::Attributes::StatusInfo value_type; + typedef value_type::value_type status_t; + + static const bool is_streamable = true; + + static size_t size_of() { return sizeof(status_t); } + static size_t size_of(const value_type&) { return size_of(); } + + static std::string type_identifier(void) { return "StatusInfo";} + static size_t n_bytes(size_t _n_elem) + { return _n_elem*sizeof(status_t); } + + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { + status_t v=_v.bits(); + return binary::store(_os, v, _swap); + } + + static + size_t restore( std::istream& _os, value_type& _v, bool _swap=false) + { + status_t v; + size_t b = binary::restore(_os, v, _swap); + _v.set_bits(v); + return b; + } +}; + + +//----------------------------------------------------------------------------- +// std::vector specializations for struct binary<> + +template +struct FunctorStore { + FunctorStore( std::ostream& _os, bool _swap) : os_(_os), swap_(_swap) { } + size_t operator () ( size_t _v1, const T& _s2 ) + { return _v1+binary::store(os_, _s2, swap_ ); } + + std::ostream& os_; + bool swap_; +}; + + +template +struct FunctorRestore { + FunctorRestore( std::istream& _is, bool _swap) : is_(_is), swap_(_swap) { } + size_t operator () ( size_t _v1, T& _s2 ) + { return _v1+binary::restore(is_, _s2, swap_ ); } + std::istream& is_; + bool swap_; +}; + +template +struct binary< std::vector< T >, typename std::enable_if::value>::type > { + typedef std::vector< T > value_type; + typedef typename value_type::value_type elem_type; + + static const bool is_streamable = binary::is_streamable; + static size_t size_of(bool /*_store_size*/ = true) + { return IO::UnknownSize; } + + static size_t size_of(const value_type& _v, bool _store_size = true) + { + if(binary::size_of() != IO::UnknownSize) + { + unsigned int N = static_cast(_v.size()); + auto res = binary::size_of()*_v.size() + (_store_size? sizeof(decltype(N)) : 0); + return res; + } + else + { + size_t size = 0; + for(auto v : _v) + size += binary::size_of(v); + if(_store_size) + size += binary::size_of(); + + return size; + } + } + + static std::string type_identifier(void) { return "std::vector<" + binary::type_identifier() + ">"; } + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false, bool _store_size = true) { + size_t bytes=0; + if(_store_size) + { + unsigned int N = static_cast(_v.size()); + bytes += binary::store( _os, N, _swap ); + } + if (_swap) + bytes += std::accumulate( _v.begin(), _v.end(), static_cast(0), + FunctorStore(_os,_swap) ); + else + { + auto elem_size = binary::size_of(); + if (elem_size != IO::UnknownSize && elem_size == sizeof(elem_type)) + { + // size of all elements is known, equal, and densely packed in vector. + // Just store vector data + auto bytes_of_vec = size_of(_v, false); + bytes += bytes_of_vec; + if (_v.size() > 0) + _os.write( reinterpret_cast(&_v[0]), bytes_of_vec); + } + else + { + // store individual elements + for (const auto& v : _v) + bytes += binary::store(_os, v, _swap); + } + } + return _os.good() ? bytes : 0; + } + + static size_t restore(std::istream& _is, value_type& _v, bool _swap=false, bool _restore_size = true) { + + size_t bytes=0; + + if(_restore_size) + { + unsigned int size_of_vec; + bytes += binary::restore(_is, size_of_vec, _swap); + _v.resize(size_of_vec); + } + + if ( _swap) + bytes += std::accumulate( _v.begin(), _v.end(), size_t(0), + FunctorRestore(_is, _swap) ); + else + { + auto elem_size = binary::size_of(); + if (elem_size != IO::UnknownSize && elem_size == sizeof(elem_type)) + { + // size of all elements is known, equal, and densely packed in vector. + // Just restore vector data + auto bytes_of_vec = size_of(_v, false); + bytes += bytes_of_vec; + if (_v.size() > 0) + _is.read( reinterpret_cast(&_v[0]), bytes_of_vec ); + } + else + { + // restore individual elements + for (auto& v : _v) + bytes += binary::restore(_is, v, _swap); + } + } + return _is.good() ? bytes : 0; + } +}; + +#include + +// ---------------------------------------------------------------------------- + +#endif // DOXY_IGNORE_THIS + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_BINARY_SPEC_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/IO/SR_binary_vector_of_bool.hh b/Sources/OpenMeshCore/Core/IO/SR_binary_vector_of_bool.hh new file mode 100644 index 0000000..70e06e3 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/SR_binary_vector_of_bool.hh @@ -0,0 +1,106 @@ + +template <> struct binary< std::vector > +{ + typedef std::vector< bool > value_type; + typedef value_type::value_type elem_type; + + static const bool is_streamable = true; + + static size_t size_of(bool /*_store_size*/ = true) { return UnknownSize; } + static size_t size_of(const value_type& _v, bool _store_size = true) + { + size_t size = _v.size() / 8 + ((_v.size() % 8)!=0); + if(_store_size) + size += binary::size_of(); + return size; + } + static std::string type_identifier(void) { return "std::vector"; } + static + size_t store( std::ostream& _ostr, const value_type& _v, bool _swap, bool _store_size = true) + { + size_t bytes = 0; + + size_t N = _v.size() / 8; + size_t R = _v.size() % 8; + + if(_store_size) + { + unsigned int size_N = static_cast(_v.size()); + bytes += binary::store( _ostr, size_N, _swap ); + } + + size_t idx; // element index + size_t bidx; + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + bits = static_cast(_v[bidx]) + | (static_cast(_v[bidx+1]) << 1) + | (static_cast(_v[bidx+2]) << 2) + | (static_cast(_v[bidx+3]) << 3) + | (static_cast(_v[bidx+4]) << 4) + | (static_cast(_v[bidx+5]) << 5) + | (static_cast(_v[bidx+6]) << 6) + | (static_cast(_v[bidx+7]) << 7); + _ostr << bits; + } + bytes += N; + + if (R) + { + bits = 0; + for (idx=0; idx < R; ++idx) + bits |= static_cast(_v[bidx+idx]) << idx; + _ostr << bits; + ++bytes; + } + assert( bytes == size_of(_v, _store_size) ); + + return bytes; + } + + static + size_t restore( std::istream& _istr, value_type& _v, bool _swap, bool _restore_size = true) + { + size_t bytes = 0; + + if(_restore_size) + { + unsigned int size_of_vec; + bytes += binary::restore(_istr, size_of_vec, _swap); + _v.resize(size_of_vec); + } + + size_t N = _v.size() / 8; + size_t R = _v.size() % 8; + + size_t idx; // element index + size_t bidx; // + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + _istr >> bits; + _v[bidx+0] = (bits & 0x01) != 0; + _v[bidx+1] = (bits & 0x02) != 0; + _v[bidx+2] = (bits & 0x04) != 0; + _v[bidx+3] = (bits & 0x08) != 0; + _v[bidx+4] = (bits & 0x10) != 0; + _v[bidx+5] = (bits & 0x20) != 0; + _v[bidx+6] = (bits & 0x40) != 0; + _v[bidx+7] = (bits & 0x80) != 0; + } + bytes += N; + + if (R) + { + _istr >> bits; + for (idx=0; idx < R; ++idx) + _v[bidx+idx] = (bits & (1< +// -------------------- STL +#if defined(OM_CC_MIPS) +# include // size_t +#else +# include // size_t +#endif +#include +#include +// -------------------- OpenMesh +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +/** this does not compile for g++3.4 and higher, hence we comment the +function body which will result in a linker error */ + +template < size_t N > inline +void _reverse_byte_order_N(uint8_t* _val); + +template <> inline +void _reverse_byte_order_N<1>(uint8_t* /*_val*/) { } + + +template <> inline +void _reverse_byte_order_N<2>(uint8_t* _val) +{ + _val[0] ^= _val[1]; _val[1] ^= _val[0]; _val[0] ^= _val[1]; +} + + +template <> inline +void _reverse_byte_order_N<4>(uint8_t* _val) +{ + _val[0] ^= _val[3]; _val[3] ^= _val[0]; _val[0] ^= _val[3]; // 0 <-> 3 + _val[1] ^= _val[2]; _val[2] ^= _val[1]; _val[1] ^= _val[2]; // 1 <-> 2 +} + + +template <> inline +void _reverse_byte_order_N<8>(uint8_t* _val) +{ + _val[0] ^= _val[7]; _val[7] ^= _val[0]; _val[0] ^= _val[7]; // 0 <-> 7 + _val[1] ^= _val[6]; _val[6] ^= _val[1]; _val[1] ^= _val[6]; // 1 <-> 6 + _val[2] ^= _val[5]; _val[5] ^= _val[2]; _val[2] ^= _val[5]; // 2 <-> 5 + _val[3] ^= _val[4]; _val[4] ^= _val[3]; _val[3] ^= _val[4]; // 3 <-> 4 +} + + +template <> inline +void _reverse_byte_order_N<12>(uint8_t* _val) +{ + _val[0] ^= _val[11]; _val[11] ^= _val[0]; _val[0] ^= _val[11]; // 0 <-> 11 + _val[1] ^= _val[10]; _val[10] ^= _val[1]; _val[1] ^= _val[10]; // 1 <-> 10 + _val[2] ^= _val[ 9]; _val[ 9] ^= _val[2]; _val[2] ^= _val[ 9]; // 2 <-> 9 + _val[3] ^= _val[ 8]; _val[ 8] ^= _val[3]; _val[3] ^= _val[ 8]; // 3 <-> 8 + _val[4] ^= _val[ 7]; _val[ 7] ^= _val[4]; _val[4] ^= _val[ 7]; // 4 <-> 7 + _val[5] ^= _val[ 6]; _val[ 6] ^= _val[5]; _val[5] ^= _val[ 6]; // 5 <-> 6 +} + + +template <> inline +void _reverse_byte_order_N<16>(uint8_t* _val) +{ + _reverse_byte_order_N<8>(_val); + _reverse_byte_order_N<8>(_val+8); + std::swap(*(uint64_t*)_val, *(((uint64_t*)_val)+1)); +} + + +//----------------------------------------------------------------------------- +// wrapper for byte reordering + +// reverting pointers makes no sense, hence forbid it. +/** this does not compile for g++3.4 and higher, hence we comment the +function body which will result in a linker error */ +template inline T* reverse_byte_order(T* t); +// Should never reach this point. If so, then some operator were not +// overloaded. Especially check for IO::binary<> specialization on +// custom data types. + + +inline void compile_time_error__no_fundamental_type() +{ + // we should never reach this point + assert(false); +} + +// default action for byte reversal: cause an error to avoid +// surprising behaviour! +template T& reverse_byte_order( T& _t ) +{ + omerr() << "Not defined for type " << typeid(T).name() << std::endl; + compile_time_error__no_fundamental_type(); + return _t; +} + +template <> inline bool& reverse_byte_order(bool & _t) { return _t; } +template <> inline char& reverse_byte_order(char & _t) { return _t; } +#if defined(OM_CC_GCC) +template <> inline signed char& reverse_byte_order(signed char & _t) { return _t; } +#endif +template <> inline uchar& reverse_byte_order(uchar& _t) { return _t; } + +// Instead do specializations for the necessary types +#define REVERSE_FUNDAMENTAL_TYPE( T ) \ + template <> inline T& reverse_byte_order( T& _t ) {\ + _reverse_byte_order_N( reinterpret_cast(&_t) ); \ + return _t; \ + } + +// REVERSE_FUNDAMENTAL_TYPE(bool) +// REVERSE_FUNDAMENTAL_TYPE(char) +// REVERSE_FUNDAMENTAL_TYPE(uchar) +REVERSE_FUNDAMENTAL_TYPE(int16_t) +REVERSE_FUNDAMENTAL_TYPE(uint16_t) +// REVERSE_FUNDAMENTAL_TYPE(int) +// REVERSE_FUNDAMENTAL_TYPE(uint) + +REVERSE_FUNDAMENTAL_TYPE(unsigned long) +REVERSE_FUNDAMENTAL_TYPE(int32_t) +REVERSE_FUNDAMENTAL_TYPE(uint32_t) +REVERSE_FUNDAMENTAL_TYPE(int64_t) +REVERSE_FUNDAMENTAL_TYPE(uint64_t) +REVERSE_FUNDAMENTAL_TYPE(float) +REVERSE_FUNDAMENTAL_TYPE(double) +REVERSE_FUNDAMENTAL_TYPE(long double) + +#undef REVERSE_FUNDAMENTAL_TYPE + +#if 0 + +#define REVERSE_VECTORT_TYPE( T ) \ + template <> inline T& reverse_byte_order(T& _v) {\ + for (size_t i; i< T::size_; ++i) \ + _reverse_byte_order_N< sizeof(T::value_type) >( reinterpret_cast(&_v[i])); \ + return _v; \ + } + +#define REVERSE_VECTORT_TYPES( N ) \ + REVERSE_VECTORT_TYPE( Vec##N##c ) \ + REVERSE_VECTORT_TYPE( Vec##N##uc ) \ + REVERSE_VECTORT_TYPE( Vec##N##s ) \ + REVERSE_VECTORT_TYPE( Vec##N##us ) \ + REVERSE_VECTORT_TYPE( Vec##N##i ) \ + REVERSE_VECTORT_TYPE( Vec##N##ui ) \ + REVERSE_VECTORT_TYPE( Vec##N##f ) \ + REVERSE_VECTORT_TYPE( Vec##N##d ) \ + +REVERSE_VECTORT_TYPES(1) +REVERSE_VECTORT_TYPES(2) +REVERSE_VECTORT_TYPES(3) +REVERSE_VECTORT_TYPES(4) +REVERSE_VECTORT_TYPES(6) + +#undef REVERSE_VECTORT_TYPES +#undef REVERSE_VECTORT_TYPE + +#endif + +template inline +T reverse_byte_order(const T& a) +{ + compile_timer_error__const_means_const(a); + return a; +} + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_RBO_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/IO/SR_store.hh b/Sources/OpenMeshCore/Core/IO/SR_store.hh new file mode 100644 index 0000000..374b415 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/SR_store.hh @@ -0,0 +1,67 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_STORE_HH +#define OPENMESH_SR_STORE_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include + +//============================================================================= +#endif // OPENMESH_STORE_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/IO/SR_types.hh b/Sources/OpenMeshCore/Core/IO/SR_types.hh new file mode 100644 index 0000000..484eb1d --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/SR_types.hh @@ -0,0 +1,107 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_TYPES_HH +#define OPENMESH_SR_TYPES_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + +//----------------------------------------------------------------------------- + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; + +typedef signed char int8_t; typedef unsigned char uint8_t; +typedef short int16_t; typedef unsigned short uint16_t; + +// Int should be 32 bit on all archs. +// long is 32 under windows but 64 under unix 64 bit +typedef int int32_t; typedef unsigned int uint32_t; +#if defined(OM_CC_MSVC) +typedef __int64 int64_t; typedef unsigned __int64 uint64_t; +#else +typedef long long int64_t; typedef unsigned long long uint64_t; +#endif + +typedef float float32_t; +typedef double float64_t; + +typedef uint8_t rgb_t[3]; +typedef uint8_t rgba_t[4]; + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/IO/StoreRestore.hh b/Sources/OpenMeshCore/Core/IO/StoreRestore.hh new file mode 100644 index 0000000..9c9631b --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/StoreRestore.hh @@ -0,0 +1,128 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_STORERESTORE_HH +#define OPENMESH_STORERESTORE_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + + +//----------------------------------------------------------------------------- +// StoreRestore definitions + +template inline +bool is_streamable(void) +{ return binary< T >::is_streamable; } + +template inline +bool is_streamable( const T& ) +{ return binary< T >::is_streamable; } + +template inline +size_t size_of( const T& _v ) +{ return binary< T >::size_of(_v); } + +template inline +size_t size_of( const std::vector & _v, bool _store_size = true) +{ return binary< std::vector >::size_of(_v, _store_size); } + +template inline +size_t size_of(void) +{ return binary< T >::size_of(); } + +template inline +size_t size_of(bool _store_size) +{ return binary< std::vector >::size_of(_store_size); } + +template inline +size_t store( std::ostream& _os, const T& _v, bool _swap =false) +{ return binary< T >::store( _os, _v, _swap ); } + +template inline +size_t store( std::ostream& _os, const std::vector& _v, bool _swap=false, bool _store_size = true) +{ return binary< std::vector >::store( _os, _v, _swap, _store_size); } + +template inline +size_t restore( std::istream& _is, T& _v, bool _swap = false) +{ return binary< T >::restore( _is, _v, _swap ); } + +template inline +size_t restore( std::istream& _is, std::vector& _v, bool _swap=false, bool _restore_size = true) +{ return binary< std::vector >::restore( _is, _v, _swap, _restore_size); } + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/exporter/BaseExporter.hh b/Sources/OpenMeshCore/Core/IO/exporter/BaseExporter.hh new file mode 100644 index 0000000..398d28a --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/exporter/BaseExporter.hh @@ -0,0 +1,181 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the baseclass for MeshWriter exporter modules +// +//============================================================================= + + +#ifndef __BASEEXPORTER_HH__ +#define __BASEEXPORTER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include + +// OpenMesh +#include +#include +#include + + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== EXPORTER ================================================================ + + +/** + Base class for exporter modules. + The exporter modules provide an interface between the writer modules and + the target data structure. +*/ + +class OPENMESHDLLEXPORT BaseExporter +{ +public: + + virtual ~BaseExporter() { } + + + // get vertex data + virtual Vec3f point(VertexHandle _vh) const = 0; + virtual Vec3d pointd(VertexHandle _vh) const = 0; + virtual bool is_point_double() const = 0; + virtual Vec3f normal(VertexHandle _vh) const = 0; + virtual Vec3d normald(VertexHandle _vh) const = 0; + virtual bool is_normal_double() const = 0; + virtual Vec3uc color(VertexHandle _vh) const = 0; + virtual Vec4uc colorA(VertexHandle _vh) const = 0; + virtual Vec3ui colori(VertexHandle _vh) const = 0; + virtual Vec4ui colorAi(VertexHandle _vh) const = 0; + virtual Vec3f colorf(VertexHandle _vh) const = 0; + virtual Vec4f colorAf(VertexHandle _vh) const = 0; + virtual Vec2f texcoord(VertexHandle _vh) const = 0; + virtual Vec2f texcoord(HalfedgeHandle _heh) const = 0; + virtual OpenMesh::Attributes::StatusInfo status(VertexHandle _vh) const = 0; + + + // get face data + virtual unsigned int + get_vhandles(FaceHandle _fh, + std::vector& _vhandles) const=0; + + /// + /// \brief getHeh returns the HalfEdgeHandle that belongs to the face + /// specified by _fh and has a toVertexHandle that corresponds to _vh. + /// \param _fh FaceHandle that is used to search for the half edge handle + /// \param _vh to_vertex_handle of the searched heh + /// \return HalfEdgeHandle or invalid HalfEdgeHandle if none is found. + /// + virtual HalfedgeHandle getHeh(FaceHandle _fh, VertexHandle _vh) const = 0; + virtual unsigned int + get_face_texcoords(std::vector& _hehandles) const = 0; + virtual Vec3f normal(FaceHandle _fh) const = 0; + virtual Vec3d normald(FaceHandle _fh) const = 0; + virtual Vec3uc color (FaceHandle _fh) const = 0; + virtual Vec4uc colorA(FaceHandle _fh) const = 0; + virtual Vec3ui colori(FaceHandle _fh) const = 0; + virtual Vec4ui colorAi(FaceHandle _fh) const = 0; + virtual Vec3f colorf(FaceHandle _fh) const = 0; + virtual Vec4f colorAf(FaceHandle _fh) const = 0; + virtual OpenMesh::Attributes::StatusInfo status(FaceHandle _fh) const = 0; + + // get edge data + virtual Vec3uc color(EdgeHandle _eh) const = 0; + virtual Vec4uc colorA(EdgeHandle _eh) const = 0; + virtual Vec3ui colori(EdgeHandle _eh) const = 0; + virtual Vec4ui colorAi(EdgeHandle _eh) const = 0; + virtual Vec3f colorf(EdgeHandle _eh) const = 0; + virtual Vec4f colorAf(EdgeHandle _eh) const = 0; + virtual OpenMesh::Attributes::StatusInfo status(EdgeHandle _eh) const = 0; + + // get halfedge data + virtual int get_halfedge_id(VertexHandle _vh) = 0; + virtual int get_halfedge_id(FaceHandle _vh) = 0; + virtual int get_next_halfedge_id(HalfedgeHandle _heh) = 0; + virtual int get_to_vertex_id(HalfedgeHandle _heh) = 0; + virtual int get_face_id(HalfedgeHandle _heh) = 0; + virtual OpenMesh::Attributes::StatusInfo status(HalfedgeHandle _heh) const = 0; + + // get reference to base kernel + virtual const BaseKernel* kernel() { return nullptr; } + + + // query number of faces, vertices, normals, texcoords + virtual size_t n_vertices() const = 0; + virtual size_t n_faces() const = 0; + virtual size_t n_edges() const = 0; + + + // property information + virtual bool is_triangle_mesh() const { return false; } + virtual bool has_vertex_normals() const { return false; } + virtual bool has_vertex_colors() const { return false; } + virtual bool has_vertex_status() const { return false; } + virtual bool has_vertex_texcoords() const { return false; } + virtual bool has_edge_colors() const { return false; } + virtual bool has_edge_status() const { return false; } + virtual bool has_halfedge_status() const { return false; } + virtual bool has_face_normals() const { return false; } + virtual bool has_face_colors() const { return false; } + virtual bool has_face_status() const { return false; } +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/exporter/ExporterT.hh b/Sources/OpenMeshCore/Core/IO/exporter/ExporterT.hh new file mode 100644 index 0000000..2c1d4be --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/exporter/ExporterT.hh @@ -0,0 +1,422 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements an exporter module for arbitrary OpenMesh meshes +// +//============================================================================= + + +#ifndef __EXPORTERT_HH__ +#define __EXPORTERT_HH__ + + +//=== INCLUDES ================================================================ + +// C++ +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include +#include +#include + + +//=== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + + +//=== EXPORTER CLASS ========================================================== + +/** + * This class template provides an exporter module for OpenMesh meshes. + */ +template +class ExporterT : public BaseExporter +{ +public: + + // Constructor + explicit ExporterT(const Mesh& _mesh) : mesh_(_mesh) {} + + + // get vertex data + + Vec3f point(VertexHandle _vh) const override + { + return vector_cast(mesh_.point(_vh)); + } + + Vec3d pointd(VertexHandle _vh) const override + { + return vector_cast(mesh_.point(_vh)); + } + + bool is_point_double() const override + { + return OMFormat::is_double(typename Mesh::Point()[0]); + } + + bool is_normal_double() const override + { + return OMFormat::is_double(typename Mesh::Normal()[0]); + } + + Vec3f normal(VertexHandle _vh) const override + { + return (mesh_.has_vertex_normals() + ? vector_cast(mesh_.normal(_vh)) + : Vec3f(0.0f, 0.0f, 0.0f)); + } + + Vec3d normald(VertexHandle _vh) const override + { + return (mesh_.has_vertex_normals() + ? vector_cast(mesh_.normal(_vh)) + : Vec3d(0.0f, 0.0f, 0.0f)); + } + + Vec3uc color(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec4uc(0, 0, 0, 0)); + } + + Vec3ui colori(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec3ui(0, 0, 0)); + } + + Vec4ui colorAi(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec4ui(0, 0, 0, 0)); + } + + Vec3f colorf(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec3f(0, 0, 0)); + } + + Vec4f colorAf(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec4f(0, 0, 0, 0)); + } + + Vec2f texcoord(VertexHandle _vh) const override + { +#if defined(OM_CC_GCC) && (OM_CC_VERSION<30000) + // Workaround! + // gcc 2.95.3 exits with internal compiler error at the + // code below!??? **) + if (mesh_.has_vertex_texcoords2D()) + return vector_cast(mesh_.texcoord2D(_vh)); + return Vec2f(0.0f, 0.0f); +#else // **) + return (mesh_.has_vertex_texcoords2D() + ? vector_cast(mesh_.texcoord2D(_vh)) + : Vec2f(0.0f, 0.0f)); +#endif + } + + Vec2f texcoord(HalfedgeHandle _heh) const override + { + return (mesh_.has_halfedge_texcoords2D() + ? vector_cast(mesh_.texcoord2D(_heh)) + : Vec2f(0.0f, 0.0f)); + } + + OpenMesh::Attributes::StatusInfo status(VertexHandle _vh) const override + { + if (mesh_.has_vertex_status()) + return mesh_.status(_vh); + return OpenMesh::Attributes::StatusInfo(); + } + + // get edge data + + Vec3uc color(EdgeHandle _eh) const override + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(EdgeHandle _eh) const override + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec4uc(0, 0, 0, 0)); + } + + Vec3ui colori(EdgeHandle _eh) const override + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec3ui(0, 0, 0)); + } + + Vec4ui colorAi(EdgeHandle _eh) const override + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec4ui(0, 0, 0, 0)); + } + + Vec3f colorf(EdgeHandle _eh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_eh)) + : Vec3f(0, 0, 0)); + } + + Vec4f colorAf(EdgeHandle _eh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_eh)) + : Vec4f(0, 0, 0, 0)); + } + + OpenMesh::Attributes::StatusInfo status(EdgeHandle _eh) const override + { + if (mesh_.has_edge_status()) + return mesh_.status(_eh); + return OpenMesh::Attributes::StatusInfo(); + } + + // get halfedge data + + int get_halfedge_id(VertexHandle _vh) override + { + return mesh_.halfedge_handle(_vh).idx(); + } + + int get_halfedge_id(FaceHandle _fh) override + { + return mesh_.halfedge_handle(_fh).idx(); + } + + int get_next_halfedge_id(HalfedgeHandle _heh) override + { + return mesh_.next_halfedge_handle(_heh).idx(); + } + + int get_to_vertex_id(HalfedgeHandle _heh) override + { + return mesh_.to_vertex_handle(_heh).idx(); + } + + int get_face_id(HalfedgeHandle _heh) override + { + return mesh_.face_handle(_heh).idx(); + } + + OpenMesh::Attributes::StatusInfo status(HalfedgeHandle _heh) const override + { + if (mesh_.has_halfedge_status()) + return mesh_.status(_heh); + return OpenMesh::Attributes::StatusInfo(); + } + + // get face data + + unsigned int get_vhandles(FaceHandle _fh, + std::vector& _vhandles) const override + { + unsigned int count(0); + _vhandles.clear(); + for (typename Mesh::CFVIter fv_it=mesh_.cfv_iter(_fh); fv_it.is_valid(); ++fv_it) + { + _vhandles.push_back(*fv_it); + ++count; + } + return count; + } + + unsigned int get_face_texcoords(std::vector& _hehandles) const override + { + unsigned int count(0); + _hehandles.clear(); + for(auto heh: mesh_.halfedges().filtered(!OpenMesh::Predicates::Boundary())) + { + _hehandles.push_back(vector_cast(mesh_.texcoord2D(heh))); + ++count; + } + + return count; + } + + HalfedgeHandle getHeh(FaceHandle _fh, VertexHandle _vh) const override + { + typename Mesh::ConstFaceHalfedgeIter fh_it; + for(fh_it = mesh_.cfh_iter(_fh); fh_it.is_valid();++fh_it) + { + if(mesh_.to_vertex_handle(*fh_it) == _vh) + return *fh_it; + } + return *fh_it; + } + + Vec3f normal(FaceHandle _fh) const override + { + return (mesh_.has_face_normals() + ? vector_cast(mesh_.normal(_fh)) + : Vec3f(0.0f, 0.0f, 0.0f)); + } + + Vec3d normald(FaceHandle _fh) const override + { + return (mesh_.has_face_normals() + ? vector_cast(mesh_.normal(_fh)) + : Vec3d(0.0, 0.0, 0.0)); + } + + Vec3uc color(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec4uc(0, 0, 0, 0)); + } + + Vec3ui colori(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec3ui(0, 0, 0)); + } + + Vec4ui colorAi(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec4ui(0, 0, 0, 0)); + } + + Vec3f colorf(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec3f(0, 0, 0)); + } + + Vec4f colorAf(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec4f(0, 0, 0, 0)); + } + + OpenMesh::Attributes::StatusInfo status(FaceHandle _fh) const override + { + if (mesh_.has_face_status()) + return mesh_.status(_fh); + return OpenMesh::Attributes::StatusInfo(); + } + + virtual const BaseKernel* kernel() override { return &mesh_; } + + + // query number of faces, vertices, normals, texcoords + size_t n_vertices() const override { return mesh_.n_vertices(); } + size_t n_faces() const override { return mesh_.n_faces(); } + size_t n_edges() const override { return mesh_.n_edges(); } + + + // property information + bool is_triangle_mesh() const override + { return Mesh::is_triangles(); } + + bool has_vertex_normals() const override { return mesh_.has_vertex_normals(); } + bool has_vertex_colors() const override { return mesh_.has_vertex_colors(); } + bool has_vertex_texcoords() const override { return mesh_.has_vertex_texcoords2D(); } + bool has_vertex_status() const override { return mesh_.has_vertex_status(); } + bool has_edge_colors() const override { return mesh_.has_edge_colors(); } + bool has_edge_status() const override { return mesh_.has_edge_status(); } + bool has_halfedge_status() const override { return mesh_.has_halfedge_status(); } + bool has_face_normals() const override { return mesh_.has_face_normals(); } + bool has_face_colors() const override { return mesh_.has_face_colors(); } + bool has_face_status() const override { return mesh_.has_face_status(); } + +private: + + const Mesh& mesh_; +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/importer/BaseImporter.hh b/Sources/OpenMeshCore/Core/IO/importer/BaseImporter.hh new file mode 100644 index 0000000..ff44141 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/importer/BaseImporter.hh @@ -0,0 +1,239 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the baseclass for IOManager importer modules +// +//============================================================================= + + +#ifndef __BASEIMPORTER_HH__ +#define __BASEIMPORTER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include + +// OpenMesh +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** Base class for importer modules. Importer modules provide an + * interface between the loader modules and the target data + * structure. This is basically a wrapper providing virtual versions + * for the required mesh functions. + */ +class OPENMESHDLLEXPORT BaseImporter +{ +public: + + // base class needs virtual destructor + virtual ~BaseImporter() {} + + + // add a vertex with coordinate \c _point + virtual VertexHandle add_vertex(const Vec3f& _point) = 0; + + // add a vertex with coordinate \c _point + virtual VertexHandle add_vertex(const Vec3d& _point) { return add_vertex(Vec3f(_point)); } + + // add a vertex without coordinate. Use set_point to set the position deferred + virtual VertexHandle add_vertex() = 0; + + // add an edge. Use set_next, set_vertex and set_face to set corresponding entities for halfedges + virtual HalfedgeHandle add_edge(VertexHandle _vh0, VertexHandle _vh1) = 0; + + // add a face with indices _indices refering to vertices + typedef std::vector VHandles; + virtual FaceHandle add_face(const VHandles& _indices) = 0; + + // add a face with incident halfedge + virtual FaceHandle add_face(HalfedgeHandle _heh) = 0; + + // add texture coordinates per face, _vh references the first texcoord + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) = 0; + + // add texture 3d coordinates per face, _vh references the first texcoord + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) = 0; + + // Set the texture index for a face + virtual void set_face_texindex( FaceHandle _fh, int _texId ) = 0; + + // Set coordinate of the given vertex. Use this function, if you created a vertex without coordinate + virtual void set_point(VertexHandle _vh, const Vec3f& _point) = 0; + + // Set outgoing halfedge for the given vertex. + virtual void set_halfedge(VertexHandle _vh, HalfedgeHandle _heh) = 0; + + // set vertex normal + virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) = 0; + + // set vertex normal + virtual void set_normal(VertexHandle _vh, const Vec3d& _normal) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec3uc& _color) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec4uc& _color) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec3f& _color) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec4f& _color) = 0; + + // set vertex texture coordinate + virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) = 0; + + // set vertex status + virtual void set_status(VertexHandle _vh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + + // set next halfedge handle + virtual void set_next(HalfedgeHandle _heh, HalfedgeHandle _next) = 0; + + // set incident face handle for given halfedge + virtual void set_face(HalfedgeHandle _heh, FaceHandle _fh) = 0; + + // request texture coordinate property + virtual void request_face_texcoords2D() = 0; + + // set vertex texture coordinate + virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) = 0; + + // set 3d vertex texture coordinate + virtual void set_texcoord(VertexHandle _vh, const Vec3f& _texcoord) = 0; + + // set 3d vertex texture coordinate + virtual void set_texcoord(HalfedgeHandle _heh, const Vec3f& _texcoord) = 0; + + // set halfedge status + virtual void set_status(HalfedgeHandle _heh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec3uc& _color) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec4uc& _color) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec3f& _color) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec4f& _color) = 0; + + // set edge status + virtual void set_status(EdgeHandle _eh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + + // set face normal + virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) = 0; + + // set face normal + virtual void set_normal(FaceHandle _fh, const Vec3d& _normal) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec3uc& _color) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec4uc& _color) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec3f& _color) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec4f& _color) = 0; + + // set face status + virtual void set_status(FaceHandle _fh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + + // Store a property in the mesh mapping from an int to a texture file + // Use set_face_texindex to set the index for each face + virtual void add_texture_information( int _id , std::string _name ) = 0; + + // get reference to base kernel + virtual BaseKernel* kernel() { return nullptr; } + + virtual bool is_triangle_mesh() const { return false; } + + // reserve mem for elements + virtual void reserve( unsigned int /* nV */, + unsigned int /* nE */, + unsigned int /* nF */) {} + + // query number of faces, vertices, normals, texcoords + virtual size_t n_vertices() const = 0; + virtual size_t n_faces() const = 0; + virtual size_t n_edges() const = 0; + + + // pre-processing + virtual void prepare() {} + + // post-processing + virtual void finish() {} +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/importer/ImporterT.hh b/Sources/OpenMeshCore/Core/IO/importer/ImporterT.hh new file mode 100644 index 0000000..55a2a2c --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/importer/ImporterT.hh @@ -0,0 +1,486 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements an importer module for arbitrary OpenMesh meshes +// +//============================================================================= + + +#ifndef __IMPORTERT_HH__ +#define __IMPORTERT_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + * This class template provides an importer module for OpenMesh meshes. + */ +template +class ImporterT : public BaseImporter +{ +public: + + typedef typename Mesh::Point Point; + typedef typename Mesh::Normal Normal; + typedef typename Mesh::Color Color; + typedef typename Mesh::TexCoord2D TexCoord2D; + typedef typename Mesh::TexCoord3D TexCoord3D; + typedef std::vector VHandles; + + + explicit ImporterT(Mesh& _mesh) : mesh_(_mesh), halfedgeNormals_() {} + + + virtual VertexHandle add_vertex(const Vec3f& _point) override + { + return mesh_.add_vertex(vector_cast(_point)); + } + + virtual VertexHandle add_vertex(const Vec3d& _point) override + { + return mesh_.add_vertex(vector_cast(_point)); + } + + virtual VertexHandle add_vertex() override + { + return mesh_.new_vertex(); + } + + virtual HalfedgeHandle add_edge(VertexHandle _vh0, VertexHandle _vh1) override + { + return mesh_.new_edge(_vh0, _vh1); + } + + virtual FaceHandle add_face(const VHandles& _indices) override + { + FaceHandle fh; + + if (_indices.size() > 2) + { + VHandles::const_iterator it, it2, end(_indices.end()); + + + // Test if all vertex handles are valid. If not, we throw an error. + if ( std::any_of(_indices.begin(),_indices.end(),[this](const VertexHandle& vh){ return !mesh_.is_valid_handle(vh); } ) ) + { + omerr() << "ImporterT: Face contains invalid vertex index\n"; + return fh; + } + + // don't allow double vertices + for (it=_indices.begin(); it!=end; ++it) + for (it2=it+1; it2!=end; ++it2) + if (*it == *it2) + { + omerr() << "ImporterT: Face has equal vertices\n"; + return fh; + } + + + // try to add face + fh = mesh_.add_face(_indices); + // separate non-manifold faces and mark them + if (!fh.is_valid()) + { + VHandles vhandles(_indices.size()); + + // double vertices + for (unsigned int j=0; j<_indices.size(); ++j) + { + // DO STORE p, reference may not work since vertex array + // may be relocated after adding a new vertex ! + Point p = mesh_.point(_indices[j]); + vhandles[j] = mesh_.add_vertex(p); + + // Mark vertices of failed face as non-manifold + if (mesh_.has_vertex_status()) { + mesh_.status(vhandles[j]).set_fixed_nonmanifold(true); + } + } + + // add face + fh = mesh_.add_face(vhandles); + + // Mark failed face as non-manifold + if (mesh_.has_face_status()) + mesh_.status(fh).set_fixed_nonmanifold(true); + + // Mark edges of failed face as non-two-manifold + if (mesh_.has_edge_status()) { + typename Mesh::FaceEdgeIter fe_it = mesh_.fe_iter(fh); + for(; fe_it.is_valid(); ++fe_it) { + mesh_.status(*fe_it).set_fixed_nonmanifold(true); + } + } + } + + //write the half edge normals + if (mesh_.has_halfedge_normals()) + { + //iterate over all incoming haldedges of the added face + for (typename Mesh::FaceHalfedgeIter fh_iter = mesh_.fh_begin(fh); + fh_iter != mesh_.fh_end(fh); ++fh_iter) + { + //and write the normals to it + typename Mesh::HalfedgeHandle heh = *fh_iter; + typename Mesh::VertexHandle vh = mesh_.to_vertex_handle(heh); + typename std::map::iterator it_heNs = halfedgeNormals_.find(vh); + if (it_heNs != halfedgeNormals_.end()) + mesh_.set_normal(heh,it_heNs->second); + } + halfedgeNormals_.clear(); + } + } + return fh; + } + + virtual FaceHandle add_face(HalfedgeHandle _heh) override + { + auto fh = mesh_.new_face(); + mesh_.set_halfedge_handle(fh, _heh); + return fh; + } + + // vertex attributes + + virtual void set_point(VertexHandle _vh, const Vec3f& _point) override + { + mesh_.set_point(_vh,vector_cast(_point)); + } + + virtual void set_halfedge(VertexHandle _vh, HalfedgeHandle _heh) override + { + mesh_.set_halfedge_handle(_vh, _heh); + } + + virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) override + { + if (mesh_.has_vertex_normals()) + mesh_.set_normal(_vh, vector_cast(_normal)); + + //saves normals for half edges. + //they will be written, when the face is added + if (mesh_.has_halfedge_normals()) + halfedgeNormals_[_vh] = vector_cast(_normal); + } + + virtual void set_normal(VertexHandle _vh, const Vec3d& _normal) override + { + if (mesh_.has_vertex_normals()) + mesh_.set_normal(_vh, vector_cast(_normal)); + + //saves normals for half edges. + //they will be written, when the face is added + if (mesh_.has_halfedge_normals()) + halfedgeNormals_[_vh] = vector_cast(_normal); + } + + virtual void set_color(VertexHandle _vh, const Vec4uc& _color) override + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_color(VertexHandle _vh, const Vec3uc& _color) override + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_color(VertexHandle _vh, const Vec4f& _color) override + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_color(VertexHandle _vh, const Vec3f& _color) override + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) override + { + if (mesh_.has_vertex_texcoords2D()) + mesh_.set_texcoord2D(_vh, vector_cast(_texcoord)); + } + + virtual void set_status(VertexHandle _vh, const OpenMesh::Attributes::StatusInfo& _status) override + { + if (!mesh_.has_vertex_status()) + mesh_.request_vertex_status(); + mesh_.status(_vh) = _status; + } + + virtual void set_next(HalfedgeHandle _heh, HalfedgeHandle _next) override + { + mesh_.set_next_halfedge_handle(_heh, _next); + } + + virtual void set_face(HalfedgeHandle _heh, FaceHandle _fh) override + { + mesh_.set_face_handle(_heh, _fh); + } + + virtual void request_face_texcoords2D() override + { + if(!mesh_.has_halfedge_texcoords2D()) + mesh_.request_halfedge_texcoords2D(); + } + + virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) override + { + if (mesh_.has_halfedge_texcoords2D()) + mesh_.set_texcoord2D(_heh, vector_cast(_texcoord)); + } + + virtual void set_texcoord(VertexHandle _vh, const Vec3f& _texcoord) override + { + if (mesh_.has_vertex_texcoords3D()) + mesh_.set_texcoord3D(_vh, vector_cast(_texcoord)); + } + + virtual void set_texcoord(HalfedgeHandle _heh, const Vec3f& _texcoord) override + { + if (mesh_.has_halfedge_texcoords3D()) + mesh_.set_texcoord3D(_heh, vector_cast(_texcoord)); + } + + virtual void set_status(HalfedgeHandle _heh, const OpenMesh::Attributes::StatusInfo& _status) override + { + if (!mesh_.has_halfedge_status()) + mesh_.request_halfedge_status(); + mesh_.status(_heh) = _status; + } + + // edge attributes + + virtual void set_color(EdgeHandle _eh, const Vec4uc& _color) override + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_color(EdgeHandle _eh, const Vec3uc& _color) override + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_color(EdgeHandle _eh, const Vec4f& _color) override + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_color(EdgeHandle _eh, const Vec3f& _color) override + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_status(EdgeHandle _eh, const OpenMesh::Attributes::StatusInfo& _status) override + { + if (!mesh_.has_edge_status()) + mesh_.request_edge_status(); + mesh_.status(_eh) = _status; + } + + // face attributes + + virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) override + { + if (mesh_.has_face_normals()) + mesh_.set_normal(_fh, vector_cast(_normal)); + } + + virtual void set_normal(FaceHandle _fh, const Vec3d& _normal) override + { + if (mesh_.has_face_normals()) + mesh_.set_normal(_fh, vector_cast(_normal)); + } + + virtual void set_color(FaceHandle _fh, const Vec3uc& _color) override + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_color(FaceHandle _fh, const Vec4uc& _color) override + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_color(FaceHandle _fh, const Vec3f& _color) override + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_color(FaceHandle _fh, const Vec4f& _color) override + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_status(FaceHandle _fh, const OpenMesh::Attributes::StatusInfo& _status) override + { + if (!mesh_.has_face_status()) + mesh_.request_face_status(); + mesh_.status(_fh) = _status; + } + + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) override + { + // get first halfedge handle + HalfedgeHandle cur_heh = mesh_.halfedge_handle(_fh); + HalfedgeHandle end_heh = mesh_.prev_halfedge_handle(cur_heh); + + // find start heh + while( mesh_.to_vertex_handle(cur_heh) != _vh && cur_heh != end_heh ) + cur_heh = mesh_.next_halfedge_handle( cur_heh); + + for(unsigned int i=0; i<_face_texcoords.size(); ++i) + { + set_texcoord( cur_heh, _face_texcoords[i]); + cur_heh = mesh_.next_halfedge_handle( cur_heh); + } + } + + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) override + { + // get first halfedge handle + HalfedgeHandle cur_heh = mesh_.halfedge_handle(_fh); + HalfedgeHandle end_heh = mesh_.prev_halfedge_handle(cur_heh); + + // find start heh + while( mesh_.to_vertex_handle(cur_heh) != _vh && cur_heh != end_heh ) + cur_heh = mesh_.next_halfedge_handle( cur_heh); + + for(unsigned int i=0; i<_face_texcoords.size(); ++i) + { + set_texcoord( cur_heh, _face_texcoords[i]); + cur_heh = mesh_.next_halfedge_handle( cur_heh); + } + } + + virtual void set_face_texindex( FaceHandle _fh, int _texId ) override + { + if ( mesh_.has_face_texture_index() ) { + mesh_.set_texture_index(_fh , _texId); + } + } + + virtual void add_texture_information( int _id , std::string _name ) override + { + OpenMesh::MPropHandleT< std::map< int, std::string > > property; + + if ( !mesh_.get_property_handle(property,"TextureMapping") ) { + mesh_.add_property(property,"TextureMapping"); + } + + if ( mesh_.property(property).find( _id ) == mesh_.property(property).end() ) { + mesh_.property(property)[_id] = _name; + } + } + + // low-level access to mesh + + virtual BaseKernel* kernel() override { return &mesh_; } + + bool is_triangle_mesh() const override + { return Mesh::is_triangles(); } + + void reserve(unsigned int nV, unsigned int nE, unsigned int nF) override + { + mesh_.reserve(nV, nE, nF); + } + + // query number of faces, vertices, normals, texcoords + size_t n_vertices() const override { return mesh_.n_vertices(); } + size_t n_faces() const override { return mesh_.n_faces(); } + size_t n_edges() const override { return mesh_.n_edges(); } + + + void prepare() override{ } + + + void finish() override { } + + +private: + + Mesh& mesh_; + // stores normals for halfedges of the next face + std::map halfedgeNormals_; +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/BaseReader.cc b/Sources/OpenMeshCore/Core/IO/reader/BaseReader.cc new file mode 100644 index 0000000..68d4a69 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/BaseReader.cc @@ -0,0 +1,127 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//=== INCLUDES ================================================================ + +#include + +#if defined(OM_CC_MIPS) +# include +#else +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +static inline char tolower(char c) +{ + using namespace std; + return ::tolower(c); +} + + +//----------------------------------------------------------------------------- + + +bool +BaseReader:: +can_u_read(const std::string& _filename) const +{ + // get file extension + std::string extension; + std::string::size_type pos(_filename.rfind(".")); + + if (pos != std::string::npos) + extension = _filename.substr(pos+1, _filename.length()-pos-1); + else + extension = _filename; //check, if the whole filename defines the extension + + std::transform( extension.begin(), extension.end(), + extension.begin(), tolower ); + + // locate extension in extension string + return (get_extensions().find(extension) != std::string::npos); +} + + +//----------------------------------------------------------------------------- + + +bool +BaseReader:: +check_extension(const std::string& _fname, const std::string& _ext) const +{ + std::string cmpExt(_ext); + + std::transform( _ext.begin(), _ext.end(), cmpExt.begin(), tolower ); + + std::string::size_type pos(_fname.rfind(".")); + + if (pos != std::string::npos && !_ext.empty() ) + { + std::string ext; + + // extension without dot! + ext = _fname.substr(pos+1, _fname.length()-pos-1); + + std::transform( ext.begin(), ext.end(), ext.begin(), tolower ); + + return ext == cmpExt; + } + return false; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/BaseReader.hh b/Sources/OpenMeshCore/Core/IO/reader/BaseReader.hh new file mode 100644 index 0000000..8705f7d --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/BaseReader.hh @@ -0,0 +1,203 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the baseclass for IOManager file access modules +// +//============================================================================= + +#pragma once + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include +#include +#include +#include + +// OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Base class for reader modules. + Reader modules access persistent data and pass them to the desired + data structure by the means of a BaseImporter derivative. + All reader modules must be derived from this class. +*/ +class OPENMESHDLLEXPORT BaseReader +{ +public: + + /// Destructor + virtual ~BaseReader() {} + + /// Returns a brief description of the file type that can be parsed. + virtual std::string get_description() const = 0; + + /** Returns a string with the accepted file extensions separated by a + whitespace and in small caps. + */ + virtual std::string get_extensions() const = 0; + + /// Return magic bits used to determine file format + virtual std::string get_magic() const { return std::string(""); } + + + /** Reads a mesh given by a filename. Usually this method opens a stream + and passes it to stream read method. Acceptance checks by filename + extension can be placed here. + + Options can be passed via _opt. After execution _opt contains the Options + that were available + */ + virtual bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) = 0; + + /** Reads a mesh given by a std::stream. This method usually uses the same stream reading method + that read uses. Options can be passed via _opt. After execution _opt contains the Options + that were available. + + Please make sure that if _is is std::ifstream, the correct std::ios_base::openmode flags are set. + */ + virtual bool read(std::istream& _is, + BaseImporter& _bi, + Options& _opt) = 0; + + + /** \brief Returns true if writer can parse _filename (checks extension). + * _filename can also provide an extension without a name for a file e.g. _filename == "om" checks, if the reader can read the "om" extension + * @param _filename complete name of a file or just the extension + * @result true, if reader can read data with the given extension + */ + virtual bool can_u_read(const std::string& _filename) const; + + +protected: + + // case insensitive search for _ext in _fname. + bool check_extension(const std::string& _fname, + const std::string& _ext) const; +}; + + +/** \brief Trim left whitespace + * + * Removes whitespace at the beginning of the string + * + * @param _string input string + * @return trimmed string + */ +static inline std::string &left_trim(std::string &_string) { + + // Find out if the compiler supports CXX11 + #if ( __cplusplus >= 201103L || _MSVC_LANG >= 201103L ) + // as with CXX11 we can use lambda expressions + _string.erase(_string.begin(), std::find_if(_string.begin(), _string.end(), [](int i)->int { return ! std::isspace(i); })); + #else + // we do what we did before + _string.erase(_string.begin(), std::find_if(_string.begin(), _string.end(), std::not1(std::ptr_fun(std::isspace)))); + #endif + + return _string; +} + +/** \brief Trim right whitespace + * + * Removes whitespace at the end of the string + * + * @param _string input string + * @return trimmed string + */ +static inline std::string &right_trim(std::string &_string) { + + // Find out if the compiler supports CXX11 + #if ( __cplusplus >= 201103L || _MSVC_LANG >= 201103L ) + // as with CXX11 we can use lambda expressions + _string.erase(std::find_if(_string.rbegin(), _string.rend(), [](int i)->int { return ! std::isspace(i); } ).base(), _string.end()); + #else + // we do what we did before + _string.erase(std::find_if(_string.rbegin(), _string.rend(), std::not1(std::ptr_fun(std::isspace))).base(), _string.end()); + #endif + + + + return _string; +} + +/** \brief Trim whitespace + * + * Removes whitespace at the beginning and end of the string + * + * @param _string input string + * @return trimmed string + */ +static inline std::string &trim(std::string &_string) { + return left_trim(right_trim(_string)); +} + + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/OBJReader.cc b/Sources/OpenMeshCore/Core/IO/reader/OBJReader.cc new file mode 100644 index 0000000..9aba3da --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/OBJReader.cc @@ -0,0 +1,804 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//== INCLUDES ================================================================= + + +// OpenMesh +#include +#include +#include +#include +// STL +#if defined(OM_CC_MIPS) +# include +/// \bug Workaround for STLPORT 4.6: isspace seems not to be in namespace std! +#elif defined(_STLPORT_VERSION) && (_STLPORT_VERSION==0x460) +# include +#else +using std::isspace; +#endif + +#ifndef WIN32 +#endif + +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +_OBJReader_ __OBJReaderInstance; +_OBJReader_& OBJReader() { return __OBJReaderInstance; } + + +//=== IMPLEMENTATION ========================================================== + +//----------------------------------------------------------------------------- + +void trimString( std::string& _string) { + // Trim Both leading and trailing spaces + + size_t start = _string.find_first_not_of(" \t\r\n"); + size_t end = _string.find_last_not_of(" \t\r\n"); + + if(( std::string::npos == start ) || ( std::string::npos == end)) + _string = ""; + else + _string = _string.substr( start, end-start+1 ); +} + +//----------------------------------------------------------------------------- + +// remove duplicated indices from one face +void remove_duplicated_vertices(BaseImporter::VHandles& _indices) +{ + BaseImporter::VHandles::iterator endIter = _indices.end(); + for (BaseImporter::VHandles::iterator iter = _indices.begin(); iter != endIter; ++iter) + endIter = std::remove(iter+1, endIter, *(iter)); + + _indices.erase(endIter,_indices.end()); +} + +//----------------------------------------------------------------------------- + +_OBJReader_:: +_OBJReader_() +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_OBJReader_:: +read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + std::fstream in( _filename.c_str(), std::ios_base::in ); + + if (!in.is_open() || !in.good()) + { + omerr() << "[OBJReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + { +#if defined(WIN32) + std::string::size_type dot_pos = _filename.find_last_of("\\/"); +#else + std::string::size_type dot_pos = _filename.rfind("/"); +#endif + path_ = (dot_pos == std::string::npos) + ? "./" + : std::string(_filename.substr(0,dot_pos+1)); + } + + bool result = read(in, _bi, _opt); + + in.close(); + return result; +} + +//----------------------------------------------------------------------------- + +bool +_OBJReader_:: +read_material(std::fstream& _in) +{ + std::string line; + std::string keyWrd; + std::string textureName; + + std::stringstream stream; + + std::string key; + Material mat; + float f1,f2,f3; + bool indef = false; + int textureId = 1; + + + materials_.clear(); + mat.cleanup(); + + while( _in && !_in.eof() ) + { + std::getline(_in,line); + if ( _in.bad() ){ + omerr() << " Warning! Could not read file properly!\n"; + return false; + } + + if ( line.empty() ) + continue; + + stream.str(line); + stream.clear(); + + stream >> keyWrd; + + if (keyWrd == "newmtl") // begin new material definition + { + // If we are in a material definition (Already reading a material) + // And a material name has been set + // And the current material definition is valid + // Then Store the current material in our lookup table + if (indef && !key.empty() && mat.is_valid()) + { + materials_[key] = mat; + mat.cleanup(); + } + + stream >> key; + indef = true; + } + + else if (keyWrd == "Kd") // diffuse color + { + stream >> f1; stream >> f2; stream >> f3; + + if( !stream.fail() ) + mat.set_Kd(f1,f2,f3); + } + + else if (keyWrd == "Ka") // ambient color + { + stream >> f1; stream >> f2; stream >> f3; + + if( !stream.fail() ) + mat.set_Ka(f1,f2,f3); + } + + else if (keyWrd == "Ks") // specular color + { + stream >> f1; stream >> f2; stream >> f3; + + if( !stream.fail() ) + mat.set_Ks(f1,f2,f3); + } +#if 0 + else if (keyWrd == "illum") // diffuse/specular shading model + { + ; // just skip this + } + + else if (keyWrd == "Ns") // Shininess [0..200] + { + ; // just skip this + } + + else if (keyWrd == "map_") // map images + { + // map_Ks, specular map + // map_Ka, ambient map + // map_Bump, bump map + // map_d, opacity map + ; // just skip this + } +#endif + else if (keyWrd == "map_Kd" ) { + // Get the rest of the line, removing leading or trailing spaces + // This will define the filename of the texture + std::getline(stream,textureName); + trimString(textureName); + if ( ! textureName.empty() ) + mat.set_map_Kd( textureName, textureId++ ); + } + else if (keyWrd == "Tr") // transparency value + { + stream >> f1; + + if( !stream.fail() ) + mat.set_Tr(f1); + } + else if (keyWrd == "d") // transparency value + { + stream >> f1; + + if( !stream.fail() ) + mat.set_Tr(f1); + } + + if ( _in && indef && mat.is_valid() && !key.empty()) + materials_[key] = mat; + } + return true; +} +//----------------------------------------------------------------------------- + +bool +_OBJReader_:: +read_vertices(std::istream& _in, BaseImporter& _bi, Options& _opt, + std::vector & normals, + std::vector & colors, + std::vector & texcoords3d, + std::vector & texcoords, + std::vector & vertexHandles, + Options & fileOptions) +{ + double x, y, z, u, v, w; + double r, g, b; + + std::string line; + std::string keyWrd; + + std::stringstream stream; + + + // Options supplied by the user + const Options & userOptions = _opt; + + while( _in && !_in.eof() ) + { + std::getline(_in,line); + if ( _in.bad() ){ + omerr() << " Warning! Could not read file properly!\n"; + return false; + } + + // Trim Both leading and trailing spaces + trimString(line); + + // comment + if ( line.size() == 0 || line[0] == '#' || isspace(line[0]) ) { + continue; + } + + stream.str(line); + stream.clear(); + + stream >> keyWrd; + + // vertex + if (keyWrd == "v") + { + stream >> x; stream >> y; stream >> z; + + if ( !stream.fail() ) + { + vertexHandles.push_back(_bi.add_vertex(OpenMesh::Vec3f(x,y,z))); + stream >> r; stream >> g; stream >> b; + + if ( !stream.fail() ) + { + if ( userOptions.vertex_has_color() ) { + fileOptions += Options::VertexColor; + colors.push_back(OpenMesh::Vec3f(r,g,b)); + } + } + } + } + + // texture coord + else if (keyWrd == "vt") + { + stream >> u; stream >> v; + + if ( !stream.fail() ){ + + if ( userOptions.vertex_has_texcoord() || userOptions.face_has_texcoord() ) { + texcoords.push_back(OpenMesh::Vec2f(u, v)); + + // Can be used for both! + fileOptions += Options::VertexTexCoord; + fileOptions += Options::FaceTexCoord; + + // try to read the w component as it is optional + stream >> w; + if ( !stream.fail() ) + texcoords3d.push_back(OpenMesh::Vec3f(u, v, w)); + + } + + }else{ + omerr() << "Only single 2D or 3D texture coordinate per vertex" + << "allowed!" << std::endl; + return false; + } + } + + // color per vertex + else if (keyWrd == "vc") + { + stream >> r; stream >> g; stream >> b; + + if ( !stream.fail() ){ + if ( userOptions.vertex_has_color() ) { + colors.push_back(OpenMesh::Vec3f(r,g,b)); + fileOptions += Options::VertexColor; + } + } + } + + // normal + else if (keyWrd == "vn") + { + stream >> x; stream >> y; stream >> z; + + if ( !stream.fail() ) { + if (userOptions.vertex_has_normal() ){ + normals.push_back(OpenMesh::Vec3f(x,y,z)); + fileOptions += Options::VertexNormal; + } + } + } + } + + return true; +} + +//----------------------------------------------------------------------------- + +bool +_OBJReader_:: +read(std::istream& _in, BaseImporter& _bi, Options& _opt) +{ + std::string line; + std::string keyWrd; + + std::vector normals; + std::vector colors; + std::vector texcoords3d; + std::vector texcoords; + std::vector vertexHandles; + + BaseImporter::VHandles vhandles; + std::vector face_texcoords3d; + std::vector face_texcoords; + + std::string matname; + + std::stringstream stream, lineData, tmp; + + + // Options supplied by the user + Options userOptions = _opt; + + // Options collected via file parsing + Options fileOptions; + + // pass 1: read vertices + if ( !read_vertices(_in, _bi, _opt, + normals, colors, texcoords3d, texcoords, + vertexHandles, fileOptions) ){ + return false; + } + + // reset stream for second pass + _in.clear(); + _in.seekg(0, std::ios::beg); + + int nCurrentPositions = 0, + nCurrentTexcoords = 0, + nCurrentNormals = 0; + + // pass 2: read faces + while( _in && !_in.eof() ) + { + std::getline(_in,line); + if ( _in.bad() ){ + omerr() << " Warning! Could not read file properly!\n"; + return false; + } + + // Trim Both leading and trailing spaces + trimString(line); + + // comment + if ( line.size() == 0 || line[0] == '#' || isspace(line[0]) ) { + continue; + } + + stream.str(line); + stream.clear(); + + stream >> keyWrd; + + // material file + if (keyWrd == "mtllib") + { + std::string matFile; + + // Get the rest of the line, removing leading or trailing spaces + // This will define the filename of the texture + std::getline(stream,matFile); + trimString(matFile); + + matFile = path_ + matFile; + + //omlog() << "Load material file " << matFile << std::endl; + + std::fstream matStream( matFile.c_str(), std::ios_base::in ); + + if ( matStream ){ + + if ( !read_material( matStream ) ) + omerr() << " Warning! Could not read file properly!\n"; + matStream.close(); + + }else + omerr() << " Warning! Material file '" << matFile << "' not found!\n"; + + //omlog() << " " << materials_.size() << " materials loaded.\n"; + + for ( MaterialList::iterator material = materials_.begin(); material != materials_.end(); ++material ) + { + // Save the texture information in a property + if ( (*material).second.has_map_Kd() ) + _bi.add_texture_information( (*material).second.map_Kd_index() , (*material).second.map_Kd() ); + } + + } + + // usemtl + else if (keyWrd == "usemtl") + { + stream >> matname; + if (materials_.find(matname)==materials_.end()) + { + omerr() << "Warning! Material '" << matname + << "' not defined in material file.\n"; + matname=""; + } + } + + // track current number of parsed vertex attributes, + // to allow for OBJs negative indices + else if (keyWrd == "v") + { + ++nCurrentPositions; + } + else if (keyWrd == "vt") + { + ++nCurrentTexcoords; + } + else if (keyWrd == "vn") + { + ++nCurrentNormals; + } + + // faces + else if (keyWrd == "f") + { + int component(0), nV(0); + int value; + + vhandles.clear(); + face_texcoords.clear(); + face_texcoords3d.clear(); + + // read full line after detecting a face + std::string faceLine; + std::getline(stream,faceLine); + lineData.str( faceLine ); + lineData.clear(); + + FaceHandle fh; + BaseImporter::VHandles faceVertices; + + // work on the line until nothing left to read + while ( !lineData.eof() ) + { + // read one block from the line ( vertex/texCoord/normal ) + std::string vertex; + lineData >> vertex; + + do{ + + //get the component (vertex/texCoord/normal) + size_t found=vertex.find("/"); + + // parts are seperated by '/' So if no '/' found its the last component + if( found != std::string::npos ){ + + // read the index value + tmp.str( vertex.substr(0,found) ); + tmp.clear(); + + // If we get an empty string this property is undefined in the file + if ( vertex.substr(0,found).empty() ) { + // Switch to next field + vertex = vertex.substr(found+1); + + // Now we are at the next component + ++component; + + // Skip further processing of this component + continue; + } + + // Read current value + tmp >> value; + + // remove the read part from the string + vertex = vertex.substr(found+1); + + } else { + + // last component of the vertex, read it. + tmp.str( vertex ); + tmp.clear(); + tmp >> value; + + // Clear vertex after finished reading the line + vertex=""; + + // Nothing to read here ( garbage at end of line ) + if ( tmp.fail() ) { + continue; + } + } + + // store the component ( each component is referenced by the index here! ) + switch (component) + { + case 0: // vertex + if ( value < 0 ) { + // Calculation of index : + // -1 is the last vertex in the list + // As obj counts from 1 and not zero add +1 + value = nCurrentPositions + value + 1; + } + // Obj counts from 1 and not zero .. array counts from zero therefore -1 + vhandles.push_back(VertexHandle(value-1)); + faceVertices.push_back(VertexHandle(value-1)); + if (fileOptions.vertex_has_color()) { + if ((unsigned int)(value - 1) < colors.size()) { + _bi.set_color(vhandles.back(), colors[value - 1]); + } + else { + omerr() << "Error setting vertex color" << std::endl; + } + } + break; + + case 1: // texture coord + if ( value < 0 ) { + // Calculation of index : + // -1 is the last vertex in the list + // As obj counts from 1 and not zero add +1 + value = nCurrentTexcoords + value + 1; + } + assert(!vhandles.empty()); + + + if ( fileOptions.vertex_has_texcoord() && userOptions.vertex_has_texcoord() ) { + + if (!texcoords.empty() && (unsigned int) (value - 1) < texcoords.size()) { + // Obj counts from 1 and not zero .. array counts from zero therefore -1 + _bi.set_texcoord(vhandles.back(), texcoords[value - 1]); + if(!texcoords3d.empty() && (unsigned int) (value -1) < texcoords3d.size()) + _bi.set_texcoord(vhandles.back(), texcoords3d[value - 1]); + } else { + omerr() << "Error setting Texture coordinates" << std::endl; + } + + } + + if (fileOptions.face_has_texcoord() && userOptions.face_has_texcoord() ) { + + if (!texcoords.empty() && (unsigned int) (value - 1) < texcoords.size()) { + face_texcoords.push_back( texcoords[value-1] ); + if(!texcoords3d.empty() && (unsigned int) (value -1) < texcoords3d.size()) + face_texcoords3d.push_back( texcoords3d[value-1] ); + } else { + omerr() << "Error setting Texture coordinates" << std::endl; + } + } + + + break; + + case 2: // normal + if ( value < 0 ) { + // Calculation of index : + // -1 is the last vertex in the list + // As obj counts from 1 and not zero add +1 + value = nCurrentNormals + value + 1; + } + + // Obj counts from 1 and not zero .. array counts from zero therefore -1 + if (fileOptions.vertex_has_normal() ) { + assert(!vhandles.empty()); + if ((unsigned int)(value - 1) < normals.size()) { + _bi.set_normal(vhandles.back(), normals[value - 1]); + } + else { + omerr() << "Error setting vertex normal" << std::endl; + } + } + break; + } + + // Prepare for reading next component + ++component; + + // Read until line does not contain any other info + } while ( !vertex.empty() ); + + component = 0; + nV++; + + } + + // note that add_face can possibly triangulate the faces, which is why we have to + // store the current number of faces first + size_t n_faces = _bi.n_faces(); + remove_duplicated_vertices(faceVertices); + + //A minimum of three vertices are required. + if (faceVertices.size() > 2) + fh = _bi.add_face(faceVertices); + + if (!vhandles.empty() && fh.is_valid() ) + { + _bi.add_face_texcoords(fh, vhandles[0], face_texcoords); + _bi.add_face_texcoords(fh, vhandles[0], face_texcoords3d); + } + + if ( !matname.empty() ) + { + std::vector newfaces; + + for( size_t i=0; i < _bi.n_faces()-n_faces; ++i ) + newfaces.push_back(FaceHandle(int(n_faces+i))); + + Material& mat = materials_[matname]; + + if ( mat.has_Kd() ) { + Vec3uc fc = color_cast(mat.Kd()); + + if ( userOptions.face_has_color()) { + + for (std::vector::iterator it = newfaces.begin(); it != newfaces.end(); ++it) + _bi.set_color(*it, fc); + + fileOptions += Options::FaceColor; + } + } + + // Set the texture index in the face index property + if ( mat.has_map_Kd() ) { + + if (userOptions.face_has_texcoord()) { + + for (std::vector::iterator it = newfaces.begin(); it != newfaces.end(); ++it) + _bi.set_face_texindex(*it, mat.map_Kd_index()); + + fileOptions += Options::FaceTexCoord; + + } + + } else { + + // If we don't have the info, set it to no texture + if (userOptions.face_has_texcoord()) { + + for (std::vector::iterator it = newfaces.begin(); it != newfaces.end(); ++it) + _bi.set_face_texindex(*it, 0); + + } + } + + } else { + std::vector newfaces; + + for( size_t i=0; i < _bi.n_faces()-n_faces; ++i ) + newfaces.push_back(FaceHandle(int(n_faces+i))); + + // Set the texture index to zero as we don't have any information + if ( userOptions.face_has_texcoord() ) + for (std::vector::iterator it = newfaces.begin(); it != newfaces.end(); ++it) + _bi.set_face_texindex(*it, 0); + } + + } + + } + + // If we do not have any faces, + // assume this is a point cloud and read the normals and colors directly + if (_bi.n_faces() == 0) + { + int i = 0; + // add normal per vertex + + if (normals.size() == _bi.n_vertices()) { + if ( fileOptions.vertex_has_normal() && userOptions.vertex_has_normal() ) { + for (std::vector::iterator it = vertexHandles.begin(); it != vertexHandles.end(); ++it, i++) + _bi.set_normal(*it, normals[i]); + } + } + + // add color per vertex + i = 0; + if (colors.size() >= _bi.n_vertices()) + if (fileOptions.vertex_has_color() && userOptions.vertex_has_color()) { + for (std::vector::iterator it = vertexHandles.begin(); it != vertexHandles.end(); ++it, i++) + _bi.set_color(*it, colors[i]); + } + + } + + // Return, what we actually read + _opt = fileOptions; + + return true; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/OBJReader.hh b/Sources/OpenMeshCore/Core/IO/reader/OBJReader.hh new file mode 100644 index 0000000..e90765d --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/OBJReader.hh @@ -0,0 +1,196 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements an reader module for OBJ files +// +//============================================================================= + + +#ifndef __OBJREADER_HH__ +#define __OBJREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OBJ format reader. +*/ +class OPENMESHDLLEXPORT _OBJReader_ : public BaseReader +{ +public: + + _OBJReader_(); + + virtual ~_OBJReader_() { } + + std::string get_description() const override { return "Alias/Wavefront"; } + std::string get_extensions() const override { return "obj"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) override; + + bool read(std::istream& _in, + BaseImporter& _bi, + Options& _opt) override; + +private: + +#ifndef DOXY_IGNORE_THIS + class Material + { + public: + + Material():Tr_(0),index_Kd_(0) { cleanup(); } + + void cleanup() + { + Kd_is_set_ = false; + Ka_is_set_ = false; + Ks_is_set_ = false; + Tr_is_set_ = false; + map_Kd_is_set_ = false; + } + + bool is_valid(void) const + { return Kd_is_set_ || Ka_is_set_ || Ks_is_set_ || Tr_is_set_ || map_Kd_is_set_; } + + bool has_Kd(void) { return Kd_is_set_; } + bool has_Ka(void) { return Ka_is_set_; } + bool has_Ks(void) { return Ks_is_set_; } + bool has_Tr(void) { return Tr_is_set_; } + bool has_map_Kd(void) { return map_Kd_is_set_; } + + void set_Kd( float r, float g, float b ) + { Kd_=Vec3f(r,g,b); Kd_is_set_=true; } + + void set_Ka( float r, float g, float b ) + { Ka_=Vec3f(r,g,b); Ka_is_set_=true; } + + void set_Ks( float r, float g, float b ) + { Ks_=Vec3f(r,g,b); Ks_is_set_=true; } + + void set_Tr( float t ) + { Tr_=t; Tr_is_set_=true; } + + void set_map_Kd( const std::string& _name, int _index_Kd ) + { map_Kd_ = _name, index_Kd_ = _index_Kd; map_Kd_is_set_ = true; }; + + const Vec3f& Kd( void ) const { return Kd_; } + const Vec3f& Ka( void ) const { return Ka_; } + const Vec3f& Ks( void ) const { return Ks_; } + float Tr( void ) const { return Tr_; } + const std::string& map_Kd( void ) { return map_Kd_ ; } + const int& map_Kd_index( void ) { return index_Kd_ ; } + + private: + + Vec3f Kd_; bool Kd_is_set_; // diffuse + Vec3f Ka_; bool Ka_is_set_; // ambient + Vec3f Ks_; bool Ks_is_set_; // specular + float Tr_; bool Tr_is_set_; // transperency + + std::string map_Kd_; int index_Kd_; bool map_Kd_is_set_; // Texture + + }; +#endif + + typedef std::map MaterialList; + + MaterialList materials_; + + bool read_material( std::fstream& _in ); + + +private: + + bool read_vertices(std::istream& _in, BaseImporter& _bi, Options& _opt, + std::vector & normals, + std::vector & colors, + std::vector & texcoords3d, + std::vector & texcoords, + std::vector & vertexHandles, + Options & fileOptions); + + std::string path_; + +}; + + +//== TYPE DEFINITION ========================================================== + + +extern _OBJReader_ __OBJReaderInstance; +OPENMESHDLLEXPORT _OBJReader_& OBJReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/OFFReader.cc b/Sources/OpenMeshCore/Core/IO/reader/OFFReader.cc new file mode 100644 index 0000000..23d8bc8 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/OFFReader.cc @@ -0,0 +1,683 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#define LINE_LEN 4096 + + +//== INCLUDES ================================================================= + +// OpenMesh +#include +#include +#include +#include +#include +// #include + +//STL +#include +#include +#include +#include + +#if defined(OM_CC_MIPS) +# include +/// \bug Workaround for STLPORT 4.6: isspace seems not to be in namespace std! +#elif defined(_STLPORT_VERSION) && (_STLPORT_VERSION==0x460) +# include +#else +using std::isspace; +#endif + +#ifndef WIN32 +#endif + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + +//=== INSTANCIATE ============================================================= + + +_OFFReader_ __OFFReaderInstance; +_OFFReader_& OFFReader() { return __OFFReaderInstance; } + + +//=== IMPLEMENTATION ========================================================== + + + +_OFFReader_::_OFFReader_() +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_OFFReader_::read(const std::string& _filename, BaseImporter& _bi, + Options& _opt) +{ + std::ifstream ifile(_filename.c_str(), (options_.is_binary() ? std::ios::binary | std::ios::in + : std::ios::in) ); + + if (!ifile.is_open() || !ifile.good()) + { + omerr() << "[OFFReader] : cannot not open file " + << _filename + << std::endl; + + return false; + } + + assert(ifile); + + bool result = read(ifile, _bi, _opt); + + ifile.close(); + return result; +} + +//----------------------------------------------------------------------------- + + +bool +_OFFReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt ) +{ + if (!_in.good()) + { + omerr() << "[OMReader] : cannot not use stream " + << std::endl; + return false; + } + + // filter relevant options for reading + bool swap_required = _opt.check( Options::Swap ); + + userOptions_ = _opt; + + // build options to be returned + _opt.clear(); + + if (options_.vertex_has_normal() && userOptions_.vertex_has_normal()) _opt += Options::VertexNormal; + if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) _opt += Options::VertexTexCoord; + if (options_.vertex_has_color() && userOptions_.vertex_has_color()) _opt += Options::VertexColor; + if (options_.face_has_color() && userOptions_.face_has_color()) _opt += Options::FaceColor; + if (options_.is_binary()) _opt += Options::Binary; + + //force user-choice for the alpha value when reading binary + if ( options_.is_binary() && userOptions_.color_has_alpha() ) + options_ += Options::ColorAlpha; + + return (options_.is_binary() ? + read_binary(_in, _bi, _opt, swap_required) : + read_ascii(_in, _bi, _opt)); + +} + + + +//----------------------------------------------------------------------------- + +bool +_OFFReader_::read_ascii(std::istream& _in, BaseImporter& _bi, Options& _opt) const +{ + + + unsigned int i, j, k, l, idx; + unsigned int nV, nF, dummy; + OpenMesh::Vec3f v, n; + OpenMesh::Vec2f t; + OpenMesh::Vec3i c3; + OpenMesh::Vec3f c3f; + OpenMesh::Vec4i c4; + OpenMesh::Vec4f c4f; + BaseImporter::VHandles vhandles; + VertexHandle vh; + std::stringstream stream; + std::string trash; + + // read header line + std::string header; + std::getline(_in,header); + + // + #Vertice, #Faces, #Edges + _in >> nV; + _in >> nF; + _in >> dummy; + + _bi.reserve(nV, 3*nV, nF); + + // read vertices: coord [hcoord] [normal] [color] [texcoord] + for (i=0; i> v[0]; _in >> v[1]; _in >> v[2]; + + vh = _bi.add_vertex(v); + + //perhaps read NORMAL + if ( options_.vertex_has_normal() ){ + + _in >> n[0]; _in >> n[1]; _in >> n[2]; + + if ( userOptions_.vertex_has_normal() ) + _bi.set_normal(vh, n); + } + + //take the rest of the line and check how colors are defined + std::string line; + std::getline(_in,line); + + int colorType = getColorType(line, options_.vertex_has_texcoord() ); + + stream.str(line); + stream.clear(); + + //perhaps read COLOR + if ( options_.vertex_has_color() ){ + + switch (colorType){ + case 0 : break; //no color + case 1 : stream >> trash; break; //one int (isn't handled atm) + case 2 : stream >> trash; stream >> trash; break; //corrupt format (ignore) + // rgb int + case 3 : stream >> c3[0]; stream >> c3[1]; stream >> c3[2]; + if ( userOptions_.vertex_has_color() ) + _bi.set_color( vh, Vec3uc( c3 ) ); + break; + // rgba int + case 4 : stream >> c4[0]; stream >> c4[1]; stream >> c4[2]; stream >> c4[3]; + if ( userOptions_.vertex_has_color() ) + _bi.set_color( vh, Vec4uc( c4 ) ); + break; + // rgb floats + case 5 : stream >> c3f[0]; stream >> c3f[1]; stream >> c3f[2]; + if ( userOptions_.vertex_has_color() ) { + _bi.set_color( vh, c3f ); + _opt += Options::ColorFloat; + } + break; + // rgba floats + case 6 : stream >> c4f[0]; stream >> c4f[1]; stream >> c4f[2]; stream >> c4f[3]; + if ( userOptions_.vertex_has_color() ) { + _bi.set_color( vh, c4f ); + _opt += Options::ColorFloat; + } + break; + + default: + std::cerr << "Error in file format (colorType = " << colorType << ")\n"; + break; + } + } + //perhaps read TEXTURE COORDs + if ( options_.vertex_has_texcoord() ){ + stream >> t[0]; stream >> t[1]; + if ( userOptions_.vertex_has_texcoord() ) + _bi.set_texcoord(vh, t); + } + } + + // faces + // #N .. [color spec] + for (i=0; i> nV; + + if (nV == 3) + { + vhandles.resize(3); + _in >> j; + _in >> k; + _in >> l; + + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); + } + else + { + vhandles.clear(); + for (j=0; j> idx; + vhandles.push_back(VertexHandle(idx)); + } + } + + FaceHandle fh = _bi.add_face(vhandles); + + //perhaps read face COLOR + if ( options_.face_has_color() ){ + + //take the rest of the line and check how colors are defined + std::string line; + std::getline(_in,line); + + int colorType = getColorType(line, false ); + + stream.str(line); + stream.clear(); + + switch (colorType){ + case 0 : break; //no color + case 1 : stream >> trash; break; //one int (isn't handled atm) + case 2 : stream >> trash; stream >> trash; break; //corrupt format (ignore) + // rgb int + case 3 : stream >> c3[0]; stream >> c3[1]; stream >> c3[2]; + if ( userOptions_.face_has_color() ) + _bi.set_color( fh, Vec3uc( c3 ) ); + break; + // rgba int + case 4 : stream >> c4[0]; stream >> c4[1]; stream >> c4[2]; stream >> c4[3]; + if ( userOptions_.face_has_color() ) + _bi.set_color( fh, Vec4uc( c4 ) ); + break; + // rgb floats + case 5 : stream >> c3f[0]; stream >> c3f[1]; stream >> c3f[2]; + if ( userOptions_.face_has_color() ) { + _bi.set_color( fh, c3f ); + _opt += Options::ColorFloat; + } + break; + // rgba floats + case 6 : stream >> c4f[0]; stream >> c4f[1]; stream >> c4f[2]; stream >> c4f[3]; + if ( userOptions_.face_has_color() ) { + _bi.set_color( fh, c4f ); + _opt += Options::ColorFloat; + } + break; + + default: + std::cerr << "Error in file format (colorType = " << colorType << ")\n"; + break; + } + } + } + + // File was successfully parsed. + return true; +} + + +//----------------------------------------------------------------------------- + +int _OFFReader_::getColorType(std::string& _line, bool _texCoordsAvailable) const +{ +/* + 0 : no Color + 1 : one int (e.g colormap index) + 2 : two items (error!) + 3 : 3 ints + 4 : 3 ints + 5 : 3 floats + 6 : 4 floats + +*/ + // Check if we have any additional information here + if ( _line.size() < 1 ) + return 0; + + //first remove spaces at start/end of the line + while (_line.size() > 0 && std::isspace(_line[0])) + _line = _line.substr(1); + while (_line.size() > 0 && std::isspace(_line[ _line.length()-1 ])) + _line = _line.substr(0, _line.length()-1); + + //count the remaining items in the line + size_t found; + int count = 0; + + found=_line.find_first_of(" "); + while (found!=std::string::npos){ + count++; + found=_line.find_first_of(" ",found+1); + } + + if (!_line.empty()) count++; + + if (_texCoordsAvailable) count -= 2; + + if (count == 3 || count == 4){ + //get first item + found = _line.find(" "); + std::string c1 = _line.substr (0,found); + + if (c1.find(".") != std::string::npos){ + if (count == 3) + count = 5; + else + count = 6; + } + } + return count; +} + +void _OFFReader_::readValue(std::istream& _in, float& _value) const{ + float32_t tmp; + + restore( _in , tmp, false ); //assuming LSB byte order + _value = tmp; +} + +void _OFFReader_::readValue(std::istream& _in, int& _value) const{ + uint32_t tmp; + + restore( _in , tmp, false ); //assuming LSB byte order + _value = tmp; +} + +void _OFFReader_::readValue(std::istream& _in, unsigned int& _value) const{ + uint32_t tmp; + + restore( _in , tmp, false ); //assuming LSB byte order + _value = tmp; +} + +bool +_OFFReader_::read_binary(std::istream& _in, BaseImporter& _bi, Options& _opt, bool /*_swap*/) const +{ + unsigned int i, j, k, l, idx; + unsigned int nV, nF, dummy; + OpenMesh::Vec3f v, n; + OpenMesh::Vec3i c; + OpenMesh::Vec4i cA; + OpenMesh::Vec3f cf; + OpenMesh::Vec4f cAf; + OpenMesh::Vec2f t; + BaseImporter::VHandles vhandles; + VertexHandle vh; + + // read header line + std::string header; + std::getline(_in,header); + + // + #Vertice, #Faces, #Edges + readValue(_in, nV); + readValue(_in, nF); + readValue(_in, dummy); + + _bi.reserve(nV, 3*nV, nF); + + // read vertices: coord [hcoord] [normal] [color] [texcoord] + for (i=0; i .. [color spec] + // So far color spec is unsupported! + for (i=0; i 1 ) && ( p[0] == 'S' && p[1] == 'T') ) + { options_ += Options::VertexTexCoord; p += 2; remainingChars -= 2; } + + if ( ( remainingChars > 0 ) && ( p[0] == 'C') ) + { options_ += Options::VertexColor; + options_ += Options::FaceColor; ++p; --remainingChars; } + + if ( ( remainingChars > 0 ) && ( p[0] == 'N') ) + { options_ += Options::VertexNormal; ++p; --remainingChars; } + + if ( ( remainingChars > 0 ) && (p[0] == '4' ) ) + { vertexDimensionTooHigh = true; ++p; --remainingChars; } + + if ( ( remainingChars > 0 ) && ( p[0] == 'n') ) + { vertexDimensionTooHigh = true; ++p; --remainingChars; } + + if ( ( remainingChars < 3 ) || (!(p[0] == 'O' && p[1] == 'F' && p[2] == 'F') ) ) + return false; + + p += 4; + + // Detect possible garbage and make sure, we don't have an underflow + if ( remainingChars >= 4 ) + remainingChars -= 4; + else + remainingChars = 0; + + if ( ( remainingChars >= 6 ) && ( strncmp(p, "BINARY", 6) == 0 ) ) + options_+= Options::Binary; + + // vertex Dimensions != 3 are currently not supported + if (vertexDimensionTooHigh) + return false; + + return true; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/OFFReader.hh b/Sources/OpenMeshCore/Core/IO/reader/OFFReader.hh new file mode 100644 index 0000000..57cda96 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/OFFReader.hh @@ -0,0 +1,161 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + +#pragma once + +//=== INCLUDES ================================================================ + + +#include +#include +#include + +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== FORWARDS ================================================================= + + +class BaseImporter; + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OFF format reader. This class is singleton'ed by + SingletonT to OFFReader. + + By passing Options to the read function you can manipulate the reading behavoir. + The following options can be set: + + VertexNormal + VertexColor + VertexTexCoord + FaceColor + ColorAlpha [only when reading binary] + + These options define if the corresponding data should be read (if available) + or if it should be omitted. + + After execution of the read function. The options object contains information about + what was actually read. + + e.g. if VertexNormal was true when the read function was called, but the file + did not contain vertex normals then it is false afterwards. + + When reading a binary off with Color Flag in the header it is assumed that all vertices + and faces have colors in the format "int int int". + If ColorAlpha is set the format "int int int int" is assumed. + +*/ + +class OPENMESHDLLEXPORT _OFFReader_ : public BaseReader +{ +public: + + _OFFReader_(); + + /// Destructor + virtual ~_OFFReader_() {}; + + std::string get_description() const override { return "Object File Format"; } + std::string get_extensions() const override { return "off"; } + std::string get_magic() const override { return "OFF"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) override; + + bool can_u_read(const std::string& _filename) const override; + + bool read(std::istream& _in, BaseImporter& _bi, Options& _opt ) override; + +private: + + bool can_u_read(std::istream& _is) const; + + bool read_ascii(std::istream& _in, BaseImporter& _bi, Options& _opt) const; + bool read_binary(std::istream& _in, BaseImporter& _bi, Options& _opt, bool swap) const; + + void readValue(std::istream& _in, float& _value) const; + void readValue(std::istream& _in, int& _value) const; + void readValue(std::istream& _in, unsigned int& _value) const; + + int getColorType(std::string & _line, bool _texCoordsAvailable) const; + + //available options for reading + mutable Options options_; + //options that the user wants to read + mutable Options userOptions_; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OFF reader +extern _OFFReader_ __OFFReaderInstance; +OPENMESHDLLEXPORT _OFFReader_& OFFReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/OMReader.cc b/Sources/OpenMeshCore/Core/IO/reader/OMReader.cc new file mode 100644 index 0000000..59730a1 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/OMReader.cc @@ -0,0 +1,890 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//== INCLUDES ================================================================= + + +//STL +#include +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include +#include + +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OMReader singleton with MeshReader +_OMReader_ __OMReaderInstance; +_OMReader_& OMReader() { return __OMReaderInstance; } + + + +//=== IMPLEMENTATION ========================================================== + + +_OMReader_::_OMReader_() +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool _OMReader_::read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + // check whether importer can give us an OpenMesh BaseKernel + if (!_bi.kernel()) + return false; + + _opt += Options::Binary; // only binary format supported! + fileOptions_ = Options::Binary; + + // Open file + std::ifstream ifs(_filename.c_str(), std::ios::binary); + + /* Clear formatting flag skipws (Skip whitespaces). If set, operator>> will + * skip bytes set to whitespace chars (e.g. 0x20 bytes) in + * Property::restore. + */ + ifs.unsetf(std::ios::skipws); + + if (!ifs.is_open() || !ifs.good()) { + omerr() << "[OMReader] : cannot not open file " << _filename << std::endl; + return false; + } + + // Pass stream to read method, remember result + bool result = read(ifs, _bi, _opt); + + // close input stream + ifs.close(); + + _opt = _opt & fileOptions_; + + return result; +} + +//----------------------------------------------------------------------------- + + +bool _OMReader_::read(std::istream& _is, BaseImporter& _bi, Options& _opt) +{ + // check whether importer can give us an OpenMesh BaseKernel + if (!_bi.kernel()) + return false; + + _opt += Options::Binary; // only binary format supported! + fileOptions_ = Options::Binary; + + if (!_is.good()) { + omerr() << "[OMReader] : cannot read from stream " << std::endl; + return false; + } + + // Pass stream to read method, remember result + bool result = read_binary(_is, _bi, _opt); + + if (result) + _opt += Options::Binary; + + _opt = _opt & fileOptions_; + + return result; +} + + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_ascii(std::istream& /* _is */, BaseImporter& /* _bi */, const Options& /* _opt */) const +{ + // not supported yet! + return false; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary(std::istream& _is, BaseImporter& _bi, const Options& _opt) const +{ + bool swap_required = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB); + + // Initialize byte counter + bytes_ = 0; + + bytes_ += restore(_is, header_, swap_required); + + + if (header_.version_ > _OMWriter_::get_version()) + { + omerr() << "File uses .om version " << OMFormat::as_string(header_.version_) << " but reader only " + << "supports up to version " << OMFormat::as_string(_OMWriter_::get_version()) << ".\n" + << "Please update your OpenMesh." << std::endl; + return false; + } + + while (!_is.eof()) { + bytes_ += restore(_is, chunk_header_, swap_required); + + if (_is.eof()) + break; + + // Is this a named property restore the name + if (chunk_header_.name_) { + OMFormat::Chunk::PropertyName pn; + bytes_ += restore(_is, property_name_, swap_required); + } + + // Read in the property data. If it is an anonymous or unknown named + // property, then skip data. + switch (chunk_header_.entity_) { + case OMFormat::Chunk::Entity_Vertex: + if (!read_binary_vertex_chunk(_is, _bi, _opt, swap_required)) + return false; + break; + case OMFormat::Chunk::Entity_Face: + if (!read_binary_face_chunk(_is, _bi, _opt, swap_required)) + return false; + break; + case OMFormat::Chunk::Entity_Edge: + if (!read_binary_edge_chunk(_is, _bi, _opt, swap_required)) + return false; + break; + case OMFormat::Chunk::Entity_Halfedge: + if (!read_binary_halfedge_chunk(_is, _bi, _opt, swap_required)) + return false; + break; + case OMFormat::Chunk::Entity_Mesh: + if (!read_binary_mesh_chunk(_is, _bi, _opt, swap_required)) + return false; + break; + case OMFormat::Chunk::Entity_Sentinel: + return true; + default: + return false; + } + + } + + // File was successfully parsed. + return true; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::can_u_read(const std::string& _filename) const +{ + // !!! Assuming BaseReader::can_u_parse( std::string& ) + // does not call BaseReader::read_magic()!!! + if (this->BaseReader::can_u_read(_filename)) { + std::ifstream ifile(_filename.c_str()); + if (ifile && can_u_read(ifile)) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- + +bool _OMReader_::can_u_read(std::istream& _is) const +{ + std::vector evt; + evt.reserve(20); + + // read first 4 characters into a buffer + while (evt.size() < 4) + evt.push_back(static_cast(_is.get())); + + // put back all read characters + std::vector::reverse_iterator it = evt.rbegin(); + while (it != evt.rend()) + _is.putback(*it++); + + // evaluate header information + OMFormat::Header *hdr = (OMFormat::Header*) &evt[0]; + + // first two characters must be 'OM' + if (hdr->magic_[0] != 'O' || hdr->magic_[1] != 'M') + return false; + + // 3rd characters defines the mesh type: + switch (hdr->mesh_) { + case 'T': // Triangle Mesh + case 'Q': // Quad Mesh + case 'P': // Polygonal Mesh + break; + default: // ? + return false; + } + + // 4th characters encodes the version + return supports(hdr->version_); +} + +//----------------------------------------------------------------------------- + +bool _OMReader_::supports(const OMFormat::uint8 /* version */) const +{ + return true; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi, const Options &_opt, bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Vertex); + + OpenMesh::Vec3f v3f; + OpenMesh::Vec3d v3d; + OpenMesh::Vec2f v2f; + OpenMesh::Vec3uc v3uc; // rgb + OpenMesh::Attributes::StatusInfo status; + + OMFormat::Chunk::PropertyName custom_prop; + + size_t vidx = 0; + switch (chunk_header_.type_) { + case Chunk::Type_Pos: + if (chunk_header_.bits_ == OMFormat::bits(0.0f)) // read floats + { + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); + + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3f, _swap); + _bi.add_vertex(v3f); + } + } + else if (chunk_header_.bits_ == OMFormat::bits(0.0)) // read doubles + { + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3d::dim())); + + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3d, _swap); + _bi.add_vertex(v3d); + } + } + else + { + omerr() << "unknown Vector size" << std::endl; + } + break; + + case Chunk::Type_Normal: + + if (chunk_header_.bits_ == OMFormat::bits(0.0f)) // read floats + { + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); + + fileOptions_ += Options::VertexNormal; + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3f, _swap); + if (fileOptions_.vertex_has_normal() && _opt.vertex_has_normal()) + _bi.set_normal(VertexHandle(int(vidx)), v3f); + } + } + else if (chunk_header_.bits_ == OMFormat::bits(0.0)) // read doubles + { + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3d::dim())); + + fileOptions_ += Options::VertexNormal; + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3d, _swap); + if (fileOptions_.vertex_has_normal() && _opt.vertex_has_normal()) + _bi.set_normal(VertexHandle(int(vidx)), v3d); + } + } + else + { + omerr() << "Unknown vertex normal format" << std::endl; + } + break; + + case Chunk::Type_Texcoord: + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec2f::dim())); + + fileOptions_ += Options::VertexTexCoord; + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v2f, _swap); + if (fileOptions_.vertex_has_texcoord() && _opt.vertex_has_texcoord()) + _bi.set_texcoord(VertexHandle(int(vidx)), v2f); + } + break; + + case Chunk::Type_Color: + + assert( OMFormat::dimensions(chunk_header_) == 3); + + fileOptions_ += Options::VertexColor; + + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3uc, _swap); + if (fileOptions_.vertex_has_color() && _opt.vertex_has_color()) + _bi.set_color(VertexHandle(int(vidx)), v3uc); + } + break; + + case Chunk::Type_Status: + { + assert( OMFormat::dimensions(chunk_header_) == 1); + + fileOptions_ += Options::Status; + + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += restore(_is, status, _swap); + if (fileOptions_.vertex_has_status() && _opt.vertex_has_status()) + _bi.set_status(VertexHandle(int(vidx)), status); + } + break; + } + + case Chunk::Type_Custom: + { + if(header_.version_ > OMFormat::mk_version(2,1)) + { + Chunk::PropertyName property_type; + bytes_ += restore(_is, property_type, _swap); + if (_opt.check(Options::Custom)) + add_generic_property(property_type, _bi); + } + + bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_vprop(property_name_), header_.n_vertices_, _swap); + vidx = header_.n_vertices_; + } + + break; + + case Chunk::Type_Topology: + { + for (; vidx < header_.n_vertices_; ++vidx) + { + int halfedge_id = 0; + bytes_ += restore( _is, halfedge_id, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + + _bi.set_halfedge(VertexHandle(static_cast(vidx)), HalfedgeHandle(halfedge_id)); + } + } + + break; + + default: // skip unknown chunks + { + omerr() << "Unknown chunk type ignored!\n"; + size_t chunk_size = header_.n_vertices_ * OMFormat::vector_size(chunk_header_); + _is.ignore(chunk_size); + bytes_ += chunk_size; + break; + } + + } + + // all chunk data has been read..?! + return vidx == header_.n_vertices_; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, const Options &_opt, bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Face); + + size_t fidx = 0; + OpenMesh::Vec3f v3f; // normal + OpenMesh::Vec3d v3d; // normal as double + OpenMesh::Vec3uc v3uc; // rgb + OpenMesh::Attributes::StatusInfo status; + + switch (chunk_header_.type_) { + case Chunk::Type_Topology: + { + if (header_.version_ < OMFormat::mk_version(2,0)) + { + // add faces based on vertex indices + BaseImporter::VHandles vhandles; + size_t nV = 0; + size_t vidx = 0; + + switch (header_.mesh_) { + case 'T': + nV = 3; + break; + case 'Q': + nV = 4; + break; + } + + for (; fidx < header_.n_faces_; ++fidx) { + if (header_.mesh_ == 'P') + bytes_ += restore(_is, nV, Chunk::Integer_16, _swap); + + vhandles.clear(); + for (size_t j = 0; j < nV; ++j) { + bytes_ += restore(_is, vidx, Chunk::Integer_Size(chunk_header_.bits_), _swap); + + vhandles.push_back(VertexHandle(int(vidx))); + } + + _bi.add_face(vhandles); + } + } + else + { + // add faces by simply setting an incident halfedge + for (; fidx < header_.n_faces_; ++fidx) + { + int halfedge_id = 0; + bytes_ += restore( _is, halfedge_id, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + + _bi.add_face(HalfedgeHandle(halfedge_id)); + } + } + } + break; + + case Chunk::Type_Normal: + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); + + fileOptions_ += Options::FaceNormal; + + if (chunk_header_.bits_ == OMFormat::bits(0.0f)) // read floats + { + for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) { + bytes_ += vector_restore(_is, v3f, _swap); + if( fileOptions_.face_has_normal() && _opt.face_has_normal()) + _bi.set_normal(FaceHandle(int(fidx)), v3f); + } + } + else if (chunk_header_.bits_ == OMFormat::bits(0.0)) // read doubles + { + for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) { + bytes_ += vector_restore(_is, v3d, _swap); + if( fileOptions_.face_has_normal() && _opt.face_has_normal()) + _bi.set_normal(FaceHandle(int(fidx)), v3d); + } + } + else + { + omerr() << "Unknown face normal format" << std::endl; + } + break; + + case Chunk::Type_Color: + + assert( OMFormat::dimensions(chunk_header_) == 3); + + fileOptions_ += Options::FaceColor; + for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) { + bytes_ += vector_restore(_is, v3uc, _swap); + if( fileOptions_.face_has_color() && _opt.face_has_color()) + _bi.set_color(FaceHandle(int(fidx)), v3uc); + } + break; + case Chunk::Type_Status: + { + assert( OMFormat::dimensions(chunk_header_) == 1); + + fileOptions_ += Options::Status; + + for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) { + bytes_ += restore(_is, status, _swap); + if (fileOptions_.face_has_status() && _opt.face_has_status()) + _bi.set_status(FaceHandle(int(fidx)), status); + } + break; + } + + case Chunk::Type_Custom: + { + if(header_.version_ > OMFormat::mk_version(2,1)) + { + Chunk::PropertyName property_type; + bytes_ += restore(_is, property_type, _swap); + if (_opt.check(Options::Custom)) + add_generic_property(property_type, _bi); + } + + bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_fprop(property_name_), header_.n_faces_, _swap); + + fidx = header_.n_faces_; + + break; + } + + default: // skip unknown chunks + { + omerr() << "Unknown chunk type ignore!\n"; + size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore(chunk_size); + bytes_ += chunk_size; + } + } + return fidx == header_.n_faces_; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, const Options &_opt, bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Edge); + + size_t b = bytes_; + + OpenMesh::Attributes::StatusInfo status; + + switch (chunk_header_.type_) { + case Chunk::Type_Custom: + { + if(header_.version_ > OMFormat::mk_version(2,1)) + { + Chunk::PropertyName property_type; + bytes_ += restore(_is, property_type, _swap); + if (_opt.check(Options::Custom)) + add_generic_property(property_type, _bi); + } + + bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_eprop(property_name_), header_.n_edges_, _swap); + + break; + } + case Chunk::Type_Status: + { + assert( OMFormat::dimensions(chunk_header_) == 1); + + fileOptions_ += Options::Status; + + for (size_t eidx = 0; eidx < header_.n_edges_ && !_is.eof(); ++eidx) { + bytes_ += restore(_is, status, _swap); + if (fileOptions_.edge_has_status() && _opt.edge_has_status()) + _bi.set_status(EdgeHandle(int(eidx)), status); + } + break; + } + + default: + // skip unknown type + size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore(chunk_size); + bytes_ += chunk_size; + } + + return b < bytes_; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi, const Options & _opt, bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Halfedge); + + size_t b = bytes_; + OpenMesh::Attributes::StatusInfo status; + + switch (chunk_header_.type_) { + case Chunk::Type_Custom: + { + if(header_.version_ > OMFormat::mk_version(2,1)) + { + Chunk::PropertyName property_type; + bytes_ += restore(_is, property_type, _swap); + if (_opt.check(Options::Custom)) + add_generic_property(property_type, _bi); + } + + bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_hprop(property_name_), 2 * header_.n_edges_, _swap); + break; + } + + //---------------------------------------------------------------------------------------- + case Chunk::Type_Texcoord: + { + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec2f::dim())); + + //fileOptions_ += OpenMesh::IO::Options::FaceTexCoord; + + if (_opt.face_has_texcoord()) + { + _bi.request_face_texcoords2D(); + } + OpenMesh::Vec2f v2f; + for (size_t e_idx = 0; e_idx < header_.n_edges_*2; ++e_idx) + { + bytes_ += vector_restore(_is, v2f, _swap); + if (_opt.face_has_texcoord()) + _bi.set_texcoord(HalfedgeHandle(int(e_idx)), v2f); + } + break; + } + //---------------------------------------------------------------------------------------- + case Chunk::Type_Topology: + { + std::vector next_halfedges; + for (size_t e_idx = 0; e_idx < header_.n_edges_; ++e_idx) + { + int next_id_0 = -1; + int to_vertex_id_0 = -1; + int face_id_0 = -1; + bytes_ += restore( _is, next_id_0, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + bytes_ += restore( _is, to_vertex_id_0, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + bytes_ += restore( _is, face_id_0, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + + int next_id_1 = -1; + int to_vertex_id_1 = -1; + int face_id_1 = -1; + bytes_ += restore( _is, next_id_1, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + bytes_ += restore( _is, to_vertex_id_1, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + bytes_ += restore( _is, face_id_1, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + + auto heh0 = _bi.add_edge(VertexHandle(to_vertex_id_1), VertexHandle(to_vertex_id_0)); + auto heh1 = HalfedgeHandle(heh0.idx() + 1); + + next_halfedges.push_back(HalfedgeHandle(next_id_0)); + next_halfedges.push_back(HalfedgeHandle(next_id_1)); + + _bi.set_face(heh0, FaceHandle(face_id_0)); + _bi.set_face(heh1, FaceHandle(face_id_1)); + } + + for (size_t i = 0; i < next_halfedges.size(); ++i) + _bi.set_next(HalfedgeHandle(static_cast(i)), next_halfedges[i]); + } + + break; + + case Chunk::Type_Status: + { + assert( OMFormat::dimensions(chunk_header_) == 1); + + fileOptions_ += Options::Status; + + for (size_t hidx = 0; hidx < header_.n_edges_ * 2 && !_is.eof(); ++hidx) { + bytes_ += restore(_is, status, _swap); + if (fileOptions_.halfedge_has_status() && _opt.halfedge_has_status()) + _bi.set_status(HalfedgeHandle(int(hidx)), status); + } + break; + } + + default: + // skip unknown chunk + omerr() << "Unknown chunk type ignored!\n"; + size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore(chunk_size); + bytes_ += chunk_size; + } + + return b < bytes_; +} + + +//----------------------------------------------------------------------------- + +bool _OMReader_::read_binary_mesh_chunk(std::istream &_is, BaseImporter &_bi, const Options& _opt , bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Mesh); + + size_t b = bytes_; + + switch (chunk_header_.type_) { + case Chunk::Type_Custom: + { + if(header_.version_ > OMFormat::mk_version(2,1)) + { + Chunk::PropertyName property_type; + bytes_ += restore(_is, property_type, _swap); + if (_opt.check(Options::Custom)) + add_generic_property(property_type, _bi); + } + + bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_mprop(property_name_), 1, _swap); + + break; + } + default: + // skip unknown chunk + size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore(chunk_size); + bytes_ += chunk_size; + } + + return b < bytes_; +} + + +//----------------------------------------------------------------------------- + + +size_t _OMReader_::restore_binary_custom_data(std::istream& _is, BaseProperty* _bp, size_t _n_elem, bool _swap) const +{ + assert( !_bp || (_bp->name() == property_name_)); + + using OMFormat::Chunk; + + size_t bytes = 0; + Chunk::esize_t block_size; + Chunk::PropertyName custom_prop; + + bytes += restore(_is, block_size, OMFormat::Chunk::Integer_32, _swap); + + if (_bp) { + size_t n_bytes = _bp->size_of(_n_elem); + + if (((n_bytes == BaseProperty::UnknownSize) || (n_bytes == block_size)) + && (_bp->element_size() == BaseProperty::UnknownSize || (_n_elem * _bp->element_size() == block_size))) { +#if defined(OM_DEBUG) + size_t b; + bytes += (b=_bp->restore( _is, _swap )); +#else + bytes += _bp->restore(_is, _swap); +#endif + +#if defined(OM_DEBUG) + assert( block_size == b); +#endif + + assert( block_size == _bp->size_of()); + + block_size = 0; + } else { + omerr() << "Warning! Property " << _bp->name() << " not loaded: " << "Mismatching data sizes!" << std::endl; + } + } + + if (block_size) { + _is.ignore(block_size); + bytes += block_size; + } + + return bytes; +} + + +//--------------------------------helper +void _OMReader_:: add_generic_property(OMFormat::Chunk::PropertyName& _property_type, BaseImporter& _bi) const +{ + // We want to support the old way of restoring properties, ie. + // the user has manually created the corresponding property. + // In that case the property does not need be registered. + // However, the _bi.kerne()->_get_prop(property_name_) checks below + // May return a property with the correct name but the wrong type. + // For now we will have to live with that. + + + PropertyCreationManager& manager = PropertyCreationManager::instance(); + switch (chunk_header_.entity_) + { + case OMFormat::Chunk::Entity_Vertex: + { + if (_bi.kernel()->_get_vprop(property_name_) == nullptr) + manager.create_property(*_bi.kernel(), _property_type, property_name_); + break; + } + case OMFormat::Chunk::Entity_Face: + { + if (_bi.kernel()->_get_fprop(property_name_) == nullptr) + manager.create_property(*_bi.kernel(), _property_type, property_name_); + break; + } + case OMFormat::Chunk::Entity_Edge: + { + if (_bi.kernel()->_get_eprop(property_name_) == nullptr) + manager.create_property(*_bi.kernel(), _property_type, property_name_); + break; + } + case OMFormat::Chunk::Entity_Halfedge: + { + if (_bi.kernel()->_get_hprop(property_name_) == nullptr) + manager.create_property(*_bi.kernel(), _property_type, property_name_); + break; + } + case OMFormat::Chunk::Entity_Mesh: + { + if (_bi.kernel()->_get_mprop(property_name_) == nullptr) + manager.create_property(*_bi.kernel(), _property_type, property_name_); + break; + } + case OMFormat::Chunk::Entity_Sentinel: + ; + break; + default: + ; + } +} +//----------------------------------------------------------------------------- + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/OMReader.hh b/Sources/OpenMeshCore/Core/IO/reader/OMReader.hh new file mode 100644 index 0000000..7382066 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/OMReader.hh @@ -0,0 +1,176 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + + +#ifndef __OMREADER_HH__ +#define __OMREADER_HH__ + + +//=== INCLUDES ================================================================ + +// OpenMesh +#include +#include +#include +#include +#include +#include + +// STD C++ +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OM format reader. This class is singleton'ed by + SingletonT to OMReader. +*/ +class OPENMESHDLLEXPORT _OMReader_ : public BaseReader +{ +public: + + _OMReader_(); + virtual ~_OMReader_() { } + + std::string get_description() const override { return "OpenMesh File Format"; } + std::string get_extensions() const override { return "om"; } + std::string get_magic() const override { return "OM"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt ) override; + +//! Stream Reader for std::istream input in binary format + bool read(std::istream& _is, + BaseImporter& _bi, + Options& _opt ) override; + + virtual bool can_u_read(const std::string& _filename) const override; + virtual bool can_u_read(std::istream& _is) const; + + +private: + + bool supports( const OMFormat::uint8 version ) const; + + bool read_ascii(std::istream& _is, BaseImporter& _bi, const Options& _opt) const; + bool read_binary(std::istream& _is, BaseImporter& _bi, const Options& _opt) const; + + typedef OMFormat::Header Header; + typedef OMFormat::Chunk::Header ChunkHeader; + typedef OMFormat::Chunk::PropertyName PropertyName; + + // initialized/updated by read_binary*/read_ascii* + mutable size_t bytes_; + mutable Options fileOptions_; + mutable Header header_; + mutable ChunkHeader chunk_header_; + mutable PropertyName property_name_; + + bool read_binary_vertex_chunk( std::istream &_is, + BaseImporter &_bi, + const Options &_opt, + bool _swap) const; + + bool read_binary_face_chunk( std::istream &_is, + BaseImporter &_bi, + const Options &_opt, + bool _swap) const; + + bool read_binary_edge_chunk( std::istream &_is, + BaseImporter &_bi, + const Options &_opt, + bool _swap) const; + + bool read_binary_halfedge_chunk( std::istream &_is, + BaseImporter &_bi, + const Options &_opt, + bool _swap) const; + + bool read_binary_mesh_chunk( std::istream &_is, + BaseImporter &_bi, + const Options &_opt, + bool _swap) const; + + size_t restore_binary_custom_data(std::istream& _is, + BaseProperty* _bp, + size_t _n_elem, + bool _swap) const; + + //------------------helper +private: + void add_generic_property(OMFormat::Chunk::PropertyName& _property_type, BaseImporter& _bi) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OM reader. +extern _OMReader_ __OMReaderInstance; +OPENMESHDLLEXPORT _OMReader_& OMReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/PLYReader.cc b/Sources/OpenMeshCore/Core/IO/reader/PLYReader.cc new file mode 100644 index 0000000..96b0dbf --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/PLYReader.cc @@ -0,0 +1,1605 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#define LINE_LEN 4096 + +//== INCLUDES ================================================================= + +// OpenMesh +#include +#include +#include +#include +#include + +//STL +#include +#include +#include +#include + +#ifndef WIN32 +#endif + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + +//============================================================================= + +//=== INSTANCIATE ============================================================= + + +_PLYReader_ __PLYReaderInstance; +_PLYReader_& PLYReader() { + return __PLYReaderInstance; +} + +//=== IMPLEMENTATION ========================================================== + + +_PLYReader_::_PLYReader_() { + IOManager().register_module(this); + + // Store sizes in byte of each property type + scalar_size_[ValueTypeINT8] = 1; + scalar_size_[ValueTypeUINT8] = 1; + scalar_size_[ValueTypeINT16] = 2; + scalar_size_[ValueTypeUINT16] = 2; + scalar_size_[ValueTypeINT32] = 4; + scalar_size_[ValueTypeUINT32] = 4; + scalar_size_[ValueTypeFLOAT32] = 4; + scalar_size_[ValueTypeFLOAT64] = 8; + + scalar_size_[ValueTypeCHAR] = 1; + scalar_size_[ValueTypeUCHAR] = 1; + scalar_size_[ValueTypeSHORT] = 2; + scalar_size_[ValueTypeUSHORT] = 2; + scalar_size_[ValueTypeINT] = 4; + scalar_size_[ValueTypeUINT] = 4; + scalar_size_[ValueTypeFLOAT] = 4; + scalar_size_[ValueTypeDOUBLE] = 8; +} + +//----------------------------------------------------------------------------- + + +bool _PLYReader_::read(const std::string& _filename, BaseImporter& _bi, Options& _opt) { + + std::fstream in(_filename.c_str(), (std::ios_base::binary | std::ios_base::in) ); + + if (!in.is_open() || !in.good()) { + omerr() << "[PLYReader] : cannot not open file " << _filename << std::endl; + return false; + } + + bool result = read(in, _bi, _opt); + + in.close(); + return result; +} + +//----------------------------------------------------------------------------- + + +bool _PLYReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt) { + + if (!_in.good()) { + omerr() << "[PLYReader] : cannot not use stream" << std::endl; + return false; + } + + // Reparse the header + if (!can_u_read(_in)) { + omerr() << "[PLYReader] : Unable to parse header\n"; + return false; + } + + // Add TextureFiles + int texture_index = 0; + for(auto const & texture_file : texture_files_) { + _bi.add_texture_information(texture_index++, texture_file); + } + + // filter relevant options for reading + bool swap_required = _opt.check(Options::Swap); + + userOptions_ = _opt; + + // build options to be returned + _opt.clear(); + + if (options_.vertex_has_normal() && userOptions_.vertex_has_normal()) { + _opt += Options::VertexNormal; + } + if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) { + _opt += Options::VertexTexCoord; + } + if (options_.vertex_has_color() && userOptions_.vertex_has_color()) { + _opt += Options::VertexColor; + } + if (options_.face_has_color() && userOptions_.face_has_color()) { + _opt += Options::FaceColor; + } + if (options_.face_has_texcoord() && userOptions_.face_has_texcoord()) { + _opt += Options::FaceTexCoord; + } + if (options_.is_binary()) { + _opt += Options::Binary; + } + if (options_.color_is_float()) { + _opt += Options::ColorFloat; + } + if (options_.check(Options::Custom) && userOptions_.check(Options::Custom)) { + _opt += Options::Custom; + } + + // //force user-choice for the alpha value when reading binary + // if ( options_.is_binary() && userOptions_.color_has_alpha() ) + // options_ += Options::ColorAlpha; + + return (options_.is_binary() ? read_binary(_in, _bi, swap_required, _opt) : read_ascii(_in, _bi, _opt)); + +} + +template +struct Handle2Prop; + +template +struct Handle2Prop +{ + typedef OpenMesh::VPropHandleT PropT; +}; + +template +struct Handle2Prop +{ + typedef OpenMesh::FPropHandleT PropT; +}; + +//read and assign custom properties with the given type. Also creates property, if not exist +template +void _PLYReader_::readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listType) const +{ + if (_listType == Unsupported) //no list type defined -> property is not a list + { + //get/add property + typename Handle2Prop::PropT prop; + if (!_bi.kernel()->get_property_handle(prop,_propName)) + { + _bi.kernel()->add_property(prop,_propName); + _bi.kernel()->property(prop).set_persistent(true); + } + + //read and assign + T in; + read(_valueType, _in, in, OpenMesh::GenProg::Bool2Type()); + _bi.kernel()->property(prop,_h) = in; + } + else + { + //get/add property + typename Handle2Prop,Handle>::PropT prop; + if (!_bi.kernel()->get_property_handle(prop,_propName)) + { + _bi.kernel()->add_property(prop,_propName); + _bi.kernel()->property(prop).set_persistent(true); + } + + //init vector + unsigned int numberOfValues; + readInteger(_listType, _in, numberOfValues, OpenMesh::GenProg::Bool2Type()); + std::vector vec(numberOfValues); + //read and assign + for (unsigned int i = 0; i < numberOfValues; ++i) + { + read(_valueType, _in, vec[i], OpenMesh::GenProg::Bool2Type()); + } + _bi.kernel()->property(prop,_h) = vec; + } +} + +template +void _PLYReader_::readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listIndexType) const +{ + switch (_valueType) + { + case ValueTypeINT8: + case ValueTypeCHAR: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeUINT8: + case ValueTypeUCHAR: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeINT16: + case ValueTypeSHORT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeUINT16: + case ValueTypeUSHORT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeINT32: + case ValueTypeINT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeUINT32: + case ValueTypeUINT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeFLOAT32: + case ValueTypeFLOAT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeFLOAT64: + case ValueTypeDOUBLE: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + default: + std::cerr << "unsupported type" << std::endl; + break; + } +} + + +//----------------------------------------------------------------------------- + +bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options& _opt) const { + + unsigned int i, j, k, l, idx; + unsigned int nV; + OpenMesh::Vec3f v, n, t3d; + std::string trash; + OpenMesh::Vec2f t; + OpenMesh::Vec4i c; + float tmp; + BaseImporter::VHandles vhandles; + std::vector face_texcoords3d; + std::vector face_texcoords; + VertexHandle vh; + + _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_); + + if (vertexDimension_ != 3) { + omerr() << "[PLYReader] : Only vertex dimension 3 is supported." << std::endl; + return false; + } + + const bool err_enabled = omerr().is_enabled(); + size_t complex_faces = 0; + if (err_enabled) + omerr().disable(); + + for (std::vector::iterator e_it = elements_.begin(); e_it != elements_.end(); ++e_it) + { + if (_in.eof()) { + if (err_enabled) + omerr().enable(); + + omerr() << "Unexpected end of file while reading." << std::endl; + return false; + } + + if (e_it->element_== VERTEX) + { + // read vertices: + for (i = 0; i < e_it->count_ && !_in.eof(); ++i) { + vh = _bi.add_vertex(); + + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; + + n[0] = 0.0; + n[1] = 0.0; + n[2] = 0.0; + + t[0] = 0.0; + t[1] = 0.0; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + case XCOORD: + _in >> v[0]; + break; + case YCOORD: + _in >> v[1]; + break; + case ZCOORD: + _in >> v[2]; + break; + case XNORM: + _in >> n[0]; + break; + case YNORM: + _in >> n[1]; + break; + case ZNORM: + _in >> n[2]; + break; + case TEXX: + _in >> t[0]; + break; + case TEXY: + _in >> t[1]; + break; + case COLORRED: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[0] = static_cast (tmp * 255.0f); + } + else + _in >> c[0]; + break; + case COLORGREEN: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[1] = static_cast (tmp * 255.0f); + } + else + _in >> c[1]; + break; + case COLORBLUE: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[2] = static_cast (tmp * 255.0f); + } + else + _in >> c[2]; + break; + case COLORALPHA: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[3] = static_cast (tmp * 255.0f); + } + else + _in >> c[3]; + break; + case CUSTOM_PROP: + if (_opt.check(Options::Custom)) + readCustomProperty(_in, _bi, vh, prop.name, prop.value, prop.listIndexType); + else + _in >> trash; + break; + default: + _in >> trash; + break; + } + } + + _bi.set_point(vh, v); + if (_opt.vertex_has_normal()) + _bi.set_normal(vh, n); + if (_opt.vertex_has_texcoord()) + _bi.set_texcoord(vh, t); + if (_opt.vertex_has_color()) + _bi.set_color(vh, Vec4uc(c)); + } + } + else if (e_it->element_ == FACE) + { + // faces + for (i = 0; i < faceCount_ && !_in.eof(); ++i) { + FaceHandle fh; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + + case VERTEX_INDICES: + // nV = number of Vertices for current face + _in >> nV; + + if (nV == 3) { + vhandles.resize(3); + _in >> j; + _in >> k; + _in >> l; + + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); + } + else { + vhandles.clear(); + for (j = 0; j < nV; ++j) { + _in >> idx; + vhandles.push_back(VertexHandle(idx)); + } + } + + fh = _bi.add_face(vhandles); + if (!fh.is_valid()) + ++complex_faces; + break; + + case TEXCOORD: + // nV = number of texcoord for current face + _in >> nV; + + if (_opt.face_has_texcoord()) { + + // need to know the number of vertex for this face + assert(!vhandles.empty()); + + if (nV == 2 * vhandles.size()) { + + face_texcoords.clear(); + face_texcoords.reserve(vhandles.size()); + + for (j = 0; j < vhandles.size(); j++) { + _in >> t[0]; + _in >> t[1]; + + face_texcoords.push_back(t); + } + + _bi.add_face_texcoords(fh, vhandles[0], face_texcoords); + + } else if (nV == 3 * vhandles.size()) { + + face_texcoords3d.clear(); + face_texcoords3d.reserve(vhandles.size()); + + for (j = 0; j < vhandles.size(); j++) { + _in >> t3d[0]; + _in >> t3d[1]; + _in >> t3d[2]; + + face_texcoords3d.push_back(t3d); + } + + _bi.add_face_texcoords(fh, vhandles[0], face_texcoords3d); + + } else { + for (j = 0; j < nV; j++) { + _in >> trash; + } + } + } else { + for (j = 0; j < nV; j++) { + _in >> trash; + } + } + break; + + case TEXNUMBER: + _in >> idx; + _bi.set_face_texindex(fh, idx); + break; + + case COLORRED: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[0] = static_cast (tmp * 255.0f); + } else + _in >> c[0]; + break; + + case COLORGREEN: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[1] = static_cast (tmp * 255.0f); + } else + _in >> c[1]; + break; + + case COLORBLUE: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[2] = static_cast (tmp * 255.0f); + } else + _in >> c[2]; + break; + + case COLORALPHA: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[3] = static_cast (tmp * 255.0f); + } else + _in >> c[3]; + break; + + case CUSTOM_PROP: + if (_opt.check(Options::Custom) && fh.is_valid()) + readCustomProperty(_in, _bi, fh, prop.name, prop.value, prop.listIndexType); + else + _in >> trash; + break; + + default: + _in >> trash; + break; + } + } + if (_opt.face_has_color()) + _bi.set_color(fh, Vec4uc(c)); + } + } + else + { + // other elements + for (i = 0; i < e_it->count_ && !_in.eof(); ++i) { + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) + { + // just skip the values + _in >> trash; + } + } + } + + if(e_it->element_== FACE) + // stop reading after the faces since additional elements are not preserved anyway + break; + } + + if (err_enabled) + omerr().enable(); + + if (complex_faces) + omerr() << complex_faces << "The reader encountered invalid faces, that could not be added.\n"; + + // File was successfully parsed. + return true; +} + +//----------------------------------------------------------------------------- + +bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap*/, const Options& _opt) const { + + OpenMesh::Vec3f v, n, t3d; // Vertex + OpenMesh::Vec2f t; // TexCoords + BaseImporter::VHandles vhandles; + std::vector face_texcoords3d; + std::vector face_texcoords; + VertexHandle vh; + OpenMesh::Vec4i c; // Color + float tmp; + + _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_); + + const bool err_enabled = omerr().is_enabled(); + size_t complex_faces = 0; + if (err_enabled) + omerr().disable(); + + for (std::vector::iterator e_it = elements_.begin(); e_it != elements_.end(); ++e_it) + { + if (e_it->element_ == VERTEX) + { + // read vertices: + for (unsigned int i = 0; i < e_it->count_ && !_in.eof(); ++i) { + vh = _bi.add_vertex(); + + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; + + n[0] = 0.0; + n[1] = 0.0; + n[2] = 0.0; + + t[0] = 0.0; + t[1] = 0.0; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + case XCOORD: + readValue(prop.value, _in, v[0]); + break; + case YCOORD: + readValue(prop.value, _in, v[1]); + break; + case ZCOORD: + readValue(prop.value, _in, v[2]); + break; + case XNORM: + readValue(prop.value, _in, n[0]); + break; + case YNORM: + readValue(prop.value, _in, n[1]); + break; + case ZNORM: + readValue(prop.value, _in, n[2]); + break; + case TEXX: + readValue(prop.value, _in, t[0]); + break; + case TEXY: + readValue(prop.value, _in, t[1]); + break; + case COLORRED: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + + c[0] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[0]); + + break; + case COLORGREEN: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[1] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[1]); + + break; + case COLORBLUE: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[2] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[2]); + + break; + case COLORALPHA: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[3] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[3]); + + break; + case CUSTOM_PROP: + if (_opt.check(Options::Custom)) + readCustomProperty(_in, _bi, vh, prop.name, prop.value, prop.listIndexType); + else + consume_input(_in, scalar_size_[prop.value]); + break; + default: + // Read unsupported property + consume_input(_in, scalar_size_[prop.value]); + break; + } + + } + + _bi.set_point(vh, v); + if (_opt.vertex_has_normal()) + _bi.set_normal(vh, n); + if (_opt.vertex_has_texcoord()) + _bi.set_texcoord(vh, t); + if (_opt.vertex_has_color()) + _bi.set_color(vh, Vec4uc(c)); + } + } + else if (e_it->element_ == FACE) { + for (unsigned i = 0; i < e_it->count_ && !_in.eof(); ++i) { + FaceHandle fh; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) + { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + + case VERTEX_INDICES: + // nV = number of Vertices for current face + unsigned int nV; + readInteger(prop.listIndexType, _in, nV); + + if (nV == 3) { + vhandles.resize(3); + unsigned int j, k, l; + readInteger(prop.value, _in, j); + readInteger(prop.value, _in, k); + readInteger(prop.value, _in, l); + + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); + } + else { + vhandles.clear(); + for (unsigned j = 0; j < nV; ++j) { + unsigned int idx; + readInteger(prop.value, _in, idx); + vhandles.push_back(VertexHandle(idx)); + } + } + + fh = _bi.add_face(vhandles); + if (!fh.is_valid()) + ++complex_faces; + break; + case TEXCOORD: + // nV = number of texcoord for current face + readInteger(prop.listIndexType, _in, nV); + + if (_opt.face_has_texcoord()) { + + // need to know the number of vertex for this face + assert(!vhandles.empty()); + + if (nV == 2 * vhandles.size()) { + + face_texcoords.clear(); + face_texcoords.reserve(vhandles.size()); + + for (std::size_t j = 0; j < vhandles.size(); j++) { + readValue(prop.value, _in, t[0]); + readValue(prop.value, _in, t[1]); + + face_texcoords.push_back(t); + } + + _bi.add_face_texcoords(fh, vhandles[0], face_texcoords); + + } else if (nV == 3 * vhandles.size()) { + + face_texcoords3d.clear(); + face_texcoords3d.reserve(vhandles.size()); + + for (std::size_t j = 0; j < vhandles.size(); j++) { + readValue(prop.value, _in, t3d[0]); + readValue(prop.value, _in, t3d[1]); + readValue(prop.value, _in, t3d[2]); + + face_texcoords3d.push_back(t3d); + } + + _bi.add_face_texcoords(fh, vhandles[0], face_texcoords3d); + + } else { + consume_input(_in, nV * scalar_size_[prop.value]); + } + } else { + consume_input(_in, nV * scalar_size_[prop.value]); + } + break; + case TEXNUMBER: + unsigned int idx; + readInteger(prop.value, _in, idx); + _bi.set_face_texindex(fh, idx); + break; + case COLORRED: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[0] = static_cast (tmp * 255.0f); + } else + readInteger(prop.value, _in, c[0]); + break; + case COLORGREEN: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[1] = static_cast (tmp * 255.0f); + } else + readInteger(prop.value, _in, c[1]); + break; + case COLORBLUE: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[2] = static_cast (tmp * 255.0f); + } else + readInteger(prop.value, _in, c[2]); + break; + case COLORALPHA: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[3] = static_cast (tmp * 255.0f); + } else + readInteger(prop.value, _in, c[3]); + break; + case CUSTOM_PROP: + if (_opt.check(Options::Custom) && fh.is_valid()) + readCustomProperty(_in, _bi, fh, prop.name, prop.value, prop.listIndexType); + else + consume_input(_in, scalar_size_[prop.value]); + break; + + default: + consume_input(_in, scalar_size_[prop.value]); + break; + } + } + if (_opt.face_has_color()) + _bi.set_color(fh, Vec4uc(c)); + } + } + else { + for (unsigned int i = 0; i < e_it->count_ && !_in.eof(); ++i) + { + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) + { + PropertyInfo prop = e_it->properties_[propertyIndex]; + // skip element values + consume_input(_in, scalar_size_[prop.value]); + } + } + } + + if (_in.eof()) { + if (err_enabled) + omerr().enable(); + + omerr() << "Unexpected end of file while reading." << std::endl; + return false; + } + + if (e_it->element_ == FACE) + // stop reading after the faces since additional elements are not preserved anyway + break; + } + if (err_enabled) + omerr().enable(); + + if (complex_faces) + omerr() << complex_faces << "The reader encountered invalid faces, that could not be added.\n"; + + + return true; +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, float& _value) const { + + switch (_type) { + case ValueTypeFLOAT32: + case ValueTypeFLOAT: + float32_t tmp; + restore(_in, tmp, options_.check(Options::MSB)); + _value = tmp; + break; + case ValueTypeDOUBLE: + case ValueTypeFLOAT64: + double dtmp; + readValue(_type, _in, dtmp); + _value = static_cast(dtmp); + break; + default: + _value = 0.0; + std::cerr << "unsupported conversion type to float: " << _type << std::endl; + break; + } +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, double& _value) const { + + switch (_type) { + + case ValueTypeFLOAT64: + + case ValueTypeDOUBLE: + + float64_t tmp; + restore(_in, tmp, options_.check(Options::MSB)); + _value = tmp; + + break; + + default: + + _value = 0.0; + std::cerr << "unsupported conversion type to double: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned char& _value) const{ + unsigned int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned short& _value) const{ + unsigned int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, signed char& _value) const{ + int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, short& _value) const{ + int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + + +//----------------------------------------------------------------------------- +void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned int& _value) const { + + uint32_t tmp_uint32_t; + uint16_t tmp_uint16_t; + uint8_t tmp_uchar; + + switch (_type) { + + case ValueTypeUINT: + + case ValueTypeUINT32: + + restore(_in, tmp_uint32_t, options_.check(Options::MSB)); + _value = tmp_uint32_t; + + break; + + case ValueTypeUSHORT: + + case ValueTypeUINT16: + + restore(_in, tmp_uint16_t, options_.check(Options::MSB)); + _value = tmp_uint16_t; + + break; + + case ValueTypeUCHAR: + + case ValueTypeUINT8: + + restore(_in, tmp_uchar, options_.check(Options::MSB)); + _value = tmp_uchar; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to unsigned int: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, int& _value) const { + + int32_t tmp_int32_t; + int16_t tmp_int16_t; + int8_t tmp_char; + + switch (_type) { + + case ValueTypeINT: + + case ValueTypeINT32: + + restore(_in, tmp_int32_t, options_.check(Options::MSB)); + _value = tmp_int32_t; + + break; + + case ValueTypeSHORT: + + case ValueTypeINT16: + + restore(_in, tmp_int16_t, options_.check(Options::MSB)); + _value = tmp_int16_t; + + break; + + case ValueTypeCHAR: + + case ValueTypeINT8: + + restore(_in, tmp_char, options_.check(Options::MSB)); + _value = tmp_char; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + +template +void _PLYReader_::readInteger(ValueType _type, std::istream& _in, T& _value) const { + + static_assert(std::is_integral::value, "Integral required."); + + int16_t tmp_int16_t; + uint16_t tmp_uint16_t; + int32_t tmp_int32_t; + uint32_t tmp_uint32_t; + int8_t tmp_char; + uint8_t tmp_uchar; + + switch (_type) { + + case ValueTypeINT16: + + case ValueTypeSHORT: + restore(_in, tmp_int16_t, options_.check(Options::MSB)); + _value = tmp_int16_t; + + break; + + case ValueTypeUINT16: + + case ValueTypeUSHORT: + restore(_in, tmp_uint16_t, options_.check(Options::MSB)); + _value = tmp_uint16_t; + + break; + + case ValueTypeINT: + + case ValueTypeINT32: + + restore(_in, tmp_int32_t, options_.check(Options::MSB)); + _value = tmp_int32_t; + + break; + + case ValueTypeUINT: + + case ValueTypeUINT32: + + restore(_in, tmp_uint32_t, options_.check(Options::MSB)); + _value = tmp_uint32_t; + + break; + + case ValueTypeCHAR: + + case ValueTypeINT8: + + restore(_in, tmp_char, options_.check(Options::MSB)); + _value = tmp_char; + + break; + + case ValueTypeUCHAR: + + case ValueTypeUINT8: + + restore(_in, tmp_uchar, options_.check(Options::MSB)); + _value = tmp_uchar; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to integral: " << _type << std::endl; + + break; + } +} + +//------------------------------------------------------------------------------ + + +bool _PLYReader_::can_u_read(const std::string& _filename) const { + + // !!! Assuming BaseReader::can_u_parse( std::string& ) + // does not call BaseReader::read_magic()!!! + + if (BaseReader::can_u_read(_filename)) { + std::ifstream ifs(_filename.c_str()); + if (ifs.is_open() && can_u_read(ifs)) { + ifs.close(); + return true; + } + } + return false; +} + + + +//----------------------------------------------------------------------------- + +std::string get_property_name(std::string _string1, std::string _string2) { + + if (_string1 == "float32" || _string1 == "float64" || _string1 == "float" || _string1 == "double" || + _string1 == "int8" || _string1 == "uint8" || _string1 == "char" || _string1 == "uchar" || + _string1 == "int32" || _string1 == "uint32" || _string1 == "int" || _string1 == "uint" || + _string1 == "int16" || _string1 == "uint16" || _string1 == "short" || _string1 == "ushort") + return _string2; + + if (_string2 == "float32" || _string2 == "float64" || _string2 == "float" || _string2 == "double" || + _string2 == "int8" || _string2 == "uint8" || _string2 == "char" || _string2 == "uchar" || + _string2 == "int32" || _string2 == "uint32" || _string2 == "int" || _string2 == "uint" || + _string2 == "int16" || _string2 == "uint16" || _string2 == "short" || _string2 == "ushort") + return _string1; + + + std::cerr << "Unsupported entry type" << std::endl; + return "Unsupported"; +} + +//----------------------------------------------------------------------------- + +_PLYReader_::ValueType get_property_type(const std::string& _string1, const std::string& _string2) { + + if (_string1 == "float32" || _string2 == "float32") + + return _PLYReader_::ValueTypeFLOAT32; + + else if (_string1 == "float64" || _string2 == "float64") + + return _PLYReader_::ValueTypeFLOAT64; + + else if (_string1 == "float" || _string2 == "float") + + return _PLYReader_::ValueTypeFLOAT; + + else if (_string1 == "double" || _string2 == "double") + + return _PLYReader_::ValueTypeDOUBLE; + + else if (_string1 == "int8" || _string2 == "int8") + + return _PLYReader_::ValueTypeINT8; + + else if (_string1 == "uint8" || _string2 == "uint8") + + return _PLYReader_::ValueTypeUINT8; + + else if (_string1 == "char" || _string2 == "char") + + return _PLYReader_::ValueTypeCHAR; + + else if (_string1 == "uchar" || _string2 == "uchar") + + return _PLYReader_::ValueTypeUCHAR; + + else if (_string1 == "int32" || _string2 == "int32") + + return _PLYReader_::ValueTypeINT32; + + else if (_string1 == "uint32" || _string2 == "uint32") + + return _PLYReader_::ValueTypeUINT32; + + else if (_string1 == "int" || _string2 == "int") + + return _PLYReader_::ValueTypeINT; + + else if (_string1 == "uint" || _string2 == "uint") + + return _PLYReader_::ValueTypeUINT; + + else if (_string1 == "int16" || _string2 == "int16") + + return _PLYReader_::ValueTypeINT16; + + else if (_string1 == "uint16" || _string2 == "uint16") + + return _PLYReader_::ValueTypeUINT16; + + else if (_string1 == "short" || _string2 == "short") + + return _PLYReader_::ValueTypeSHORT; + + else if (_string1 == "ushort" || _string2 == "ushort") + + return _PLYReader_::ValueTypeUSHORT; + + return _PLYReader_::Unsupported; +} + + +//----------------------------------------------------------------------------- + +bool _PLYReader_::can_u_read(std::istream& _is) const { + + // Clear per file options + options_.cleanup(); + + // clear element list + elements_.clear(); + + // clear texture list + texture_files_.clear(); + + // read 1st line + std::string line; + std::getline(_is, line); + trim(line); + + // Handle '\r\n' newlines + const size_t s = line.size(); + if( s > 0 && line[s - 1] == '\r') line.resize(s - 1); + + //Check if this file is really a ply format + if (line != "PLY" && line != "ply") + return false; + + vertexCount_ = 0; + faceCount_ = 0; + vertexDimension_ = 0; + + unsigned int elementCount = 0; + + std::string keyword; + std::string fileType; + std::string elementName = ""; + std::string propertyName; + std::string listIndexType; + std::string listEntryType; + float version; + + _is >> keyword; + _is >> fileType; + _is >> version; + + if (_is.bad()) { + omerr() << "Defect PLY header detected" << std::endl; + return false; + } + + if (fileType == "ascii") { + options_ -= Options::Binary; + } else if (fileType == "binary_little_endian") { + options_ += Options::Binary; + options_ += Options::LSB; + //if (Endian::local() == Endian::MSB) + + // options_ += Options::Swap; + } else if (fileType == "binary_big_endian") { + options_ += Options::Binary; + options_ += Options::MSB; + //if (Endian::local() == Endian::LSB) + + // options_ += Options::Swap; + } else { + omerr() << "Unsupported PLY format: " << fileType << std::endl; + return false; + } + + std::streamoff streamPos = _is.tellg(); + _is >> keyword; + while (keyword != "end_header") { + + if (keyword == "comment") { + std::getline(_is, line); + + // Meshlab puts texture filenames as comments + // We collect them into a vector and add them in the + // given order to our mesh to keep the indices. + if (line.rfind(" TextureFile ", 0) == 0) { + std::string filename = line.substr(13); + + // This trim is required especially on windows as + // we can run into problems with line endings on + // files from different platforms. + trim(filename); + texture_files_.push_back(filename); + } + } else if (keyword == "element") { + _is >> elementName; + _is >> elementCount; + + ElementInfo element; + element.name_ = elementName; + element.count_ = elementCount; + + if (elementName == "vertex") { + vertexCount_ = elementCount; + element.element_ = VERTEX; + } else if (elementName == "face") { + faceCount_ = elementCount; + element.element_ = FACE; + } else { + omerr() << "PLY header unsupported element type: " << elementName << std::endl; + element.element_ = UNKNOWN; + } + + elements_.push_back(element); + } else if (keyword == "property") { + std::string tmp1; + + // Read first keyword, as it might be a list + _is >> tmp1; + + if (tmp1 == "list") { + _is >> listIndexType; + _is >> listEntryType; + _is >> propertyName; + + ValueType indexType = Unsupported; + ValueType entryType = Unsupported; + + if (listIndexType == "uint8") { + indexType = ValueTypeUINT8; + } else if (listIndexType == "uint16") { + indexType = ValueTypeUINT16; + } else if (listIndexType == "uchar") { + indexType = ValueTypeUCHAR; + } else if (listIndexType == "int") { + indexType = ValueTypeINT; + } else { + omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl; + return false; + } + + entryType = get_property_type(listEntryType, listEntryType); + + if (entryType == Unsupported) { + omerr() << "Unsupported Entry type for property list: " << listEntryType << std::endl; + } + + PropertyInfo property(CUSTOM_PROP, entryType, propertyName); + property.listIndexType = indexType; + + if (elementName == "face") + { + // special case for vertex indices + if (propertyName == "vertex_index" || propertyName == "vertex_indices") + { + property.property = VERTEX_INDICES; + + if (!elements_.back().properties_.empty()) + { + omerr() << "Custom face Properties defined, before 'vertex_indices' property was defined. They will be skipped" << std::endl; + elements_.back().properties_.clear(); + } + } else if (propertyName == "texcoord") + { + property.property = TEXCOORD; + options_ += Options::FaceTexCoord; + + } else { + options_ += Options::Custom; + } + + } + else + omerr() << "property " << propertyName << " belongs to unsupported element " << elementName << std::endl; + + elements_.back().properties_.push_back(property); + + } else { + + std::string tmp2; + + // as this is not a list property, read second value of property + _is >> tmp2; + + + // Extract name and type of property + // As the order seems to be different in some files, autodetect it. + ValueType valueType = get_property_type(tmp1, tmp2); + propertyName = get_property_name(tmp1, tmp2); + + PropertyInfo entry; + + //special treatment for some vertex properties. + if (elementName == "vertex") { + if (propertyName == "x") { + entry = PropertyInfo(XCOORD, valueType); + vertexDimension_++; + } else if (propertyName == "y") { + entry = PropertyInfo(YCOORD, valueType); + vertexDimension_++; + } else if (propertyName == "z") { + entry = PropertyInfo(ZCOORD, valueType); + vertexDimension_++; + } else if (propertyName == "nx") { + entry = PropertyInfo(XNORM, valueType); + options_ += Options::VertexNormal; + } else if (propertyName == "ny") { + entry = PropertyInfo(YNORM, valueType); + options_ += Options::VertexNormal; + } else if (propertyName == "nz") { + entry = PropertyInfo(ZNORM, valueType); + options_ += Options::VertexNormal; + } else if (propertyName == "u" || propertyName == "s") { + entry = PropertyInfo(TEXX, valueType); + options_ += Options::VertexTexCoord; + } else if (propertyName == "v" || propertyName == "t") { + entry = PropertyInfo(TEXY, valueType); + options_ += Options::VertexTexCoord; + } else if (propertyName == "red") { + entry = PropertyInfo(COLORRED, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "green") { + entry = PropertyInfo(COLORGREEN, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "blue") { + entry = PropertyInfo(COLORBLUE, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "diffuse_red") { + entry = PropertyInfo(COLORRED, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "diffuse_green") { + entry = PropertyInfo(COLORGREEN, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "diffuse_blue") { + entry = PropertyInfo(COLORBLUE, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "alpha") { + entry = PropertyInfo(COLORALPHA, valueType); + options_ += Options::VertexColor; + options_ += Options::ColorAlpha; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } + } + else if (elementName == "face") { + if (propertyName == "red") { + entry = PropertyInfo(COLORRED, valueType); + options_ += Options::FaceColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "green") { + entry = PropertyInfo(COLORGREEN, valueType); + options_ += Options::FaceColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "blue") { + entry = PropertyInfo(COLORBLUE, valueType); + options_ += Options::FaceColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "alpha") { + entry = PropertyInfo(COLORALPHA, valueType); + options_ += Options::FaceColor; + options_ += Options::ColorAlpha; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "texnumber") { + entry = PropertyInfo(TEXNUMBER, valueType); + options_ += Options::FaceTexCoord; + } + } + + //not a special property, load as custom + if (entry.value == Unsupported){ + Property prop = CUSTOM_PROP; + options_ += Options::Custom; + entry = PropertyInfo(prop, valueType, propertyName); + } + + if (entry.property != UNSUPPORTED) + { + elements_.back().properties_.push_back(entry); + } + } + + } else { + omlog() << "Unsupported keyword : " << keyword << std::endl; + } + + streamPos = _is.tellg(); + _is >> keyword; + if (_is.bad()) { + omerr() << "Error while reading PLY file header" << std::endl; + return false; + } + } + + // As the binary data is directy after the end_header keyword + // and the stream removes too many bytes, seek back to the right position + if (options_.is_binary()) { + _is.seekg(streamPos); + + char c1 = 0; + char c2 = 0; + _is.get(c1); + _is.get(c2); + + if (c1 == 0x0D && c2 == 0x0A) { + _is.seekg(streamPos + 14); + } + else { + _is.seekg(streamPos + 12); + } + } + + return true; +} + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/PLYReader.hh b/Sources/OpenMeshCore/Core/IO/reader/PLYReader.hh new file mode 100644 index 0000000..58cb2ea --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/PLYReader.hh @@ -0,0 +1,262 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + + +#ifndef __PLYREADER_HH__ +#define __PLYREADER_HH__ + + +//=== INCLUDES ================================================================ + + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== FORWARDS ================================================================= + + +class BaseImporter; + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the PLY format reader. This class is singleton'ed by + SingletonT to OFFReader. It can read custom properties, accessible via the name + of the custom properties. List properties has the type std::vector. + +*/ + +class OPENMESHDLLEXPORT _PLYReader_ : public BaseReader +{ +public: + + _PLYReader_(); + + std::string get_description() const override { return "PLY polygon file format"; } + std::string get_extensions() const override { return "ply"; } + std::string get_magic() const override { return "PLY"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) override; + + bool read(std::istream& _is, + BaseImporter& _bi, + Options& _opt) override; + + bool can_u_read(const std::string& _filename) const override; + + enum ValueType { + Unsupported, + ValueTypeINT8, ValueTypeCHAR, + ValueTypeUINT8, ValueTypeUCHAR, + ValueTypeINT16, ValueTypeSHORT, + ValueTypeUINT16, ValueTypeUSHORT, + ValueTypeINT32, ValueTypeINT, + ValueTypeUINT32, ValueTypeUINT, + ValueTypeFLOAT32, ValueTypeFLOAT, + ValueTypeFLOAT64, ValueTypeDOUBLE + }; + +private: + + bool can_u_read(std::istream& _is) const; + + bool read_ascii(std::istream& _in, BaseImporter& _bi, const Options& _opt) const; + bool read_binary(std::istream& _in, BaseImporter& _bi, bool swap, const Options& _opt) const; + + void readValue(ValueType _type , std::istream& _in, float& _value) const; + void readValue(ValueType _type , std::istream& _in, double& _value) const; + void readValue(ValueType _type , std::istream& _in, unsigned int& _value) const; + void readValue(ValueType _type , std::istream& _in, unsigned short& _value) const; + void readValue(ValueType _type , std::istream& _in, unsigned char& _value) const; + void readValue(ValueType _type , std::istream& _in, int& _value) const; + void readValue(ValueType _type , std::istream& _in, short& _value) const; + void readValue(ValueType _type , std::istream& _in, signed char& _value) const; + + template + void readInteger(ValueType _type, std::istream& _in, T& _value) const; + + /// Read unsupported properties in PLY file + void consume_input(std::istream& _in, int _count) const { + + // Make sure, we do not run over our buffer size + int loops = _count / 8 ; + + // Read only our buffer size batches + for ( auto i = 0 ; i < loops; ++i) { + _in.read(reinterpret_cast(&buff[0]), 8); + } + + // Read reminder which is smaller than our buffer size + _in.read(reinterpret_cast(&buff[0]), _count - 8 * loops ); + } + + mutable unsigned char buff[8]; + + /// Available per file options for reading + mutable Options options_; + + /// Options that the user wants to read + mutable Options userOptions_; + + mutable unsigned int vertexCount_; + mutable unsigned int faceCount_; + + mutable uint vertexDimension_; + + enum Property { + XCOORD,YCOORD,ZCOORD, + TEXX,TEXY, + COLORRED,COLORGREEN,COLORBLUE,COLORALPHA, + XNORM,YNORM,ZNORM, CUSTOM_PROP, VERTEX_INDICES, + TEXCOORD, TEXNUMBER, UNSUPPORTED + }; + + /// Stores sizes of property types + mutable std::map scalar_size_; + + // Number of vertex properties + struct PropertyInfo + { + Property property; + ValueType value; + std::string name;//for custom properties + ValueType listIndexType;//if type is unsupported, the poerty is not a list. otherwise, it the index type + PropertyInfo():property(UNSUPPORTED),value(Unsupported),name(""),listIndexType(Unsupported){} + PropertyInfo(Property _p, ValueType _v):property(_p),value(_v),name(""),listIndexType(Unsupported){} + PropertyInfo(Property _p, ValueType _v, const std::string& _n):property(_p),value(_v),name(_n),listIndexType(Unsupported){} + }; + + enum Element { + VERTEX, + FACE, + UNKNOWN + }; + + // Information on the elements + struct ElementInfo + { + Element element_; + std::string name_; + unsigned int count_; + std::vector< PropertyInfo > properties_; + }; + + mutable std::vector< ElementInfo > elements_; + + mutable std::vector< std::string > texture_files_; + + template + inline void read(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::TrueType /*_binary*/) const + { + readValue(_type, _in, _value); + } + + template + inline void read(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::FalseType /*_binary*/) const + { + _in >> _value; + } + + template + inline void readInteger(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::TrueType /*_binary*/) const + { + readInteger(_type, _in, _value); + } + + template + inline void readInteger(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::FalseType /*_binary*/) const + { + _in >> _value; + } + + //read and assign custom properties with the given type. Also creates property, if not exist + template + void readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const ValueType _valueType, const ValueType _listType) const; + + template + void readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listIndexType) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the PLY reader +extern _PLYReader_ __PLYReaderInstance; +OPENMESHDLLEXPORT _PLYReader_& PLYReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/STLReader.cc b/Sources/OpenMeshCore/Core/IO/reader/STLReader.cc new file mode 100644 index 0000000..9bce0d7 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/STLReader.cc @@ -0,0 +1,489 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//== INCLUDES ================================================================= + + +// STL +#include + +#include +#include +#include + +// OpenMesh +#include +#include +#include + +//comppare strings crossplatform ignorign case +#ifdef _WIN32 + #define strnicmp _strnicmp +#else + #define strnicmp strncasecmp +#endif + + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the STLReader singleton with MeshReader +_STLReader_ __STLReaderInstance; +_STLReader_& STLReader() { return __STLReaderInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_STLReader_:: +_STLReader_() + : eps_(FLT_MIN) +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_STLReader_:: +read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + bool result = false; + + STL_Type file_type = NONE; + + if ( check_extension( _filename, "stla" ) ) + { + file_type = STLA; + } + + else if ( check_extension( _filename, "stlb" ) ) + { + file_type = STLB; + } + + else if ( check_extension( _filename, "stl" ) ) + { + file_type = check_stl_type(_filename); + } + + + switch (file_type) + { + case STLA: + { + result = read_stla(_filename, _bi, _opt); + _opt -= Options::Binary; + break; + } + + case STLB: + { + result = read_stlb(_filename, _bi, _opt); + _opt += Options::Binary; + break; + } + + default: + { + result = false; + break; + } + } + + + return result; +} + +bool +_STLReader_::read(std::istream& _is, + BaseImporter& _bi, + Options& _opt) +{ + + bool result = false; + + if (_opt & Options::Binary) + result = read_stlb(_is, _bi, _opt); + else + result = read_stla(_is, _bi, _opt); + + return result; +} + + +//----------------------------------------------------------------------------- + + +#ifndef DOXY_IGNORE_THIS + +class CmpVec +{ +public: + + explicit CmpVec(float _eps=FLT_MIN) : eps_(_eps) {} + + bool operator()( const Vec3f& _v0, const Vec3f& _v1 ) const + { + if (fabs(_v0[0] - _v1[0]) <= eps_) + { + if (fabs(_v0[1] - _v1[1]) <= eps_) + { + return (_v0[2] < _v1[2] - eps_); + } + else return (_v0[1] < _v1[1] - eps_); + } + else return (_v0[0] < _v1[0] - eps_); + } + +private: + float eps_; +}; + +#endif + + +//----------------------------------------------------------------------------- + +void trimStdString( std::string& _string) { + // Trim Both leading and trailing spaces + + size_t start = _string.find_first_not_of(" \t\r\n"); + size_t end = _string.find_last_not_of(" \t\r\n"); + + if(( std::string::npos == start ) || ( std::string::npos == end)) + _string = ""; + else + _string = _string.substr( start, end-start+1 ); +} + +//----------------------------------------------------------------------------- + +bool +_STLReader_:: +read_stla(const std::string& _filename, BaseImporter& _bi, Options& _opt) const +{ + std::fstream in( _filename.c_str(), std::ios_base::in ); + + if (!in) + { + omerr() << "[STLReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + bool res = read_stla(in, _bi, _opt); + + if (in) + in.close(); + + return res; +} + +//----------------------------------------------------------------------------- + +bool +_STLReader_:: +read_stla(std::istream& _in, BaseImporter& _bi, Options& _opt) const +{ + + unsigned int i; + OpenMesh::Vec3f v; + OpenMesh::Vec3f n; + BaseImporter::VHandles vhandles; + + CmpVec comp(eps_); + std::map vMap(comp); + std::map::iterator vMapIt; + + std::string line; + + std::string garbage; + std::stringstream strstream; + + bool facet_normal(false); + + while( _in && !_in.eof() ) { + + // Get one line + std::getline(_in, line); + if ( _in.bad() ){ + omerr() << " Warning! Could not read stream properly!\n"; + return false; + } + + // Trim Both leading and trailing spaces + trimStdString(line); + + // Normal found? + if (line.find("facet normal") != std::string::npos) { + strstream.str(line); + strstream.clear(); + + // facet + strstream >> garbage; + + // normal + strstream >> garbage; + + strstream >> n[0]; + strstream >> n[1]; + strstream >> n[2]; + + facet_normal = true; + } + + // Detected a triangle + if ( (line.find("outer") != std::string::npos) || (line.find("OUTER") != std::string::npos ) ) { + + vhandles.clear(); + + for (i=0; i<3; ++i) { + // Get one vertex + std::getline(_in, line); + trimStdString(line); + + strstream.str(line); + strstream.clear(); + + strstream >> garbage; + + strstream >> v[0]; + strstream >> v[1]; + strstream >> v[2]; + + // has vector been referenced before? + if ((vMapIt=vMap.find(v)) == vMap.end()) + { + // No : add vertex and remember idx/vector mapping + VertexHandle handle = _bi.add_vertex(v); + vhandles.push_back(handle); + vMap[v] = handle; + } + else + // Yes : get index from map + vhandles.push_back(vMapIt->second); + + } + + // Add face only if it is not degenerated + if ((vhandles[0] != vhandles[1]) && + (vhandles[0] != vhandles[2]) && + (vhandles[1] != vhandles[2])) { + + + FaceHandle fh = _bi.add_face(vhandles); + + // set the normal if requested + // if a normal was requested but could not be found we unset the option + if (facet_normal) { + if (fh.is_valid() && _opt.face_has_normal()) + _bi.set_normal(fh, n); + } else + _opt -= Options::FaceNormal; + } + + facet_normal = false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- + +bool +_STLReader_:: +read_stlb(const std::string& _filename, BaseImporter& _bi, Options& _opt) const +{ + std::fstream in( _filename.c_str(), std::ios_base::in | std::ios_base::binary); + + if (!in) + { + omerr() << "[STLReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + bool res = read_stlb(in, _bi, _opt); + + if (in) + in.close(); + + return res; +} + +//----------------------------------------------------------------------------- + +bool +_STLReader_:: +read_stlb(std::istream& _in, BaseImporter& _bi, Options& _opt) const +{ + char dummy[100]; + bool swapFlag; + unsigned int i, nT; + OpenMesh::Vec3f v, n; + BaseImporter::VHandles vhandles; + + std::map vMap; + std::map::iterator vMapIt; + + + // check size of types + if ((sizeof(float) != 4) || (sizeof(int) != 4)) { + omerr() << "[STLReader] : wrong type size\n"; + return false; + } + + // determine endian mode + union { unsigned int i; unsigned char c[4]; } endian_test; + endian_test.i = 1; + swapFlag = (endian_test.c[3] == 1); + + // read number of triangles + _in.read(dummy, 80); + nT = read_int(_in, swapFlag); + + // read triangles + while (nT) + { + vhandles.clear(); + + // read triangle normal + n[0] = read_float(_in, swapFlag); + n[1] = read_float(_in, swapFlag); + n[2] = read_float(_in, swapFlag); + + // triangle's vertices + for (i=0; i<3; ++i) + { + v[0] = read_float(_in, swapFlag); + v[1] = read_float(_in, swapFlag); + v[2] = read_float(_in, swapFlag); + + // has vector been referenced before? + if ((vMapIt=vMap.find(v)) == vMap.end()) + { + // No : add vertex and remember idx/vector mapping + VertexHandle handle = _bi.add_vertex(v); + vhandles.push_back(handle); + vMap[v] = handle; + } + else + // Yes : get index from map + vhandles.push_back(vMapIt->second); + } + + + // Add face only if it is not degenerated + if ((vhandles[0] != vhandles[1]) && + (vhandles[0] != vhandles[2]) && + (vhandles[1] != vhandles[2])) { + FaceHandle fh = _bi.add_face(vhandles); + + if (fh.is_valid() && _opt.face_has_normal()) + _bi.set_normal(fh, n); + } + + _in.read(dummy, 2); + --nT; + } + + return true; +} + +//----------------------------------------------------------------------------- + +_STLReader_::STL_Type +_STLReader_:: +check_stl_type(const std::string& _filename) const +{ + + // Check the file size if it matches the binary value given after the header. + + //open the file + FILE* in = fopen(_filename.c_str(), "rb"); + if (!in) return NONE; + + // determine endian mode + union { unsigned int i; unsigned char c[4]; } endian_test; + endian_test.i = 1; + bool swapFlag = (endian_test.c[3] == 1); + + + // read number of triangles + char dummy[100]; + fread(dummy, 1, 80, in); + size_t nT = read_int(in, swapFlag); + + // compute file size from nT + size_t binary_size = 84 + nT*50; + + // get actual file size + size_t file_size(0); + rewind(in); + while (!feof(in)) + file_size += fread(dummy, 1, 100, in); + fclose(in); + + // if sizes match -> it's STLB otherwise STLA is assumed + return (binary_size == file_size ? STLB : STLA); +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/reader/STLReader.hh b/Sources/OpenMeshCore/Core/IO/reader/STLReader.hh new file mode 100644 index 0000000..78af039 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/reader/STLReader.hh @@ -0,0 +1,146 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements an reader module for STL files +// +//============================================================================= + + +#ifndef __STLREADER_HH__ +#define __STLREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include + +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +//== FORWARDS ================================================================= + +class BaseImporter; + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the STL format reader. This class is singleton'ed by + SingletonT to STLReader. +*/ +class OPENMESHDLLEXPORT _STLReader_ : public BaseReader +{ +public: + + // constructor + _STLReader_(); + + /// Destructor + virtual ~_STLReader_() {}; + + + std::string get_description() const override + { return "Stereolithography Interface Format"; } + std::string get_extensions() const override { return "stl stla stlb"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) override; + + bool read(std::istream& _in, + BaseImporter& _bi, + Options& _opt) override; + + /** Set the threshold to be used for considering two point to be equal. + Can be used to merge small gaps */ + void set_epsilon(float _eps) { eps_=_eps; } + + /// Returns the threshold to be used for considering two point to be equal. + float epsilon() const { return eps_; } + + + +private: + + enum STL_Type { STLA, STLB, NONE }; + STL_Type check_stl_type(const std::string& _filename) const; + + bool read_stla(const std::string& _filename, BaseImporter& _bi, Options& _opt) const; + bool read_stla(std::istream& _in, BaseImporter& _bi, Options& _opt) const; + bool read_stlb(const std::string& _filename, BaseImporter& _bi, Options& _opt) const; + bool read_stlb(std::istream& _in, BaseImporter& _bi, Options& _opt) const; + + +private: + + float eps_; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the STL reader +extern _STLReader_ __STLReaderInstance; +OPENMESHDLLEXPORT _STLReader_& STLReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/BaseWriter.cc b/Sources/OpenMeshCore/Core/IO/writer/BaseWriter.cc new file mode 100644 index 0000000..7feb829 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/BaseWriter.cc @@ -0,0 +1,102 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//=== INCLUDES ================================================================ + + +#include + +#if defined(OM_CC_MIPS) +# include +#else +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + +#ifndef DOXY_IGNORE_THIS + +static inline char tolower(char c) +{ + using namespace std; + return ::tolower(c); +} + +#endif + +//----------------------------------------------------------------------------- + + +bool +BaseWriter:: +can_u_write(const std::string& _filename) const +{ + // get file extension + std::string extension; + std::string::size_type pos(_filename.rfind(".")); + + if (pos != std::string::npos) + extension = _filename.substr(pos+1, _filename.length()-pos-1); + else + extension = _filename; //check, if the whole filename defines the extension + + std::transform( extension.begin(), extension.end(), + extension.begin(), tolower ); + + // locate extension in extension string + return (get_extensions().find(extension) != std::string::npos); +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/BaseWriter.hh b/Sources/OpenMeshCore/Core/IO/writer/BaseWriter.hh new file mode 100644 index 0000000..20babbb --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/BaseWriter.hh @@ -0,0 +1,152 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the baseclass for IOManager writer modules +// +//============================================================================= + + +#ifndef __BASEWRITER_HH__ +#define __BASEWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include + +// OpenMesh +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Base class for all writer modules. The module should register itself at + the IOManager by calling the register_module function. +*/ +class OPENMESHDLLEXPORT BaseWriter +{ +public: + + typedef unsigned int Option; + + /// Destructor + virtual ~BaseWriter() {}; + + /// Return short description of the supported file format. + virtual std::string get_description() const = 0; + + /// Return file format's extension. + virtual std::string get_extensions() const = 0; + + /** \brief Returns true if writer can write _filename (checks extension). + * _filename can also provide an extension without a name for a file e.g. _filename == "om" checks, if the writer can write the "om" extension + * @param _filename complete name of a file or just the extension + * @result true, if writer can write data with the given extension + */ + virtual bool can_u_write(const std::string& _filename) const; + + /** Write to a file + * @param _filename write to file with the given filename + * @param _be BaseExporter, which specifies the data source + * @param _writeOptions writing options + * @param _precision can be used to specify the precision of the floating point notation. + */ + virtual bool write(const std::string& _filename, + BaseExporter& _be, + const Options& _writeOptions, + std::streamsize _precision = 6) const = 0; + + /** Write to a std::ostream + * @param _os write to std::ostream + * @param _be BaseExporter, which specifies the data source + * @param _writeOptions writing options + * @param _precision can be used to specify the precision of the floating point notation. + */ + virtual bool write(std::ostream& _os, + BaseExporter& _be, + const Options& _writeOptions, + std::streamsize _precision = 6) const = 0; + + /// Returns expected size of file if binary format is supported else 0. + virtual size_t binary_size(BaseExporter&, const Options&) const { return 0; } + + + +protected: + + bool check(BaseExporter& _be, const Options& _writeOptions) const + { + // Check for all Options. When we want to write them (_opt.check() ) , they have to be available ( has_ ) + // Converts to not A (write them) or B (available) + return ( !_writeOptions.check(Options::VertexNormal ) || _be.has_vertex_normals()) + && ( !_writeOptions.check(Options::VertexTexCoord)|| _be.has_vertex_texcoords()) + && ( !_writeOptions.check(Options::VertexColor) || _be.has_vertex_colors()) + && ( !_writeOptions.check(Options::FaceNormal) || _be.has_face_normals()) + && ( !_writeOptions.check(Options::FaceColor) || _be.has_face_colors()); + } +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/OBJWriter.cc b/Sources/OpenMeshCore/Core/IO/writer/OBJWriter.cc new file mode 100644 index 0000000..6410f1e --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/OBJWriter.cc @@ -0,0 +1,420 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//== INCLUDES ================================================================= + + +//STL +#include +#include + +// OpenMesh +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OBJLoader singleton with MeshLoader +_OBJWriter_ __OBJWriterinstance; +_OBJWriter_& OBJWriter() { return __OBJWriterinstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_OBJWriter_::_OBJWriter_() { IOManager().register_module(this); } + + +//----------------------------------------------------------------------------- + + +bool +_OBJWriter_:: +write(const std::string& _filename, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const +{ + std::fstream out(_filename.c_str(), std::ios_base::out ); + + if (!out) + { + omerr() << "[OBJWriter] : cannot open file " + << _filename << std::endl; + return false; + } + + // Set precision on output stream. The default is set via IOManager and passed through to all writers. + out.precision(_precision); + + // Set fixed output to avoid problems with programs not reading scientific notation correctly + out << std::fixed; + + { +#if defined(WIN32) + std::string::size_type dotposition = _filename.find_last_of("\\/"); +#else + std::string::size_type dotposition = _filename.rfind("/"); +#endif + + if (dotposition == std::string::npos){ + path_ = "./"; + objName_ = _filename; + }else{ + path_ = _filename.substr(0,dotposition+1); + objName_ = _filename.substr(dotposition+1); + } + + //remove the file extension + dotposition = objName_.find_last_of("."); + + if(dotposition != std::string::npos) + objName_ = objName_.substr(0,dotposition); + } + + bool result = write(out, _be, _writeOptions, _precision); + + out.close(); + return result; +} + +//----------------------------------------------------------------------------- + +size_t _OBJWriter_::getMaterial(OpenMesh::Vec3f _color) const +{ + auto idx_it = material_idx_.find(_color); + if (idx_it != material_idx_.end()) { + return idx_it->second; + } else { + size_t idx = material_.size(); + material_.push_back(_color); + material_idx_[_color] = idx; + + return idx; + } +} + +//----------------------------------------------------------------------------- + +size_t _OBJWriter_::getMaterial(OpenMesh::Vec4f _color) const +{ + auto idx_it = materialA_idx_.find(_color); + if (idx_it != materialA_idx_.end()) { + return idx_it->second; + } else { + size_t idx = materialA_.size(); + materialA_.push_back(_color); + materialA_idx_[_color] = idx; + return idx; + } +} + +//----------------------------------------------------------------------------- + +bool +_OBJWriter_:: +writeMaterial(std::ostream& _out, BaseExporter& _be, Options _opt) const +{ + OpenMesh::Vec3f c; + OpenMesh::Vec4f cA; + + material_.clear(); + material_idx_.clear(); + materialA_.clear(); + materialA_idx_.clear(); + + //iterate over faces + for (size_t i=0, nF=_be.n_faces(); i (_be.colorA( FaceHandle(int(i)) )); + getMaterial(cA); + }else{ + //and without alpha + c = color_cast (_be.color( FaceHandle(int(i)) )); + getMaterial(c); + } + } + + //write the materials + if ( _opt.color_has_alpha() ) + for (size_t i=0; i < materialA_.size(); i++){ + _out << "newmtl " << "mat" << i << '\n'; + _out << "Ka 0.5000 0.5000 0.5000" << '\n'; + _out << "Kd " << materialA_[i][0] << ' ' << materialA_[i][1] << ' ' << materialA_[i][2] << '\n'; + _out << "Tr " << materialA_[i][3] << '\n'; + _out << "illum 1" << '\n'; + } + else + for (size_t i=0; i < material_.size(); i++){ + _out << "newmtl " << "mat" << i << '\n'; + _out << "Ka 0.5000 0.5000 0.5000" << '\n'; + _out << "Kd " << material_[i][0] << ' ' << material_[i][1] << ' ' << material_[i][2] << '\n'; + _out << "illum 1" << '\n'; + } + + if (_opt.texture_file != "") { + _out << "map_Kd " << _opt.texture_file << std::endl; + } + return true; +} + +//----------------------------------------------------------------------------- + + +bool +_OBJWriter_:: +write(std::ostream& _out, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const +{ + unsigned int idx; + VertexHandle vh; + std::vector vhandles; + bool useMatrial = false; + OpenMesh::Vec3f c; + OpenMesh::Vec4f cA; + + omlog() << "[OBJWriter] : write file\n"; + + _out.precision(_precision); + + // check exporter features + if (!check( _be, _writeOptions)) { + return false; + } + + + // No binary mode for OBJ + if ( _writeOptions.check(Options::Binary) ) { + omout() << "[OBJWriter] : Warning, Binary mode requested for OBJ Writer (No support for Binary mode), falling back to standard." << std::endl; + } + + // check for unsupported writer features + if (_writeOptions.check(Options::FaceNormal) ) { + omerr() << "[OBJWriter] : FaceNormal not supported by OBJ Writer" << std::endl; + return false; + } + + // check for unsupported writer features + if (_writeOptions.check(Options::VertexColor) ) { + omerr() << "[OBJWriter] : VertexColor not supported by OBJ Writer" << std::endl; + return false; + } + + //create material file if needed + if ( _writeOptions.check(Options::FaceColor) || _writeOptions.texture_file != ""){ + + std::string matFile = path_ + objName_ + _writeOptions.material_file_extension; + + std::fstream matStream(matFile.c_str(), std::ios_base::out ); + + if (!matStream) + { + omerr() << "[OBJWriter] : cannot write material file " << matFile << std::endl; + + }else{ + useMatrial = writeMaterial(matStream, _be, _writeOptions); + + matStream.close(); + } + } + + // header + _out << "# " << _be.n_vertices() << " vertices, "; + _out << _be.n_faces() << " faces" << '\n'; + + // material file + if ( (useMatrial && _writeOptions.check(Options::FaceColor)) || _writeOptions.texture_file != "") + _out << "mtllib " << objName_ << _writeOptions.material_file_extension << '\n'; + + std::map texMap; + //collect Texturevertices from halfedges + if(_writeOptions.check(Options::FaceTexCoord)) + { + std::vector texCoords; + //add all texCoords to map + unsigned int num = _be.get_face_texcoords(texCoords); + for(size_t i = 0; i < num ; ++i) + { + texMap[texCoords[i]] = static_cast(i); + } + } + + //collect Texture coordinates from vertices + if(_writeOptions.check(Options::VertexTexCoord)) + { + for (size_t i=0, nV=_be.n_vertices(); i(i)); + Vec2f t = _be.texcoord(vh); + texMap[t] = static_cast(i); + } + } + + // assign each texcoord in the map its id + // and write the vt entries + if(_writeOptions.check(Options::VertexTexCoord) || _writeOptions.check(Options::FaceTexCoord)) + { + int texCount = 0; + for(std::map::iterator it = texMap.begin(); it != texMap.end() ; ++it) + { + _out << "vt " << it->first[0] << " " << it->first[1] << '\n'; + it->second = ++texCount; + } + } + + const bool normal_double = _be.is_normal_double(); + const bool point_double = _be.is_point_double(); + for (size_t i=0, nV=_be.n_vertices(); i::max(); + + // we do not want to write seperators if we only write vertex indices + bool onlyVertices = !_writeOptions.check(Options::VertexTexCoord) + && !_writeOptions.check(Options::VertexNormal) + && !_writeOptions.check(Options::FaceTexCoord); + + // faces (indices starting at 1 not 0) + for (size_t i=0, nF=_be.n_faces(); i (_be.colorA( FaceHandle(int(i)) )); + material = getMaterial(cA); + } else{ + //and without alpha + c = color_cast (_be.color( FaceHandle(int(i)) )); + material = getMaterial(c); + } + + // if we are ina a new material block, specify in the file which material to use + if(lastMat != material) { + _out << "usemtl mat" << material << '\n'; + lastMat = material; + } + } + + _out << "f"; + + _be.get_vhandles(FaceHandle(int(i)), vhandles); + + for (size_t j=0; j< vhandles.size(); ++j) + { + + // Write vertex index + idx = vhandles[j].idx() + 1; + _out << " " << idx; + + if (!onlyVertices) { + // write separator + _out << "/" ; + + //write texCoords index from halfedge + if(_writeOptions.check(Options::FaceTexCoord)) + { + _out << texMap[_be.texcoord(_be.getHeh(FaceHandle(int(i)),vhandles[j]))]; + } + + else + { + // write vertex texture coordinate index + if (_writeOptions.check(Options::VertexTexCoord)) + _out << texMap[_be.texcoord(vhandles[j])]; + } + + // write vertex normal index + if ( _writeOptions.check(Options::VertexNormal) ) { + // write separator + _out << "/" ; + _out << idx; + } + } + } + + _out << '\n'; + } + + material_.clear(); + material_idx_.clear(); + materialA_.clear(); + materialA_idx_.clear(); + + return true; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/OBJWriter.hh b/Sources/OpenMeshCore/Core/IO/writer/OBJWriter.hh new file mode 100644 index 0000000..e48b3ca --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/OBJWriter.hh @@ -0,0 +1,133 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements an IOManager writer module for OBJ files +// +//============================================================================= + + +#ifndef __OBJWRITER_HH__ +#define __OBJWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + This class defines the OBJ writer. This class is further singleton'ed + by SingletonT to OBJWriter. +*/ +class OPENMESHDLLEXPORT _OBJWriter_ : public BaseWriter +{ +public: + + _OBJWriter_(); + + /// Destructor + virtual ~_OBJWriter_() {}; + + std::string get_description() const override { return "Alias/Wavefront"; } + std::string get_extensions() const override { return "obj"; } + + bool write(const std::string&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter&, const Options&) const override { return 0; } + +private: + + mutable std::string path_; + mutable std::string objName_; + + mutable std::vector< OpenMesh::Vec3f > material_; + mutable std::map< OpenMesh::Vec3f, size_t> material_idx_; + mutable std::vector< OpenMesh::Vec4f > materialA_; + mutable std::map< OpenMesh::Vec4f, size_t> materialA_idx_; + + size_t getMaterial(OpenMesh::Vec3f _color) const; + + size_t getMaterial(OpenMesh::Vec4f _color) const; + + bool writeMaterial(std::ostream& _out, BaseExporter&, Options) const; + + +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OBJ writer +extern _OBJWriter_ __OBJWriterinstance; +OPENMESHDLLEXPORT _OBJWriter_& OBJWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/OFFWriter.cc b/Sources/OpenMeshCore/Core/IO/writer/OFFWriter.cc new file mode 100644 index 0000000..458581e --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/OFFWriter.cc @@ -0,0 +1,522 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OFFLoader singleton with MeshLoader +_OFFWriter_ __OFFWriterInstance; +_OFFWriter_& OFFWriter() { return __OFFWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_OFFWriter_::_OFFWriter_() { IOManager().register_module(this); } + + +//----------------------------------------------------------------------------- + + +bool +_OFFWriter_:: +write(const std::string& _filename, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const +{ + std::ofstream out(_filename.c_str(), (_writeOptions.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out + : std::ios_base::out) ); + + return write(out, _be, _writeOptions, _precision); +} + +//----------------------------------------------------------------------------- + + +bool +_OFFWriter_:: +write(std::ostream& _os, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const +{ + // check exporter features + if ( !check( _be, _writeOptions ) ) + return false; + + + // check writer features + if ( _writeOptions.check(Options::FaceNormal) ) // not supported by format + return false; + + + if (!_os.good()) + { + omerr() << "[OFFWriter] : cannot write to stream " + << std::endl; + return false; + } + + // write header line + if (_writeOptions.check(Options::VertexTexCoord)) _os << "ST"; + if (_writeOptions.check(Options::VertexColor) || _writeOptions.check(Options::FaceColor)) _os << "C"; + if (_writeOptions.check(Options::VertexNormal)) _os << "N"; + _os << "OFF"; + if (_writeOptions.check(Options::Binary)) _os << " BINARY"; + _os << "\n"; + + if (!_writeOptions.check(Options::Binary)) + _os.precision(_precision); + + // write to file + bool result = (_writeOptions.check(Options::Binary) ? + write_binary(_os, _be, _writeOptions) : + write_ascii(_os, _be, _writeOptions)); + + + // return result + return result; +} + +//----------------------------------------------------------------------------- + + +bool +_OFFWriter_:: +write_ascii(std::ostream& _out, BaseExporter& _be, const Options& _writeOptions) const +{ + + unsigned int i, nV, nF; + Vec3f v, n; + Vec2f t; + OpenMesh::Vec3i c; + OpenMesh::Vec4i cA; + OpenMesh::Vec3f cf; + OpenMesh::Vec4f cAf; + VertexHandle vh; + std::vector vhandles; + + + // #vertices, #faces + _out << _be.n_vertices() << " "; + _out << _be.n_faces() << " "; + _out << 0 << "\n"; + + if (_writeOptions.color_is_float()) + _out << std::fixed; + + + // vertex data (point, normals, colors, texcoords) + for (i=0, nV=int(_be.n_vertices()); i vhandles; + + // #vertices, #faces + writeValue(_out, (uint)_be.n_vertices() ); + writeValue(_out, (uint) _be.n_faces() ); + writeValue(_out, 0 ); + + // vertex data (point, normals, texcoords) + for (i=0, nV=int(_be.n_vertices()); i vhandles; + + for (i=0, nF=int(_be.n_faces()); i +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the OFF format writer. This class is singleton'ed by + SingletonT to OFFWriter. + + By passing Options to the write function you can manipulate the writing behavoir. + The following options can be set: + + Binary + VertexNormal + VertexColor + VertexTexCoord + FaceColor + ColorAlpha + +*/ +class OPENMESHDLLEXPORT _OFFWriter_ : public BaseWriter +{ +public: + + _OFFWriter_(); + + virtual ~_OFFWriter_() {}; + + std::string get_description() const override { return "no description"; } + std::string get_extensions() const override { return "off"; } + + bool write(const std::string&, BaseExporter&, const Options&, std::streamsize _precision = 6) const override; + + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter& _be, const Options& _opt) const override; + + +protected: + void writeValue(std::ostream& _out, int value) const; + void writeValue(std::ostream& _out, unsigned int value) const; + void writeValue(std::ostream& _out, float value) const; + + bool write_ascii(std::ostream& _in, BaseExporter&, const Options& _writeOptions) const; + bool write_binary(std::ostream& _in, BaseExporter&, const Options& _writeOptions) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OFF writer. +extern _OFFWriter_ __OFFWriterInstance; +OPENMESHDLLEXPORT _OFFWriter_& OFFWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/OMWriter.cc b/Sources/OpenMeshCore/Core/IO/writer/OMWriter.cc new file mode 100644 index 0000000..2d6088b --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/OMWriter.cc @@ -0,0 +1,688 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#if defined( OM_CC_MIPS ) + #include + #include +#else + #include + #include +#endif + +#include +#include + +// -------------------- OpenMesh +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OMLoader singleton with MeshLoader +_OMWriter_ __OMWriterInstance; +_OMWriter_& OMWriter() { return __OMWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +const OMFormat::uchar _OMWriter_::magic_[3] = "OM"; +const OMFormat::uint8 _OMWriter_::version_ = OMFormat::mk_version(2,2); + + +_OMWriter_:: +_OMWriter_() +{ + IOManager().register_module(this); +} + + +bool +_OMWriter_::write(const std::string& _filename, BaseExporter& _be, + const Options& _writeOptions, std::streamsize /*_precision*/) const +{ + // check whether exporter can give us an OpenMesh BaseKernel + if (!_be.kernel()) return false; + + + // check for om extension in filename, we can only handle OM + if (_filename.rfind(".om") == std::string::npos) + return false; + + Options tmpOptions = _writeOptions; + + tmpOptions += Options::Binary; // only binary format supported + + std::ofstream ofs(_filename.c_str(), std::ios::binary); + + // check if file is open + if (!ofs.is_open()) + { + omerr() << "[OMWriter] : cannot open file " << _filename << std::endl; + return false; + } + + // call stream save method + bool rc = write(ofs, _be, tmpOptions); + + // close filestream + ofs.close(); + + // return success/failure notice + return rc; +} + + +//----------------------------------------------------------------------------- + +bool +_OMWriter_::write(std::ostream& _os, BaseExporter& _be, const Options& _writeOptions, std::streamsize /*_precision*/) const +{ +// std::clog << "[OMWriter]::write( stream )\n"; + + Options tmpOptions = _writeOptions; + + // check exporter features + if ( !check( _be, tmpOptions ) ) + { + omerr() << "[OMWriter]: exporter does not support wanted feature!\n"; + return false; + } + + + + // Maybe an ascii version will be implemented in the future. + // For now, support only a binary format + if ( !tmpOptions.check( Options::Binary ) ) + tmpOptions += Options::Binary; + + // Ignore LSB/MSB bit. Always store in LSB (little endian) + tmpOptions += Options::LSB; + tmpOptions -= Options::MSB; + + return write_binary(_os, _be, tmpOptions); +} + + +//----------------------------------------------------------------------------- + + +#ifndef DOXY_IGNORE_THIS +template struct Enabler +{ + explicit Enabler( T& obj ) : obj_(obj) + {} + + ~Enabler() { obj_.enable(); } + + T& obj_; +}; +#endif + + +bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, + const Options& _writeOptions) const +{ + #ifndef DOXY_IGNORE_THIS + Enabler enabler(omlog()); + #endif + + size_t bytes = 0; + + const bool swap_required = + _writeOptions.check(Options::Swap) || (Endian::local() == Endian::MSB); + + unsigned int i, nV, nF; + Vec3f v; + Vec3d vd; + Vec2f t; + + // -------------------- write header + OMFormat::Header header; + + header.magic_[0] = 'O'; + header.magic_[1] = 'M'; + header.mesh_ = _be.is_triangle_mesh() ? 'T' : 'P'; + header.version_ = version_; + header.n_vertices_ = int(_be.n_vertices()); + header.n_faces_ = int(_be.n_faces()); + header.n_edges_ = int(_be.n_edges()); + + bytes += store( _os, header, swap_required ); + + // ---------------------------------------- write chunks + + OMFormat::Chunk::Header chunk_header; + + + // -------------------- write vertex data + + // ---------- write vertex position + if (_be.n_vertices()) + { + v = _be.point(VertexHandle(0)); + chunk_header.reserved_ = 0; + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.type_ = OMFormat::Chunk::Type_Pos; + if (_be.is_point_double()) + { + chunk_header.signed_ = OMFormat::is_signed(vd[0]); + chunk_header.float_ = OMFormat::is_float(vd[0]); + chunk_header.dim_ = OMFormat::dim(vd); + chunk_header.bits_ = OMFormat::bits(vd[0]); + } + else + { + chunk_header.signed_ = OMFormat::is_signed(v[0]); + chunk_header.float_ = OMFormat::is_float(v[0]); + chunk_header.dim_ = OMFormat::dim(v); + chunk_header.bits_ = OMFormat::bits(v[0]); + } + + bytes += store( _os, chunk_header, swap_required ); + if (_be.is_point_double()) + for (i=0, nV=header.n_vertices_; i(i))); + auto to_vertex_id = _be.get_to_vertex_id(HalfedgeHandle(static_cast(i))); + auto face_id = _be.get_face_id(HalfedgeHandle(static_cast(i))); + + bytes += store( _os, next_id, OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap_required ); + bytes += store( _os, to_vertex_id, OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap_required ); + bytes += store( _os, face_id, OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap_required ); + } + } + + + // ---------- write face texture coords + if (_OMWriter_::version_ > OMFormat::mk_version(2,1) && _be.n_edges() && _writeOptions.check(Options::FaceTexCoord)) + { + + t = _be.texcoord(HalfedgeHandle(0)); + + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Halfedge; + chunk_header.type_ = OMFormat::Chunk::Type_Texcoord; + chunk_header.signed_ = OMFormat::is_signed(t[0]); + chunk_header.float_ = OMFormat::is_float(t[0]); + chunk_header.dim_ = OMFormat::dim(t); + chunk_header.bits_ = OMFormat::bits(t[0]); + + bytes += store(_os, chunk_header, swap_required); + + unsigned int nHE; + for (i = 0, nHE = header.n_edges_*2; i < nHE; ++i) + bytes += vector_store(_os, _be.texcoord(HalfedgeHandle(i)), swap_required); + + } + //--------------------------------------------------------------- + + // ---------- write vertex topology (outgoing halfedge) + if (_be.n_vertices()) + { + chunk_header.reserved_ = 0; + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.type_ = OMFormat::Chunk::Type_Topology; + chunk_header.signed_ = true; + chunk_header.float_ = true; // TODO: is this correct? This causes a scalar size of 1 in OMFormat.hh scalar_size which we need I think? + chunk_header.dim_ = OMFormat::Chunk::Dim_1D; + chunk_header.bits_ = OMFormat::needed_bits(_be.n_edges()*4); // *2 due to halfedge ids being stored, *2 due to signedness + + bytes += store( _os, chunk_header, swap_required ); + for (i=0, nV=header.n_vertices_; istore(_os, swap ); + } + else + return false; +#endif +#undef NEW_STYLE + } + + + // ---------- write face color + + if (_be.n_faces() && _be.has_face_colors() && _writeOptions.check( Options::FaceColor )) + { +#define NEW_STYLE 0 +#if NEW_STYLE + const BaseProperty *bp = _be.kernel()._get_fprop("f:colors"); + + if (bp) + { +#endif + Vec3uc c; + + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Face; + chunk_header.type_ = OMFormat::Chunk::Type_Color; + chunk_header.signed_ = OMFormat::is_signed( c[0] ); + chunk_header.float_ = OMFormat::is_float( c[0] ); + chunk_header.dim_ = OMFormat::dim( c ); + chunk_header.bits_ = OMFormat::bits( c[0] ); + + bytes += store( _os, chunk_header, swap_required ); +#if !NEW_STYLE + for (i=0, nF=header.n_faces_; istore(_os, swap); + } + else + return false; +#endif + } + + // ---------- write vertex status + if (_be.n_vertices() && _be.has_vertex_status() && _writeOptions.check(Options::Status)) + { + auto s = _be.status(VertexHandle(0)); + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.type_ = OMFormat::Chunk::Type_Status; + chunk_header.signed_ = false; + chunk_header.float_ = false; + chunk_header.dim_ = OMFormat::Chunk::Dim_1D; + chunk_header.bits_ = OMFormat::bits(s); + + // std::clog << chunk_header << std::endl; + bytes += store(_os, chunk_header, swap_required); + + for (i = 0, nV = header.n_vertices_; i < nV; ++i) + bytes += store(_os, _be.status(VertexHandle(i)), swap_required); + } + + // ---------- write edge status + if (_be.n_edges() && _be.has_edge_status() && _writeOptions.check(Options::Status)) + { + auto s = _be.status(EdgeHandle(0)); + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Edge; + chunk_header.type_ = OMFormat::Chunk::Type_Status; + chunk_header.signed_ = false; + chunk_header.float_ = false; + chunk_header.dim_ = OMFormat::Chunk::Dim_1D; + chunk_header.bits_ = OMFormat::bits(s); + + // std::clog << chunk_header << std::endl; + bytes += store(_os, chunk_header, swap_required); + + for (i = 0, nV = header.n_edges_; i < nV; ++i) + bytes += store(_os, _be.status(EdgeHandle(i)), swap_required); + } + + // ---------- write halfedge status + if (_be.n_edges() && _be.has_halfedge_status() && _writeOptions.check(Options::Status)) + { + auto s = _be.status(HalfedgeHandle(0)); + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Halfedge; + chunk_header.type_ = OMFormat::Chunk::Type_Status; + chunk_header.signed_ = false; + chunk_header.float_ = false; + chunk_header.dim_ = OMFormat::Chunk::Dim_1D; + chunk_header.bits_ = OMFormat::bits(s); + + // std::clog << chunk_header << std::endl; + bytes += store(_os, chunk_header, swap_required); + + for (i = 0, nV = header.n_edges_ * 2; i < nV; ++i) + bytes += store(_os, _be.status(HalfedgeHandle(i)), swap_required); + } + + // ---------- write face status + if (_be.n_faces() && _be.has_face_status() && _writeOptions.check(Options::Status)) + { + auto s = _be.status(FaceHandle(0)); + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Face; + chunk_header.type_ = OMFormat::Chunk::Type_Status; + chunk_header.signed_ = false; + chunk_header.float_ = false; + chunk_header.dim_ = OMFormat::Chunk::Dim_1D; + chunk_header.bits_ = OMFormat::bits(s); + + // std::clog << chunk_header << std::endl; + bytes += store(_os, chunk_header, swap_required); + + for (i = 0, nV = header.n_faces_; i < nV; ++i) + bytes += store(_os, _be.status(FaceHandle(i)), swap_required); + } + + // -------------------- write custom properties + + if (_writeOptions.check(Options::Custom)) + { + const auto store_property = [this, &_os, swap_required, &bytes]( + const BaseKernel::const_prop_iterator _it_begin, + const BaseKernel::const_prop_iterator _it_end, + const OMFormat::Chunk::Entity _ent) + { + for (auto prop = _it_begin; prop != _it_end; ++prop) + { + if (!*prop || (*prop)->name().empty() || + ((*prop)->name().size() > 1 && (*prop)->name()[1] == ':')) + { // skip dead and "private" properties (no name or name matches "?:*") + continue; + } + bytes += store_binary_custom_chunk(_os, **prop, _ent, swap_required); + } + }; + + store_property(_be.kernel()->vprops_begin(), _be.kernel()->vprops_end(), + OMFormat::Chunk::Entity_Vertex); + store_property(_be.kernel()->fprops_begin(), _be.kernel()->fprops_end(), + OMFormat::Chunk::Entity_Face); + store_property(_be.kernel()->eprops_begin(), _be.kernel()->eprops_end(), + OMFormat::Chunk::Entity_Edge); + store_property(_be.kernel()->hprops_begin(), _be.kernel()->hprops_end(), + OMFormat::Chunk::Entity_Halfedge); + store_property(_be.kernel()->mprops_begin(), _be.kernel()->mprops_end(), + OMFormat::Chunk::Entity_Mesh); + } + + memset(&chunk_header, 0, sizeof(chunk_header)); + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Sentinel; + bytes += store(_os, chunk_header, swap_required); + + omlog() << "#bytes written: " << bytes << std::endl; + + return true; +} + +// ---------------------------------------------------------------------------- + +size_t _OMWriter_::store_binary_custom_chunk(std::ostream& _os, + BaseProperty& _bp, + OMFormat::Chunk::Entity _entity, + bool _swap) const +{ + //omlog() << "Custom Property " << OMFormat::as_string(_entity) << " property [" + // << _bp.name() << "]" << std::endl; + + // Don't store if + // 1. it is not persistent + // 2. it's name is empty + if ( !_bp.persistent() || _bp.name().empty() ) + { + //omlog() << " skipped\n"; + return 0; + } + + size_t bytes = 0; + + OMFormat::Chunk::esize_t element_size = OMFormat::Chunk::esize_t(_bp.element_size()); + OMFormat::Chunk::Header chdr; + + // set header + chdr.name_ = true; + chdr.entity_ = _entity; + chdr.type_ = OMFormat::Chunk::Type_Custom; + chdr.signed_ = 0; + chdr.float_ = 0; + chdr.dim_ = OMFormat::Chunk::Dim_1D; // ignored + chdr.bits_ = element_size; + + + // write custom chunk + + // 1. chunk header + bytes += store( _os, chdr, _swap ); + + // 2. property name + bytes += store( _os, OMFormat::Chunk::PropertyName(_bp.name()), _swap ); + + // 3. data type needed to add property automatically, supported by version 2.1 or later + if(_OMWriter_::version_ > OMFormat::mk_version(2,1)) + { + OMFormat::Chunk::PropertyName type = OMFormat::Chunk::PropertyName(_bp.get_storage_name()); + bytes += store(_os, type, _swap); + } + + // 4. block size + bytes += store( _os, _bp.size_of(), OMFormat::Chunk::Integer_32, _swap ); + //omlog() << " block size = " << _bp.size_of() << std::endl; + + // 5. data + { + size_t b; + bytes += ( b=_bp.store( _os, _swap ) ); + assert(b == _bp.size_of()); + } + return bytes; +} + +// ---------------------------------------------------------------------------- + +size_t _OMWriter_::binary_size(BaseExporter& /* _be */, const Options& /* _opt */) const +{ + // std::clog << "[OMWriter]: binary_size()" << std::endl; + size_t bytes = sizeof( OMFormat::Header ); + + // !!!TODO!!! + + return bytes; +} + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/OMWriter.hh b/Sources/OpenMeshCore/Core/IO/writer/OMWriter.hh new file mode 100644 index 0000000..083a69a --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/OMWriter.hh @@ -0,0 +1,142 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a writer module for OM files +// +//============================================================================= + + +#ifndef __OMWRITER_HH__ +#define __OMWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +//=== FORWARDS ================================================================ + + +class BaseExporter; + + +//=== IMPLEMENTATION ========================================================== + + +/** + * Implementation of the OM format writer. This class is singleton'ed by + * SingletonT to OMWriter. + */ +class OPENMESHDLLEXPORT _OMWriter_ : public BaseWriter +{ +public: + + /// Constructor + _OMWriter_(); + + /// Destructor + virtual ~_OMWriter_() {}; + + std::string get_description() const override + { return "OpenMesh Format"; } + + std::string get_extensions() const override + { return "om"; } + + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter& _be, const Options& _opt) const override; + + static OMFormat::uint8 get_version() { return version_; } + + +protected: + + static const OMFormat::uchar magic_[3]; + static const OMFormat::uint8 version_; + + bool write(const std::string&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + bool write_binary(std::ostream&, BaseExporter&, const Options& _writeOptions) const; + + + size_t store_binary_custom_chunk(std::ostream&, BaseProperty&, + OMFormat::Chunk::Entity, bool) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OM writer. +extern _OMWriter_ __OMWriterInstance; +OPENMESHDLLEXPORT _OMWriter_& OMWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/PLYWriter.cc b/Sources/OpenMeshCore/Core/IO/writer/PLYWriter.cc new file mode 100644 index 0000000..053dc15 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/PLYWriter.cc @@ -0,0 +1,782 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include + +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the PLYLoader singleton with MeshLoader +_PLYWriter_ __PLYWriterInstance; +_PLYWriter_& PLYWriter() { return __PLYWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_PLYWriter_::_PLYWriter_() +{ + IOManager().register_module(this); + + nameOfType_[Unsupported] = ""; + nameOfType_[ValueTypeCHAR] = "char"; + nameOfType_[ValueTypeUCHAR] = nameOfType_[ValueTypeUINT8] = "uchar"; + nameOfType_[ValueTypeUSHORT] = "ushort"; + nameOfType_[ValueTypeSHORT] = "short"; + nameOfType_[ValueTypeUINT] = "uint"; + nameOfType_[ValueTypeINT] = "int"; + nameOfType_[ValueTypeFLOAT32] = nameOfType_[ValueTypeFLOAT] = "float"; + nameOfType_[ValueTypeDOUBLE] = "double"; +} + + +//----------------------------------------------------------------------------- + + +bool +_PLYWriter_:: +write(const std::string& _filename, BaseExporter& _be, const Options& _opt, std::streamsize _precision) const +{ + + // open file + std::ofstream out(_filename.c_str(), (_opt.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out + : std::ios_base::out) ); + return write(out, _be, _opt, _precision); +} + +//----------------------------------------------------------------------------- + + +bool +_PLYWriter_:: +write(std::ostream& _os, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const +{ + + options_ = _writeOptions; + + // check exporter features + if ( !check( _be, options_ ) ) + return false; + + // check writer features + if ( options_.check(Options::FaceNormal) ) { + // Face normals are not supported + // Uncheck these options and output message that + // they are not written out even though they were requested + options_.unset(Options::FaceNormal); + omerr() << "[PLYWriter] : Warning: Face normals are not supported and thus not exported! " << std::endl; + } + + + + if (!_os.good()) + { + omerr() << "[PLYWriter] : cannot write to stream " + << std::endl; + return false; + } + + if (!options_.check(Options::Binary)) + _os.precision(_precision); + + // write to file + bool result = (options_.check(Options::Binary) ? + write_binary(_os, _be, options_) : + write_ascii(_os, _be, options_)); + + return result; +} + +//----------------------------------------------------------------------------- + +// helper function for casting a property +template +const PropertyT* castProperty(const BaseProperty* _prop) +{ + return dynamic_cast< const PropertyT* >(_prop); +} + +//----------------------------------------------------------------------------- +std::vector<_PLYWriter_::CustomProperty> _PLYWriter_::writeCustomTypeHeader(std::ostream& _out, BaseKernel::const_prop_iterator _begin, BaseKernel::const_prop_iterator _end) const +{ + std::vector customProps; + for (;_begin != _end; ++_begin) + { + BaseProperty* prop = *_begin; + + + // check, if property is persistant + if (!prop || !prop->persistent()) + continue; + + + // identify type of property + CustomProperty cProp(prop); + size_t propSize = prop->element_size(); + switch (propSize) + { + case 1: + { + assert_compile(sizeof(char) == 1); + //check, if prop is a char or unsigned char by dynamic_cast + //char, unsigned char and signed char are 3 distinct types + if (castProperty(prop) != 0 || castProperty(prop) != 0) //treat char as signed char + cProp.type = ValueTypeCHAR; + else if (castProperty(prop) != 0) + cProp.type = ValueTypeUCHAR; + break; + } + case 2: + { + assert_compile (sizeof(short) == 2); + if (castProperty(prop) != 0) + cProp.type = ValueTypeSHORT; + else if (castProperty(prop) != 0) + cProp.type = ValueTypeUSHORT; + break; + } + case 4: + { + assert_compile (sizeof(int) == 4); + assert_compile (sizeof(float) == 4); + if (castProperty(prop) != 0) + cProp.type = ValueTypeINT; + else if (castProperty(prop) != 0) + cProp.type = ValueTypeUINT; + else if (castProperty(prop) != 0) + cProp.type = ValueTypeFLOAT; + break; + + } + case 8: + assert_compile (sizeof(double) == 8); + if (castProperty(prop) != 0) + cProp.type = ValueTypeDOUBLE; + break; + default: + break; + } + + if (cProp.type != Unsupported) + { + // property type was identified and it is persistant, write into header + customProps.push_back(cProp); + _out << "property " << nameOfType_[cProp.type] << " " << cProp.property->name() << "\n"; + } + } + return customProps; +} + +//----------------------------------------------------------------------------- + +template +void _PLYWriter_::write_customProp(std::ostream& _out, const CustomProperty& _prop, size_t _index) const +{ + if (_prop.type == ValueTypeCHAR) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeUCHAR || _prop.type == ValueTypeUINT8) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeSHORT) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeUSHORT) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeUINT) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeINT || _prop.type == ValueTypeINT32) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeFLOAT || _prop.type == ValueTypeFLOAT32) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); + else if (_prop.type == ValueTypeDOUBLE) + writeProxy(_prop.type,_out, castProperty(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type()); +} + + +//----------------------------------------------------------------------------- + + + +void _PLYWriter_::write_header(std::ostream& _out, BaseExporter& _be, Options& _opt, std::vector& _ovProps, std::vector& _ofProps) const { + //writing header + _out << "ply" << '\n'; + + if (_opt.is_binary()) { + _out << "format "; + if ( options_.check(Options::MSB) ) + _out << "binary_big_endian "; + else + _out << "binary_little_endian "; + _out << "1.0" << '\n'; + } else + _out << "format ascii 1.0" << '\n'; + + _out << "element vertex " << _be.n_vertices() << '\n'; + + _out << "property float x" << '\n'; + _out << "property float y" << '\n'; + _out << "property float z" << '\n'; + + if ( _opt.vertex_has_normal() ){ + _out << "property float nx" << '\n'; + _out << "property float ny" << '\n'; + _out << "property float nz" << '\n'; + } + + if ( _opt.vertex_has_texcoord() ){ + if ( _opt.use_st_coordinates() ){ + _out << "property float s" << '\n'; + _out << "property float t" << '\n'; + } else { + _out << "property float u" << '\n'; + _out << "property float v" << '\n'; + } + } + + if ( _opt.vertex_has_color() ){ + if ( _opt.color_is_float() ) { + _out << "property float red" << '\n'; + _out << "property float green" << '\n'; + _out << "property float blue" << '\n'; + + if ( _opt.color_has_alpha() ) + _out << "property float alpha" << '\n'; + } else { + _out << "property uchar red" << '\n'; + _out << "property uchar green" << '\n'; + _out << "property uchar blue" << '\n'; + + if ( _opt.color_has_alpha() ) + _out << "property uchar alpha" << '\n'; + } + } + + _ovProps = writeCustomTypeHeader(_out, _be.kernel()->vprops_begin(), _be.kernel()->vprops_end()); + + _out << "element face " << _be.n_faces() << '\n'; + _out << "property list uchar int vertex_indices" << '\n'; + + if ( _opt.face_has_color() ){ + if ( _opt.color_is_float() ) { + _out << "property float red" << '\n'; + _out << "property float green" << '\n'; + _out << "property float blue" << '\n'; + + if ( _opt.color_has_alpha() ) + _out << "property float alpha" << '\n'; + } else { + _out << "property uchar red" << '\n'; + _out << "property uchar green" << '\n'; + _out << "property uchar blue" << '\n'; + + if ( _opt.color_has_alpha() ) + _out << "property uchar alpha" << '\n'; + } + } + + _ofProps = writeCustomTypeHeader(_out, _be.kernel()->fprops_begin(), _be.kernel()->fprops_end()); + + _out << "end_header" << '\n'; +} + + +//----------------------------------------------------------------------------- + + +bool +_PLYWriter_:: +write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const +{ + + unsigned int i, nV, nF; + Vec3f v, n; + OpenMesh::Vec3ui c; + OpenMesh::Vec4ui cA; + OpenMesh::Vec3f cf; + OpenMesh::Vec4f cAf; + OpenMesh::Vec2f t; + VertexHandle vh; + FaceHandle fh; + std::vector vhandles; + + std::vector vProps; + std::vector fProps; + + write_header(_out, _be, _opt, vProps, fProps); + + if (_opt.color_is_float()) + _out << std::fixed; + + // vertex data (point, normals, colors, texcoords) + for (i=0, nV=int(_be.n_vertices()); i::iterator iter = vProps.begin(); iter < vProps.end(); ++iter) + write_customProp(_out,*iter,i); + + _out << "\n"; + } + + // faces (indices starting at 0) + for (i=0, nF=int(_be.n_faces()); i::iterator iter = fProps.begin(); iter < fProps.end(); ++iter) + write_customProp(_out,*iter,i); + _out << "\n"; + } + + + return true; +} + + +//----------------------------------------------------------------------------- + +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, int value) const { + + uint32_t tmp32; + uint8_t tmp8; + + switch (_type) { + case ValueTypeINT: + case ValueTypeINT32: + tmp32 = value; + store(_out, tmp32, options_.check(Options::MSB) ); + break; +// case ValueTypeUINT8: +default : + tmp8 = value; + store(_out, tmp8, options_.check(Options::MSB) ); + break; +// default : +// std::cerr << "unsupported conversion type to int: " << _type << std::endl; +// break; + } +} + +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned int value) const { + + uint32_t tmp32; + uint8_t tmp8; + + switch (_type) { + case ValueTypeINT: + case ValueTypeINT32: + tmp32 = value; + store(_out, tmp32, options_.check(Options::MSB) ); + break; +// case ValueTypeUINT8: +default : + tmp8 = value; + store(_out, tmp8, options_.check(Options::MSB) ); + break; +// default : +// std::cerr << "unsupported conversion type to int: " << _type << std::endl; +// break; + } +} + +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, float value) const { + + float32_t tmp; + + switch (_type) { + case ValueTypeFLOAT32: + case ValueTypeFLOAT: + tmp = value; + store( _out , tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to float: " << _type << std::endl; + break; + } +} + +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, double value) const { + + float64_t tmp; + + switch (_type) { + case ValueTypeDOUBLE: + tmp = value; + store( _out , tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to float: " << _type << std::endl; + break; + } +} + +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, signed char value) const{ + + int8_t tmp; + + switch (_type) { + case ValueTypeCHAR: + tmp = value; + store(_out, tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + break; + } +} +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned char value) const{ + + uint8_t tmp; + + switch (_type) { + case ValueTypeUCHAR: + tmp = value; + store(_out, tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + break; + } +} +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, short value) const{ + + int16_t tmp; + + switch (_type) { + case ValueTypeSHORT: + tmp = value; + store(_out, tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + break; + } +} +void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned short value) const{ + + uint16_t tmp; + + switch (_type) { + case ValueTypeUSHORT: + tmp = value; + store(_out, tmp, options_.check(Options::MSB) ); + break; + default : + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + break; + } +} + +bool +_PLYWriter_:: +write_binary(std::ostream& _out, BaseExporter& _be, Options _opt) const +{ + + unsigned int i, nV, nF; + Vec3f v, n; + Vec2f t; + OpenMesh::Vec4uc c; + OpenMesh::Vec4f cf; + VertexHandle vh; + FaceHandle fh; + std::vector vhandles; + + // vProps and fProps will be empty, until custom properties are supported by the binary writer + std::vector vProps; + std::vector fProps; + + write_header(_out, _be, _opt, vProps, fProps); + + // vertex data (point, normals, texcoords) + for (i=0, nV=int(_be.n_vertices()); i::iterator iter = vProps.begin(); iter < vProps.end(); ++iter) + write_customProp(_out,*iter,i); + } + + + for (i=0, nF=int(_be.n_faces()); i::iterator iter = fProps.begin(); iter < fProps.end(); ++iter) + write_customProp(_out,*iter,i); + } + + return true; +} + +// ---------------------------------------------------------------------------- + + +size_t +_PLYWriter_:: +binary_size(BaseExporter& _be, const Options& _writeOptions) const +{ + size_t header(0); + size_t data(0); + size_t _3floats(3*sizeof(float)); + size_t _3ui(3*sizeof(unsigned int)); + size_t _4ui(4*sizeof(unsigned int)); + + if ( !_writeOptions.is_binary() ) + return 0; + else + { + + size_t _3longs(3*sizeof(long)); + + header += 11; // 'OFF BINARY\n' + header += _3longs; // #V #F #E + data += _be.n_vertices() * _3floats; // vertex data + } + + if ( _writeOptions.vertex_has_normal() && _be.has_vertex_normals() ) + { + header += 1; // N + data += _be.n_vertices() * _3floats; + } + + if ( _writeOptions.vertex_has_color() && _be.has_vertex_colors() ) + { + header += 1; // C + data += _be.n_vertices() * _3floats; + } + + if ( _writeOptions.vertex_has_texcoord() && _be.has_vertex_texcoords() ) + { + size_t _2floats(2*sizeof(float)); + header += 2; // ST + data += _be.n_vertices() * _2floats; + } + + // topology + if (_be.is_triangle_mesh()) + { + data += _be.n_faces() * _4ui; + } + else + { + unsigned int i, nF; + std::vector vhandles; + + for (i=0, nF=int(_be.n_faces()); i +#include +#include + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the PLY format writer. This class is singleton'ed by + SingletonT to PLYWriter. + + currently supported options: + - VertexColors + - FaceColors + - Binary + - Binary -> MSB +*/ +class OPENMESHDLLEXPORT _PLYWriter_ : public BaseWriter +{ +public: + + _PLYWriter_(); + + /// Destructor + virtual ~_PLYWriter_() {}; + + std::string get_description() const override { return "PLY polygon file format"; } + std::string get_extensions() const override { return "ply"; } + + bool write(const std::string&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter& _be, const Options& _opt) const override; + + enum ValueType { + Unsupported = 0, + ValueTypeFLOAT32, ValueTypeFLOAT, + ValueTypeINT32, ValueTypeINT , ValueTypeUINT, + ValueTypeUCHAR, ValueTypeCHAR, ValueTypeUINT8, + ValueTypeUSHORT, ValueTypeSHORT, + ValueTypeDOUBLE + }; + +private: + mutable Options options_; + + struct CustomProperty + { + ValueType type; + const BaseProperty* property; + explicit CustomProperty(const BaseProperty* const _p):type(Unsupported),property(_p){} + }; + + const char* nameOfType_[12]; + + /// write custom persistant properties into the header for the current element, returns all properties, which were written sorted + std::vector writeCustomTypeHeader(std::ostream& _out, BaseKernel::const_prop_iterator _begin, BaseKernel::const_prop_iterator _end) const; + template + void write_customProp(std::ostream& _our, const CustomProperty& _prop, size_t _index) const; + template + void writeProxy(ValueType _type, std::ostream& _out, T _value, OpenMesh::GenProg::TrueType /*_binary*/) const + { + writeValue(_type, _out, _value); + } + template + void writeProxy(ValueType /*_type*/, std::ostream& _out, T _value, OpenMesh::GenProg::FalseType /*_binary*/) const + { + _out << " " << _value; + } + +protected: + void writeValue(ValueType _type, std::ostream& _out, signed char value) const; + void writeValue(ValueType _type, std::ostream& _out, unsigned char value) const; + void writeValue(ValueType _type, std::ostream& _out, short value) const; + void writeValue(ValueType _type, std::ostream& _out, unsigned short value) const; + void writeValue(ValueType _type, std::ostream& _out, int value) const; + void writeValue(ValueType _type, std::ostream& _out, unsigned int value) const; + void writeValue(ValueType _type, std::ostream& _out, float value) const; + void writeValue(ValueType _type, std::ostream& _out, double value) const; + + bool write_ascii(std::ostream& _out, BaseExporter&, Options) const; + bool write_binary(std::ostream& _out, BaseExporter&, Options) const; + /// write header into the stream _out. Returns custom properties (vertex and face) which are written into the header + void write_header(std::ostream& _out, BaseExporter& _be, Options& _opt, std::vector& _ovProps, std::vector& _ofProps) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the PLY writer. +extern _PLYWriter_ __PLYWriterInstance; +OPENMESHDLLEXPORT _PLYWriter_& PLYWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/STLWriter.cc b/Sources/OpenMeshCore/Core/IO/writer/STLWriter.cc new file mode 100644 index 0000000..bf6bb89 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/STLWriter.cc @@ -0,0 +1,437 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//== INCLUDES ================================================================= + + +//STL +#include + +// OpenMesh +#include +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +_STLWriter_ __STLWriterInstance; +_STLWriter_& STLWriter() { return __STLWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_STLWriter_::_STLWriter_() { IOManager().register_module(this); } + + +//----------------------------------------------------------------------------- + + +bool +_STLWriter_:: +write(const std::string& _filename, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const +{ + Options tmpOptions = _writeOptions; + + // binary or ascii ? + if (_filename.rfind(".stla") != std::string::npos) + { + tmpOptions -= Options::Binary; + } + else if (_filename.rfind(".stlb") != std::string::npos) + { + tmpOptions += Options::Binary; + } + + // open file + std::fstream out(_filename.c_str(), (tmpOptions.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out + : std::ios_base::out) ); + + bool result = write(out, _be, tmpOptions, _precision); + + out.close(); + + return result; +} + +//----------------------------------------------------------------------------- + + +bool +_STLWriter_:: +write(std::ostream& _os, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const +{ + // check exporter features + if (!check(_be, _writeOptions)) return false; + + // check writer features + if (_writeOptions.check(Options::VertexNormal) || + _writeOptions.check(Options::VertexTexCoord) || + _writeOptions.check(Options::FaceColor)) + return false; + + if (!_writeOptions.check(Options::Binary)) + _os.precision(_precision); + + if (_writeOptions & Options::Binary) + return write_stlb(_os, _be, _writeOptions); + else + return write_stla(_os, _be, _writeOptions); + + return false; +} + + + +//----------------------------------------------------------------------------- + + +bool +_STLWriter_:: +write_stla(const std::string& _filename, const BaseExporter& _be, Options /* _opt */) const +{ + omlog() << "[STLWriter] : write ascii file\n"; + + + // open file + FILE* out = fopen(_filename.c_str(), "w"); + if (!out) + { + omerr() << "[STLWriter] : cannot open file " << _filename << std::endl; + return false; + } + + + + + int i, nF(int(_be.n_faces())); + Vec3f a, b, c, n; + std::vector vhandles; + FaceHandle fh; + + + // header + fprintf(out, "solid \n"); + + + // write face set + for (i=0; i vhandles; + FaceHandle fh; + _out.precision(_precision); + + + // header + _out << "solid \n"; + + + // write face set + for (i=0; i vhandles; + FaceHandle fh; + + + // write header + const char header[80] = + "binary stl file" + " "; + fwrite(header, 1, 80, out); + + + // number of faces + write_int( int(_be.n_faces()), out); + + + // write face set + for (i=0; i vhandles; + FaceHandle fh; + _out.precision(_precision); + + + // write header + const char header[80] = + "binary stl file" + " "; + _out.write(header, 80); + + + // number of faces + write_int(int(_be.n_faces()), _out); + + + // write face set + for (i=0; i vhandles; + + for (i=0; i +#include +// -------------------- OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the STL format writer. This class is singleton'ed by + SingletonT to STLWriter. +*/ +class OPENMESHDLLEXPORT _STLWriter_ : public BaseWriter +{ +public: + + _STLWriter_(); + + /// Destructor + virtual ~_STLWriter_() {}; + + std::string get_description() const override { return "Stereolithography Format"; } + std::string get_extensions() const override { return "stl stla stlb"; } + + bool write(const std::string&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter&, const Options&) const override; + +private: + bool write_stla(const std::string&, const BaseExporter&, Options) const; + bool write_stla(std::ostream&, const BaseExporter&, Options, std::streamsize _precision = 6) const; + bool write_stlb(const std::string&, const BaseExporter&, Options) const; + bool write_stlb(std::ostream&, const BaseExporter&, Options, std::streamsize _precision = 6) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +// Declare the single entity of STL writer. +extern _STLWriter_ __STLWriterInstance; +OPENMESHDLLEXPORT _STLWriter_& STLWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/VTKWriter.cc b/Sources/OpenMeshCore/Core/IO/writer/VTKWriter.cc new file mode 100644 index 0000000..5c5d417 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/VTKWriter.cc @@ -0,0 +1,97 @@ +//== INCLUDES ================================================================= + +#include +#include + +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + +//=== INSTANTIATE ============================================================= + +_VTKWriter_ __VTKWriterinstance; +_VTKWriter_& VTKWriter() { return __VTKWriterinstance; } + +//=== IMPLEMENTATION ========================================================== + +_VTKWriter_::_VTKWriter_() { IOManager().register_module(this); } + +//----------------------------------------------------------------------------- + +bool _VTKWriter_::write(const std::string& _filename, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const +{ + std::ofstream out(_filename.c_str()); + + if (!out) { + omerr() << "[VTKWriter] : cannot open file " << _filename << std::endl; + return false; + } + + return write(out, _be, _writeOptions, _precision); +} + +//----------------------------------------------------------------------------- + +bool _VTKWriter_::write(std::ostream& _out, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const +{ + // check exporter features + if (!check(_be, _writeOptions)) { + return false; + } + + // check writer features + if (!_writeOptions.is_empty()) { + omlog() << "[VTKWriter] : writer does not support any options\n"; + return false; + } + + omlog() << "[VTKWriter] : write file\n"; + _out.precision(_precision); + + std::vector vhandles; + size_t polygon_table_size = 0; + size_t nf = _be.n_faces(); + for (size_t i = 0; i < nf; ++i) { + polygon_table_size += _be.get_vhandles(FaceHandle(int(i)), vhandles); + } + polygon_table_size += nf; + + // header + _out << "# vtk DataFile Version 3.0\n"; + _out << "Generated by OpenMesh\n"; + _out << "ASCII\n"; + _out << "DATASET POLYDATA\n"; + + // points + _out << "POINTS " << _be.n_vertices() << " float\n"; + size_t nv = _be.n_vertices(); + for (size_t i = 0; i < nv; ++i) { + const Vec3f v = _be.point(VertexHandle(int(i))); + _out << v[0] << ' ' << v[1] << ' ' << v[2] << '\n'; + } + + // faces + _out << "POLYGONS " << nf << ' ' << polygon_table_size << '\n'; + for (size_t i = 0; i < nf; ++i) { + _be.get_vhandles(FaceHandle(int(i)), vhandles); + + _out << vhandles.size() << ' '; + for (size_t j = 0; j < vhandles.size(); ++j) { + _out << " " << vhandles[j].idx(); + } + _out << '\n'; + } + + return true; +} + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/IO/writer/VTKWriter.hh b/Sources/OpenMeshCore/Core/IO/writer/VTKWriter.hh new file mode 100644 index 0000000..8887a40 --- /dev/null +++ b/Sources/OpenMeshCore/Core/IO/writer/VTKWriter.hh @@ -0,0 +1,52 @@ +//============================================================================= +// +// Implements an IOManager writer module for VTK files +// +//============================================================================= + +#ifndef __VTKWRITER_HH__ +#define __VTKWRITER_HH__ + +//=== INCLUDES ================================================================ + +#include +#include + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + +//=== IMPLEMENTATION ========================================================== + +class OPENMESHDLLEXPORT _VTKWriter_ : public BaseWriter +{ +public: + _VTKWriter_(); + + std::string get_description() const override { return "VTK"; } + std::string get_extensions() const override { return "vtk"; } + + bool write(const std::string&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter&, const Options&) const override { return 0; } +}; + +//== TYPE DEFINITION ========================================================== + +/// Declare the single entity of the OBJ writer +extern _VTKWriter_ __VTKWriterinstance; +OPENMESHDLLEXPORT _VTKWriter_& VTKWriter(); + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/ArrayItems.hh b/Sources/OpenMeshCore/Core/Mesh/ArrayItems.hh new file mode 100644 index 0000000..9031ba2 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/ArrayItems.hh @@ -0,0 +1,126 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_ARRAY_ITEMS_HH +#define OPENMESH_ARRAY_ITEMS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/// Definition of mesh items for use in the ArrayKernel +struct ArrayItems +{ + + //------------------------------------------------------ internal vertex type + + /// The vertex item + class Vertex + { + friend class ArrayKernel; + HalfedgeHandle halfedge_handle_; + }; + + + //---------------------------------------------------- internal halfedge type + +#ifndef DOXY_IGNORE_THIS + class Halfedge_without_prev + { + friend class ArrayKernel; + FaceHandle face_handle_; + VertexHandle vertex_handle_; + HalfedgeHandle next_halfedge_handle_; + }; +#endif + +#ifndef DOXY_IGNORE_THIS + class Halfedge_with_prev : public Halfedge_without_prev + { + friend class ArrayKernel; + HalfedgeHandle prev_halfedge_handle_; + }; +#endif + + //TODO: should be selected with config.h define + typedef Halfedge_with_prev Halfedge; + typedef Halfedge_without_prev HalfedgeNoPrev; + typedef GenProg::Bool2Type HasPrevHalfedge; + + //-------------------------------------------------------- internal edge type +#ifndef DOXY_IGNORE_THIS + class Edge + { + friend class ArrayKernel; + Halfedge halfedges_[2]; + }; +#endif + + //-------------------------------------------------------- internal face type +#ifndef DOXY_IGNORE_THIS + class Face + { + friend class ArrayKernel; + HalfedgeHandle halfedge_handle_; + }; +}; +#endif + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ITEMS_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/ArrayKernel.cc b/Sources/OpenMeshCore/Core/Mesh/ArrayKernel.cc new file mode 100644 index 0000000..0d7f988 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/ArrayKernel.cc @@ -0,0 +1,254 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#include + +namespace OpenMesh +{ + +ArrayKernel::ArrayKernel() +: refcount_vstatus_(0), refcount_hstatus_(0), + refcount_estatus_(0), refcount_fstatus_(0) +{ + init_bit_masks(); //Status bit masks initialization +} + +ArrayKernel::~ArrayKernel() +{ + clear(); +} + +// ArrayKernel::ArrayKernel(const ArrayKernel& _rhs) +// : BaseKernel(_rhs), +// vertices_(_rhs.vertices_), edges_(_rhs.edges_), faces_(_rhs.faces_), +// vertex_status_(_rhs.vertex_status_), halfedge_status_(_rhs.halfedge_status_), +// edge_status_(_rhs.edge_status_), face_status_(_rhs.face_status_), +// refcount_vstatus_(_rhs.refcount_vstatus_), refcount_hstatus_(_rhs.refcount_hstatus_), +// refcount_estatus_(_rhs.refcount_estatus_), refcount_fstatus_(_rhs.refcount_fstatus_) +// {} + + +void ArrayKernel::assign_connectivity(const ArrayKernel& _other) +{ + vertices_ = _other.vertices_; + edges_ = _other.edges_; + faces_ = _other.faces_; + + vprops_resize(n_vertices()); + hprops_resize(n_halfedges()); + eprops_resize(n_edges()); + fprops_resize(n_faces()); + + //just copy status properties for now, + //until a proper solution for refcounted + //properties is available + vertex_status_ = _other.vertex_status_; + halfedge_status_ = _other.halfedge_status_; + edge_status_ = _other.edge_status_; + face_status_ = _other.face_status_; + + //initialize refcounter to 1 for the new mesh, + //if status is available. + refcount_estatus_ = _other.refcount_estatus_ > 0 ? 1 : 0; + refcount_vstatus_ = _other.refcount_vstatus_ > 0 ? 1 : 0; + refcount_hstatus_ = _other.refcount_hstatus_ > 0 ? 1 : 0; + refcount_fstatus_ = _other.refcount_fstatus_ > 0 ? 1 : 0; +} + +// --- handle -> item --- +VertexHandle ArrayKernel::handle(const Vertex& _v) const +{ + return VertexHandle( int( &_v - &vertices_.front())); +} + +HalfedgeHandle ArrayKernel::handle(const Halfedge& _he) const +{ + // Calculate edge belonging to given halfedge + // There are two halfedges stored per edge + // Get memory position inside edge vector and devide by size of an edge + // to get the corresponding edge for the requested halfedge + size_t eh = ( (char*)&_he - (char*)&edges_.front() ) / sizeof(Edge) ; + assert((&_he == &edges_[eh].halfedges_[0]) || + (&_he == &edges_[eh].halfedges_[1])); + return ((&_he == &edges_[eh].halfedges_[0]) ? + HalfedgeHandle( int(eh)<<1) : HalfedgeHandle((int(eh)<<1)+1)); +} + +EdgeHandle ArrayKernel::handle(const Edge& _e) const +{ + return EdgeHandle( int(&_e - &edges_.front() ) ); +} + +FaceHandle ArrayKernel::handle(const Face& _f) const +{ + return FaceHandle( int(&_f - &faces_.front()) ); +} + +#define SIGNED(x) signed( (x) ) + +bool ArrayKernel::is_valid_handle(VertexHandle _vh) const +{ + return 0 <= _vh.idx() && _vh.idx() < SIGNED(n_vertices()); +} + +bool ArrayKernel::is_valid_handle(HalfedgeHandle _heh) const +{ + return 0 <= _heh.idx() && _heh.idx() < SIGNED(n_edges()*2); +} + +bool ArrayKernel::is_valid_handle(EdgeHandle _eh) const +{ + return 0 <= _eh.idx() && _eh.idx() < SIGNED(n_edges()); +} + +bool ArrayKernel::is_valid_handle(FaceHandle _fh) const +{ + return 0 <= _fh.idx() && _fh.idx() < SIGNED(n_faces()); +} + +#undef SIGNED + +unsigned int ArrayKernel::delete_isolated_vertices() +{ + assert(has_vertex_status());//this function requires vertex status property + unsigned int n_isolated = 0; + for (KernelVertexIter v_it = vertices_begin(); v_it != vertices_end(); ++v_it) + { + if (is_isolated(handle(*v_it))) + { + status(handle(*v_it)).set_deleted(true); + n_isolated++; + } + } + return n_isolated; +} + +void ArrayKernel::garbage_collection(bool _v, bool _e, bool _f) +{ + std::vector empty_vh; + std::vector empty_hh; + std::vector empty_fh; + garbage_collection( empty_vh,empty_hh,empty_fh,_v, _e, _f); +} + +void ArrayKernel::clean_keep_reservation() +{ + vertices_.clear(); + + edges_.clear(); + + faces_.clear(); + +} + +void ArrayKernel::clean() +{ + + vertices_.clear(); + VertexContainer().swap( vertices_ ); + + edges_.clear(); + EdgeContainer().swap( edges_ ); + + faces_.clear(); + FaceContainer().swap( faces_ ); + +} + + +void ArrayKernel::clear() +{ + vprops_clear(); + eprops_clear(); + hprops_clear(); + fprops_clear(); + + clean(); +} + + + +void ArrayKernel::resize( size_t _n_vertices, size_t _n_edges, size_t _n_faces ) +{ + vertices_.resize(_n_vertices); + edges_.resize(_n_edges); + faces_.resize(_n_faces); + + vprops_resize(n_vertices()); + hprops_resize(n_halfedges()); + eprops_resize(n_edges()); + fprops_resize(n_faces()); +} + +void ArrayKernel::reserve(size_t _n_vertices, size_t _n_edges, size_t _n_faces ) +{ + vertices_.reserve(_n_vertices); + edges_.reserve(_n_edges); + faces_.reserve(_n_faces); + + vprops_reserve(_n_vertices); + hprops_reserve(_n_edges*2); + eprops_reserve(_n_edges); + fprops_reserve(_n_faces); +} + +// Status Sets API +void ArrayKernel::init_bit_masks(BitMaskContainer& _bmc) +{ + for (unsigned int i = Attributes::UNUSED; i != 0; i <<= 1) + { + _bmc.push_back(i); + } +} + +void ArrayKernel::init_bit_masks() +{ + init_bit_masks(vertex_bit_masks_); + edge_bit_masks_ = vertex_bit_masks_;//init_bit_masks(edge_bit_masks_); + face_bit_masks_ = vertex_bit_masks_;//init_bit_masks(face_bit_masks_); + halfedge_bit_masks_= vertex_bit_masks_;//init_bit_masks(halfedge_bit_masks_); +} + + +}; + diff --git a/Sources/OpenMeshCore/Core/Mesh/ArrayKernel.hh b/Sources/OpenMeshCore/Core/Mesh/ArrayKernel.hh new file mode 100644 index 0000000..833519e --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/ArrayKernel.hh @@ -0,0 +1,913 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS ArrayKernel +// +//============================================================================= + + +#ifndef OPENMESH_ARRAY_KERNEL_HH +#define OPENMESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= +#include + +#include +#include + +#include +#include +#include + +//== NAMESPACES =============================================================== +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= +/** \ingroup mesh_kernels_group + + Mesh kernel using arrays for mesh item storage. + + This mesh kernel uses the std::vector as container to store the + mesh items. Therefore all handle types are internally represented + by integers. To get the index from a handle use the handle's \c + idx() method. + + \note For a description of the minimal kernel interface see + OpenMesh::Mesh::BaseKernel. + \note You do not have to use this class directly, use the predefined + mesh-kernel combinations in \ref mesh_types_group. + \see OpenMesh::Concepts::KernelT, \ref mesh_type +*/ + +class OPENMESHDLLEXPORT ArrayKernel : public BaseKernel, public ArrayItems +{ +public: + + // handles + typedef OpenMesh::VertexHandle VertexHandle; + typedef OpenMesh::HalfedgeHandle HalfedgeHandle; + typedef OpenMesh::EdgeHandle EdgeHandle; + typedef OpenMesh::FaceHandle FaceHandle; + typedef Attributes::StatusInfo StatusInfo; + typedef VPropHandleT VertexStatusPropertyHandle; + typedef HPropHandleT HalfedgeStatusPropertyHandle; + typedef EPropHandleT EdgeStatusPropertyHandle; + typedef FPropHandleT FaceStatusPropertyHandle; + +public: + + // --- constructor/destructor --- + ArrayKernel(); + virtual ~ArrayKernel(); + + /** ArrayKernel uses the default copy constructor and assignment operator, which means + that the connectivity and all properties are copied, including reference + counters, allocated bit status masks, etc.. In contrast assign_connectivity + copies only the connectivity, i.e. vertices, edges, faces and their status fields. + NOTE: The geometry (the points property) is NOT copied. Poly/TriConnectivity + override(and hide) that function to provide connectivity consistence.*/ + void assign_connectivity(const ArrayKernel& _other); + + // --- handle -> item --- + VertexHandle handle(const Vertex& _v) const; + + HalfedgeHandle handle(const Halfedge& _he) const; + + EdgeHandle handle(const Edge& _e) const; + + FaceHandle handle(const Face& _f) const; + + + ///checks handle validity - useful for debugging + bool is_valid_handle(VertexHandle _vh) const; + + ///checks handle validity - useful for debugging + bool is_valid_handle(HalfedgeHandle _heh) const; + + ///checks handle validity - useful for debugging + bool is_valid_handle(EdgeHandle _eh) const; + + ///checks handle validity - useful for debugging + bool is_valid_handle(FaceHandle _fh) const; + + + // --- item -> handle --- + const Vertex& vertex(VertexHandle _vh) const + { + assert(is_valid_handle(_vh)); + return vertices_[_vh.idx()]; + } + + Vertex& vertex(VertexHandle _vh) + { + assert(is_valid_handle(_vh)); + return vertices_[_vh.idx()]; + } + + const Halfedge& halfedge(HalfedgeHandle _heh) const + { + assert(is_valid_handle(_heh)); + return edges_[_heh.idx() >> 1].halfedges_[_heh.idx() & 1]; + } + + Halfedge& halfedge(HalfedgeHandle _heh) + { + assert(is_valid_handle(_heh)); + return edges_[_heh.idx() >> 1].halfedges_[_heh.idx() & 1]; + } + + const Edge& edge(EdgeHandle _eh) const + { + assert(is_valid_handle(_eh)); + return edges_[_eh.idx()]; + } + + Edge& edge(EdgeHandle _eh) + { + assert(is_valid_handle(_eh)); + return edges_[_eh.idx()]; + } + + const Face& face(FaceHandle _fh) const + { + assert(is_valid_handle(_fh)); + return faces_[_fh.idx()]; + } + + Face& face(FaceHandle _fh) + { + assert(is_valid_handle(_fh)); + return faces_[_fh.idx()]; + } + + // --- get i'th items --- + + VertexHandle vertex_handle(unsigned int _i) const + { return (_i < n_vertices()) ? handle( vertices_[_i] ) : VertexHandle(); } + + HalfedgeHandle halfedge_handle(unsigned int _i) const + { + return (_i < n_halfedges()) ? + halfedge_handle(edge_handle(_i/2), _i%2) : HalfedgeHandle(); + } + + EdgeHandle edge_handle(unsigned int _i) const + { return (_i < n_edges()) ? handle(edges_[_i]) : EdgeHandle(); } + + FaceHandle face_handle(unsigned int _i) const + { return (_i < n_faces()) ? handle(faces_[_i]) : FaceHandle(); } + +public: + + /** + * \brief Add a new vertex. + * + * If you are rebuilding a mesh that you previously erased using clean() or + * clean_keep_reservation() you probably want to use new_vertex_dirty() + * instead. + * + * \sa new_vertex_dirty() + */ + inline VertexHandle new_vertex() + { + vertices_.push_back(Vertex()); + vprops_resize(n_vertices());//TODO:should it be push_back()? + + return handle(vertices_.back()); + } + + /** + * Same as new_vertex() but uses PropertyContainer::resize_if_smaller() to + * resize the vertex property container. + * + * If you are rebuilding a mesh that you erased with clean() or + * clean_keep_reservation() using this method instead of new_vertex() saves + * reallocation and reinitialization of property memory. + * + * \sa new_vertex() + */ + inline VertexHandle new_vertex_dirty() + { + vertices_.push_back(Vertex()); + vprops_resize_if_smaller(n_vertices());//TODO:should it be push_back()? + + return handle(vertices_.back()); + } + + inline HalfedgeHandle new_edge(VertexHandle _start_vh, VertexHandle _end_vh) + { +// assert(_start_vh != _end_vh); + edges_.push_back(Edge()); + eprops_resize(n_edges());//TODO:should it be push_back()? + hprops_resize(n_halfedges());//TODO:should it be push_back()? + + EdgeHandle eh(handle(edges_.back())); + HalfedgeHandle heh0(halfedge_handle(eh, 0)); + HalfedgeHandle heh1(halfedge_handle(eh, 1)); + set_vertex_handle(heh0, _end_vh); + set_vertex_handle(heh1, _start_vh); + return heh0; + } + + inline FaceHandle new_face() + { + faces_.push_back(Face()); + fprops_resize(n_faces()); + return handle(faces_.back()); + } + + inline FaceHandle new_face(const Face& _f) + { + faces_.push_back(_f); + fprops_resize(n_faces()); + return handle(faces_.back()); + } + +public: + // --- resize/reserve --- + void resize( size_t _n_vertices, size_t _n_edges, size_t _n_faces ); + void reserve(size_t _n_vertices, size_t _n_edges, size_t _n_faces ); + + // --- deletion --- + /** \brief garbage collection + * + * Usually if you delete primitives in OpenMesh, they are only flagged as deleted. + * Only when you call garbage collection, they will be actually removed. + * + * \note Garbage collection invalidates all handles. If you need to keep track of + * a set of handles, you can pass them to the second garbage collection + * function, which will update a vector of handles. + * See also \ref deletedElements. + * + * @param _v Remove deleted vertices? + * @param _e Remove deleted edges? + * @param _f Remove deleted faces? + * + */ + void garbage_collection(bool _v=true, bool _e=true, bool _f=true); + + /** \brief garbage collection with handle tracking + * + * Usually if you delete primitives in OpenMesh, they are only flagged as deleted. + * Only when you call garbage collection, they will be actually removed. + * + * \note Garbage collection invalidates all handles. If you need to keep track of + * a set of handles, you can pass them to this function. The handles that the + * given pointers point to are updated in place. Warning: You cannot update + * handles stored in a mesh property, as the memory might be moved + * during garbage collection! + * See also \ref deletedElements. + * + * @param vh_to_update Pointers to vertex handles that should get updated + * @param hh_to_update Pointers to halfedge handles that should get updated + * @param fh_to_update Pointers to face handles that should get updated + * @param _v Remove deleted vertices? + * @param _e Remove deleted edges? + * @param _f Remove deleted faces? + */ + template + void garbage_collection(std_API_Container_VHandlePointer& vh_to_update, + std_API_Container_HHandlePointer& hh_to_update, + std_API_Container_FHandlePointer& fh_to_update, + bool _v=true, bool _e=true, bool _f=true); + + /// \brief Does the same as clean() and in addition erases all properties. + void clear(); + + /** \brief Remove all vertices, edges and faces and deallocates their memory. + * + * In contrast to clear() this method does neither erases the properties + * nor clears the property vectors. Depending on how you add any new entities + * to the mesh after calling this method, your properties will be initialized + * with old values. + * + * \sa clean_keep_reservation() + */ + void clean(); + + /** \brief Remove all vertices, edges and faces but keep memory allocated. + * + * This method behaves like clean() (also regarding the properties) but + * leaves the memory used for vertex, edge and face storage allocated. This + * leads to no reduction in memory consumption but allows for faster + * performance when rebuilding the mesh. + */ + void clean_keep_reservation(); + + // --- number of items --- + size_t n_vertices() const override { return vertices_.size(); } + size_t n_halfedges() const override { return 2*edges_.size(); } + size_t n_edges() const override { return edges_.size(); } + size_t n_faces() const override { return faces_.size(); } + + bool vertices_empty() const { return vertices_.empty(); } + bool halfedges_empty() const { return edges_.empty(); } + bool edges_empty() const { return edges_.empty(); } + bool faces_empty() const { return faces_.empty(); } + + // --- vertex connectivity --- + + HalfedgeHandle halfedge_handle(VertexHandle _vh) const + { return vertex(_vh).halfedge_handle_; } + + void set_halfedge_handle(VertexHandle _vh, HalfedgeHandle _heh) + { +// assert(is_valid_handle(_heh)); + vertex(_vh).halfedge_handle_ = _heh; + } + + bool is_isolated(VertexHandle _vh) const + { return !halfedge_handle(_vh).is_valid(); } + + void set_isolated(VertexHandle _vh) + { vertex(_vh).halfedge_handle_.invalidate(); } + + unsigned int delete_isolated_vertices(); + + // --- halfedge connectivity --- + VertexHandle to_vertex_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).vertex_handle_; } + + VertexHandle from_vertex_handle(HalfedgeHandle _heh) const + { return to_vertex_handle(opposite_halfedge_handle(_heh)); } + + void set_vertex_handle(HalfedgeHandle _heh, VertexHandle _vh) + { +// assert(is_valid_handle(_vh)); + halfedge(_heh).vertex_handle_ = _vh; + } + + FaceHandle face_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).face_handle_; } + + void set_face_handle(HalfedgeHandle _heh, FaceHandle _fh) + { +// assert(is_valid_handle(_fh)); + halfedge(_heh).face_handle_ = _fh; + } + + void set_boundary(HalfedgeHandle _heh) + { halfedge(_heh).face_handle_.invalidate(); } + + /// Is halfedge _heh a boundary halfedge (is its face handle invalid) ? + bool is_boundary(HalfedgeHandle _heh) const + { return !face_handle(_heh).is_valid(); } + + HalfedgeHandle next_halfedge_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).next_halfedge_handle_; } + + void set_next_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _nheh) + { + assert(is_valid_handle(_nheh)); +// assert(to_vertex_handle(_heh) == from_vertex_handle(_nheh)); + halfedge(_heh).next_halfedge_handle_ = _nheh; + set_prev_halfedge_handle(_nheh, _heh); + } + + + void set_prev_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _pheh) + { + assert(is_valid_handle(_pheh)); + set_prev_halfedge_handle(_heh, _pheh, HasPrevHalfedge()); + } + + void set_prev_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _pheh, + GenProg::TrueType) + { halfedge(_heh).prev_halfedge_handle_ = _pheh; } + + void set_prev_halfedge_handle(HalfedgeHandle /* _heh */, HalfedgeHandle /* _pheh */, + GenProg::FalseType) + {} + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh) const + { return prev_halfedge_handle(_heh, HasPrevHalfedge() ); } + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh, GenProg::TrueType) const + { return halfedge(_heh).prev_halfedge_handle_; } + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh, GenProg::FalseType) const + { + if (is_boundary(_heh)) + {//iterating around the vertex should be faster than iterating the boundary + HalfedgeHandle curr_heh(opposite_halfedge_handle(_heh)); + HalfedgeHandle next_heh(next_halfedge_handle(curr_heh)); + do + { + curr_heh = opposite_halfedge_handle(next_heh); + next_heh = next_halfedge_handle(curr_heh); + } + while (next_heh != _heh); + return curr_heh; + } + else + { + HalfedgeHandle heh(_heh); + HalfedgeHandle next_heh(next_halfedge_handle(heh)); + while (next_heh != _heh) { + heh = next_heh; + next_heh = next_halfedge_handle(next_heh); + } + return heh; + } + } + + + HalfedgeHandle opposite_halfedge_handle(HalfedgeHandle _heh) const + { return HalfedgeHandle(_heh.idx() ^ 1); } + + + HalfedgeHandle ccw_rotated_halfedge_handle(HalfedgeHandle _heh) const + { return opposite_halfedge_handle(prev_halfedge_handle(_heh)); } + + + HalfedgeHandle cw_rotated_halfedge_handle(HalfedgeHandle _heh) const + { return next_halfedge_handle(opposite_halfedge_handle(_heh)); } + + // --- edge connectivity --- + static HalfedgeHandle s_halfedge_handle(EdgeHandle _eh, unsigned int _i = 0) + { + assert(_i<=1); + return HalfedgeHandle((_eh.idx() << 1) + _i); + } + + static EdgeHandle s_edge_handle(HalfedgeHandle _heh) + { return EdgeHandle(_heh.idx() >> 1); } + + HalfedgeHandle halfedge_handle(EdgeHandle _eh, unsigned int _i = 0) const + { + return s_halfedge_handle(_eh, _i); + } + + EdgeHandle edge_handle(HalfedgeHandle _heh) const + { return s_edge_handle(_heh); } + + // --- face connectivity --- + HalfedgeHandle halfedge_handle(FaceHandle _fh) const + { return face(_fh).halfedge_handle_; } + + void set_halfedge_handle(FaceHandle _fh, HalfedgeHandle _heh) + { +// assert(is_valid_handle(_heh)); + face(_fh).halfedge_handle_ = _heh; + } + + /// Status Query API + //------------------------------------------------------------ vertex status + const StatusInfo& status(VertexHandle _vh) const + { return property(vertex_status_, _vh); } + + StatusInfo& status(VertexHandle _vh) + { return property(vertex_status_, _vh); } + + /** + * Reinitializes the status of all vertices using the StatusInfo default + * constructor, i.e. all flags will be set to false. + */ + void reset_status() { + PropertyT &status_prop = property(vertex_status_); + PropertyT::vector_type &sprop_v = status_prop.data_vector(); + std::fill(sprop_v.begin(), sprop_v.begin() + n_vertices(), StatusInfo()); + } + + //----------------------------------------------------------- halfedge status + const StatusInfo& status(HalfedgeHandle _hh) const + { return property(halfedge_status_, _hh); } + + StatusInfo& status(HalfedgeHandle _hh) + { return property(halfedge_status_, _hh); } + + //--------------------------------------------------------------- edge status + const StatusInfo& status(EdgeHandle _eh) const + { return property(edge_status_, _eh); } + + StatusInfo& status(EdgeHandle _eh) + { return property(edge_status_, _eh); } + + //--------------------------------------------------------------- face status + const StatusInfo& status(FaceHandle _fh) const + { return property(face_status_, _fh); } + + StatusInfo& status(FaceHandle _fh) + { return property(face_status_, _fh); } + + inline bool has_vertex_status() const + { return vertex_status_.is_valid(); } + + inline bool has_halfedge_status() const + { return halfedge_status_.is_valid(); } + + inline bool has_edge_status() const + { return edge_status_.is_valid(); } + + inline bool has_face_status() const + { return face_status_.is_valid(); } + + inline VertexStatusPropertyHandle vertex_status_pph() const + { return vertex_status_; } + + inline HalfedgeStatusPropertyHandle halfedge_status_pph() const + { return halfedge_status_; } + + inline EdgeStatusPropertyHandle edge_status_pph() const + { return edge_status_; } + + inline FaceStatusPropertyHandle face_status_pph() const + { return face_status_; } + + /// status property by handle + inline VertexStatusPropertyHandle status_pph(VertexHandle /*_hnd*/) const + { return vertex_status_pph(); } + + inline HalfedgeStatusPropertyHandle status_pph(HalfedgeHandle /*_hnd*/) const + { return halfedge_status_pph(); } + + inline EdgeStatusPropertyHandle status_pph(EdgeHandle /*_hnd*/) const + { return edge_status_pph(); } + + inline FaceStatusPropertyHandle status_pph(FaceHandle /*_hnd*/) const + { return face_status_pph(); } + + /// Status Request API + void request_vertex_status() + { + if (!refcount_vstatus_++) + add_property( vertex_status_, "v:status" ); + } + + void request_halfedge_status() + { + if (!refcount_hstatus_++) + add_property( halfedge_status_, "h:status" ); + } + + void request_edge_status() + { + if (!refcount_estatus_++) + add_property( edge_status_, "e:status" ); + } + + void request_face_status() + { + if (!refcount_fstatus_++) + add_property( face_status_, "f:status" ); + } + + /// Status Release API + void release_vertex_status() + { + if ((refcount_vstatus_ > 0) && (! --refcount_vstatus_)) + remove_property(vertex_status_); + } + + void release_halfedge_status() + { + if ((refcount_hstatus_ > 0) && (! --refcount_hstatus_)) + remove_property(halfedge_status_); + } + + void release_edge_status() + { + if ((refcount_estatus_ > 0) && (! --refcount_estatus_)) + remove_property(edge_status_); + } + + void release_face_status() + { + if ((refcount_fstatus_ > 0) && (! --refcount_fstatus_)) + remove_property(face_status_); + } + + /// --- StatusSet API --- + + /*! + Implements a set of connectivity entities (vertex, edge, face, halfedge) + using the available bits in the corresponding mesh status field. + + Status-based sets are much faster than std::set<> and equivalent + in performance to std::vector, but much more convenient. + */ + template + class StatusSetT + { + public: + typedef HandleT Handle; + + protected: + ArrayKernel& kernel_; + + public: + const unsigned int bit_mask_; + + public: + StatusSetT(ArrayKernel& _kernel, const unsigned int _bit_mask) + : kernel_(_kernel), bit_mask_(_bit_mask) + {} + + ~StatusSetT() + {} + + inline bool is_in(Handle _hnd) const + { return kernel_.status(_hnd).is_bit_set(bit_mask_); } + + inline void insert(Handle _hnd) + { kernel_.status(_hnd).set_bit(bit_mask_); } + + inline void erase(Handle _hnd) + { kernel_.status(_hnd).unset_bit(bit_mask_); } + + //! Note: 0(n) complexity + size_t size() const + { + const int n = kernel_.status_pph(Handle()).is_valid() ? + (int)kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; + + size_t sz = 0; + for (int i = 0; i < n; ++i) + sz += (size_t)is_in(Handle(i)); + return sz; + } + + //! Note: O(n) complexity + void clear() + { + const int n = kernel_.status_pph(Handle()).is_valid() ? + (int)kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; + + for (int i = 0; i < n; ++i) + erase(Handle(i)); + } + }; + + friend class StatusSetT; + friend class StatusSetT; + friend class StatusSetT; + friend class StatusSetT; + + //! AutoStatusSetT: A status set that automatically picks a status bit + template + class AutoStatusSetT : public StatusSetT + { + private: + typedef HandleT Handle; + typedef StatusSetT Base; + + public: + explicit AutoStatusSetT(ArrayKernel& _kernel) + : StatusSetT(_kernel, _kernel.pop_bit_mask(Handle())) + { /*assert(size() == 0);*/ } //the set should be empty on creation + + ~AutoStatusSetT() + { + //assert(size() == 0);//the set should be empty on leave? + Base::kernel_.push_bit_mask(Handle(), Base::bit_mask_); + } + }; + + friend class AutoStatusSetT; + friend class AutoStatusSetT; + friend class AutoStatusSetT; + friend class AutoStatusSetT; + + typedef AutoStatusSetT VertexStatusSet; + typedef AutoStatusSetT EdgeStatusSet; + typedef AutoStatusSetT FaceStatusSet; + typedef AutoStatusSetT HalfedgeStatusSet; + + //! ExtStatusSet: A status set augmented with an array + template + class ExtStatusSetT : public AutoStatusSetT + { + public: + typedef HandleT Handle; + typedef AutoStatusSetT Base; + + protected: + typedef std::vector HandleContainer; + HandleContainer handles_; + + public: + typedef typename HandleContainer::iterator + iterator; + typedef typename HandleContainer::const_iterator + const_iterator; + public: + explicit ExtStatusSetT(ArrayKernel& _kernel, size_t _capacity_hint = 0) + : Base(_kernel) + { handles_.reserve(_capacity_hint); } + + ~ExtStatusSetT() + { Base::clear(); } + + // Complexity: O(1) + inline void insert(Handle _hnd) + { + if (!Base::is_in(_hnd)) + { + Base::insert(_hnd); + handles_.push_back(_hnd); + } + } + + //! Complexity: O(k), (k - number of the elements in the set) + inline void erase(Handle _hnd) + { + if (is_in(_hnd)) + { + iterator it = std::find(begin(), end(), _hnd); + erase(it); + } + } + + //! Complexity: O(1) + inline void erase(iterator _it) + { + assert(_it != const_cast(this)->end() && + Base::is_in(*_it)); + Base::erase(*_it); + *_it = handles_.back(); + _it.pop_back(); + } + + inline void clear() + { + for (iterator it = begin(); it != end(); ++it) + { + assert(Base::is_in(*it)); + Base::erase(*it); + } + handles_.clear(); + } + + /// Complexity: 0(1) + inline unsigned int size() const + { return handles_.size(); } + inline bool empty() const + { return handles_.empty(); } + + //Vector API + inline iterator begin() + { return handles_.begin(); } + inline const_iterator begin() const + { return handles_.begin(); } + + inline iterator end() + { return handles_.end(); } + inline const_iterator end() const + { return handles_.end(); } + + inline Handle& front() + { return handles_.front(); } + inline const Handle& front() const + { return handles_.front(); } + + inline Handle& back() + { return handles_.back(); } + inline const Handle& back() const + { return handles_.back(); } + }; + + typedef ExtStatusSetT ExtFaceStatusSet; + typedef ExtStatusSetT ExtVertexStatusSet; + typedef ExtStatusSetT ExtEdgeStatusSet; + typedef ExtStatusSetT ExtHalfedgeStatusSet; + +private: + // iterators + typedef std::vector VertexContainer; + typedef std::vector EdgeContainer; + typedef std::vector FaceContainer; + typedef VertexContainer::iterator KernelVertexIter; + typedef VertexContainer::const_iterator KernelConstVertexIter; + typedef EdgeContainer::iterator KernelEdgeIter; + typedef EdgeContainer::const_iterator KernelConstEdgeIter; + typedef FaceContainer::iterator KernelFaceIter; + typedef FaceContainer::const_iterator KernelConstFaceIter; + typedef std::vector BitMaskContainer; + + + KernelVertexIter vertices_begin() { return vertices_.begin(); } + KernelConstVertexIter vertices_begin() const { return vertices_.begin(); } + KernelVertexIter vertices_end() { return vertices_.end(); } + KernelConstVertexIter vertices_end() const { return vertices_.end(); } + + KernelEdgeIter edges_begin() { return edges_.begin(); } + KernelConstEdgeIter edges_begin() const { return edges_.begin(); } + KernelEdgeIter edges_end() { return edges_.end(); } + KernelConstEdgeIter edges_end() const { return edges_.end(); } + + KernelFaceIter faces_begin() { return faces_.begin(); } + KernelConstFaceIter faces_begin() const { return faces_.begin(); } + KernelFaceIter faces_end() { return faces_.end(); } + KernelConstFaceIter faces_end() const { return faces_.end(); } + + /// bit mask container by handle + inline BitMaskContainer& bit_masks(VertexHandle /*_dummy_hnd*/) + { return vertex_bit_masks_; } + inline BitMaskContainer& bit_masks(EdgeHandle /*_dummy_hnd*/) + { return edge_bit_masks_; } + inline BitMaskContainer& bit_masks(FaceHandle /*_dummy_hnd*/) + { return face_bit_masks_; } + inline BitMaskContainer& bit_masks(HalfedgeHandle /*_dummy_hnd*/) + { return halfedge_bit_masks_; } + + template + unsigned int pop_bit_mask(Handle _hnd) + { + assert(!bit_masks(_hnd).empty());//check if the client request too many status sets + unsigned int bit_mask = bit_masks(_hnd).back(); + bit_masks(_hnd).pop_back(); + return bit_mask; + } + + template + void push_bit_mask(Handle _hnd, unsigned int _bit_mask) + { + assert(std::find(bit_masks(_hnd).begin(), bit_masks(_hnd).end(), _bit_mask) == + bit_masks(_hnd).end());//this mask should be not already used + bit_masks(_hnd).push_back(_bit_mask); + } + + void init_bit_masks(BitMaskContainer& _bmc); + void init_bit_masks(); + +protected: + + VertexStatusPropertyHandle vertex_status_; + HalfedgeStatusPropertyHandle halfedge_status_; + EdgeStatusPropertyHandle edge_status_; + FaceStatusPropertyHandle face_status_; + + unsigned int refcount_vstatus_; + unsigned int refcount_hstatus_; + unsigned int refcount_estatus_; + unsigned int refcount_fstatus_; + +private: + VertexContainer vertices_; + EdgeContainer edges_; + FaceContainer faces_; + + BitMaskContainer halfedge_bit_masks_; + BitMaskContainer edge_bit_masks_; + BitMaskContainer vertex_bit_masks_; + BitMaskContainer face_bit_masks_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_ARRAY_KERNEL_C) +# define OPENMESH_ARRAY_KERNEL_TEMPLATES +# include "ArrayKernelT_impl.hh" +#endif +//============================================================================= +#endif // OPENMESH_ARRAY_KERNEL_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/ArrayKernelT_impl.hh b/Sources/OpenMeshCore/Core/Mesh/ArrayKernelT_impl.hh new file mode 100644 index 0000000..2a8a156 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/ArrayKernelT_impl.hh @@ -0,0 +1,308 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#define OPENMESH_ARRAY_KERNEL_C + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh +{ + +//== IMPLEMENTATION ========================================================== + +template +void ArrayKernel::garbage_collection(std_API_Container_VHandlePointer& vh_to_update, + std_API_Container_HHandlePointer& hh_to_update, + std_API_Container_FHandlePointer& fh_to_update, + bool _v, bool _e, bool _f) +{ + +#ifdef DEBUG + #ifndef OM_GARBAGE_NO_STATUS_WARNING + if ( !this->has_vertex_status() ) + omerr() << "garbage_collection: No vertex status available. You can request it: mesh.request_vertex_status() or define OM_GARBAGE_NO_STATUS_WARNING to silence this warning." << std::endl; + if ( !this->has_edge_status() ) + omerr() << "garbage_collection: No edge status available. You can request it: mesh.request_edge_status() or define OM_GARBAGE_NO_STATUS_WARNING to silence this warning." << std::endl; + if ( !this->has_face_status() ) + omerr() << "garbage_collection: No face status available. You can request it: mesh.request_face_status() or define OM_GARBAGE_NO_STATUS_WARNING to silence this warning." << std::endl; + #endif +#endif + + const bool track_vhandles = ( !vh_to_update.empty() ); + const bool track_hhandles = ( !hh_to_update.empty() ); + const bool track_fhandles = ( !fh_to_update.empty() ); + + int i, i0, i1; + + int nV = int(n_vertices()); + int nE = int(n_edges()); + int nH = int(2*n_edges()); + int nF = (int(n_faces())); + + std::vector vh_map; + std::vector hh_map; + std::vector fh_map; + + std::map vertex_inverse_map; + std::map halfedge_inverse_map; + std::map face_inverse_map; + + // setup handle mapping: + vh_map.reserve(nV); + for (i=0; i 0 && this->has_vertex_status() ) + { + i0=0; i1=nV-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(VertexHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(VertexHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // If we keep track of the vertex handles for updates, + // we need to have the opposite direction + if ( track_vhandles ) { + vertex_inverse_map[i1] = i0; + vertex_inverse_map[i0] = -1; + } + + // swap + std::swap(vertices_[i0], vertices_[i1]); + std::swap(vh_map[i0], vh_map[i1]); + vprops_swap(i0, i1); + }; + + vertices_.resize(status(VertexHandle(i0)).deleted() ? i0 : i0+1); + vprops_resize(n_vertices()); + } + + + // remove deleted edges + if (_e && n_edges() > 0 && this->has_edge_status() ) + { + i0=0; i1=nE-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(EdgeHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(EdgeHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // If we keep track of the vertex handles for updates, + // we need to have the opposite direction + if ( track_hhandles ) { + halfedge_inverse_map[2*i1] = 2 * i0; + halfedge_inverse_map[2*i0] = -1; + + halfedge_inverse_map[2*i1 + 1] = 2 * i0 + 1; + halfedge_inverse_map[2*i0 + 1] = -1; + } + + // swap + std::swap(edges_[i0], edges_[i1]); + std::swap(hh_map[2*i0], hh_map[2*i1]); + std::swap(hh_map[2*i0+1], hh_map[2*i1+1]); + eprops_swap(i0, i1); + hprops_swap(2*i0, 2*i1); + hprops_swap(2*i0+1, 2*i1+1); + }; + + edges_.resize(status(EdgeHandle(i0)).deleted() ? i0 : i0+1); + eprops_resize(n_edges()); + hprops_resize(n_halfedges()); + } + + + // remove deleted faces + if (_f && n_faces() > 0 && this->has_face_status() ) + { + i0=0; i1=nF-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(FaceHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(FaceHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // If we keep track of the face handles for updates, + // we need to have the opposite direction + if ( track_fhandles ) { + face_inverse_map[i1] = i0; + face_inverse_map[i0] = -1; + } + + // swap + std::swap(faces_[i0], faces_[i1]); + std::swap(fh_map[i0], fh_map[i1]); + fprops_swap(i0, i1); + }; + + faces_.resize(status(FaceHandle(i0)).deleted() ? i0 : i0+1); + fprops_resize(n_faces()); + } + + + // update handles of vertices + if (_e) + { + KernelVertexIter v_it(vertices_begin()), v_end(vertices_end()); + VertexHandle vh; + + for (; v_it!=v_end; ++v_it) + { + vh = handle(*v_it); + if (!is_isolated(vh)) + { + set_halfedge_handle(vh, hh_map[halfedge_handle(vh).idx()]); + } + } + } + + HalfedgeHandle hh; + // update handles of halfedges + for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) + {//in the first pass update the (half)edges vertices + hh = halfedge_handle(handle(*e_it), 0); + set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); + hh = halfedge_handle(handle(*e_it), 1); + set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); + } + for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) + {//in the second pass update the connectivity of the (half)edges + hh = halfedge_handle(handle(*e_it), 0); + set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); + if (!is_boundary(hh)) + { + set_face_handle(hh, fh_map[face_handle(hh).idx()]); + } + hh = halfedge_handle(handle(*e_it), 1); + set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); + if (!is_boundary(hh)) + { + set_face_handle(hh, fh_map[face_handle(hh).idx()]); + } + } + + // update handles of faces + if (_e) + { + KernelFaceIter f_it(faces_begin()), f_end(faces_end()); + FaceHandle fh; + + for (; f_it!=f_end; ++f_it) + { + fh = handle(*f_it); + set_halfedge_handle(fh, hh_map[halfedge_handle(fh).idx()]); + } + } + + const int vertexCount = int(vertices_.size()); + const int halfedgeCount = int(edges_.size() * 2); + const int faceCount = int(faces_.size()); + + // Update the vertex handles in the vertex handle vector + typename std_API_Container_VHandlePointer::iterator v_it(vh_to_update.begin()), v_it_end(vh_to_update.end()); + for(; v_it != v_it_end; ++v_it) + { + + // Only changed vertices need to be considered + if ( (*v_it)->idx() != vh_map[(*v_it)->idx()].idx() ) { + *(*v_it) = VertexHandle(vertex_inverse_map[(*v_it)->idx()]); + + // Vertices above the vertex count have to be already mapped, or they are invalid now! + } else if ( ((*v_it)->idx() >= vertexCount) && (vertex_inverse_map.find((*v_it)->idx()) == vertex_inverse_map.end()) ) { + (*v_it)->invalidate(); + } + + } + + // Update the halfedge handles in the halfedge handle vector + typename std_API_Container_HHandlePointer::iterator hh_it(hh_to_update.begin()), hh_it_end(hh_to_update.end()); + for(; hh_it != hh_it_end; ++hh_it) + { + // Only changed faces need to be considered + if ( (*hh_it)->idx() != hh_map[(*hh_it)->idx()].idx() ) { + *(*hh_it) = HalfedgeHandle(halfedge_inverse_map[(*hh_it)->idx()]); + + // Vertices above the face count have to be already mapped, or they are invalid now! + } else if ( ((*hh_it)->idx() >= halfedgeCount) && (halfedge_inverse_map.find((*hh_it)->idx()) == halfedge_inverse_map.end()) ) { + (*hh_it)->invalidate(); + } + + } + + // Update the face handles in the face handle vector + typename std_API_Container_FHandlePointer::iterator fh_it(fh_to_update.begin()), fh_it_end(fh_to_update.end()); + for(; fh_it != fh_it_end; ++fh_it) + { + + // Only changed faces need to be considered + if ( (*fh_it)->idx() != fh_map[(*fh_it)->idx()].idx() ) { + *(*fh_it) = FaceHandle(face_inverse_map[(*fh_it)->idx()]); + + // Vertices above the face count have to be already mapped, or they are invalid now! + } else if ( ((*fh_it)->idx() >= faceCount) && (face_inverse_map.find((*fh_it)->idx()) == face_inverse_map.end()) ) { + (*fh_it)->invalidate(); + } + + } +} + +} + diff --git a/Sources/OpenMeshCore/Core/Mesh/AttribKernelT.hh b/Sources/OpenMeshCore/Core/Mesh/AttribKernelT.hh new file mode 100644 index 0000000..125be37 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/AttribKernelT.hh @@ -0,0 +1,792 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_ATTRIBKERNEL_HH +#define OPENMESH_ATTRIBKERNEL_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/** \class AttribKernelT AttribKernelT.hh + + The attribute kernel adds all standard properties to the kernel. Therefore + the functions/types defined here provide a subset of the kernel + interface as described in Concepts::KernelT. + + \see Concepts::KernelT +*/ +template +class AttribKernelT : public Connectivity +{ +public: + + //---------------------------------------------------------------- item types + + enum Attribs { + VAttribs = MeshItems::VAttribs, + HAttribs = MeshItems::HAttribs, + EAttribs = MeshItems::EAttribs, + FAttribs = MeshItems::FAttribs + }; + + typedef MeshItems MeshItemsT; + typedef Connectivity ConnectivityT; + typedef typename Connectivity::Vertex Vertex; + + //Define Halfedge based on PrevHalfedge. + typedef typename GenProg::IF< + (bool)(HAttribs & Attributes::PrevHalfedge), + typename Connectivity::Halfedge, + typename Connectivity::HalfedgeNoPrev + >::Result Halfedge; + typedef typename GenProg::IF< + (bool)(HAttribs & Attributes::PrevHalfedge), + GenProg::Bool2Type, + GenProg::Bool2Type + >::Result HasPrevHalfedge; + + //typedef typename Connectivity::Halfedge Halfedge; + typedef typename Connectivity::Edge Edge; + typedef typename Connectivity::Face Face; + + typedef typename MeshItems::Point Point; + typedef typename MeshItems::Normal Normal; + typedef typename MeshItems::Color Color; + typedef typename MeshItems::TexCoord1D TexCoord1D; + typedef typename MeshItems::TexCoord2D TexCoord2D; + typedef typename MeshItems::TexCoord3D TexCoord3D; + typedef typename MeshItems::Scalar Scalar; + typedef typename MeshItems::TextureIndex TextureIndex; + + typedef typename MeshItems::VertexData VertexData; + typedef typename MeshItems::HalfedgeData HalfedgeData; + typedef typename MeshItems::EdgeData EdgeData; + typedef typename MeshItems::FaceData FaceData; + + typedef AttribKernelT AttribKernel; + + + typedef VPropHandleT DataVPropHandle; + typedef HPropHandleT DataHPropHandle; + typedef EPropHandleT DataEPropHandle; + typedef FPropHandleT DataFPropHandle; + + typedef VPropHandleT PointsPropertyHandle; + typedef VPropHandleT VertexNormalsPropertyHandle; + typedef VPropHandleT VertexColorsPropertyHandle; + typedef VPropHandleT VertexTexCoords1DPropertyHandle; + typedef VPropHandleT VertexTexCoords2DPropertyHandle; + typedef VPropHandleT VertexTexCoords3DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords1DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords2DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords3DPropertyHandle; + typedef EPropHandleT EdgeColorsPropertyHandle; + typedef HPropHandleT HalfedgeNormalsPropertyHandle; + typedef HPropHandleT HalfedgeColorsPropertyHandle; + typedef FPropHandleT FaceNormalsPropertyHandle; + typedef FPropHandleT FaceColorsPropertyHandle; + typedef FPropHandleT FaceTextureIndexPropertyHandle; + +public: + + //-------------------------------------------------- constructor / destructor + + AttribKernelT() + : refcount_vnormals_(0), + refcount_vcolors_(0), + refcount_vtexcoords1D_(0), + refcount_vtexcoords2D_(0), + refcount_vtexcoords3D_(0), + refcount_htexcoords1D_(0), + refcount_htexcoords2D_(0), + refcount_htexcoords3D_(0), + refcount_henormals_(0), + refcount_hecolors_(0), + refcount_ecolors_(0), + refcount_fnormals_(0), + refcount_fcolors_(0), + refcount_ftextureIndex_(0) + { + this->add_property( points_, "v:points" ); + + if (VAttribs & Attributes::Normal) + request_vertex_normals(); + + if (VAttribs & Attributes::Color) + request_vertex_colors(); + + if (VAttribs & Attributes::TexCoord1D) + request_vertex_texcoords1D(); + + if (VAttribs & Attributes::TexCoord2D) + request_vertex_texcoords2D(); + + if (VAttribs & Attributes::TexCoord3D) + request_vertex_texcoords3D(); + + if (HAttribs & Attributes::TexCoord1D) + request_halfedge_texcoords1D(); + + if (HAttribs & Attributes::TexCoord2D) + request_halfedge_texcoords2D(); + + if (HAttribs & Attributes::TexCoord3D) + request_halfedge_texcoords3D(); + + if (HAttribs & Attributes::Color) + request_halfedge_colors(); + + if (VAttribs & Attributes::Status) + Connectivity::request_vertex_status(); + + if (HAttribs & Attributes::Status) + Connectivity::request_halfedge_status(); + + if (HAttribs & Attributes::Normal) + request_halfedge_normals(); + + if (EAttribs & Attributes::Status) + Connectivity::request_edge_status(); + + if (EAttribs & Attributes::Color) + request_edge_colors(); + + if (FAttribs & Attributes::Normal) + request_face_normals(); + + if (FAttribs & Attributes::Color) + request_face_colors(); + + if (FAttribs & Attributes::Status) + Connectivity::request_face_status(); + + if (FAttribs & Attributes::TextureIndex) + request_face_texture_index(); + + //FIXME: data properties might actually cost storage even + //if there are no data traits?? + this->add_property(data_vpph_); + this->add_property(data_fpph_); + this->add_property(data_hpph_); + this->add_property(data_epph_); + } + + virtual ~AttribKernelT() + { + // should remove properties, but this will be done in + // BaseKernel's destructor anyway... + } + + /** Assignment from another mesh of \em another type. + \note All that's copied is connectivity and vertex positions. + All other information (like e.g. attributes or additional + elements from traits classes) is not copied. + \note If you want to copy all information, including *custom* properties, + use PolyMeshT::operator=() instead. + */ + template + void assign(const _AttribKernel& _other, bool copyStandardProperties = false) + { + //copy standard properties if necessary + if(copyStandardProperties) + this->copy_all_kernel_properties(_other); + + this->assign_connectivity(_other); + for (typename Connectivity::VertexIter v_it = Connectivity::vertices_begin(); + v_it != Connectivity::vertices_end(); ++v_it) + {//assumes Point constructor supports cast from _AttribKernel::Point + set_point(*v_it, (Point)_other.point(*v_it)); + } + + //initialize standard properties if necessary + if(copyStandardProperties) + initializeStandardProperties(); + } + + //-------------------------------------------------------------------- points + + const Point* points() const + { return this->property(points_).data(); } + + const Point& point(VertexHandle _vh) const + { return this->property(points_, _vh); } + + Point& point(VertexHandle _vh) + { return this->property(points_, _vh); } + + void set_point(VertexHandle _vh, const Point& _p) + { this->property(points_, _vh) = _p; } + + const PointsPropertyHandle& points_property_handle() const + { return points_; } + + + //------------------------------------------------------------ vertex normals + + const Normal* vertex_normals() const + { return this->property(vertex_normals_).data(); } + + const Normal& normal(VertexHandle _vh) const + { return this->property(vertex_normals_, _vh); } + + void set_normal(VertexHandle _vh, const Normal& _n) + { this->property(vertex_normals_, _vh) = _n; } + + + //------------------------------------------------------------- vertex colors + + const Color* vertex_colors() const + { return this->property(vertex_colors_).data(); } + + const Color& color(VertexHandle _vh) const + { return this->property(vertex_colors_, _vh); } + + void set_color(VertexHandle _vh, const Color& _c) + { this->property(vertex_colors_, _vh) = _c; } + + + //------------------------------------------------------- vertex 1D texcoords + + const TexCoord1D* texcoords1D() const { + return this->property(vertex_texcoords1D_).data(); + } + + const TexCoord1D& texcoord1D(VertexHandle _vh) const { + return this->property(vertex_texcoords1D_, _vh); + } + + void set_texcoord1D(VertexHandle _vh, const TexCoord1D& _t) { + this->property(vertex_texcoords1D_, _vh) = _t; + } + + + //------------------------------------------------------- vertex 2D texcoords + + const TexCoord2D* texcoords2D() const { + return this->property(vertex_texcoords2D_).data(); + } + + const TexCoord2D& texcoord2D(VertexHandle _vh) const { + return this->property(vertex_texcoords2D_, _vh); + } + + void set_texcoord2D(VertexHandle _vh, const TexCoord2D& _t) { + this->property(vertex_texcoords2D_, _vh) = _t; + } + + + //------------------------------------------------------- vertex 3D texcoords + + const TexCoord3D* texcoords3D() const { + return this->property(vertex_texcoords3D_).data(); + } + + const TexCoord3D& texcoord3D(VertexHandle _vh) const { + return this->property(vertex_texcoords3D_, _vh); + } + + void set_texcoord3D(VertexHandle _vh, const TexCoord3D& _t) { + this->property(vertex_texcoords3D_, _vh) = _t; + } + + //.------------------------------------------------------ halfedge 1D texcoords + + const TexCoord1D* htexcoords1D() const { + return this->property(halfedge_texcoords1D_).data(); + } + + const TexCoord1D& texcoord1D(HalfedgeHandle _heh) const { + return this->property(halfedge_texcoords1D_, _heh); + } + + void set_texcoord1D(HalfedgeHandle _heh, const TexCoord1D& _t) { + this->property(halfedge_texcoords1D_, _heh) = _t; + } + + + //------------------------------------------------------- halfedge 2D texcoords + + const TexCoord2D* htexcoords2D() const { + return this->property(halfedge_texcoords2D_).data(); + } + + const TexCoord2D& texcoord2D(HalfedgeHandle _heh) const { + return this->property(halfedge_texcoords2D_, _heh); + } + + void set_texcoord2D(HalfedgeHandle _heh, const TexCoord2D& _t) { + this->property(halfedge_texcoords2D_, _heh) = _t; + } + + + //------------------------------------------------------- halfedge 3D texcoords + + const TexCoord3D* htexcoords3D() const { + return this->property(halfedge_texcoords3D_).data(); + } + + const TexCoord3D& texcoord3D(HalfedgeHandle _heh) const { + return this->property(halfedge_texcoords3D_, _heh); + } + + void set_texcoord3D(HalfedgeHandle _heh, const TexCoord3D& _t) { + this->property(halfedge_texcoords3D_, _heh) = _t; + } + + //------------------------------------------------------------- edge colors + + const Color* edge_colors() const + { return this->property(edge_colors_).data(); } + + const Color& color(EdgeHandle _eh) const + { return this->property(edge_colors_, _eh); } + + void set_color(EdgeHandle _eh, const Color& _c) + { this->property(edge_colors_, _eh) = _c; } + + + //------------------------------------------------------------- halfedge normals + + const Normal& normal(HalfedgeHandle _heh) const + { return this->property(halfedge_normals_, _heh); } + + void set_normal(HalfedgeHandle _heh, const Normal& _n) + { this->property(halfedge_normals_, _heh) = _n; } + + + //------------------------------------------------------------- halfedge colors + + const Color* halfedge_colors() const + { return this->property(halfedge_colors_).data(); } + + const Color& color(HalfedgeHandle _heh) const + { return this->property(halfedge_colors_, _heh); } + + void set_color(HalfedgeHandle _heh, const Color& _c) + { this->property(halfedge_colors_, _heh) = _c; } + + //-------------------------------------------------------------- face normals + + const Normal& normal(FaceHandle _fh) const + { return this->property(face_normals_, _fh); } + + void set_normal(FaceHandle _fh, const Normal& _n) + { this->property(face_normals_, _fh) = _n; } + + //-------------------------------------------------------------- per Face Texture index + + const TextureIndex& texture_index(FaceHandle _fh) const + { return this->property(face_texture_index_, _fh); } + + void set_texture_index(FaceHandle _fh, const TextureIndex& _t) + { this->property(face_texture_index_, _fh) = _t; } + + //--------------------------------------------------------------- face colors + + const Color& color(FaceHandle _fh) const + { return this->property(face_colors_, _fh); } + + void set_color(FaceHandle _fh, const Color& _c) + { this->property(face_colors_, _fh) = _c; } + + //------------------------------------------------ request / alloc properties + + void request_vertex_normals() + { + if (!refcount_vnormals_++) + this->add_property( vertex_normals_, "v:normals" ); + } + + void request_vertex_colors() + { + if (!refcount_vcolors_++) + this->add_property( vertex_colors_, "v:colors" ); + } + + void request_vertex_texcoords1D() + { + if (!refcount_vtexcoords1D_++) + this->add_property( vertex_texcoords1D_, "v:texcoords1D" ); + } + + void request_vertex_texcoords2D() + { + if (!refcount_vtexcoords2D_++) + this->add_property( vertex_texcoords2D_, "v:texcoords2D" ); + } + + void request_vertex_texcoords3D() + { + if (!refcount_vtexcoords3D_++) + this->add_property( vertex_texcoords3D_, "v:texcoords3D" ); + } + + void request_halfedge_texcoords1D() + { + if (!refcount_htexcoords1D_++) + this->add_property( halfedge_texcoords1D_, "h:texcoords1D" ); + } + + void request_halfedge_texcoords2D() + { + if (!refcount_htexcoords2D_++) + this->add_property( halfedge_texcoords2D_, "h:texcoords2D" ); + } + + void request_halfedge_texcoords3D() + { + if (!refcount_htexcoords3D_++) + this->add_property( halfedge_texcoords3D_, "h:texcoords3D" ); + } + + void request_edge_colors() + { + if (!refcount_ecolors_++) + this->add_property( edge_colors_, "e:colors" ); + } + + void request_halfedge_normals() + { + if (!refcount_henormals_++) + this->add_property( halfedge_normals_, "h:normals" ); + } + + void request_halfedge_colors() + { + if (!refcount_hecolors_++) + this->add_property( halfedge_colors_, "h:colors" ); + } + + void request_face_normals() + { + if (!refcount_fnormals_++) + this->add_property( face_normals_, "f:normals" ); + } + + void request_face_colors() + { + if (!refcount_fcolors_++) + this->add_property( face_colors_, "f:colors" ); + } + + void request_face_texture_index() + { + if (!refcount_ftextureIndex_++) + this->add_property( face_texture_index_, "f:textureindex" ); + } + + //------------------------------------------------- release / free properties + + void release_vertex_normals() + { + if ((refcount_vnormals_ > 0) && (! --refcount_vnormals_)) + this->remove_property(vertex_normals_); + } + + void release_vertex_colors() + { + if ((refcount_vcolors_ > 0) && (! --refcount_vcolors_)) + this->remove_property(vertex_colors_); + } + + void release_vertex_texcoords1D() { + if ((refcount_vtexcoords1D_ > 0) && (! --refcount_vtexcoords1D_)) + this->remove_property(vertex_texcoords1D_); + } + + void release_vertex_texcoords2D() { + if ((refcount_vtexcoords2D_ > 0) && (! --refcount_vtexcoords2D_)) + this->remove_property(vertex_texcoords2D_); + } + + void release_vertex_texcoords3D() { + if ((refcount_vtexcoords3D_ > 0) && (! --refcount_vtexcoords3D_)) + this->remove_property(vertex_texcoords3D_); + } + + void release_halfedge_texcoords1D() { + if ((refcount_htexcoords1D_ > 0) && (! --refcount_htexcoords1D_)) + this->remove_property(halfedge_texcoords1D_); + } + + void release_halfedge_texcoords2D() { + if ((refcount_htexcoords2D_ > 0) && (! --refcount_htexcoords2D_)) + this->remove_property(halfedge_texcoords2D_); + } + + void release_halfedge_texcoords3D() { + if ((refcount_htexcoords3D_ > 0) && (! --refcount_htexcoords3D_)) + this->remove_property(halfedge_texcoords3D_); + } + + void release_edge_colors() + { + if ((refcount_ecolors_ > 0) && (! --refcount_ecolors_)) + this->remove_property(edge_colors_); + } + + void release_halfedge_normals() + { + if ((refcount_henormals_ > 0) && (! --refcount_henormals_)) + this->remove_property(halfedge_normals_); + } + + void release_halfedge_colors() + { + if ((refcount_hecolors_ > 0) && (! --refcount_hecolors_)) + this->remove_property(halfedge_colors_); + } + + void release_face_normals() + { + if ((refcount_fnormals_ > 0) && (! --refcount_fnormals_)) + this->remove_property(face_normals_); + } + + void release_face_colors() + { + if ((refcount_fcolors_ > 0) && (! --refcount_fcolors_)) + this->remove_property(face_colors_); + } + + void release_face_texture_index() + { + if ((refcount_ftextureIndex_ > 0) && (! --refcount_ftextureIndex_)) + this->remove_property(face_texture_index_); + } + + //---------------------------------------------- dynamic check for properties + + bool has_vertex_normals() const { return vertex_normals_.is_valid(); } + bool has_vertex_colors() const { return vertex_colors_.is_valid(); } + bool has_vertex_texcoords1D() const { return vertex_texcoords1D_.is_valid(); } + bool has_vertex_texcoords2D() const { return vertex_texcoords2D_.is_valid(); } + bool has_vertex_texcoords3D() const { return vertex_texcoords3D_.is_valid(); } + bool has_halfedge_texcoords1D() const { return halfedge_texcoords1D_.is_valid();} + bool has_halfedge_texcoords2D() const { return halfedge_texcoords2D_.is_valid();} + bool has_halfedge_texcoords3D() const { return halfedge_texcoords3D_.is_valid();} + bool has_edge_colors() const { return edge_colors_.is_valid(); } + bool has_halfedge_normals() const { return halfedge_normals_.is_valid(); } + bool has_halfedge_colors() const { return halfedge_colors_.is_valid(); } + bool has_face_normals() const { return face_normals_.is_valid(); } + bool has_face_colors() const { return face_colors_.is_valid(); } + bool has_face_texture_index() const { return face_texture_index_.is_valid(); } + +public: + //standard vertex properties + PointsPropertyHandle points_pph() const + { return points_; } + + VertexNormalsPropertyHandle vertex_normals_pph() const + { return vertex_normals_; } + + VertexColorsPropertyHandle vertex_colors_pph() const + { return vertex_colors_; } + + VertexTexCoords1DPropertyHandle vertex_texcoords1D_pph() const + { return vertex_texcoords1D_; } + + VertexTexCoords2DPropertyHandle vertex_texcoords2D_pph() const + { return vertex_texcoords2D_; } + + VertexTexCoords3DPropertyHandle vertex_texcoords3D_pph() const + { return vertex_texcoords3D_; } + + //standard halfedge properties + HalfedgeTexCoords1DPropertyHandle halfedge_texcoords1D_pph() const + { return halfedge_texcoords1D_; } + + HalfedgeTexCoords2DPropertyHandle halfedge_texcoords2D_pph() const + { return halfedge_texcoords2D_; } + + HalfedgeTexCoords3DPropertyHandle halfedge_texcoords3D_pph() const + { return halfedge_texcoords3D_; } + + // standard edge properties + HalfedgeNormalsPropertyHandle halfedge_normals_pph() const + { return halfedge_normals_; } + + + // standard edge properties + HalfedgeColorsPropertyHandle halfedge_colors_pph() const + { return halfedge_colors_; } + + // standard edge properties + EdgeColorsPropertyHandle edge_colors_pph() const + { return edge_colors_; } + + //standard face properties + FaceNormalsPropertyHandle face_normals_pph() const + { return face_normals_; } + + FaceColorsPropertyHandle face_colors_pph() const + { return face_colors_; } + + FaceTextureIndexPropertyHandle face_texture_index_pph() const + { return face_texture_index_; } + + VertexData& data(VertexHandle _vh) + { return this->property(data_vpph_, _vh); } + + const VertexData& data(VertexHandle _vh) const + { return this->property(data_vpph_, _vh); } + + FaceData& data(FaceHandle _fh) + { return this->property(data_fpph_, _fh); } + + const FaceData& data(FaceHandle _fh) const + { return this->property(data_fpph_, _fh); } + + EdgeData& data(EdgeHandle _eh) + { return this->property(data_epph_, _eh); } + + const EdgeData& data(EdgeHandle _eh) const + { return this->property(data_epph_, _eh); } + + HalfedgeData& data(HalfedgeHandle _heh) + { return this->property(data_hpph_, _heh); } + + const HalfedgeData& data(HalfedgeHandle _heh) const + { return this->property(data_hpph_, _heh); } + +private: + //standard vertex properties + PointsPropertyHandle points_; + VertexNormalsPropertyHandle vertex_normals_; + VertexColorsPropertyHandle vertex_colors_; + VertexTexCoords1DPropertyHandle vertex_texcoords1D_; + VertexTexCoords2DPropertyHandle vertex_texcoords2D_; + VertexTexCoords3DPropertyHandle vertex_texcoords3D_; + //standard halfedge properties + HalfedgeTexCoords1DPropertyHandle halfedge_texcoords1D_; + HalfedgeTexCoords2DPropertyHandle halfedge_texcoords2D_; + HalfedgeTexCoords3DPropertyHandle halfedge_texcoords3D_; + HalfedgeNormalsPropertyHandle halfedge_normals_; + HalfedgeColorsPropertyHandle halfedge_colors_; + // standard edge properties + EdgeColorsPropertyHandle edge_colors_; + //standard face properties + FaceNormalsPropertyHandle face_normals_; + FaceColorsPropertyHandle face_colors_; + FaceTextureIndexPropertyHandle face_texture_index_; + //data properties handles + DataVPropHandle data_vpph_; + DataHPropHandle data_hpph_; + DataEPropHandle data_epph_; + DataFPropHandle data_fpph_; + + unsigned int refcount_vnormals_; + unsigned int refcount_vcolors_; + unsigned int refcount_vtexcoords1D_; + unsigned int refcount_vtexcoords2D_; + unsigned int refcount_vtexcoords3D_; + unsigned int refcount_htexcoords1D_; + unsigned int refcount_htexcoords2D_; + unsigned int refcount_htexcoords3D_; + unsigned int refcount_henormals_; + unsigned int refcount_hecolors_; + unsigned int refcount_ecolors_; + unsigned int refcount_fnormals_; + unsigned int refcount_fcolors_; + unsigned int refcount_ftextureIndex_; + + /** + * @brief initializeStandardProperties Initializes the standard properties + * and sets refcount to 1 if found. (e.g. when the copy constructor was used) + */ + void initializeStandardProperties() + { + if(!this->get_property_handle(points_, + "v:points")) + { + //mesh has no points? + } + refcount_vnormals_ = this->get_property_handle(vertex_normals_, + "v:normals") ? 1 : 0 ; + refcount_vcolors_ = this->get_property_handle(vertex_colors_, + "v:colors") ? 1 : 0 ; + refcount_vtexcoords1D_ = this->get_property_handle(vertex_texcoords1D_, + "v:texcoords1D") ? 1 : 0 ; + refcount_vtexcoords2D_ = this->get_property_handle(vertex_texcoords2D_, + "v:texcoords2D") ? 1 : 0 ; + refcount_vtexcoords3D_ = this->get_property_handle(vertex_texcoords3D_, + "v:texcoords3D") ? 1 : 0 ; + refcount_htexcoords1D_ = this->get_property_handle(halfedge_texcoords1D_, + "h:texcoords1D") ? 1 : 0 ; + refcount_htexcoords2D_ = this->get_property_handle(halfedge_texcoords2D_, + "h:texcoords2D") ? 1 : 0 ; + refcount_htexcoords3D_ = this->get_property_handle(halfedge_texcoords3D_, + "h:texcoords3D") ? 1 : 0 ; + refcount_henormals_ = this->get_property_handle(halfedge_normals_, + "h:normals") ? 1 : 0 ; + refcount_hecolors_ = this->get_property_handle(halfedge_colors_, + "h:colors") ? 1 : 0 ; + refcount_ecolors_ = this->get_property_handle(edge_colors_, + "e:colors") ? 1 : 0 ; + refcount_fnormals_ = this->get_property_handle(face_normals_, + "f:normals") ? 1 : 0 ; + refcount_fcolors_ = this->get_property_handle(face_colors_, + "f:colors") ? 1 : 0 ; + refcount_ftextureIndex_ = this->get_property_handle(face_texture_index_, + "f:textureindex") ? 1 : 0 ; + } +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBKERNEL_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/Attributes.hh b/Sources/OpenMeshCore/Core/Mesh/Attributes.hh new file mode 100644 index 0000000..b7bccc5 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/Attributes.hh @@ -0,0 +1,98 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +/** + \file Attributes.hh + This file provides some macros containing attribute usage. +*/ + + +#ifndef OPENMESH_ATTRIBUTES_HH +#define OPENMESH_ATTRIBUTES_HH + + +//== INCLUDES ================================================================= + + +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Attributes { + + +//== CLASS DEFINITION ======================================================== + +/** Attribute bits + * + * Use the bits to define a standard property at compile time using traits. + * + * \include traits5.cc + * + * \see \ref mesh_type + */ +enum AttributeBits +{ + None = 0, ///< Clear all attribute bits + Normal = 1, ///< Add normals to mesh item (vertices/faces) + Color = 2, ///< Add colors to mesh item (vertices/faces/edges) + PrevHalfedge = 4, ///< Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits. + Status = 8, ///< Add status to mesh item (all items) + TexCoord1D = 16, ///< Add 1D texture coordinates (vertices, halfedges) + TexCoord2D = 32, ///< Add 2D texture coordinates (vertices, halfedges) + TexCoord3D = 64, ///< Add 3D texture coordinates (vertices, halfedges) + TextureIndex = 128 ///< Add texture index (faces) +}; + + +//============================================================================= +} // namespace Attributes +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBUTES_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/BaseKernel.cc b/Sources/OpenMeshCore/Core/Mesh/BaseKernel.cc new file mode 100644 index 0000000..88ee709 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/BaseKernel.cc @@ -0,0 +1,234 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#include +#include + +namespace OpenMesh +{ + +void BaseKernel::property_stats() const +{ + property_stats(std::clog); +} +void BaseKernel::property_stats(std::ostream& _ostr) const +{ + const PropertyContainer::Properties& vps = vprops_.properties(); + const PropertyContainer::Properties& hps = hprops_.properties(); + const PropertyContainer::Properties& eps = eprops_.properties(); + const PropertyContainer::Properties& fps = fprops_.properties(); + const PropertyContainer::Properties& mps = mprops_.properties(); + + PropertyContainer::Properties::const_iterator it; + + _ostr << vprops_.size() << " vprops:\n"; + for (it=vps.begin(); it!=vps.end(); ++it) + { + *it == nullptr ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << hprops_.size() << " hprops:\n"; + for (it=hps.begin(); it!=hps.end(); ++it) + { + *it == nullptr ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << eprops_.size() << " eprops:\n"; + for (it=eps.begin(); it!=eps.end(); ++it) + { + *it == nullptr ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << fprops_.size() << " fprops:\n"; + for (it=fps.begin(); it!=fps.end(); ++it) + { + *it == nullptr ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << mprops_.size() << " mprops:\n"; + for (it=mps.begin(); it!=mps.end(); ++it) + { + *it == nullptr ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } +} + + + +void BaseKernel::vprop_stats( std::string& _string ) const +{ + _string.clear(); + + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& vps = vprops_.properties(); + for (it=vps.begin(); it!=vps.end(); ++it) + if ( *it == nullptr ) + _string += "[deleted] \n"; + else { + _string += (*it)->name(); + _string += "\n"; + } + +} + +void BaseKernel::hprop_stats( std::string& _string ) const +{ + _string.clear(); + + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& hps = hprops_.properties(); + for (it=hps.begin(); it!=hps.end(); ++it) + if ( *it == nullptr ) + _string += "[deleted] \n"; + else { + _string += (*it)->name(); + _string += "\n"; + } + +} + +void BaseKernel::eprop_stats( std::string& _string ) const +{ + _string.clear(); + + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& eps = eprops_.properties(); + for (it=eps.begin(); it!=eps.end(); ++it) + if ( *it == nullptr ) + _string += "[deleted] \n"; + else { + _string += (*it)->name(); + _string += "\n"; + } + +} +void BaseKernel::fprop_stats( std::string& _string ) const +{ + _string.clear(); + + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& fps = fprops_.properties(); + for (it=fps.begin(); it!=fps.end(); ++it) + if ( *it == nullptr ) + _string += "[deleted] \n"; + else { + _string += (*it)->name(); + _string += "\n"; + } + +} + +void BaseKernel::mprop_stats( std::string& _string ) const +{ + _string.clear(); + + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& mps = mprops_.properties(); + for (it=mps.begin(); it!=mps.end(); ++it) + if ( *it == nullptr ) + _string += "[deleted] \n"; + else { + _string += (*it)->name(); + _string += "\n"; + } + +} + +void BaseKernel::vprop_stats() const +{ + vprop_stats(std::clog); +} +void BaseKernel::vprop_stats(std::ostream& _ostr ) const +{ + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& vps = vprops_.properties(); + for (it=vps.begin(); it!=vps.end(); ++it) + *it == nullptr ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + +} +void BaseKernel::hprop_stats() const +{ + hprop_stats(std::clog); +} +void BaseKernel::hprop_stats(std::ostream& _ostr ) const +{ + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& hps = hprops_.properties(); + for (it=hps.begin(); it!=hps.end(); ++it) + *it == nullptr ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + +} +void BaseKernel::eprop_stats() const +{ + eprop_stats(std::clog); +} +void BaseKernel::eprop_stats(std::ostream& _ostr ) const +{ + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& eps = eprops_.properties(); + for (it=eps.begin(); it!=eps.end(); ++it) + *it == nullptr ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + +} +void BaseKernel::fprop_stats() const +{ + fprop_stats(std::clog); +} +void BaseKernel::fprop_stats(std::ostream& _ostr ) const +{ + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& fps = fprops_.properties(); + for (it=fps.begin(); it!=fps.end(); ++it) + *it == nullptr ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + +} +void BaseKernel::mprop_stats() const +{ + mprop_stats(std::clog); +} +void BaseKernel::mprop_stats(std::ostream& _ostr ) const +{ + PropertyContainer::Properties::const_iterator it; + const PropertyContainer::Properties& mps = mprops_.properties(); + for (it=mps.begin(); it!=mps.end(); ++it) + *it == nullptr ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + +} + + +} diff --git a/Sources/OpenMeshCore/Core/Mesh/BaseKernel.hh b/Sources/OpenMeshCore/Core/Mesh/BaseKernel.hh new file mode 100644 index 0000000..ca2873f --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/BaseKernel.hh @@ -0,0 +1,834 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS BaseKernel +// +//============================================================================= + + +#ifndef OPENMESH_BASE_KERNEL_HH +#define OPENMESH_BASE_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +// -------------------- +#include +#include +#include +#include +// -------------------- +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/// This class provides low-level property management like adding/removing +/// properties and access to properties. Under most circumstances, it is +/// advisable to use the high-level property management provided by +/// PropertyManager, instead. +/// +/// All operations provided by %BaseKernel need at least a property handle +/// (VPropHandleT, EPropHandleT, HPropHandleT, FPropHandleT, MPropHandleT). +/// which keeps the data type of the property, too. +/// +/// There are two types of properties: +/// -# Standard properties - mesh data (e.g. vertex normal or face color) +/// -# Custom properties - user defined data +/// +/// The differentiation is only semantically, technically both are +/// equally handled. Therefore the methods provided by the %BaseKernel +/// are applicable to both property types. +/// +/// \attention Since the class PolyMeshT derives from a kernel, hence all public +/// elements of %BaseKernel are usable. + +class OPENMESHDLLEXPORT BaseKernel +{ +public: //-------------------------------------------- constructor / destructor + + BaseKernel() {} + virtual ~BaseKernel() { + vprops_.clear(); + eprops_.clear(); + hprops_.clear(); + fprops_.clear(); + } + + +public: //-------------------------------------------------- add new properties + + /// \name Add a property to a mesh item + + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper and/or one of its helper functions such as + * makePropertyManagerFromNew, makePropertyManagerFromExisting, or + * makePropertyManagerFromExistingOrNew. + * + * Adds a property + * + * Depending on the property handle type a vertex, (half-)edge, face or + * mesh property is added to the mesh. If the action fails the handle + * is invalid. + * On success the handle must be used to access the property data with + * property(). + * + * \param _ph A property handle defining the data type to bind to mesh. + * On success the handle is valid else invalid. + * \param _name Optional name of property. Following restrictions apply + * to the name: + * -# Maximum length of name is 256 characters + * -# The prefixes matching "^[vhefm]:" are reserved for + * internal usage. + * -# The expression "^<.*>$" is reserved for internal usage. + * + */ + + template + void add_property( VPropHandleT& _ph, const std::string& _name="") + { + _ph = VPropHandleT( vprops_.add(T(), _name) ); + vprops_.resize(n_vertices()); + } + + template + void add_property( HPropHandleT& _ph, const std::string& _name="") + { + _ph = HPropHandleT( hprops_.add(T(), _name) ); + hprops_.resize(n_halfedges()); + } + + template + void add_property( EPropHandleT& _ph, const std::string& _name="") + { + _ph = EPropHandleT( eprops_.add(T(), _name) ); + eprops_.resize(n_edges()); + } + + template + void add_property( FPropHandleT& _ph, const std::string& _name="") + { + _ph = FPropHandleT( fprops_.add(T(), _name) ); + fprops_.resize(n_faces()); + } + + template + void add_property( MPropHandleT& _ph, const std::string& _name="") + { + _ph = MPropHandleT( mprops_.add(T(), _name) ); + mprops_.resize(1); + } + + //@} + + +public: //--------------------------------------------------- remove properties + + /// \name Removing a property from a mesh tiem + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper to manage (and remove) properties. + * + * Remove a property. + * + * Removes the property represented by the handle from the apropriate + * mesh item. + * \param _ph Property to be removed. The handle is invalid afterwords. + */ + + template + void remove_property(VPropHandleT& _ph) + { + if (_ph.is_valid()) + vprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(HPropHandleT& _ph) + { + if (_ph.is_valid()) + hprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(EPropHandleT& _ph) + { + if (_ph.is_valid()) + eprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(FPropHandleT& _ph) + { + if (_ph.is_valid()) + fprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(MPropHandleT& _ph) + { + if (_ph.is_valid()) + mprops_.remove(_ph); + _ph.reset(); + } + + //@} + +public: //------------------------------------------------ get handle from name + + /// \name Get property handle by name + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::propertyExists) or one of + * its higher level helper functions such as + * makePropertyManagerFromExisting, or makePropertyManagerFromExistingOrNew. + * + * Retrieves the handle to a named property by it's name. + * + * \param _ph A property handle. On success the handle is valid else + * invalid. + * \param _name Name of wanted property. + * \return \c true if such a named property is available, else \c false. + */ + + template + bool get_property_handle(VPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = VPropHandleT(vprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(HPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = HPropHandleT(hprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(EPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = EPropHandleT(eprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(FPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = FPropHandleT(fprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(MPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = MPropHandleT(mprops_.handle(T(), _name))).is_valid(); + } + + //@} + +public: //--------------------------------------------------- access properties + + /// \name Access a property + //@{ + + /** In most cases you should use the convenient PropertyManager wrapper + * and use of this function should not be necessary. Under some + * circumstances, however (i.e. making a property persistent), it might be + * necessary to use this function. + * + * Access a property + * + * This method returns a reference to property. The property handle + * must be valid! The result is unpredictable if the handle is invalid! + * + * \param _ph A \em valid (!) property handle. + * \return The wanted property if the handle is valid. + */ + + template + PropertyT& property(VPropHandleT _ph) { + return vprops_.property(_ph); + } + template + const PropertyT& property(VPropHandleT _ph) const { + return vprops_.property(_ph); + } + + template + PropertyT& property(HPropHandleT _ph) { + return hprops_.property(_ph); + } + template + const PropertyT& property(HPropHandleT _ph) const { + return hprops_.property(_ph); + } + + template + PropertyT& property(EPropHandleT _ph) { + return eprops_.property(_ph); + } + template + const PropertyT& property(EPropHandleT _ph) const { + return eprops_.property(_ph); + } + + template + PropertyT& property(FPropHandleT _ph) { + return fprops_.property(_ph); + } + template + const PropertyT& property(FPropHandleT _ph) const { + return fprops_.property(_ph); + } + + template + PropertyT& mproperty(MPropHandleT _ph) { + return mprops_.property(_ph); + } + template + const PropertyT& mproperty(MPropHandleT _ph) const { + return mprops_.property(_ph); + } + + //@} + +public: //-------------------------------------------- access property elements + + /// \name Access a property element using a handle to a mesh item + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper. + * + * Return value of property for an item + */ + + template + typename VPropHandleT::reference + property(VPropHandleT _ph, VertexHandle _vh) { + return vprops_.property(_ph)[_vh.idx()]; + } + + template + typename VPropHandleT::const_reference + property(VPropHandleT _ph, VertexHandle _vh) const { + return vprops_.property(_ph)[_vh.idx()]; + } + + + template + typename HPropHandleT::reference + property(HPropHandleT _ph, HalfedgeHandle _hh) { + return hprops_.property(_ph)[_hh.idx()]; + } + + template + typename HPropHandleT::const_reference + property(HPropHandleT _ph, HalfedgeHandle _hh) const { + return hprops_.property(_ph)[_hh.idx()]; + } + + + template + typename EPropHandleT::reference + property(EPropHandleT _ph, EdgeHandle _eh) { + return eprops_.property(_ph)[_eh.idx()]; + } + + template + typename EPropHandleT::const_reference + property(EPropHandleT _ph, EdgeHandle _eh) const { + return eprops_.property(_ph)[_eh.idx()]; + } + + + template + typename FPropHandleT::reference + property(FPropHandleT _ph, FaceHandle _fh) { + return fprops_.property(_ph)[_fh.idx()]; + } + + template + typename FPropHandleT::const_reference + property(FPropHandleT _ph, FaceHandle _fh) const { + return fprops_.property(_ph)[_fh.idx()]; + } + + + template + typename MPropHandleT::reference + property(MPropHandleT _ph) { + return mprops_.property(_ph)[0]; + } + + template + typename MPropHandleT::const_reference + property(MPropHandleT _ph) const { + return mprops_.property(_ph)[0]; + } + + //@} + + +public: //------------------------------------------------ copy property + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph A vertex property handle + * @param _vh_from From vertex handle + * @param _vh_to To vertex handle + */ + template + void copy_property(VPropHandleT& _ph, VertexHandle _vh_from, VertexHandle _vh_to) { + if(_vh_from.is_valid() && _vh_to.is_valid()) + vprops_.property(_ph)[_vh_to.idx()] = vprops_.property(_ph)[_vh_from.idx()]; + } + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph A halfedge property handle + * @param _hh_from From halfedge handle + * @param _hh_to To halfedge handle + */ + template + void copy_property(HPropHandleT _ph, HalfedgeHandle _hh_from, HalfedgeHandle _hh_to) { + if(_hh_from.is_valid() && _hh_to.is_valid()) + hprops_.property(_ph)[_hh_to.idx()] = hprops_.property(_ph)[_hh_from.idx()]; + } + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph An edge property handle + * @param _eh_from From edge handle + * @param _eh_to To edge handle + */ + template + void copy_property(EPropHandleT _ph, EdgeHandle _eh_from, EdgeHandle _eh_to) { + if(_eh_from.is_valid() && _eh_to.is_valid()) + eprops_.property(_ph)[_eh_to.idx()] = eprops_.property(_ph)[_eh_from.idx()]; + } + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph A face property handle + * @param _fh_from From face handle + * @param _fh_to To face handle + */ + template + void copy_property(FPropHandleT _ph, FaceHandle _fh_from, FaceHandle _fh_to) { + if(_fh_from.is_valid() && _fh_to.is_valid()) + fprops_.property(_ph)[_fh_to.idx()] = fprops_.property(_ph)[_fh_from.idx()]; + } + + +public: + //------------------------------------------------ copy all properties + + /** Copies all properties from one mesh element to another (of the same type) + * + * + * @param _vh_from A vertex handle - source + * @param _vh_to A vertex handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + */ + void copy_all_properties(VertexHandle _vh_from, VertexHandle _vh_to, bool _copyBuildIn = false) { + + for( PropertyContainer::iterator p_it = vprops_.begin(); + p_it != vprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "v:" ) ) + (*p_it)->copy(static_cast(_vh_from.idx()), static_cast(_vh_to.idx())); + + } + } + + /** Copies all properties from one mesh element to another (of the same type) + * + * @param _hh_from A halfedge handle - source + * @param _hh_to A halfedge handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + */ + void copy_all_properties(HalfedgeHandle _hh_from, HalfedgeHandle _hh_to, bool _copyBuildIn = false) { + + for( PropertyContainer::iterator p_it = hprops_.begin(); + p_it != hprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "h:") ) + (*p_it)->copy(_hh_from.idx(), _hh_to.idx()); + + } + } + + /** Copies all properties from one mesh element to another (of the same type) + * + * @param _eh_from An edge handle - source + * @param _eh_to An edge handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + */ + void copy_all_properties(EdgeHandle _eh_from, EdgeHandle _eh_to, bool _copyBuildIn = false) { + for( PropertyContainer::iterator p_it = eprops_.begin(); + p_it != eprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "e:") ) + (*p_it)->copy(_eh_from.idx(), _eh_to.idx()); + + } + } + + /** Copies all properties from one mesh element to another (of the same type) + * + * @param _fh_from A face handle - source + * @param _fh_to A face handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + * + */ + void copy_all_properties(FaceHandle _fh_from, FaceHandle _fh_to, bool _copyBuildIn = false) { + + for( PropertyContainer::iterator p_it = fprops_.begin(); + p_it != fprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "f:") ) + (*p_it)->copy(_fh_from.idx(), _fh_to.idx()); + } + + } + + /** + * @brief copy_all_kernel_properties uses the = operator to copy all properties from a given other BaseKernel. + * @param _other Another BaseKernel, to copy the properties from. + */ + void copy_all_kernel_properties(const BaseKernel & _other) + { + this->vprops_ = _other.vprops_; + this->eprops_ = _other.eprops_; + this->hprops_ = _other.hprops_; + this->fprops_ = _other.fprops_; + } + +protected: //------------------------------------------------- low-level access + +public: // used by non-native kernel and MeshIO, should be protected + + size_t n_vprops(void) const { return vprops_.size(); } + + size_t n_eprops(void) const { return eprops_.size(); } + + size_t n_hprops(void) const { return hprops_.size(); } + + size_t n_fprops(void) const { return fprops_.size(); } + + size_t n_mprops(void) const { return mprops_.size(); } + + BaseProperty* _get_vprop( const std::string& _name) + { return vprops_.property(_name); } + + BaseProperty* _get_eprop( const std::string& _name) + { return eprops_.property(_name); } + + BaseProperty* _get_hprop( const std::string& _name) + { return hprops_.property(_name); } + + BaseProperty* _get_fprop( const std::string& _name) + { return fprops_.property(_name); } + + BaseProperty* _get_mprop( const std::string& _name) + { return mprops_.property(_name); } + + const BaseProperty* _get_vprop( const std::string& _name) const + { return vprops_.property(_name); } + + const BaseProperty* _get_eprop( const std::string& _name) const + { return eprops_.property(_name); } + + const BaseProperty* _get_hprop( const std::string& _name) const + { return hprops_.property(_name); } + + const BaseProperty* _get_fprop( const std::string& _name) const + { return fprops_.property(_name); } + + const BaseProperty* _get_mprop( const std::string& _name) const + { return mprops_.property(_name); } + + BaseProperty& _vprop( size_t _idx ) { return vprops_._property( _idx ); } + BaseProperty& _eprop( size_t _idx ) { return eprops_._property( _idx ); } + BaseProperty& _hprop( size_t _idx ) { return hprops_._property( _idx ); } + BaseProperty& _fprop( size_t _idx ) { return fprops_._property( _idx ); } + BaseProperty& _mprop( size_t _idx ) { return mprops_._property( _idx ); } + + const BaseProperty& _vprop( size_t _idx ) const + { return vprops_._property( _idx ); } + const BaseProperty& _eprop( size_t _idx ) const + { return eprops_._property( _idx ); } + const BaseProperty& _hprop( size_t _idx ) const + { return hprops_._property( _idx ); } + const BaseProperty& _fprop( size_t _idx ) const + { return fprops_._property( _idx ); } + const BaseProperty& _mprop( size_t _idx ) const + { return mprops_._property( _idx ); } + + size_t _add_vprop( BaseProperty* _bp ) { return vprops_._add( _bp ); } + size_t _add_eprop( BaseProperty* _bp ) { return eprops_._add( _bp ); } + size_t _add_hprop( BaseProperty* _bp ) { return hprops_._add( _bp ); } + size_t _add_fprop( BaseProperty* _bp ) { return fprops_._add( _bp ); } + size_t _add_mprop( BaseProperty* _bp ) { return mprops_._add( _bp ); } + +protected: // low-level access non-public + + BaseProperty& _vprop( BaseHandle _h ) + { return vprops_._property( _h.idx() ); } + BaseProperty& _eprop( BaseHandle _h ) + { return eprops_._property( _h.idx() ); } + BaseProperty& _hprop( BaseHandle _h ) + { return hprops_._property( _h.idx() ); } + BaseProperty& _fprop( BaseHandle _h ) + { return fprops_._property( _h.idx() ); } + BaseProperty& _mprop( BaseHandle _h ) + { return mprops_._property( _h.idx() ); } + + const BaseProperty& _vprop( BaseHandle _h ) const + { return vprops_._property( _h.idx() ); } + const BaseProperty& _eprop( BaseHandle _h ) const + { return eprops_._property( _h.idx() ); } + const BaseProperty& _hprop( BaseHandle _h ) const + { return hprops_._property( _h.idx() ); } + const BaseProperty& _fprop( BaseHandle _h ) const + { return fprops_._property( _h.idx() ); } + const BaseProperty& _mprop( BaseHandle _h ) const + { return mprops_._property( _h.idx() ); } + + +public: //----------------------------------------------------- element numbers + + + virtual size_t n_vertices() const { return 0; } + virtual size_t n_halfedges() const { return 0; } + virtual size_t n_edges() const { return 0; } + virtual size_t n_faces() const { return 0; } + + template + size_t n_elements() const; + + +protected: //------------------------------------------- synchronize properties + + /// Reserves space for \p _n elements in all vertex property vectors. + void vprops_reserve(size_t _n) const { vprops_.reserve(_n); } + + /// Resizes all vertex property vectors to the specified size. + void vprops_resize(size_t _n) const { vprops_.resize(_n); } + + /** + * Same as vprops_resize() but ignores vertex property vectors that have + * a size larger than \p _n. + * + * Use this method instead of vprops_resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ + void vprops_resize_if_smaller(size_t _n) const { vprops_.resize_if_smaller(_n); } + + void vprops_clear() { + vprops_.clear(); + } + + void vprops_swap(unsigned int _i0, unsigned int _i1) const { + vprops_.swap(_i0, _i1); + } + + void hprops_reserve(size_t _n) const { hprops_.reserve(_n); } + void hprops_resize(size_t _n) const { hprops_.resize(_n); } + void hprops_clear() { + hprops_.clear(); + } + void hprops_swap(unsigned int _i0, unsigned int _i1) const { + hprops_.swap(_i0, _i1); + } + + void eprops_reserve(size_t _n) const { eprops_.reserve(_n); } + void eprops_resize(size_t _n) const { eprops_.resize(_n); } + void eprops_clear() { + eprops_.clear(); + } + void eprops_swap(unsigned int _i0, unsigned int _i1) const { + eprops_.swap(_i0, _i1); + } + + void fprops_reserve(size_t _n) const { fprops_.reserve(_n); } + void fprops_resize(size_t _n) const { fprops_.resize(_n); } + void fprops_clear() { + fprops_.clear(); + } + void fprops_swap(unsigned int _i0, unsigned int _i1) const { + fprops_.swap(_i0, _i1); + } + + void mprops_resize(size_t _n) const { mprops_.resize(_n); } + void mprops_clear() { + mprops_.clear(); + } + +public: + + // uses std::clog as output stream + void property_stats() const; + void property_stats(std::ostream& _ostr) const; + + void vprop_stats( std::string& _string ) const; + void hprop_stats( std::string& _string ) const; + void eprop_stats( std::string& _string ) const; + void fprop_stats( std::string& _string ) const; + void mprop_stats( std::string& _string ) const; + + // uses std::clog as output stream + void vprop_stats() const; + void hprop_stats() const; + void eprop_stats() const; + void fprop_stats() const; + void mprop_stats() const; + + void vprop_stats(std::ostream& _ostr) const; + void hprop_stats(std::ostream& _ostr) const; + void eprop_stats(std::ostream& _ostr) const; + void fprop_stats(std::ostream& _ostr) const; + void mprop_stats(std::ostream& _ostr) const; + +public: + + typedef PropertyContainer::iterator prop_iterator; + typedef PropertyContainer::const_iterator const_prop_iterator; + + prop_iterator vprops_begin() { return vprops_.begin(); } + prop_iterator vprops_end() { return vprops_.end(); } + const_prop_iterator vprops_begin() const { return vprops_.begin(); } + const_prop_iterator vprops_end() const { return vprops_.end(); } + + prop_iterator eprops_begin() { return eprops_.begin(); } + prop_iterator eprops_end() { return eprops_.end(); } + const_prop_iterator eprops_begin() const { return eprops_.begin(); } + const_prop_iterator eprops_end() const { return eprops_.end(); } + + prop_iterator hprops_begin() { return hprops_.begin(); } + prop_iterator hprops_end() { return hprops_.end(); } + const_prop_iterator hprops_begin() const { return hprops_.begin(); } + const_prop_iterator hprops_end() const { return hprops_.end(); } + + prop_iterator fprops_begin() { return fprops_.begin(); } + prop_iterator fprops_end() { return fprops_.end(); } + const_prop_iterator fprops_begin() const { return fprops_.begin(); } + const_prop_iterator fprops_end() const { return fprops_.end(); } + + prop_iterator mprops_begin() { return mprops_.begin(); } + prop_iterator mprops_end() { return mprops_.end(); } + const_prop_iterator mprops_begin() const { return mprops_.begin(); } + const_prop_iterator mprops_end() const { return mprops_.end(); } + +private: + + PropertyContainer vprops_; + PropertyContainer hprops_; + PropertyContainer eprops_; + PropertyContainer fprops_; + PropertyContainer mprops_; +}; + + +template <> +inline size_t BaseKernel::n_elements() const { return n_vertices(); } +template <> +inline size_t BaseKernel::n_elements() const { return n_halfedges(); } +template <> +inline size_t BaseKernel::n_elements() const { return n_edges(); } +template <> +inline size_t BaseKernel::n_elements() const { return n_faces(); } + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_BASE_KERNEL_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/BaseMesh.hh b/Sources/OpenMeshCore/Core/Mesh/BaseMesh.hh new file mode 100644 index 0000000..17af0fb --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/BaseMesh.hh @@ -0,0 +1,92 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS BaseMesh +// +//============================================================================= + + +#ifndef OPENMESH_BASEMESH_HH +#define OPENMESH_BASEMESH_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class BaseMesh BaseMesh.hh + + Base class for all meshes. +*/ + +class BaseMesh { +public: + virtual ~BaseMesh(void) {;} +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_BASEMESH_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/Casts.hh b/Sources/OpenMeshCore/Core/Mesh/Casts.hh new file mode 100644 index 0000000..cb7388f --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/Casts.hh @@ -0,0 +1,72 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_CASTS_HH +#define OPENMESH_CASTS_HH +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== +namespace OpenMesh +{ + +template +inline TriMesh_ArrayKernelT& TRIMESH_CAST(PolyMesh_ArrayKernelT& _poly_mesh) +{ return reinterpret_cast< TriMesh_ArrayKernelT& >(_poly_mesh); } + +template +inline const TriMesh_ArrayKernelT& TRIMESH_CAST(const PolyMesh_ArrayKernelT& _poly_mesh) +{ return reinterpret_cast< const TriMesh_ArrayKernelT& >(_poly_mesh); } + +template +inline PolyMesh_ArrayKernelT& POLYMESH_CAST(TriMesh_ArrayKernelT& _tri_mesh) +{ return reinterpret_cast< PolyMesh_ArrayKernelT& >(_tri_mesh); } + +template +inline const PolyMesh_ArrayKernelT& POLYMESH_CAST(const TriMesh_ArrayKernelT& _tri_mesh) +{ return reinterpret_cast< const PolyMesh_ArrayKernelT& >(_tri_mesh); } + +}; +#endif//OPENMESH_CASTS_HH diff --git a/Sources/OpenMeshCore/Core/Mesh/CirculatorsT.hh b/Sources/OpenMeshCore/Core/Mesh/CirculatorsT.hh new file mode 100644 index 0000000..90412a1 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/CirculatorsT.hh @@ -0,0 +1,654 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#pragma once + +//============================================================================= +// +// Vertex, Face, and Edge circulators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +template class CirculatorRange; + +namespace Iterators { + +template +class GenericCirculator_CenterEntityFnsT { + public: + static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter); + static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter); +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->cw_rotated_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->ccw_rotated_halfedge_handle(heh); + } +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->next_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->prev_halfedge_handle(heh); + } +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->opposite_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->opposite_halfedge_handle(heh); + } +}; + +///////////////////////////////////////////////////////////// +// CCW + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->ccw_rotated_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->cw_rotated_halfedge_handle(heh); + } +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->prev_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->next_halfedge_handle(heh); + } +}; +///////////////////////////////////////////////////////////// + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + //inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, const int &lap_counter); +}; + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) { + return mesh->face_handle(mesh->opposite_halfedge_handle(heh)).is_valid(); + } +}; + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) { + return mesh->face_handle(heh).is_valid(); + } +}; + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) { + return mesh->face_handle(heh).is_valid(); + } +}; + +template +class GenericCirculator_ValueHandleFnsT { + public: + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) { + return ( heh.is_valid() && (lap_counter == 0 ) ); + } + inline static void init(const Mesh* mesh, typename Mesh::HalfedgeHandle& heh, typename Mesh::HalfedgeHandle& start, int& lap_counter, bool adjust_for_ccw) + { + if (!CW) // TODO: constexpr if + { + if (adjust_for_ccw) + { + // increment current heh and start so that cw and ccw version dont start with the same element but ranges are actually reversed + int lc = lap_counter; + increment(mesh, heh, start, lap_counter); + start = heh; + lap_counter = lc; + } + } + } + + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } +}; + +template +class GenericCirculator_ValueHandleFnsT { + public: + typedef GenericCirculator_DereferenciabilityCheckT GenericCirculator_DereferenciabilityCheck; + + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) { + return ( heh.is_valid() && (lap_counter == 0)); + } + inline static void init(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter, bool adjust_for_ccw) + { + if (!CW) // TODO: constexpr if + { + if (adjust_for_ccw) + { + // increment current heh and start so that cw and ccw version dont start with the same element but ranges are actually reversed + int lc = lap_counter; + increment(mesh, heh, start, lap_counter); + start = heh; + lap_counter = lc; + } + } + if (heh.is_valid() && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh) && lap_counter == 0 ) + increment(mesh, heh, start, lap_counter); + }; + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } +}; + +template +class GenericCirculatorBaseT { + public: + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; + + template friend class OpenMesh::CirculatorRange; + + public: + GenericCirculatorBaseT() : mesh_(0), lap_counter_(0) {} + + GenericCirculatorBaseT(mesh_ref mesh, typename Mesh::HalfedgeHandle heh, bool end = false) : + mesh_(&mesh), start_(heh), heh_(heh), lap_counter_(static_cast(end && heh.is_valid())) {} + + GenericCirculatorBaseT(const GenericCirculatorBaseT &rhs) : + mesh_(rhs.mesh_), start_(rhs.start_), heh_(rhs.heh_), lap_counter_(rhs.lap_counter_) {} + + inline typename Mesh::FaceHandle toFaceHandle() const { + return mesh_->face_handle(heh_); + } + + inline typename Mesh::FaceHandle toOppositeFaceHandle() const { + return mesh_->face_handle(toOppositeHalfedgeHandle()); + } + + inline typename Mesh::EdgeHandle toEdgeHandle() const { + return mesh_->edge_handle(heh_); + } + + inline typename Mesh::HalfedgeHandle toHalfedgeHandle() const { + return heh_; + } + + inline typename Mesh::HalfedgeHandle toOppositeHalfedgeHandle() const { + return mesh_->opposite_halfedge_handle(heh_); + } + + inline typename Mesh::VertexHandle toVertexHandle() const { + return mesh_->to_vertex_handle(heh_); + } + + inline GenericCirculatorBaseT &operator=(const GenericCirculatorBaseT &rhs) { + mesh_ = rhs.mesh_; + start_ = rhs.start_; + heh_ = rhs.heh_; + lap_counter_ = rhs.lap_counter_; + return *this; + } + + inline bool operator==(const GenericCirculatorBaseT &rhs) const { + return mesh_ == rhs.mesh_ && start_ == rhs.start_ && heh_ == rhs.heh_ && lap_counter_ == rhs.lap_counter_; + } + + inline bool operator!=(const GenericCirculatorBaseT &rhs) const { + return !operator==(rhs); + } + + protected: + mesh_ptr mesh_; + typename Mesh::HalfedgeHandle start_, heh_; + int lap_counter_; +}; + +//template::*Handle2Value)() const, bool CW = true > +template +class GenericCirculatorT : protected GenericCirculatorBaseT { + public: + using Mesh = typename GenericCirculatorT_TraitsT::Mesh; + using value_type = typename GenericCirculatorT_TraitsT::ValueHandle; + using CenterEntityHandle = typename GenericCirculatorT_TraitsT::CenterEntityHandle; + + using smart_value_type = decltype(make_smart(std::declval(), std::declval())); + + typedef std::ptrdiff_t difference_type; + typedef const value_type& reference; + typedef const smart_value_type* pointer; + typedef std::bidirectional_iterator_tag iterator_category; + + typedef typename GenericCirculatorBaseT::mesh_ptr mesh_ptr; + typedef typename GenericCirculatorBaseT::mesh_ref mesh_ref; + typedef GenericCirculator_ValueHandleFnsT GenericCirculator_ValueHandleFns; + + template friend class OpenMesh::CirculatorRange; + + public: + GenericCirculatorT() {} + GenericCirculatorT(mesh_ref mesh, CenterEntityHandle start, bool end = false) : + GenericCirculatorBaseT(mesh, mesh.halfedge_handle(start), end) + { + bool adjust_for_ccw = true; + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_, adjust_for_ccw); + } + GenericCirculatorT(mesh_ref mesh, typename Mesh::HalfedgeHandle heh, bool end = false) : + GenericCirculatorBaseT(mesh, heh, end) + { + bool adjust_for_ccw = false; // if iterator is initialized with specific heh, we want to start there + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_, adjust_for_ccw); + } + GenericCirculatorT(const GenericCirculatorT &rhs) : GenericCirculatorBaseT(rhs) {} + + friend class GenericCirculatorT; + explicit GenericCirculatorT( const GenericCirculatorT& rhs ) + :GenericCirculatorBaseT(rhs){} + + GenericCirculatorT& operator++() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } + GenericCirculatorT& operator--() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::decrement(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } + + /// Post-increment + GenericCirculatorT operator++(int) { + assert(this->mesh_); + GenericCirculatorT cpy(*this); + ++(*this); + return cpy; + } + + /// Post-decrement + GenericCirculatorT operator--(int) { + assert(this->mesh_); + GenericCirculatorT cpy(*this); + --(*this); + return cpy; + } + + /// Standard dereferencing operator. + smart_value_type operator*() const { +#ifndef NDEBUG + assert(this->heh_.is_valid()); + value_type res = GenericCirculatorT_TraitsT::toHandle(this->mesh_, this->heh_); + assert(res.is_valid()); + return make_smart(res, this->mesh_); +#else + return make_smart(GenericCirculatorT_TraitsT::toHandle(this->mesh_, this->heh_), this->mesh_); +#endif + } + + /** + * @brief Pointer dereferentiation. + * + * This returns a pointer which points to a handle + * that loses its validity once this dereferentiation is + * invoked again. Thus, do not store the result of + * this operation. + */ + pointer operator->() const { + pointer_deref_value = **this; + return &pointer_deref_value; + } + + GenericCirculatorT &operator=(const GenericCirculatorT &rhs) { + GenericCirculatorBaseT::operator=(rhs); + return *this; + }; + + bool operator==(const GenericCirculatorT &rhs) const { + return GenericCirculatorBaseT::operator==(rhs); + } + + bool operator!=(const GenericCirculatorT &rhs) const { + return GenericCirculatorBaseT::operator!=(rhs); + } + + bool is_valid() const { + return GenericCirculator_ValueHandleFns::is_valid(this->heh_, this->lap_counter_); + } + + template + friend STREAM &operator<< (STREAM &s, const GenericCirculatorT &self) { + return s << self.mesh_ << ", " << self.start_.idx() << ", " << self.heh_.idx() << ", " << self.lap_counter_; + } + + private: + mutable smart_value_type pointer_deref_value; +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////// OLD /////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// OLD CIRCULATORS +// deprecated circulators, will be removed soon +// if you remove these circulators and go to the old ones, PLEASE ENABLE FOLLOWING UNITTESTS: +// +// OpenMeshTrimeshCirculatorVertexIHalfEdge.VertexIHalfEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexEdge.VertexEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexVertex.VertexVertexIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexOHalfEdge.VertexOHalfEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexFace.VertexFaceIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexFace.VertexFaceIterWithoutHolesDecrement +// OpenMeshTrimeshCirculatorFaceEdge.FaceEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorFaceFace.FaceFaceIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorFaceHalfEdge.FaceHalfedgeIterWithoutHolesIncrement +// OpenMeshTrimeshCirculatorFaceVertex.FaceVertexIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorFaceHalfEdge.FaceHalfedgeIterCheckInvalidationAtEnds +// + +template +class GenericCirculator_ValueHandleFnsT_DEPRECATED { + public: + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh,const typename Mesh::HalfedgeHandle &start, const int lap_counter) { + return ( heh.is_valid() && ((start != heh) || (lap_counter == 0 )) ); + } + inline static void init(const Mesh*, typename Mesh::HalfedgeHandle&, typename Mesh::HalfedgeHandle&, int&) {}; + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } +}; + +template +class GenericCirculator_ValueHandleFnsT_DEPRECATED { + public: + typedef GenericCirculator_DereferenciabilityCheckT GenericCirculator_DereferenciabilityCheck; + + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, const int lap_counter) { + return ( heh.is_valid() && ((start != heh) || (lap_counter == 0 ))); + } + inline static void init(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh.is_valid() && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh) && lap_counter == 0 ) + increment(mesh, heh, start, lap_counter); + }; + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } while (is_valid(heh, start, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } while (is_valid(heh, start, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } +}; + +template +class GenericCirculatorT_DEPRECATED : protected GenericCirculatorBaseT { + public: + using Mesh = typename GenericCirculatorT_DEPRECATED_TraitsT::Mesh; + using CenterEntityHandle = typename GenericCirculatorT_DEPRECATED_TraitsT::CenterEntityHandle; + using value_type = typename GenericCirculatorT_DEPRECATED_TraitsT::ValueHandle; + using smart_value_type = decltype (make_smart(std::declval(), std::declval())); + + typedef std::ptrdiff_t difference_type; + typedef const value_type& reference; + typedef const smart_value_type* pointer; + typedef std::bidirectional_iterator_tag iterator_category; + + typedef typename GenericCirculatorBaseT::mesh_ptr mesh_ptr; + typedef typename GenericCirculatorBaseT::mesh_ref mesh_ref; + typedef GenericCirculator_ValueHandleFnsT_DEPRECATED GenericCirculator_ValueHandleFns; + + template friend class OpenMesh::CirculatorRange; + + public: + GenericCirculatorT_DEPRECATED() {} + GenericCirculatorT_DEPRECATED(mesh_ref mesh, CenterEntityHandle start, bool end = false) : + GenericCirculatorBaseT(mesh, mesh.halfedge_handle(start), end) { + + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_); + } + GenericCirculatorT_DEPRECATED(mesh_ref mesh, typename Mesh::HalfedgeHandle heh, bool end = false) : + GenericCirculatorBaseT(mesh, heh, end) { + + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_); + } + GenericCirculatorT_DEPRECATED(const GenericCirculatorT_DEPRECATED &rhs) : GenericCirculatorBaseT(rhs) {} + + GenericCirculatorT_DEPRECATED& operator++() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } +#ifndef NO_DECREMENT_DEPRECATED_WARNINGS +#define DECREMENT_DEPRECATED_WARNINGS_TEXT "The current decrement operator has the unintended behavior that it stays\ + valid when iterating below the start and will visit the first entity\ + twice before getting invalid. Furthermore it gets valid again, if you\ + increment at the end.\ + When you are sure that you don't iterate below the start anywhere in\ + your code or rely on this behaviour, you can disable this warning by\ + setting the define NO_DECREMENT_DEPRECATED_WARNINGS at the command line (or enable it via the\ + cmake flags).\ + To be save, you can use the CW/CCW circulator definitions, which behave\ + the same as the original ones, without the previously mentioned issues." + + OM_DEPRECATED( DECREMENT_DEPRECATED_WARNINGS_TEXT ) +#endif // NO_DECREMENT_DEPRECATED_WARNINGS + GenericCirculatorT_DEPRECATED& operator--() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::decrement(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } + + /// Post-increment + GenericCirculatorT_DEPRECATED operator++(int) { + assert(this->mesh_); + GenericCirculatorT_DEPRECATED cpy(*this); + ++(*this); + return cpy; + } + + /// Post-decrement +#ifndef NO_DECREMENT_DEPRECATED_WARNINGS + OM_DEPRECATED( DECREMENT_DEPRECATED_WARNINGS_TEXT ) +#undef DECREMENT_DEPRECATED_WARNINGS_TEXT +#endif //NO_DECREMENT_DEPRECATED_WARNINGS + GenericCirculatorT_DEPRECATED operator--(int) { + assert(this->mesh_); + GenericCirculatorT_DEPRECATED cpy(*this); + --(*this); + return cpy; + } + + /// Standard dereferencing operator. + smart_value_type operator*() const { +#ifndef NDEBUG + assert(this->heh_.is_valid()); + value_type res = (GenericCirculatorT_DEPRECATED_TraitsT::toHandle(this->mesh_, this->heh_)); + assert(res.is_valid()); + return make_smart(res, this->mesh_); +#else + return make_smart(GenericCirculatorT_DEPRECATED_TraitsT::toHandle(this->mesh_, this->heh_), this->mesh_); +#endif + } + + /** + * @brief Pointer dereferentiation. + * + * This returns a pointer which points to a handle + * that loses its validity once this dereferentiation is + * invoked again. Thus, do not store the result of + * this operation. + */ + pointer operator->() const { + pointer_deref_value = **this; + return &pointer_deref_value; + } + + GenericCirculatorT_DEPRECATED &operator=(const GenericCirculatorT_DEPRECATED &rhs) { + GenericCirculatorBaseT::operator=(rhs); + return *this; + }; + + bool operator==(const GenericCirculatorT_DEPRECATED &rhs) const { + return GenericCirculatorBaseT::operator==(rhs); + } + + bool operator!=(const GenericCirculatorT_DEPRECATED &rhs) const { + return GenericCirculatorBaseT::operator!=(rhs); + } + + bool is_valid() const { + return GenericCirculator_ValueHandleFns::is_valid(this->heh_,this->start_, this->lap_counter_); + } + + OM_DEPRECATED("current_halfedge_handle() is an implementation detail and should not be accessed from outside the iterator class.") + /** + * \deprecated + * current_halfedge_handle() is an implementation detail and should not + * be accessed from outside the iterator class. + */ + const typename Mesh::HalfedgeHandle ¤t_halfedge_handle() const { + return this->heh_; + } + + OM_DEPRECATED("Do not use this error prone implicit cast. Compare to end-iterator or use is_valid(), instead.") + /** + * \deprecated + * Do not use this error prone implicit cast. Compare to the + * end-iterator or use is_valid() instead. + */ + operator bool() const { + return is_valid(); + } + + /** + * \brief Return the handle of the current target. + * \deprecated + * This function clutters your code. Use dereferencing operators -> and * instead. + */ + OM_DEPRECATED("This function clutters your code. Use dereferencing operators -> and * instead.") + smart_value_type handle() const { + return **this; + } + + /** + * \brief Cast to the handle of the current target. + * \deprecated + * Implicit casts of iterators are unsafe. Use dereferencing operators + * -> and * instead. + */ + OM_DEPRECATED("Implicit casts of iterators are unsafe. Use dereferencing operators -> and * instead.") + operator value_type() const { + return **this; + } + + template + friend STREAM &operator<< (STREAM &s, const GenericCirculatorT_DEPRECATED &self) { + return s << self.mesh_ << ", " << self.start_.idx() << ", " << self.heh_.idx() << ", " << self.lap_counter_; + } + + private: + mutable smart_value_type pointer_deref_value; +}; + +} // namespace Iterators +} // namespace OpenMesh + diff --git a/Sources/OpenMeshCore/Core/Mesh/DefaultPolyMesh.hh b/Sources/OpenMeshCore/Core/Mesh/DefaultPolyMesh.hh new file mode 100644 index 0000000..76c9ede --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/DefaultPolyMesh.hh @@ -0,0 +1,66 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#ifndef OPENMESH_DEFAULTPOLYMESH_HH +#define OPENMESH_DEFAULTPOLYMESH_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== TYPEDEFS ================================================================= + +typedef PolyMesh_ArrayKernelT PolyMesh; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_DEFAULTPOLYMESH_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/DefaultTriMesh.hh b/Sources/OpenMeshCore/Core/Mesh/DefaultTriMesh.hh new file mode 100644 index 0000000..5d0b434 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/DefaultTriMesh.hh @@ -0,0 +1,66 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#ifndef OPENMESH_DEFAULTTRIMESH_HH +#define OPENMESH_DEFAULTTRIMESH_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== TYPEDEFS ================================================================= + +typedef TriMesh_ArrayKernelT TriMesh; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_DEFAULTTRIMESH_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/FinalMeshItemsT.hh b/Sources/OpenMeshCore/Core/Mesh/FinalMeshItemsT.hh new file mode 100644 index 0000000..872e783 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/FinalMeshItemsT.hh @@ -0,0 +1,222 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_MESH_ITEMS_HH +#define OPENMESH_MESH_ITEMS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/// Definition of the mesh entities (items). +template +struct FinalMeshItemsT +{ + //--- build Refs structure --- +#ifndef DOXY_IGNORE_THIS + struct Refs + { + typedef typename Traits::Point Point; + typedef typename vector_traits::value_type Scalar; + + typedef typename Traits::Normal Normal; + typedef typename Traits::Color Color; + typedef typename Traits::TexCoord1D TexCoord1D; + typedef typename Traits::TexCoord2D TexCoord2D; + typedef typename Traits::TexCoord3D TexCoord3D; + typedef typename Traits::TextureIndex TextureIndex; + typedef OpenMesh::VertexHandle VertexHandle; + typedef OpenMesh::FaceHandle FaceHandle; + typedef OpenMesh::EdgeHandle EdgeHandle; + typedef OpenMesh::HalfedgeHandle HalfedgeHandle; + }; +#endif + //--- export Refs types --- + typedef typename Refs::Point Point; + typedef typename Refs::Scalar Scalar; + typedef typename Refs::Normal Normal; + typedef typename Refs::Color Color; + typedef typename Refs::TexCoord1D TexCoord1D; + typedef typename Refs::TexCoord2D TexCoord2D; + typedef typename Refs::TexCoord3D TexCoord3D; + typedef typename Refs::TextureIndex TextureIndex; + + //--- get attribute bits from Traits --- + enum Attribs + { + VAttribs = Traits::VertexAttributes, + HAttribs = Traits::HalfedgeAttributes, + EAttribs = Traits::EdgeAttributes, + FAttribs = Traits::FaceAttributes + }; + //--- merge internal items with traits items --- + + +/* + typedef typename GenProg::IF< + (bool)(HAttribs & Attributes::PrevHalfedge), + typename InternalItems::Halfedge_with_prev, + typename InternalItems::Halfedge_without_prev + >::Result InternalHalfedge; +*/ + //typedef typename InternalItems::Vertex InternalVertex; + //typedef typename InternalItems::template Edge InternalEdge; + //typedef typename InternalItems::template Face InternalFace; + class ITraits + {}; + + typedef typename Traits::template VertexT VertexData; + typedef typename Traits::template HalfedgeT HalfedgeData; + typedef typename Traits::template EdgeT EdgeData; + typedef typename Traits::template FaceT FaceData; +}; + + +#ifndef DOXY_IGNORE_THIS +namespace { +namespace TM { +template struct TypeEquality; +template struct TypeEquality {}; + +template struct ItemsEquality { + TypeEquality te1; + TypeEquality te2; + TypeEquality te3; + TypeEquality te4; + TypeEquality te5; + TypeEquality te6; + TypeEquality te7; + TypeEquality te8; +}; + +} /* namespace TM */ +} /* anonymous namespace */ +#endif + +/** + * @brief Cast a mesh with different but identical traits into each other. + * + * Note that there exists a syntactically more convenient global method + * mesh_cast(). + * + * Example: + * @code{.cpp} + * struct TriTraits1 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits2 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits3 : public OpenMesh::DefaultTraits { + * typedef Vec3f Point; + * }; + * + * TriMesh_ArrayKernelT a; + * TriMesh_ArrayKernelT &b = MeshCast&, TriMesh_ArrayKernelT&>::cast(a); // OK + * TriMesh_ArrayKernelT &c = MeshCast&, TriMesh_ArrayKernelT&>::cast(a); // ERROR + * @endcode + * + * @see mesh_cast() + * + * @param rhs + * @return + */ +template struct MeshCast; + +template +struct MeshCast { + static LhsMeshT &cast(RhsMeshT &rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + +template +struct MeshCast { + static const LhsMeshT &cast(const RhsMeshT &rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + +template +struct MeshCast { + static LhsMeshT *cast(RhsMeshT *rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + +template +struct MeshCast { + static const LhsMeshT *cast(const RhsMeshT *rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESH_ITEMS_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/Mesh/Handles.hh b/Sources/OpenMeshCore/Core/Mesh/Handles.hh new file mode 100644 index 0000000..9023f3f --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/Handles.hh @@ -0,0 +1,242 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_HANDLES_HH +#define OPENMESH_HANDLES_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + + +/// Base class for all handle types +class OPENMESHDLLEXPORT BaseHandle +{ +public: + + explicit BaseHandle(int _idx=-1) : idx_(_idx) {} + + /// Get the underlying index of this handle + int idx() const { return idx_; } + + /// The handle is valid iff the index is not negative. + bool is_valid() const { return idx_ >= 0; } + + /// reset handle to be invalid + void reset() { idx_=-1; } + /// reset handle to be invalid + void invalidate() { idx_ = -1; } + + bool operator==(const BaseHandle& _rhs) const { + return (this->idx_ == _rhs.idx_); + } + + bool operator!=(const BaseHandle& _rhs) const { + return (this->idx_ != _rhs.idx_); + } + + bool operator<(const BaseHandle& _rhs) const { + return (this->idx_ < _rhs.idx_); + } + + + // this is to be used only by the iterators + void __increment() { ++idx_; } + void __decrement() { --idx_; } + + void __increment(int amount) { idx_ += amount; } + void __decrement(int amount) { idx_ -= amount; } + +private: + + int idx_; +}; + +// this is used by boost::unordered_set/map +inline size_t hash_value(const BaseHandle& h) { return h.idx(); } + +//----------------------------------------------------------------------------- + +/// Write handle \c _hnd to stream \c _os +inline std::ostream& operator<<(std::ostream& _os, const BaseHandle& _hnd) +{ + return (_os << _hnd.idx()); +} + + +//----------------------------------------------------------------------------- + + +/// Handle for a vertex entity +struct OPENMESHDLLEXPORT VertexHandle : public BaseHandle +{ + explicit VertexHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a halfedge entity +struct OPENMESHDLLEXPORT HalfedgeHandle : public BaseHandle +{ + explicit HalfedgeHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a edge entity +struct OPENMESHDLLEXPORT EdgeHandle : public BaseHandle +{ + explicit EdgeHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a face entity +struct OPENMESHDLLEXPORT FaceHandle : public BaseHandle +{ + explicit FaceHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle type for meshes to simplify some template programming +struct OPENMESHDLLEXPORT MeshHandle : public BaseHandle +{ + explicit MeshHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +#ifdef OM_HAS_HASH +#include +namespace std { + +#if defined(_MSVC_VER) +# pragma warning(push) +# pragma warning(disable:4099) // For VC++ it is class hash +#endif + + +template <> +struct hash +{ + typedef OpenMesh::BaseHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::BaseHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + typedef OpenMesh::VertexHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::VertexHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + + typedef OpenMesh::HalfedgeHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::HalfedgeHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + + typedef OpenMesh::EdgeHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::EdgeHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + + typedef OpenMesh::FaceHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::FaceHandle& h) const + { + return h.idx(); + } +}; + +#if defined(_MSVC_VER) +# pragma warning(pop) +#endif + +} +#endif // OM_HAS_HASH + + +#endif // OPENMESH_HANDLES_HH +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/IteratorsT.hh b/Sources/OpenMeshCore/Core/Mesh/IteratorsT.hh new file mode 100644 index 0000000..1ca32c9 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/IteratorsT.hh @@ -0,0 +1,250 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#pragma once + +//============================================================================= +// +// Iterators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class ConstVertexIterT; +template class VertexIterT; +template class ConstHalfedgeIterT; +template class HalfedgeIterT; +template class ConstEdgeIterT; +template class EdgeIterT; +template class ConstFaceIterT; +template class FaceIterT; + + +template +class GenericIteratorT { + public: + //--- Typedefs --- + + typedef ValueHandle value_handle; + typedef value_handle value_type; + typedef std::bidirectional_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; + typedef decltype(make_smart(std::declval(), std::declval())) SmartHandle; + typedef const SmartHandle& reference; + typedef const SmartHandle* pointer; + + /// Default constructor. + GenericIteratorT() + : hnd_(make_smart(ValueHandle(),nullptr)), skip_bits_(0) + {} + + /// Construct with mesh and a target handle. + GenericIteratorT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : hnd_(make_smart(_hnd, _mesh)), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + /// Standard dereferencing operator. + reference operator*() const { + return hnd_; + } + + /// Standard pointer operator. + pointer operator->() const { + return &hnd_; + } + + /** + * \brief Get the handle of the item the iterator refers to. + * \deprecated + * This function clutters your code. Use dereferencing operators -> and * instead. + */ + OM_DEPRECATED("This function clutters your code. Use dereferencing operators -> and * instead.") + value_handle handle() const { + return hnd_; + } + + /** + * \brief Cast to the handle of the item the iterator refers to. + * \deprecated + * Implicit casts of iterators are unsafe. Use dereferencing operators + * -> and * instead. + */ + OM_DEPRECATED("Implicit casts of iterators are unsafe. Use dereferencing operators -> and * instead.") + operator value_handle() const { + return hnd_; + } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const GenericIteratorT& _rhs) const { + return ((hnd_.mesh() == _rhs.hnd_.mesh()) && (hnd_ == _rhs.hnd_)); + } + + /// Not equal? + bool operator!=(const GenericIteratorT& _rhs) const { + return !operator==(_rhs); + } + + /// Standard pre-increment operator + GenericIteratorT& operator++() { + hnd_.__increment(); + if (skip_bits_) + skip_fwd(); + return *this; + } + + /// Standard post-increment operator + GenericIteratorT operator++(int) { + GenericIteratorT cpy(*this); + ++(*this); + return cpy; + } + +#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) + template + auto operator+=(int amount) -> + typename std::enable_if< + sizeof(decltype(std::declval().__increment(amount))) >= 0, + GenericIteratorT&>::type { + static_assert(std::is_same::value, + "Template parameter must not deviate from default."); + if (skip_bits_) + throw std::logic_error("Skipping iterators do not support " + "random access."); + hnd_.__increment(amount); + return *this; + } + + template + auto operator+(int rhs) -> + typename std::enable_if< + sizeof(decltype(std::declval().__increment(rhs), void (), int {})) >= 0, + GenericIteratorT>::type { + static_assert(std::is_same::value, + "Template parameter must not deviate from default."); + if (skip_bits_) + throw std::logic_error("Skipping iterators do not support " + "random access."); + GenericIteratorT result = *this; + result.hnd_.__increment(rhs); + return result; + } +#endif + + /// Standard pre-decrement operator + GenericIteratorT& operator--() { + hnd_.__decrement(); + if (skip_bits_) + skip_bwd(); + return *this; + } + + /// Standard post-decrement operator + GenericIteratorT operator--(int) { + GenericIteratorT cpy(*this); + --(*this); + return cpy; + } + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() { + if (hnd_.mesh() && (hnd_.mesh()->*PrimitiveStatusMember)()) { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } else + skip_bits_ = 0; + } + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { + skip_bits_ = 0; + } + + private: + + void skip_fwd() { + assert(hnd_.mesh() && skip_bits_); + while ((hnd_.idx() < (signed) (hnd_.mesh()->*PrimitiveCountMember)()) + && (hnd_.mesh()->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + void skip_bwd() { + assert(hnd_.mesh() && skip_bits_); + while ((hnd_.idx() >= 0) && (hnd_.mesh()->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + protected: + SmartHandle hnd_; + unsigned int skip_bits_; +}; + +//============================================================================= +} // namespace Iterators +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/PolyConnectivity.cc b/Sources/OpenMeshCore/Core/Mesh/PolyConnectivity.cc new file mode 100644 index 0000000..6aa80ba --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/PolyConnectivity.cc @@ -0,0 +1,1168 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//== IMPLEMENTATION ========================================================== +#include +#include + +namespace OpenMesh { + +const PolyConnectivity::VertexHandle PolyConnectivity::InvalidVertexHandle; +const PolyConnectivity::HalfedgeHandle PolyConnectivity::InvalidHalfedgeHandle; +const PolyConnectivity::EdgeHandle PolyConnectivity::InvalidEdgeHandle; +const PolyConnectivity::FaceHandle PolyConnectivity::InvalidFaceHandle; + +//----------------------------------------------------------------------------- + +SmartHalfedgeHandle PolyConnectivity::find_halfedge(VertexHandle _start_vh, VertexHandle _end_vh ) const +{ + assert(_start_vh.is_valid() && _end_vh.is_valid()); + + for (ConstVertexOHalfedgeIter voh_it = cvoh_iter(_start_vh); voh_it.is_valid(); ++voh_it) + if (to_vertex_handle(*voh_it) == _end_vh) + return *voh_it; + + return make_smart(InvalidHalfedgeHandle, this); +} + + +bool PolyConnectivity::is_boundary(FaceHandle _fh, bool _check_vertex) const +{ + for (ConstFaceEdgeIter cfeit = cfe_iter( _fh ); cfeit.is_valid(); ++cfeit) + if (is_boundary( *cfeit ) ) + return true; + + if (_check_vertex) + { + for (ConstFaceVertexIter cfvit = cfv_iter( _fh ); cfvit.is_valid(); ++cfvit) + if (is_boundary( *cfvit ) ) + return true; + } + return false; +} + +bool PolyConnectivity::is_manifold(VertexHandle _vh) const +{ + /* The vertex is non-manifold if more than one gap exists, i.e. + more than one outgoing boundary halfedge. If (at least) one + boundary halfedge exists, the vertex' halfedge must be a + boundary halfedge. If iterating around the vertex finds another + boundary halfedge, the vertex is non-manifold. */ + + ConstVertexOHalfedgeIter vh_it(*this, _vh); + if (vh_it.is_valid()) + for (++vh_it; vh_it.is_valid(); ++vh_it) + if (is_boundary(*vh_it)) + return false; + return true; +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::adjust_outgoing_halfedge(VertexHandle _vh) +{ + for (ConstVertexOHalfedgeIter vh_it=cvoh_iter(_vh); vh_it.is_valid(); ++vh_it) + { + if (is_boundary(*vh_it)) + { + set_halfedge_handle(_vh, *vh_it); + break; + } + } +} + +//----------------------------------------------------------------------------- + +SmartFaceHandle +PolyConnectivity::add_face(const VertexHandle* _vertex_handles, size_t _vhs_size) +{ + VertexHandle vh; + size_t i, ii, n(_vhs_size); + HalfedgeHandle inner_next, inner_prev, + outer_next, outer_prev, + boundary_next, boundary_prev, + patch_start, patch_end; + + + // Check sufficient working storage available + if (edgeData_.size() < n) + { + edgeData_.resize(n); + next_cache_.resize(6*n); + } + + size_t next_cache_count = 0; + + // don't allow degenerated faces + assert (n > 2); + + // test for topological errors + for (i=0, ii=1; i& _vhandles) +{ return add_face(&_vhandles.front(), _vhandles.size()); } + +//----------------------------------------------------------------------------- + +SmartFaceHandle PolyConnectivity::add_face(const std::vector& _vhandles) +{ + std::vector vhandles(_vhandles.begin(), _vhandles.end()); + return add_face(&vhandles.front(), vhandles.size()); +} + + +//----------------------------------------------------------------------------- +bool PolyConnectivity::is_collapse_ok(HalfedgeHandle v0v1) +{ + //is edge already deleteed? + if (status(edge_handle(v0v1)).deleted()) + { + return false; + } + + HalfedgeHandle v1v0(opposite_halfedge_handle(v0v1)); + VertexHandle v0(to_vertex_handle(v1v0)); + VertexHandle v1(to_vertex_handle(v0v1)); + + bool v0v1_triangle = false; + bool v1v0_triangle = false; + + if (!is_boundary(v0v1)) + v0v1_triangle = valence(face_handle(v0v1)) == 3; + + if (!is_boundary(v1v0)) + v1v0_triangle = valence(face_handle(v1v0)) == 3; + + //in a quadmesh we dont have the "next" or "previous" vhandle, so we need to look at previous and next on both sides + //VertexHandle v_01_p = from_vertex_handle(prev_halfedge_handle(v0v1)); + VertexHandle v_01_n = to_vertex_handle(next_halfedge_handle(v0v1)); + + //VertexHandle v_10_p = from_vertex_handle(prev_halfedge_handle(v1v0)); + VertexHandle v_10_n = to_vertex_handle(next_halfedge_handle(v1v0)); + + //are the vertices already deleted ? + if (status(v0).deleted() || status(v1).deleted()) + { + return false; + } + + //the edges v1-vl and vl-v0 must not be both boundary edges + //this test makes only sense in a polymesh if the side face is a triangle + VertexHandle vl; + if (!is_boundary(v0v1)) + { + if (v0v1_triangle) + { + HalfedgeHandle h1 = next_halfedge_handle(v0v1); + HalfedgeHandle h2 = next_halfedge_handle(h1); + + vl = to_vertex_handle(h1); + + if (is_boundary(opposite_halfedge_handle(h1)) && is_boundary(opposite_halfedge_handle(h2))) + return false; + } + } + + //the edges v0-vr and vr-v1 must not be both boundary edges + //this test makes only sense in a polymesh if the side face is a triangle + VertexHandle vr; + if (!is_boundary(v1v0)) + { + if (v1v0_triangle) + { + HalfedgeHandle h1 = next_halfedge_handle(v1v0); + HalfedgeHandle h2 = next_halfedge_handle(h1); + + vr = to_vertex_handle(h1); + + if (is_boundary(opposite_halfedge_handle(h1)) && is_boundary(opposite_halfedge_handle(h2))) + return false; + } + } + + // if vl and vr are equal and valid (e.g. triangle case) -> fail + if ( vl.is_valid() && (vl == vr)) return false; + + // edge between two boundary vertices should be a boundary edge + if ( is_boundary(v0) && is_boundary(v1) && !is_boundary(v0v1) && !is_boundary(v1v0)) + return false; + + VertexVertexIter vv_it; + // test intersection of the one-rings of v0 and v1 + for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it) + { + status(*vv_it).set_tagged(false); + } + + for (vv_it = vv_iter(v1); vv_it.is_valid(); ++vv_it) + { + status(*vv_it).set_tagged(true); + } + + for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it) + { + if (status(*vv_it).tagged() && + !(*vv_it == v_01_n && v0v1_triangle) && + !(*vv_it == v_10_n && v1v0_triangle) + ) + { + return false; + } + } + + //test for a face on the backside/other side that might degenerate + if (v0v1_triangle) + { + HalfedgeHandle one, two; + one = next_halfedge_handle(v0v1); + two = next_halfedge_handle(one); + + one = opposite_halfedge_handle(one); + two = opposite_halfedge_handle(two); + + if (face_handle(one) == face_handle(two) && valence(face_handle(one)) != 3) + { + return false; + } + } + + if (v1v0_triangle) + { + HalfedgeHandle one, two; + one = next_halfedge_handle(v1v0); + two = next_halfedge_handle(one); + + one = opposite_halfedge_handle(one); + two = opposite_halfedge_handle(two); + + if (face_handle(one) == face_handle(two) && valence(face_handle(one)) != 3) + { + return false; + } + } + + if (status(*vv_it).tagged() && v_01_n == v_10_n && v0v1_triangle && v1v0_triangle) + { + return false; + } + + // passed all tests + return true; +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices) +{ + // store incident faces + std::vector face_handles; + face_handles.reserve(8); + for (VFIter vf_it(vf_iter(_vh)); vf_it.is_valid(); ++vf_it) + face_handles.push_back(*vf_it); + + + // delete collected faces + for (auto delete_fh_it : face_handles) + delete_face(delete_fh_it, _delete_isolated_vertices); + + status(_vh).set_deleted(true); +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices) +{ + FaceHandle fh0(face_handle(halfedge_handle(_eh, 0))); + FaceHandle fh1(face_handle(halfedge_handle(_eh, 1))); + + if (fh0.is_valid()) delete_face(fh0, _delete_isolated_vertices); + if (fh1.is_valid()) delete_face(fh1, _delete_isolated_vertices); + + // If there is no face, we delete the edge + // here + if ( ! fh0.is_valid() && !fh1.is_valid()) { + // mark edge deleted if the mesh has a edge status + if ( has_edge_status() ) + status(_eh).set_deleted(true); + + // mark corresponding halfedges as deleted + // As the deleted edge is boundary, + // all corresponding halfedges will also be deleted. + if ( has_halfedge_status() ) { + status(halfedge_handle(_eh, 0)).set_deleted(true); + status(halfedge_handle(_eh, 1)).set_deleted(true); + } + } +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::delete_face(FaceHandle _fh, bool _delete_isolated_vertices) +{ + assert(_fh.is_valid() && !status(_fh).deleted()); + + // mark face deleted + status(_fh).set_deleted(true); + + + // this vector will hold all boundary edges of face _fh + // these edges will be deleted + std::vector deleted_edges; + deleted_edges.reserve(3); + + + // this vector will hold all vertices of face _fh + // for updating their outgoing halfedge + std::vector vhandles; + vhandles.reserve(3); + + + // for all halfedges of face _fh do: + // 1) invalidate face handle. + // 2) collect all boundary halfedges, set them deleted + // 3) store vertex handles + HalfedgeHandle hh; + for (FaceHalfedgeIter fh_it(fh_iter(_fh)); fh_it.is_valid(); ++fh_it) + { + hh = *fh_it; + + set_boundary(hh);//set_face_handle(hh, InvalidFaceHandle); + + if (is_boundary(opposite_halfedge_handle(hh))) + deleted_edges.push_back(edge_handle(hh)); + + vhandles.push_back(to_vertex_handle(hh)); + } + + + // delete all collected (half)edges + // these edges were all boundary + // delete isolated vertices (if _delete_isolated_vertices is true) + if (!deleted_edges.empty()) + { + std::vector::iterator del_it(deleted_edges.begin()), + del_end(deleted_edges.end()); + HalfedgeHandle h0, h1, next0, next1, prev0, prev1; + VertexHandle v0, v1; + + for (; del_it!=del_end; ++del_it) + { + h0 = halfedge_handle(*del_it, 0); + v0 = to_vertex_handle(h0); + next0 = next_halfedge_handle(h0); + prev0 = prev_halfedge_handle(h0); + + h1 = halfedge_handle(*del_it, 1); + v1 = to_vertex_handle(h1); + next1 = next_halfedge_handle(h1); + prev1 = prev_halfedge_handle(h1); + + // adjust next and prev handles + set_next_halfedge_handle(prev0, next1); + set_next_halfedge_handle(prev1, next0); + + // mark edge deleted if the mesh has a edge status + if ( has_edge_status() ) + status(*del_it).set_deleted(true); + + + // mark corresponding halfedges as deleted + // As the deleted edge is boundary, + // all corresponding halfedges will also be deleted. + if ( has_halfedge_status() ) { + status(h0).set_deleted(true); + status(h1).set_deleted(true); + } + + // update v0 + if (halfedge_handle(v0) == h1) + { + // isolated ? + if (next0 == h1) + { + if (_delete_isolated_vertices) + status(v0).set_deleted(true); + set_isolated(v0); + } + else set_halfedge_handle(v0, next0); + } + + // update v1 + if (halfedge_handle(v1) == h0) + { + // isolated ? + if (next1 == h0) + { + if (_delete_isolated_vertices) + status(v1).set_deleted(true); + set_isolated(v1); + } + else set_halfedge_handle(v1, next1); + } + } + } + + // update outgoing halfedge handles of remaining vertices + std::vector::iterator v_it(vhandles.begin()), + v_end(vhandles.end()); + for (; v_it!=v_end; ++v_it) + adjust_outgoing_halfedge(*v_it); +} + + +//----------------------------------------------------------------------------- +void PolyConnectivity::collapse(HalfedgeHandle _hh) +{ + HalfedgeHandle h0 = _hh; + HalfedgeHandle h1 = next_halfedge_handle(h0); + HalfedgeHandle o0 = opposite_halfedge_handle(h0); + HalfedgeHandle o1 = next_halfedge_handle(o0); + + // remove edge + collapse_edge(h0); + + // remove loops + if (next_halfedge_handle(next_halfedge_handle(h1)) == h1) + collapse_loop(next_halfedge_handle(h1)); + if (next_halfedge_handle(next_halfedge_handle(o1)) == o1) + collapse_loop(o1); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::collapse_edge(HalfedgeHandle _hh) +{ + HalfedgeHandle h = _hh; + HalfedgeHandle hn = next_halfedge_handle(h); + HalfedgeHandle hp = prev_halfedge_handle(h); + + HalfedgeHandle o = opposite_halfedge_handle(h); + HalfedgeHandle on = next_halfedge_handle(o); + HalfedgeHandle op = prev_halfedge_handle(o); + + FaceHandle fh = face_handle(h); + FaceHandle fo = face_handle(o); + + VertexHandle vh = to_vertex_handle(h); + VertexHandle vo = to_vertex_handle(o); + + + + // halfedge -> vertex + for (VertexIHalfedgeIter vih_it(vih_iter(vo)); vih_it.is_valid(); ++vih_it) + set_vertex_handle(*vih_it, vh); + + + // halfedge -> halfedge + set_next_halfedge_handle(hp, hn); + set_next_halfedge_handle(op, on); + + + // face -> halfedge + if (fh.is_valid()) set_halfedge_handle(fh, hn); + if (fo.is_valid()) set_halfedge_handle(fo, on); + + + // vertex -> halfedge + if (halfedge_handle(vh) == o) set_halfedge_handle(vh, hn); + adjust_outgoing_halfedge(vh); + set_isolated(vo); + + // delete stuff + status(edge_handle(h)).set_deleted(true); + status(vo).set_deleted(true); + if (has_halfedge_status()) + { + status(h).set_deleted(true); + status(o).set_deleted(true); + } +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::collapse_loop(HalfedgeHandle _hh) +{ + HalfedgeHandle h0 = _hh; + HalfedgeHandle h1 = next_halfedge_handle(h0); + + HalfedgeHandle o0 = opposite_halfedge_handle(h0); + HalfedgeHandle o1 = opposite_halfedge_handle(h1); + + VertexHandle v0 = to_vertex_handle(h0); + VertexHandle v1 = to_vertex_handle(h1); + + FaceHandle fh = face_handle(h0); + FaceHandle fo = face_handle(o0); + + + + // is it a loop ? + assert ((next_halfedge_handle(h1) == h0) && (h1 != o0)); + + + // halfedge -> halfedge + set_next_halfedge_handle(h1, next_halfedge_handle(o0)); + set_next_halfedge_handle(prev_halfedge_handle(o0), h1); + + + // halfedge -> face + set_face_handle(h1, fo); + + + // vertex -> halfedge + set_halfedge_handle(v0, h1); adjust_outgoing_halfedge(v0); + set_halfedge_handle(v1, o1); adjust_outgoing_halfedge(v1); + + + // face -> halfedge + if (fo.is_valid() && halfedge_handle(fo) == o0) + { + set_halfedge_handle(fo, h1); + } + + // delete stuff + if (fh.is_valid()) + { + set_halfedge_handle(fh, InvalidHalfedgeHandle); + status(fh).set_deleted(true); + } + status(edge_handle(h0)).set_deleted(true); + if (has_halfedge_status()) + { + status(h0).set_deleted(true); + status(o0).set_deleted(true); + } +} + +//----------------------------------------------------------------------------- +bool PolyConnectivity::is_simple_link(EdgeHandle _eh) const +{ + HalfedgeHandle heh0 = halfedge_handle(_eh, 0); + HalfedgeHandle heh1 = halfedge_handle(_eh, 1); + + //FaceHandle fh0 = face_handle(heh0);//fh0 or fh1 might be a invalid, + FaceHandle fh1 = face_handle(heh1);//i.e., representing the boundary + + HalfedgeHandle next_heh = next_halfedge_handle(heh0); + while (next_heh != heh0) + {//check if there are no other edges shared between fh0 & fh1 + if (opposite_face_handle(next_heh) == fh1) + { + return false; + } + next_heh = next_halfedge_handle(next_heh); + } + return true; +} + +//----------------------------------------------------------------------------- +bool PolyConnectivity::is_simply_connected(FaceHandle _fh) const +{ + std::set nb_fhs; + for (ConstFaceFaceIter cff_it = cff_iter(_fh); cff_it.is_valid(); ++cff_it) + { + if (nb_fhs.find(*cff_it) == nb_fhs.end()) + { + nb_fhs.insert(*cff_it); + } + else + {//there is more than one link + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +PolyConnectivity::FaceHandle +PolyConnectivity::remove_edge(EdgeHandle _eh) +{ + //don't allow "dangling" vertices and edges + assert(!status(_eh).deleted() && is_simple_link(_eh)); + + HalfedgeHandle heh0 = halfedge_handle(_eh, 0); + HalfedgeHandle heh1 = halfedge_handle(_eh, 1); + + //deal with the faces + FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1); + if (!del_fh.is_valid()) + {//boundary case - we must delete the rem_fh + std::swap(del_fh, rem_fh); + } + assert(del_fh.is_valid()); +/* for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it; ++fh_it) + {//set the face handle of the halfedges of del_fh to point to rem_fh + set_face_handle(fh_it, rem_fh); + } */ + //fix the halfedge relations + HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0); + HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1); + + HalfedgeHandle next_heh0 = next_halfedge_handle(heh0); + HalfedgeHandle next_heh1 = next_halfedge_handle(heh1); + + set_next_halfedge_handle(prev_heh0, next_heh1); + set_next_halfedge_handle(prev_heh1, next_heh0); + //correct outgoing vertex handles for the _eh vertices (if needed) + VertexHandle vh0 = to_vertex_handle(heh0); + VertexHandle vh1 = to_vertex_handle(heh1); + + if (halfedge_handle(vh0) == heh1) + { + set_halfedge_handle(vh0, next_heh0); + } + if (halfedge_handle(vh1) == heh0) + { + set_halfedge_handle(vh1, next_heh1); + } + + //correct the hafledge handle of rem_fh if needed and preserve its first vertex + if (halfedge_handle(rem_fh) == heh0) + {//rem_fh is the face at heh0 + set_halfedge_handle(rem_fh, prev_heh1); + } + else if (halfedge_handle(rem_fh) == heh1) + {//rem_fh is the face at heh1 + set_halfedge_handle(rem_fh, prev_heh0); + } + for (FaceHalfedgeIter fh_it = fh_iter(rem_fh); fh_it.is_valid(); ++fh_it) + {//set the face handle of the halfedges of del_fh to point to rem_fh + set_face_handle(*fh_it, rem_fh); + } + + status(_eh).set_deleted(true); + status(del_fh).set_deleted(true); + return rem_fh;//returns the remaining face handle +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::reinsert_edge(EdgeHandle _eh) +{ + //this does not work without prev_halfedge_handle + assert_compile(sizeof(Halfedge) == sizeof(Halfedge_with_prev)); + //shoudl be deleted + assert(status(_eh).deleted()); + status(_eh).set_deleted(false); + + HalfedgeHandle heh0 = halfedge_handle(_eh, 0); + HalfedgeHandle heh1 = halfedge_handle(_eh, 1); + FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1); + if (!del_fh.is_valid()) + {//boundary case - we must delete the rem_fh + std::swap(del_fh, rem_fh); + } + assert(status(del_fh).deleted()); + status(del_fh).set_deleted(false); + + //restore halfedge relations + HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0); + HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1); + + HalfedgeHandle next_heh0 = next_halfedge_handle(heh0); + HalfedgeHandle next_heh1 = next_halfedge_handle(heh1); + + set_next_halfedge_handle(prev_heh0, heh0); + set_prev_halfedge_handle(next_heh0, heh0); + + set_next_halfedge_handle(prev_heh1, heh1); + set_prev_halfedge_handle(next_heh1, heh1); + + for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it.is_valid(); ++fh_it) + {//reassign halfedges to del_fh + set_face_handle(*fh_it, del_fh); + } + + if (face_handle(halfedge_handle(rem_fh)) == del_fh) + {//correct the halfedge handle of rem_fh + if (halfedge_handle(rem_fh) == prev_heh0) + {//rem_fh is the face at heh1 + set_halfedge_handle(rem_fh, heh1); + } + else + {//rem_fh is the face at heh0 + assert(halfedge_handle(rem_fh) == prev_heh1); + set_halfedge_handle(rem_fh, heh0); + } + } +} + +//----------------------------------------------------------------------------- +PolyConnectivity::HalfedgeHandle +PolyConnectivity::insert_edge(HalfedgeHandle _prev_heh, HalfedgeHandle _next_heh) +{ + assert(face_handle(_prev_heh) == face_handle(_next_heh));//only the manifold case + assert(next_halfedge_handle(_prev_heh) != _next_heh);//this can not be done + VertexHandle vh0 = to_vertex_handle(_prev_heh); + VertexHandle vh1 = from_vertex_handle(_next_heh); + //create the link between vh0 and vh1 + HalfedgeHandle heh0 = new_edge(vh0, vh1); + HalfedgeHandle heh1 = opposite_halfedge_handle(heh0); + HalfedgeHandle next_prev_heh = next_halfedge_handle(_prev_heh); + HalfedgeHandle prev_next_heh = prev_halfedge_handle(_next_heh); + set_next_halfedge_handle(_prev_heh, heh0); + set_next_halfedge_handle(heh0, _next_heh); + set_next_halfedge_handle(prev_next_heh, heh1); + set_next_halfedge_handle(heh1, next_prev_heh); + + //now set the face handles - the new face is assigned to heh0 + FaceHandle new_fh = new_face(); + set_halfedge_handle(new_fh, heh0); + for (FaceHalfedgeIter fh_it = fh_iter(new_fh); fh_it.is_valid(); ++fh_it) + { + set_face_handle(*fh_it, new_fh); + } + FaceHandle old_fh = face_handle(next_prev_heh); + set_face_handle(heh1, old_fh); + if (old_fh.is_valid() && face_handle(halfedge_handle(old_fh)) == new_fh) + {//fh pointed to one of the halfedges now assigned to new_fh + set_halfedge_handle(old_fh, heh1); + } + adjust_outgoing_halfedge(vh0); + adjust_outgoing_halfedge(vh1); + return heh0; +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::triangulate(FaceHandle _fh) +{ + /* + Split an arbitrary face into triangles by connecting + each vertex of fh after its second to vh. + + - fh will remain valid (it will become one of the + triangles) + - the halfedge handles of the new triangles will + point to the old halfedges + */ + + HalfedgeHandle base_heh(halfedge_handle(_fh)); + VertexHandle start_vh = from_vertex_handle(base_heh); + HalfedgeHandle prev_heh(prev_halfedge_handle(base_heh)); + HalfedgeHandle next_heh(next_halfedge_handle(base_heh)); + + while (to_vertex_handle(next_halfedge_handle(next_heh)) != start_vh) + { + HalfedgeHandle next_next_heh(next_halfedge_handle(next_heh)); + + FaceHandle new_fh = new_face(); + set_halfedge_handle(new_fh, base_heh); + + HalfedgeHandle new_heh = new_edge(to_vertex_handle(next_heh), start_vh); + + set_next_halfedge_handle(base_heh, next_heh); + set_next_halfedge_handle(next_heh, new_heh); + set_next_halfedge_handle(new_heh, base_heh); + + set_face_handle(base_heh, new_fh); + set_face_handle(next_heh, new_fh); + set_face_handle(new_heh, new_fh); + + copy_all_properties(prev_heh, new_heh, true); + copy_all_properties(prev_heh, opposite_halfedge_handle(new_heh), true); + copy_all_properties(_fh, new_fh, true); + + base_heh = opposite_halfedge_handle(new_heh); + next_heh = next_next_heh; + } + set_halfedge_handle(_fh, base_heh); //the last face takes the handle _fh + + set_next_halfedge_handle(base_heh, next_heh); + set_next_halfedge_handle(next_halfedge_handle(next_heh), base_heh); + + set_face_handle(base_heh, _fh); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::triangulate() +{ + /* The iterators will stay valid, even though new faces are added, + because they are now implemented index-based instead of + pointer-based. + */ + FaceIter f_it(faces_begin()), f_end(faces_end()); + for (; f_it!=f_end; ++f_it) + triangulate(*f_it); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::split(FaceHandle fh, VertexHandle vh) +{ + HalfedgeHandle hend = halfedge_handle(fh); + HalfedgeHandle hh = next_halfedge_handle(hend); + + HalfedgeHandle hold = new_edge(to_vertex_handle(hend), vh); + + set_next_halfedge_handle(hend, hold); + set_face_handle(hold, fh); + + hold = opposite_halfedge_handle(hold); + + while (hh != hend) { + + HalfedgeHandle hnext = next_halfedge_handle(hh); + + FaceHandle fnew = new_face(); + set_halfedge_handle(fnew, hh); + + HalfedgeHandle hnew = new_edge(to_vertex_handle(hh), vh); + + set_next_halfedge_handle(hnew, hold); + set_next_halfedge_handle(hold, hh); + set_next_halfedge_handle(hh, hnew); + + set_face_handle(hnew, fnew); + set_face_handle(hold, fnew); + set_face_handle(hh, fnew); + + hold = opposite_halfedge_handle(hnew); + + hh = hnext; + } + + set_next_halfedge_handle(hold, hend); + set_next_halfedge_handle(next_halfedge_handle(hend), hold); + + set_face_handle(hold, fh); + + set_halfedge_handle(vh, hold); +} + + +void PolyConnectivity::split_copy(FaceHandle fh, VertexHandle vh) { + + // Split the given face (fh will still be valid) + split(fh, vh); + + // Copy the property of the original face to all new faces + for(VertexFaceIter vf_it = vf_iter(vh); vf_it.is_valid(); ++vf_it) + copy_all_properties(fh, *vf_it, true); +} + +//----------------------------------------------------------------------------- +uint PolyConnectivity::valence(VertexHandle _vh) const +{ + uint count(0); + for (ConstVertexVertexIter vv_it=cvv_iter(_vh); vv_it.is_valid(); ++vv_it) + ++count; + return count; +} + +//----------------------------------------------------------------------------- +uint PolyConnectivity::valence(FaceHandle _fh) const +{ + uint count(0); + for (ConstFaceVertexIter fv_it=cfv_iter(_fh); fv_it.is_valid(); ++fv_it) + ++count; + return count; +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::split_edge(EdgeHandle _eh, VertexHandle _vh) +{ + HalfedgeHandle h0 = halfedge_handle(_eh, 0); + HalfedgeHandle h1 = halfedge_handle(_eh, 1); + + VertexHandle vfrom = from_vertex_handle(h0); + + HalfedgeHandle ph0 = prev_halfedge_handle(h0); + //HalfedgeHandle ph1 = prev_halfedge_handle(h1); + + //HalfedgeHandle nh0 = next_halfedge_handle(h0); + HalfedgeHandle nh1 = next_halfedge_handle(h1); + + bool boundary0 = is_boundary(h0); + bool boundary1 = is_boundary(h1); + + //add the new edge + HalfedgeHandle new_e = new_edge(from_vertex_handle(h0), _vh); + + //fix the vertex of the opposite halfedge + set_vertex_handle(h1, _vh); + + //fix the halfedge connectivity + set_next_halfedge_handle(new_e, h0); + set_next_halfedge_handle(h1, opposite_halfedge_handle(new_e)); + + set_next_halfedge_handle(ph0, new_e); + set_next_halfedge_handle(opposite_halfedge_handle(new_e), nh1); + +// set_prev_halfedge_handle(new_e, ph0); +// set_prev_halfedge_handle(opposite_halfedge_handle(new_e), h1); + +// set_prev_halfedge_handle(nh1, opposite_halfedge_handle(new_e)); +// set_prev_halfedge_handle(h0, new_e); + + if (!boundary0) + { + set_face_handle(new_e, face_handle(h0)); + } + else + { + set_boundary(new_e); + } + + if (!boundary1) + { + set_face_handle(opposite_halfedge_handle(new_e), face_handle(h1)); + } + else + { + set_boundary(opposite_halfedge_handle(new_e)); + } + + set_halfedge_handle( _vh, h0 ); + adjust_outgoing_halfedge( _vh ); + + if (halfedge_handle(vfrom) == h0) + { + set_halfedge_handle(vfrom, new_e); + adjust_outgoing_halfedge( vfrom ); + } +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::split_edge_copy(EdgeHandle _eh, VertexHandle _vh) +{ + // Split the edge (handle is kept!) + split_edge(_eh, _vh); + + // Navigate to the new edge + EdgeHandle eh0 = edge_handle( next_halfedge_handle( halfedge_handle(_eh, 1) ) ); + + // Copy the property from the original to the new edge + copy_all_properties(_eh, eh0, true); +} + +} // namespace OpenMesh + diff --git a/Sources/OpenMeshCore/Core/Mesh/PolyConnectivity.hh b/Sources/OpenMeshCore/Core/Mesh/PolyConnectivity.hh new file mode 100644 index 0000000..aa427ca --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/PolyConnectivity.hh @@ -0,0 +1,1841 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_POLYCONNECTIVITY_HH +#define OPENMESH_POLYCONNECTIVITY_HH + +#include +#include + +namespace OpenMesh +{ + +namespace Iterators +{ + template + class GenericIteratorT; + + template + class GenericCirculatorBaseT; + + template + class GenericCirculatorT_DEPRECATED; + + template + class GenericCirculatorT; +} + +template +class EntityRange; + +template< + typename CONTAINER_T, + typename ITER_T, + ITER_T (CONTAINER_T::*begin_fn)() const, + ITER_T (CONTAINER_T::*end_fn)() const> +struct RangeTraitT +{ + using CONTAINER_TYPE = CONTAINER_T; + using ITER_TYPE = ITER_T; + static ITER_TYPE begin(const CONTAINER_TYPE& _container) { return (_container.*begin_fn)(); } + static ITER_TYPE end(const CONTAINER_TYPE& _container) { return (_container.*end_fn)(); } +}; + + +template +class CirculatorRange; + +template< + typename CONTAINER_T, + typename ITER_T, + typename CENTER_ENTITY_T, + typename TO_ENTITY_T, + ITER_T (CONTAINER_T::*begin_fn)(CENTER_ENTITY_T) const, + ITER_T (CONTAINER_T::*end_fn)(CENTER_ENTITY_T) const> +struct CirculatorRangeTraitT +{ + using CONTAINER_TYPE = CONTAINER_T; + using ITER_TYPE = ITER_T; + using CENTER_ENTITY_TYPE = CENTER_ENTITY_T; + using TO_ENTITYE_TYPE = TO_ENTITY_T; + static ITER_TYPE begin(const CONTAINER_TYPE& _container, CENTER_ENTITY_TYPE _ce) { return (_container.*begin_fn)(_ce); } + static ITER_TYPE begin(const CONTAINER_TYPE& _container, HalfedgeHandle _heh, int) { return ITER_TYPE(_container, _heh); } + static ITER_TYPE end(const CONTAINER_TYPE& _container, CENTER_ENTITY_TYPE _ce) { return (_container.*end_fn)(_ce); } + static ITER_TYPE end(const CONTAINER_TYPE& _container, HalfedgeHandle _heh, int) { return ITER_TYPE(_container, _heh, true); } +}; + +struct SmartVertexHandle; +struct SmartHalfedgeHandle; +struct SmartEdgeHandle; +struct SmartFaceHandle; + +/** \brief Connectivity Class for polygonal meshes +*/ +class OPENMESHDLLEXPORT PolyConnectivity : public ArrayKernel +{ +public: + /// \name Mesh Handles + //@{ + /// Invalid handle + static const VertexHandle InvalidVertexHandle; + /// Invalid handle + static const HalfedgeHandle InvalidHalfedgeHandle; + /// Invalid handle + static const EdgeHandle InvalidEdgeHandle; + /// Invalid handle + static const FaceHandle InvalidFaceHandle; + //@} + + typedef PolyConnectivity This; + + //--- iterators --- + + /** \name Mesh Iterators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators for + documentation. + */ + //@{ + /// Linear iterator + typedef Iterators::GenericIteratorT VertexIter; + typedef Iterators::GenericIteratorT HalfedgeIter; + typedef Iterators::GenericIteratorT EdgeIter; + typedef Iterators::GenericIteratorT FaceIter; + + typedef VertexIter ConstVertexIter; + typedef HalfedgeIter ConstHalfedgeIter; + typedef EdgeIter ConstEdgeIter; + typedef FaceIter ConstFaceIter; + //@} + + //--- circulators --- + + /** \name Mesh Circulators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators + for documentation. + */ + //@{ + + /* + * Vertex-centered circulators + */ + + struct VertexVertexTraits + { + using Mesh = This; + using CenterEntityHandle = This::VertexHandle; + using ValueHandle = This::VertexHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return _mesh->to_vertex_handle(_heh);} + }; + + + /** + * Enumerates 1-ring vertices in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED VertexVertexIter; + typedef Iterators::GenericCirculatorT VertexVertexCWIter; + + /** + * Enumerates 1-ring vertices in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT VertexVertexCCWIter; + + + struct VertexHalfedgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::VertexHandle; + using ValueHandle = This::HalfedgeHandle; + static ValueHandle toHandle(const Mesh* const /*_mesh*/, This::HalfedgeHandle _heh) { return _heh;} + }; + + /** + * Enumerates outgoing half edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED VertexOHalfedgeIter; + typedef Iterators::GenericCirculatorT VertexOHalfedgeCWIter; + + /** + * Enumerates outgoing half edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT VertexOHalfedgeCCWIter; + + struct VertexOppositeHalfedgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::VertexHandle; + using ValueHandle = This::HalfedgeHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return _mesh->opposite_halfedge_handle(_heh); } + }; + + /** + * Enumerates incoming half edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED VertexIHalfedgeIter; + typedef Iterators::GenericCirculatorT VertexIHalfedgeCWIter; + + /** + * Enumerates incoming half edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT VertexIHalfedgeCCWIter; + + + struct VertexFaceTraits + { + using Mesh = This; + using CenterEntityHandle = This::VertexHandle; + using ValueHandle = This::FaceHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->face_handle(_heh); } + }; + + /** + * Enumerates incident faces in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED VertexFaceIter; + typedef Iterators::GenericCirculatorT VertexFaceCWIter; + + /** + * Enumerates incident faces in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT VertexFaceCCWIter; + + + struct VertexEdgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::VertexHandle; + using ValueHandle = This::EdgeHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->edge_handle(_heh); } + }; + + /** + * Enumerates incident edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED VertexEdgeIter; + typedef Iterators::GenericCirculatorT VertexEdgeCWIter; + /** + * Enumerates incident edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT VertexEdgeCCWIter; + + + struct FaceHalfedgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::FaceHandle; + using ValueHandle = This::HalfedgeHandle; + static ValueHandle toHandle(const Mesh* const /*_mesh*/, This::HalfedgeHandle _heh) { return _heh; } + }; + + /** + * Identical to #FaceHalfedgeIter. God knows why this typedef exists. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED HalfedgeLoopIter; + typedef Iterators::GenericCirculatorT HalfedgeLoopCWIter; + /** + * Identical to #FaceHalfedgeIter. God knows why this typedef exists. + */ + typedef Iterators::GenericCirculatorT HalfedgeLoopCCWIter; + + typedef VertexVertexIter ConstVertexVertexIter; + typedef VertexVertexCWIter ConstVertexVertexCWIter; + typedef VertexVertexCCWIter ConstVertexVertexCCWIter; + typedef VertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef VertexOHalfedgeCWIter ConstVertexOHalfedgeCWIter; + typedef VertexOHalfedgeCCWIter ConstVertexOHalfedgeCCWIter; + typedef VertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef VertexIHalfedgeCWIter ConstVertexIHalfedgeCWIter; + typedef VertexIHalfedgeCCWIter ConstVertexIHalfedgeCCWIter; + typedef VertexFaceIter ConstVertexFaceIter; + typedef VertexFaceCWIter ConstVertexFaceCWIter; + typedef VertexFaceCCWIter ConstVertexFaceCCWIter; + typedef VertexEdgeIter ConstVertexEdgeIter; + typedef VertexEdgeCWIter ConstVertexEdgeCWIter; + typedef VertexEdgeCCWIter ConstVertexEdgeCCWIter; + + /* + * Face-centered circulators + */ + + struct FaceVertexTraits + { + using Mesh = This; + using CenterEntityHandle = This::FaceHandle; + using ValueHandle = This::VertexHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->to_vertex_handle(_heh); } + }; + + /** + * Enumerate incident vertices in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED FaceVertexIter; + typedef Iterators::GenericCirculatorT FaceVertexCCWIter; + + /** + * Enumerate incident vertices in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT FaceVertexCWIter; + + /** + * Enumerate incident half edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED FaceHalfedgeIter; + typedef Iterators::GenericCirculatorT FaceHalfedgeCCWIter; + + /** + * Enumerate incident half edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT FaceHalfedgeCWIter; + + + struct FaceEdgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::FaceHandle; + using ValueHandle = This::EdgeHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->edge_handle(_heh); } + }; + + /** + * Enumerate incident edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED FaceEdgeIter; + typedef Iterators::GenericCirculatorT FaceEdgeCCWIter; + + /** + * Enumerate incident edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT FaceEdgeCWIter; + + + struct FaceFaceTraits + { + using Mesh = This; + using CenterEntityHandle = This::FaceHandle; + using ValueHandle = This::FaceHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->face_handle(_mesh->opposite_halfedge_handle(_heh)); } + }; + + /** + * Enumerate adjacent faces in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED FaceFaceIter; + typedef Iterators::GenericCirculatorT FaceFaceCCWIter; + + /** + * Enumerate adjacent faces in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT FaceFaceCWIter; + + typedef FaceVertexIter ConstFaceVertexIter; + typedef FaceVertexCWIter ConstFaceVertexCWIter; + typedef FaceVertexCCWIter ConstFaceVertexCCWIter; + typedef FaceHalfedgeIter ConstFaceHalfedgeIter; + typedef FaceHalfedgeCWIter ConstFaceHalfedgeCWIter; + typedef FaceHalfedgeCCWIter ConstFaceHalfedgeCCWIter; + typedef FaceEdgeIter ConstFaceEdgeIter; + typedef FaceEdgeCWIter ConstFaceEdgeCWIter; + typedef FaceEdgeCCWIter ConstFaceEdgeCCWIter; + typedef FaceFaceIter ConstFaceFaceIter; + typedef FaceFaceCWIter ConstFaceFaceCWIter; + typedef FaceFaceCCWIter ConstFaceFaceCCWIter; + + /* + * Edge-centered circulators + */ + + struct EdgeVertexTraits + { + using Mesh = This; + using CenterEntityHandle = This::EdgeHandle; + using ValueHandle = This::VertexHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->from_vertex_handle(_heh); } + }; + + /** + * Enumerate vertices incident to an edge. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED EdgeVertexIter; + + struct EdgeHalfedgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::EdgeHandle; + using ValueHandle = This::HalfedgeHandle; + static ValueHandle toHandle(const Mesh* const /* _mesh */, This::HalfedgeHandle _heh) { return _heh; } + }; + + /** + * Enumerate the halfedges of an edge. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED EdgeHalfedgeIter; + + struct EdgeFaceTraits + { + using Mesh = This; + using CenterEntityHandle = This::EdgeHandle; + using ValueHandle = This::FaceHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->face_handle(_heh); } + }; + + /** + * Enumerate faces incident to an edge. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED EdgeFaceIter; + + typedef EdgeVertexIter ConstEdgeVertexIter; + typedef EdgeHalfedgeIter ConstEdgeHalfedgeIter; + typedef EdgeFaceIter ConstEdgeFaceIter; + + /* + * Halfedge circulator + */ + typedef HalfedgeLoopIter ConstHalfedgeLoopIter; + typedef HalfedgeLoopCWIter ConstHalfedgeLoopCWIter; + typedef HalfedgeLoopCCWIter ConstHalfedgeLoopCCWIter; + + //@} + + // --- shortcuts + + /** \name Typedef Shortcuts + Provided for convenience only + */ + //@{ + /// Alias typedef + typedef VertexHandle VHandle; + typedef HalfedgeHandle HHandle; + typedef EdgeHandle EHandle; + typedef FaceHandle FHandle; + + typedef VertexIter VIter; + typedef HalfedgeIter HIter; + typedef EdgeIter EIter; + typedef FaceIter FIter; + + typedef ConstVertexIter CVIter; + typedef ConstHalfedgeIter CHIter; + typedef ConstEdgeIter CEIter; + typedef ConstFaceIter CFIter; + + typedef VertexVertexIter VVIter; + typedef VertexVertexCWIter VVCWIter; + typedef VertexVertexCCWIter VVCCWIter; + typedef VertexOHalfedgeIter VOHIter; + typedef VertexOHalfedgeCWIter VOHCWIter; + typedef VertexOHalfedgeCCWIter VOHCCWIter; + typedef VertexIHalfedgeIter VIHIter; + typedef VertexIHalfedgeCWIter VIHICWter; + typedef VertexIHalfedgeCCWIter VIHICCWter; + typedef VertexEdgeIter VEIter; + typedef VertexEdgeCWIter VECWIter; + typedef VertexEdgeCCWIter VECCWIter; + typedef VertexFaceIter VFIter; + typedef VertexFaceCWIter VFCWIter; + typedef VertexFaceCCWIter VFCCWIter; + typedef FaceVertexIter FVIter; + typedef FaceVertexCWIter FVCWIter; + typedef FaceVertexCCWIter FVCCWIter; + typedef FaceHalfedgeIter FHIter; + typedef FaceHalfedgeCWIter FHCWIter; + typedef FaceHalfedgeCCWIter FHCWWIter; + typedef FaceEdgeIter FEIter; + typedef FaceEdgeCWIter FECWIter; + typedef FaceEdgeCCWIter FECWWIter; + typedef FaceFaceIter FFIter; + typedef EdgeVertexIter EVIter; + typedef EdgeHalfedgeIter EHIter; + typedef EdgeFaceIter EFIter; + + typedef ConstVertexVertexIter CVVIter; + typedef ConstVertexVertexCWIter CVVCWIter; + typedef ConstVertexVertexCCWIter CVVCCWIter; + typedef ConstVertexOHalfedgeIter CVOHIter; + typedef ConstVertexOHalfedgeCWIter CVOHCWIter; + typedef ConstVertexOHalfedgeCCWIter CVOHCCWIter; + typedef ConstVertexIHalfedgeIter CVIHIter; + typedef ConstVertexIHalfedgeCWIter CVIHCWIter; + typedef ConstVertexIHalfedgeCCWIter CVIHCCWIter; + typedef ConstVertexEdgeIter CVEIter; + typedef ConstVertexEdgeCWIter CVECWIter; + typedef ConstVertexEdgeCCWIter CVECCWIter; + typedef ConstVertexFaceIter CVFIter; + typedef ConstVertexFaceCWIter CVFCWIter; + typedef ConstVertexFaceCCWIter CVFCCWIter; + typedef ConstFaceVertexIter CFVIter; + typedef ConstFaceVertexCWIter CFVCWIter; + typedef ConstFaceVertexCCWIter CFVCCWIter; + typedef ConstFaceHalfedgeIter CFHIter; + typedef ConstFaceHalfedgeCWIter CFHCWIter; + typedef ConstFaceHalfedgeCCWIter CFHCCWIter; + typedef ConstFaceEdgeIter CFEIter; + typedef ConstFaceEdgeCWIter CFECWIter; + typedef ConstFaceEdgeCCWIter CFECCWIter; + typedef ConstFaceFaceIter CFFIter; + typedef ConstFaceFaceCWIter CFFCWIter; + typedef ConstFaceFaceCCWIter CFFCCWIter; + typedef ConstEdgeVertexIter CEVIter; + typedef ConstEdgeHalfedgeIter CEHIter; + typedef ConstEdgeFaceIter CEFIter; + //@} + +public: + + PolyConnectivity() {} + virtual ~PolyConnectivity() {} + + inline static bool is_triangles() + { return false; } + + /** assign_connectivity() method. See ArrayKernel::assign_connectivity() + for more details. */ + inline void assign_connectivity(const PolyConnectivity& _other) + { ArrayKernel::assign_connectivity(_other); } + + /** \name Adding items to a mesh + */ + //@{ + + /// Add a new vertex + inline SmartVertexHandle add_vertex(); + + /** \brief Add and connect a new face + * + * Create a new face consisting of the vertices provided by the vertex handle vector. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vhandles sorted list of vertex handles (also defines order in which the vertices are added to the face) + */ + SmartFaceHandle add_face(const std::vector& _vhandles); + + /** \brief Add and connect a new face + * + * Create a new face consisting of the vertices provided by the vertex handle vector. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vhandles sorted list of vertex handles (also defines order in which the vertices are added to the face) + */ + SmartFaceHandle add_face(const std::vector& _vhandles); + + + /** \brief Add and connect a new face + * + * Create a new face consisting of three vertices provided by the handles. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vh0 First vertex handle + * @param _vh1 Second vertex handle + * @param _vh2 Third vertex handle + */ + SmartFaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2); + + /** \brief Add and connect a new face + * + * Create a new face consisting of four vertices provided by the handles. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vh0 First vertex handle + * @param _vh1 Second vertex handle + * @param _vh2 Third vertex handle + * @param _vh3 Fourth vertex handle + */ + SmartFaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2, VertexHandle _vh3); + + /** \brief Add and connect a new face + * + * Create a new face consisting of vertices provided by a handle array. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vhandles pointer to a sorted list of vertex handles (also defines order in which the vertices are added to the face) + * @param _vhs_size number of vertex handles in the array + */ + SmartFaceHandle add_face(const VertexHandle* _vhandles, size_t _vhs_size); + + //@} + + /// \name Deleting mesh items and other connectivity/topology modifications + //@{ + + /** Returns whether collapsing halfedge _heh is ok or would lead to + topological inconsistencies. + \attention This method need the Attributes::Status attribute and + changes the \em tagged bit. */ + bool is_collapse_ok(HalfedgeHandle _he); + + + /** Mark vertex and all incident edges and faces deleted. + Items marked deleted will be removed by garbageCollection(). + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices = true); + + /** Mark edge (two opposite halfedges) and incident faces deleted. + Resulting isolated vertices are marked deleted if + _delete_isolated_vertices is true. Items marked deleted will be + removed by garbageCollection(). + + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices=true); + + /** Delete face _fh and resulting degenerated empty halfedges as + well. Resulting isolated vertices will be deleted if + _delete_isolated_vertices is true. + + \attention All item will only be marked to be deleted. They will + actually be removed by calling garbage_collection(). + + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_face(FaceHandle _fh, bool _delete_isolated_vertices=true); + + + //@} + + /** \name Navigation with smart handles to allow usage of old-style navigation with smart handles + */ + //@{ + + using ArrayKernel::next_halfedge_handle; + using ArrayKernel::prev_halfedge_handle; + using ArrayKernel::opposite_halfedge_handle; + using ArrayKernel::ccw_rotated_halfedge_handle; + using ArrayKernel::cw_rotated_halfedge_handle; + + inline SmartHalfedgeHandle next_halfedge_handle (SmartHalfedgeHandle _heh) const; + inline SmartHalfedgeHandle prev_halfedge_handle (SmartHalfedgeHandle _heh) const; + inline SmartHalfedgeHandle opposite_halfedge_handle (SmartHalfedgeHandle _heh) const; + inline SmartHalfedgeHandle ccw_rotated_halfedge_handle(SmartHalfedgeHandle _heh) const; + inline SmartHalfedgeHandle cw_rotated_halfedge_handle (SmartHalfedgeHandle _heh) const; + + using ArrayKernel::s_halfedge_handle; + using ArrayKernel::s_edge_handle; + + static SmartHalfedgeHandle s_halfedge_handle(SmartEdgeHandle _eh, unsigned int _i = 0); + static SmartEdgeHandle s_edge_handle(SmartHalfedgeHandle _heh); + + using ArrayKernel::halfedge_handle; + using ArrayKernel::edge_handle; + using ArrayKernel::face_handle; + + inline SmartHalfedgeHandle halfedge_handle(SmartEdgeHandle _eh, unsigned int _i = 0) const; + inline SmartHalfedgeHandle halfedge_handle(SmartFaceHandle _fh) const; + inline SmartHalfedgeHandle halfedge_handle(SmartVertexHandle _vh) const; + inline SmartEdgeHandle edge_handle(SmartHalfedgeHandle _heh) const; + inline SmartFaceHandle face_handle(SmartHalfedgeHandle _heh) const; + + /// returns the face handle of the opposite halfedge + inline SmartFaceHandle opposite_face_handle(HalfedgeHandle _heh) const; + + //@} + + /** \name Begin and end iterators + */ + //@{ + + /// Begin iterator for vertices + VertexIter vertices_begin(); + /// Const begin iterator for vertices + ConstVertexIter vertices_begin() const; + /// End iterator for vertices + VertexIter vertices_end(); + /// Const end iterator for vertices + ConstVertexIter vertices_end() const; + + /// Begin iterator for halfedges + HalfedgeIter halfedges_begin(); + /// Const begin iterator for halfedges + ConstHalfedgeIter halfedges_begin() const; + /// End iterator for halfedges + HalfedgeIter halfedges_end(); + /// Const end iterator for halfedges + ConstHalfedgeIter halfedges_end() const; + + /// Begin iterator for edges + EdgeIter edges_begin(); + /// Const begin iterator for edges + ConstEdgeIter edges_begin() const; + /// End iterator for edges + EdgeIter edges_end(); + /// Const end iterator for edges + ConstEdgeIter edges_end() const; + + /// Begin iterator for faces + FaceIter faces_begin(); + /// Const begin iterator for faces + ConstFaceIter faces_begin() const; + /// End iterator for faces + FaceIter faces_end(); + /// Const end iterator for faces + ConstFaceIter faces_end() const; + //@} + + + /** \name Begin for skipping iterators + */ + //@{ + + /// Begin iterator for vertices + VertexIter vertices_sbegin(); + /// Const begin iterator for vertices + ConstVertexIter vertices_sbegin() const; + + /// Begin iterator for halfedges + HalfedgeIter halfedges_sbegin(); + /// Const begin iterator for halfedges + ConstHalfedgeIter halfedges_sbegin() const; + + /// Begin iterator for edges + EdgeIter edges_sbegin(); + /// Const begin iterator for edges + ConstEdgeIter edges_sbegin() const; + + /// Begin iterator for faces + FaceIter faces_sbegin(); + /// Const begin iterator for faces + ConstFaceIter faces_sbegin() const; + + //@} + + //--- circulators --- + + /** \name Vertex, Face, and Edge circulators + */ + //@{ + + /// vertex - vertex circulator + VertexVertexIter vv_iter(VertexHandle _vh); + /// vertex - vertex circulator cw + VertexVertexCWIter vv_cwiter(VertexHandle _vh); + /// vertex - vertex circulator ccw + VertexVertexCCWIter vv_ccwiter(VertexHandle _vh); + /// vertex - incoming halfedge circulator + VertexIHalfedgeIter vih_iter(VertexHandle _vh); + /// vertex - incoming halfedge circulator cw + VertexIHalfedgeCWIter vih_cwiter(VertexHandle _vh); + /// vertex - incoming halfedge circulator ccw + VertexIHalfedgeCCWIter vih_ccwiter(VertexHandle _vh); + /// vertex - outgoing halfedge circulator + VertexOHalfedgeIter voh_iter(VertexHandle _vh); + /// vertex - outgoing halfedge circulator cw + VertexOHalfedgeCWIter voh_cwiter(VertexHandle _vh); + /// vertex - outgoing halfedge circulator ccw + VertexOHalfedgeCCWIter voh_ccwiter(VertexHandle _vh); + /// vertex - edge circulator + VertexEdgeIter ve_iter(VertexHandle _vh); + /// vertex - edge circulator cw + VertexEdgeCWIter ve_cwiter(VertexHandle _vh); + /// vertex - edge circulator ccw + VertexEdgeCCWIter ve_ccwiter(VertexHandle _vh); + /// vertex - face circulator + VertexFaceIter vf_iter(VertexHandle _vh); + /// vertex - face circulator cw + VertexFaceCWIter vf_cwiter(VertexHandle _vh); + /// vertex - face circulator ccw + VertexFaceCCWIter vf_ccwiter(VertexHandle _vh); + + /// const vertex circulator + ConstVertexVertexIter cvv_iter(VertexHandle _vh) const; + /// const vertex circulator cw + ConstVertexVertexCWIter cvv_cwiter(VertexHandle _vh) const; + /// const vertex circulator ccw + ConstVertexVertexCCWIter cvv_ccwiter(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator + ConstVertexIHalfedgeIter cvih_iter(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator cw + ConstVertexIHalfedgeCWIter cvih_cwiter(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator ccw + ConstVertexIHalfedgeCCWIter cvih_ccwiter(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator + ConstVertexOHalfedgeIter cvoh_iter(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator cw + ConstVertexOHalfedgeCWIter cvoh_cwiter(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator ccw + ConstVertexOHalfedgeCCWIter cvoh_ccwiter(VertexHandle _vh) const; + /// const vertex - edge circulator + ConstVertexEdgeIter cve_iter(VertexHandle _vh) const; + /// const vertex - edge circulator cw + ConstVertexEdgeCWIter cve_cwiter(VertexHandle _vh) const; + /// const vertex - edge circulator ccw + ConstVertexEdgeCCWIter cve_ccwiter(VertexHandle _vh) const; + /// const vertex - face circulator + ConstVertexFaceIter cvf_iter(VertexHandle _vh) const; + /// const vertex - face circulator cw + ConstVertexFaceCWIter cvf_cwiter(VertexHandle _vh) const; + /// const vertex - face circulator ccw + ConstVertexFaceCCWIter cvf_ccwiter(VertexHandle _vh) const; + + /// face - vertex circulator + FaceVertexIter fv_iter(FaceHandle _fh); + /// face - vertex circulator cw + FaceVertexCWIter fv_cwiter(FaceHandle _fh); + /// face - vertex circulator ccw + FaceVertexCCWIter fv_ccwiter(FaceHandle _fh); + /// face - halfedge circulator + FaceHalfedgeIter fh_iter(FaceHandle _fh); + /// face - halfedge circulator cw + FaceHalfedgeCWIter fh_cwiter(FaceHandle _fh); + /// face - halfedge circulator ccw + FaceHalfedgeCCWIter fh_ccwiter(FaceHandle _fh); + /// face - edge circulator + FaceEdgeIter fe_iter(FaceHandle _fh); + /// face - edge circulator cw + FaceEdgeCWIter fe_cwiter(FaceHandle _fh); + /// face - edge circulator ccw + FaceEdgeCCWIter fe_ccwiter(FaceHandle _fh); + /// face - face circulator + FaceFaceIter ff_iter(FaceHandle _fh); + /// face - face circulator cw + FaceFaceCWIter ff_cwiter(FaceHandle _fh); + /// face - face circulator ccw + FaceFaceCCWIter ff_ccwiter(FaceHandle _fh); + + /// const face - vertex circulator + ConstFaceVertexIter cfv_iter(FaceHandle _fh) const; + /// const face - vertex circulator cw + ConstFaceVertexCWIter cfv_cwiter(FaceHandle _fh) const; + /// const face - vertex circulator ccw + ConstFaceVertexCCWIter cfv_ccwiter(FaceHandle _fh) const; + /// const face - halfedge circulator + ConstFaceHalfedgeIter cfh_iter(FaceHandle _fh) const; + /// const face - halfedge circulator cw + ConstFaceHalfedgeCWIter cfh_cwiter(FaceHandle _fh) const; + /// const face - halfedge circulator ccw + ConstFaceHalfedgeCCWIter cfh_ccwiter(FaceHandle _fh) const; + /// const face - edge circulator + ConstFaceEdgeIter cfe_iter(FaceHandle _fh) const; + /// const face - edge circulator cw + ConstFaceEdgeCWIter cfe_cwiter(FaceHandle _fh) const; + /// const face - edge circulator ccw + ConstFaceEdgeCCWIter cfe_ccwiter(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceIter cff_iter(FaceHandle _fh) const; + /// const face - face circulator cw + ConstFaceFaceCWIter cff_cwiter(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceCCWIter cff_ccwiter(FaceHandle _fh) const; + + /// edge - vertex circulator + EdgeVertexIter ev_iter(EdgeHandle _eh); + /// edge - halfedge circulator + EdgeHalfedgeIter eh_iter(EdgeHandle _eh); + /// edge - face circulator + EdgeFaceIter ef_iter(EdgeHandle _eh); + + /// const edge - vertex circulator + ConstEdgeVertexIter cev_iter(EdgeHandle _eh) const; + /// const edge - halfedge circulator + ConstEdgeHalfedgeIter ceh_iter(EdgeHandle _eh) const; + /// const edge - face circulator + ConstEdgeFaceIter cef_iter(EdgeHandle _eh) const; + + // 'begin' circulators + + /// vertex - vertex circulator + VertexVertexIter vv_begin(VertexHandle _vh); + /// vertex - vertex circulator cw + VertexVertexCWIter vv_cwbegin(VertexHandle _vh); + /// vertex - vertex circulator ccw + VertexVertexCCWIter vv_ccwbegin(VertexHandle _vh); + /// vertex - incoming halfedge circulator + VertexIHalfedgeIter vih_begin(VertexHandle _vh); + /// vertex - incoming halfedge circulator cw + VertexIHalfedgeCWIter vih_cwbegin(VertexHandle _vh); + /// vertex - incoming halfedge circulator ccw + VertexIHalfedgeCCWIter vih_ccwbegin(VertexHandle _vh); + /// vertex - outgoing halfedge circulator + VertexOHalfedgeIter voh_begin(VertexHandle _vh); + /// vertex - outgoing halfedge circulator cw + VertexOHalfedgeCWIter voh_cwbegin(VertexHandle _vh); + /// vertex - outgoing halfedge circulator ccw + VertexOHalfedgeCCWIter voh_ccwbegin(VertexHandle _vh); + /// vertex - edge circulator + VertexEdgeIter ve_begin(VertexHandle _vh); + /// vertex - edge circulator cw + VertexEdgeCWIter ve_cwbegin(VertexHandle _vh); + /// vertex - edge circulator ccw + VertexEdgeCCWIter ve_ccwbegin(VertexHandle _vh); + /// vertex - face circulator + VertexFaceIter vf_begin(VertexHandle _vh); + /// vertex - face circulator cw + VertexFaceCWIter vf_cwbegin(VertexHandle _vh); + /// vertex - face circulator ccw + VertexFaceCCWIter vf_ccwbegin(VertexHandle _vh); + + + /// const vertex circulator + ConstVertexVertexIter cvv_begin(VertexHandle _vh) const; + /// const vertex circulator cw + ConstVertexVertexCWIter cvv_cwbegin(VertexHandle _vh) const; + /// const vertex circulator ccw + ConstVertexVertexCCWIter cvv_ccwbegin(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator + ConstVertexIHalfedgeIter cvih_begin(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator cw + ConstVertexIHalfedgeCWIter cvih_cwbegin(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator ccw + ConstVertexIHalfedgeCCWIter cvih_ccwbegin(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator + ConstVertexOHalfedgeIter cvoh_begin(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator cw + ConstVertexOHalfedgeCWIter cvoh_cwbegin(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator ccw + ConstVertexOHalfedgeCCWIter cvoh_ccwbegin(VertexHandle _vh) const; + /// const vertex - edge circulator + ConstVertexEdgeIter cve_begin(VertexHandle _vh) const; + /// const vertex - edge circulator cw + ConstVertexEdgeCWIter cve_cwbegin(VertexHandle _vh) const; + /// const vertex - edge circulator ccw + ConstVertexEdgeCCWIter cve_ccwbegin(VertexHandle _vh) const; + /// const vertex - face circulator + ConstVertexFaceIter cvf_begin(VertexHandle _vh) const; + /// const vertex - face circulator cw + ConstVertexFaceCWIter cvf_cwbegin(VertexHandle _vh) const; + /// const vertex - face circulator ccw + ConstVertexFaceCCWIter cvf_ccwbegin(VertexHandle _vh) const; + + /// face - vertex circulator + FaceVertexIter fv_begin(FaceHandle _fh); + /// face - vertex circulator cw + FaceVertexCWIter fv_cwbegin(FaceHandle _fh); + /// face - vertex circulator ccw + FaceVertexCCWIter fv_ccwbegin(FaceHandle _fh); + /// face - halfedge circulator + FaceHalfedgeIter fh_begin(FaceHandle _fh); + /// face - halfedge circulator cw + FaceHalfedgeCWIter fh_cwbegin(FaceHandle _fh); + /// face - halfedge circulator ccw + FaceHalfedgeCCWIter fh_ccwbegin(FaceHandle _fh); + /// face - edge circulator + FaceEdgeIter fe_begin(FaceHandle _fh); + /// face - edge circulator cw + FaceEdgeCWIter fe_cwbegin(FaceHandle _fh); + /// face - edge circulator ccw + FaceEdgeCCWIter fe_ccwbegin(FaceHandle _fh); + /// face - face circulator + FaceFaceIter ff_begin(FaceHandle _fh); + /// face - face circulator cw + FaceFaceCWIter ff_cwbegin(FaceHandle _fh); + /// face - face circulator ccw + FaceFaceCCWIter ff_ccwbegin(FaceHandle _fh); + /// halfedge circulator + HalfedgeLoopIter hl_begin(HalfedgeHandle _heh); + /// halfedge circulator + HalfedgeLoopCWIter hl_cwbegin(HalfedgeHandle _heh); + /// halfedge circulator ccw + HalfedgeLoopCCWIter hl_ccwbegin(HalfedgeHandle _heh); + + /// const face - vertex circulator + ConstFaceVertexIter cfv_begin(FaceHandle _fh) const; + /// const face - vertex circulator cw + ConstFaceVertexCWIter cfv_cwbegin(FaceHandle _fh) const; + /// const face - vertex circulator ccw + ConstFaceVertexCCWIter cfv_ccwbegin(FaceHandle _fh) const; + /// const face - halfedge circulator + ConstFaceHalfedgeIter cfh_begin(FaceHandle _fh) const; + /// const face - halfedge circulator cw + ConstFaceHalfedgeCWIter cfh_cwbegin(FaceHandle _fh) const; + /// const face - halfedge circulator ccw + ConstFaceHalfedgeCCWIter cfh_ccwbegin(FaceHandle _fh) const; + /// const face - edge circulator + ConstFaceEdgeIter cfe_begin(FaceHandle _fh) const; + /// const face - edge circulator cw + ConstFaceEdgeCWIter cfe_cwbegin(FaceHandle _fh) const; + /// const face - edge circulator ccw + ConstFaceEdgeCCWIter cfe_ccwbegin(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceIter cff_begin(FaceHandle _fh) const; + /// const face - face circulator cw + ConstFaceFaceCWIter cff_cwbegin(FaceHandle _fh) const; + /// const face - face circulator ccw + ConstFaceFaceCCWIter cff_ccwbegin(FaceHandle _fh) const; + /// const halfedge circulator + ConstHalfedgeLoopIter chl_begin(HalfedgeHandle _heh) const; + /// const halfedge circulator cw + ConstHalfedgeLoopCWIter chl_cwbegin(HalfedgeHandle _heh) const; + /// const halfedge circulator ccw + ConstHalfedgeLoopCCWIter chl_ccwbegin(HalfedgeHandle _heh) const; + + /// edge - vertex circulator + EdgeVertexIter ev_begin(EdgeHandle _eh); + /// edge - halfedge circulator + EdgeHalfedgeIter eh_begin(EdgeHandle _eh); + /// edge - face circulator + EdgeFaceIter ef_begin(EdgeHandle _eh); + + /// const edge - vertex circulator + ConstEdgeVertexIter cev_begin(EdgeHandle _eh) const; + /// const edge - halfedge circulator + ConstEdgeHalfedgeIter ceh_begin(EdgeHandle _eh) const; + /// const edge - face circulator + ConstEdgeFaceIter cef_begin(EdgeHandle _eh) const; + + // 'end' circulators + + /// vertex - vertex circulator + VertexVertexIter vv_end(VertexHandle _vh); + /// vertex - vertex circulator cw + VertexVertexCWIter vv_cwend(VertexHandle _vh); + /// vertex - vertex circulator ccw + VertexVertexCCWIter vv_ccwend(VertexHandle _vh); + /// vertex - incoming halfedge circulator + VertexIHalfedgeIter vih_end(VertexHandle _vh); + /// vertex - incoming halfedge circulator cw + VertexIHalfedgeCWIter vih_cwend(VertexHandle _vh); + /// vertex - incoming halfedge circulator ccw + VertexIHalfedgeCCWIter vih_ccwend(VertexHandle _vh); + /// vertex - outgoing halfedge circulator + VertexOHalfedgeIter voh_end(VertexHandle _vh); + /// vertex - outgoing halfedge circulator cw + VertexOHalfedgeCWIter voh_cwend(VertexHandle _vh); + /// vertex - outgoing halfedge circulator ccw + VertexOHalfedgeCCWIter voh_ccwend(VertexHandle _vh); + /// vertex - edge circulator + VertexEdgeIter ve_end(VertexHandle _vh); + /// vertex - edge circulator cw + VertexEdgeCWIter ve_cwend(VertexHandle _vh); + /// vertex - edge circulator ccw + VertexEdgeCCWIter ve_ccwend(VertexHandle _vh); + /// vertex - face circulator + VertexFaceIter vf_end(VertexHandle _vh); + /// vertex - face circulator cw + VertexFaceCWIter vf_cwend(VertexHandle _vh); + /// vertex - face circulator ccw + VertexFaceCCWIter vf_ccwend(VertexHandle _vh); + + /// const vertex circulator + ConstVertexVertexIter cvv_end(VertexHandle _vh) const; + /// const vertex circulator cw + ConstVertexVertexCWIter cvv_cwend(VertexHandle _vh) const; + /// const vertex circulator ccw + ConstVertexVertexCCWIter cvv_ccwend(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator + ConstVertexIHalfedgeIter cvih_end(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator cw + ConstVertexIHalfedgeCWIter cvih_cwend(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator ccw + ConstVertexIHalfedgeCCWIter cvih_ccwend(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator + ConstVertexOHalfedgeIter cvoh_end(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator cw + ConstVertexOHalfedgeCWIter cvoh_cwend(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator ccw + ConstVertexOHalfedgeCCWIter cvoh_ccwend(VertexHandle _vh) const; + /// const vertex - edge circulator + ConstVertexEdgeIter cve_end(VertexHandle _vh) const; + /// const vertex - edge circulator cw + ConstVertexEdgeCWIter cve_cwend(VertexHandle _vh) const; + /// const vertex - edge circulator ccw + ConstVertexEdgeCCWIter cve_ccwend(VertexHandle _vh) const; + /// const vertex - face circulator + ConstVertexFaceIter cvf_end(VertexHandle _vh) const; + /// const vertex - face circulator cw + ConstVertexFaceCWIter cvf_cwend(VertexHandle _vh) const; + /// const vertex - face circulator ccw + ConstVertexFaceCCWIter cvf_ccwend(VertexHandle _vh) const; + + /// face - vertex circulator + FaceVertexIter fv_end(FaceHandle _fh); + /// face - vertex circulator cw + FaceVertexCWIter fv_cwend(FaceHandle _fh); + /// face - vertex circulator ccw + FaceVertexCCWIter fv_ccwend(FaceHandle _fh); + /// face - halfedge circulator + FaceHalfedgeIter fh_end(FaceHandle _fh); + /// face - halfedge circulator cw + FaceHalfedgeCWIter fh_cwend(FaceHandle _fh); + /// face - halfedge circulator ccw + FaceHalfedgeCCWIter fh_ccwend(FaceHandle _fh); + /// face - edge circulator + FaceEdgeIter fe_end(FaceHandle _fh); + /// face - edge circulator cw + FaceEdgeCWIter fe_cwend(FaceHandle _fh); + /// face - edge circulator ccw + FaceEdgeCCWIter fe_ccwend(FaceHandle _fh); + /// face - face circulator + FaceFaceIter ff_end(FaceHandle _fh); + /// face - face circulator cw + FaceFaceCWIter ff_cwend(FaceHandle _fh); + /// face - face circulator ccw + FaceFaceCCWIter ff_ccwend(FaceHandle _fh); + /// face - face circulator + HalfedgeLoopIter hl_end(HalfedgeHandle _heh); + /// face - face circulator cw + HalfedgeLoopCWIter hl_cwend(HalfedgeHandle _heh); + /// face - face circulator ccw + HalfedgeLoopCCWIter hl_ccwend(HalfedgeHandle _heh); + + /// const face - vertex circulator + ConstFaceVertexIter cfv_end(FaceHandle _fh) const; + /// const face - vertex circulator cw + ConstFaceVertexCWIter cfv_cwend(FaceHandle _fh) const; + /// const face - vertex circulator ccw + ConstFaceVertexCCWIter cfv_ccwend(FaceHandle _fh) const; + /// const face - halfedge circulator + ConstFaceHalfedgeIter cfh_end(FaceHandle _fh) const; + /// const face - halfedge circulator cw + ConstFaceHalfedgeCWIter cfh_cwend(FaceHandle _fh) const; + /// const face - halfedge circulator ccw + ConstFaceHalfedgeCCWIter cfh_ccwend(FaceHandle _fh) const; + /// const face - edge circulator + ConstFaceEdgeIter cfe_end(FaceHandle _fh) const; + /// const face - edge circulator cw + ConstFaceEdgeCWIter cfe_cwend(FaceHandle _fh) const; + /// const face - edge circulator ccw + ConstFaceEdgeCCWIter cfe_ccwend(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceIter cff_end(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceCWIter cff_cwend(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceCCWIter cff_ccwend(FaceHandle _fh) const; + /// const face - face circulator + ConstHalfedgeLoopIter chl_end(HalfedgeHandle _heh) const; + /// const face - face circulator cw + ConstHalfedgeLoopCWIter chl_cwend(HalfedgeHandle _heh) const; + /// const face - face circulator ccw + ConstHalfedgeLoopCCWIter chl_ccwend(HalfedgeHandle _heh) const; + + /// edge - vertex circulator + EdgeVertexIter ev_end(EdgeHandle _eh); + /// edge - halfedge circulator + EdgeHalfedgeIter eh_end(EdgeHandle _eh); + /// edge - face circulator + EdgeFaceIter ef_end(EdgeHandle _eh); + + /// const edge - vertex circulator + ConstEdgeVertexIter cev_end(EdgeHandle _eh) const; + /// const edge - halfedge circulator + ConstEdgeHalfedgeIter ceh_end(EdgeHandle _eh) const; + /// const edge - face circulator + ConstEdgeFaceIter cef_end(EdgeHandle _eh) const; + + //@} + + /** @name Range based iterators and circulators */ + //@{ + + typedef EntityRange> ConstVertexRange; + typedef EntityRange> ConstVertexRangeSkipping; + typedef EntityRange> ConstHalfedgeRange; + typedef EntityRange> ConstHalfedgeRangeSkipping; + typedef EntityRange> ConstEdgeRange; + typedef EntityRange> ConstEdgeRangeSkipping; + typedef EntityRange> ConstFaceRange; + typedef EntityRange> ConstFaceRangeSkipping; + + + template + struct ElementRange; + + /** + * @return The vertices as a range object suitable + * for C++11 range based for loops. Will skip deleted vertices. + */ + ConstVertexRangeSkipping vertices() const; + + /** + * @return The vertices as a range object suitable + * for C++11 range based for loops. Will include deleted vertices. + */ + ConstVertexRange all_vertices() const; + + /** + * @return The halfedges as a range object suitable + * for C++11 range based for loops. Will skip deleted halfedges. + */ + ConstHalfedgeRangeSkipping halfedges() const; + + /** + * @return The halfedges as a range object suitable + * for C++11 range based for loops. Will include deleted halfedges. + */ + ConstHalfedgeRange all_halfedges() const; + + /** + * @return The edges as a range object suitable + * for C++11 range based for loops. Will skip deleted edges. + */ + ConstEdgeRangeSkipping edges() const; + + /** + * @return The edges as a range object suitable + * for C++11 range based for loops. Will include deleted edges. + */ + ConstEdgeRange all_edges() const; + + /** + * @return The faces as a range object suitable + * for C++11 range based for loops. Will skip deleted faces. + */ + ConstFaceRangeSkipping faces() const; + + /** + * @return The faces as a range object suitable + * for C++11 range based for loops. Will include deleted faces. + */ + ConstFaceRange all_faces() const; + + /** + * @return The elements corresponding to the template type as a range object suitable + * for C++11 range based for loops. Will skip deleted faces. + */ + template + typename ElementRange::RangeSkipping elements() const; + + /** + * @return The elements corresponding to the template type as a range object suitable + * for C++11 range based for loops. Will include deleted faces. + */ + template + typename ElementRange::Range all_elements() const; + + + typedef CirculatorRange> ConstVertexVertexRange; + typedef CirculatorRange> ConstVertexIHalfedgeRange; + typedef CirculatorRange> ConstVertexOHalfedgeRange; + typedef CirculatorRange> ConstVertexEdgeRange; + typedef CirculatorRange> ConstVertexFaceRange; + typedef CirculatorRange> ConstFaceVertexRange; + typedef CirculatorRange> ConstFaceHalfedgeRange; + typedef CirculatorRange> ConstFaceEdgeRange; + typedef CirculatorRange> ConstFaceFaceRange; + typedef CirculatorRange> ConstEdgeVertexRange; + typedef CirculatorRange> ConstEdgeHalfedgeRange; + typedef CirculatorRange> ConstEdgeFaceRange; + typedef CirculatorRange> ConstHalfedgeLoopRange; + + typedef CirculatorRange> ConstVertexVertexCWRange; + typedef CirculatorRange> ConstVertexIHalfedgeCWRange; + typedef CirculatorRange> ConstVertexOHalfedgeCWRange; + typedef CirculatorRange> ConstVertexEdgeCWRange; + typedef CirculatorRange> ConstVertexFaceCWRange; + typedef CirculatorRange> ConstFaceVertexCWRange; + typedef CirculatorRange> ConstFaceHalfedgeCWRange; + typedef CirculatorRange> ConstFaceEdgeCWRange; + typedef CirculatorRange> ConstFaceFaceCWRange; + typedef CirculatorRange> ConstHalfedgeLoopCWRange; + + typedef CirculatorRange> ConstVertexVertexCCWRange; + typedef CirculatorRange> ConstVertexIHalfedgeCCWRange; + typedef CirculatorRange> ConstVertexOHalfedgeCCWRange; + typedef CirculatorRange> ConstVertexEdgeCCWRange; + typedef CirculatorRange> ConstVertexFaceCCWRange; + typedef CirculatorRange> ConstFaceVertexCCWRange; + typedef CirculatorRange> ConstFaceHalfedgeCCWRange; + typedef CirculatorRange> ConstFaceEdgeCCWRange; + typedef CirculatorRange> ConstFaceFaceCCWRange; + typedef CirculatorRange> ConstHalfedgeLoopCCWRange; + + /** + * @return The vertices adjacent to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexVertexRange vv_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexIHalfedgeRange vih_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like vih_range(VertexHandle _heh.to()) but starts iteration at _heh + */ + ConstVertexIHalfedgeRange vih_range(HalfedgeHandle _heh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexOHalfedgeRange voh_range(VertexHandle _vh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like voh_range(VertexHandle _heh.from()) but starts iteration at _heh + */ + ConstVertexOHalfedgeRange voh_range(HalfedgeHandle _heh) const; + + /** + * @return The edges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexEdgeRange ve_range(VertexHandle _vh) const ; + + /** + * @return The faces incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexFaceRange vf_range(VertexHandle _vh) const; + + /** + * @return The vertices incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceVertexRange fv_range(FaceHandle _fh) const; + + /** + * @return The halfedges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceHalfedgeRange fh_range(FaceHandle _fh) const; + + /** + * @return The edges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceEdgeRange fe_range(FaceHandle _fh) const; + + /** + * @return The faces adjacent to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceFaceRange ff_range(FaceHandle _fh) const; + + /** + * @return The vertices incident to the specified edge + * as a range object suitable for C++11 range based for loops. + */ + ConstEdgeVertexRange ev_range(EdgeHandle _eh) const; + + /** + * @return The halfedges of the specified edge + * as a range object suitable for C++11 range based for loops. + */ + ConstEdgeHalfedgeRange eh_range(EdgeHandle _eh) const; + + /** + * @return The halfedges of the specified edge + * as a range object suitable for C++11 range based for loops. + * Like eh_range(_heh.edge()) but starts iteration at _heh + */ + ConstEdgeHalfedgeRange eh_range(HalfedgeHandle _heh) const; + + /** + * @return The faces incident to the specified edge + * as a range object suitable for C++11 range based for loops. + */ + ConstEdgeFaceRange ef_range(EdgeHandle _eh) const; + + /** + * @return The halfedges in the face + * as a range object suitable for C++11 range based for loops. + */ + ConstHalfedgeLoopRange hl_range(HalfedgeHandle _heh) const; + + + /** + * @return The vertices adjacent to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexVertexCWRange vv_cw_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexIHalfedgeCWRange vih_cw_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like vih_cw_range(VertexHandle _heh.to()) but starts iteration at _heh + */ + ConstVertexIHalfedgeCWRange vih_cw_range(HalfedgeHandle _heh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexOHalfedgeCWRange voh_cw_range(VertexHandle _vh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like voh_cw_range(VertexHandle _heh.from()) but starts iteration at _heh + */ + ConstVertexOHalfedgeCWRange voh_cw_range(HalfedgeHandle _heh) const; + + /** + * @return The edges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexEdgeCWRange ve_cw_range(VertexHandle _vh) const; + + /** + * @return The faces incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexFaceCWRange vf_cw_range(VertexHandle _vh) const; + + /** + * @return The vertices incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceVertexCWRange fv_cw_range(FaceHandle _fh) const; + + /** + * @return The halfedges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceHalfedgeCWRange fh_cw_range(FaceHandle _fh) const; + + /** + * @return The edges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceEdgeCWRange fe_cw_range(FaceHandle _fh) const; + + /** + * @return The faces adjacent to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceFaceCWRange ff_cw_range(FaceHandle _fh) const; + + /** + * @return The halfedges in the face + * as a range object suitable for C++11 range based for loops. + */ + ConstHalfedgeLoopCWRange hl_cw_range(HalfedgeHandle _heh) const; + + + /** + * @return The vertices adjacent to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexVertexCCWRange vv_ccw_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexIHalfedgeCCWRange vih_ccw_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like vih_ccw_range(VertexHandle _heh.to()) but starts iteration at _heh + */ + ConstVertexIHalfedgeCCWRange vih_ccw_range(HalfedgeHandle _heh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexOHalfedgeCCWRange voh_ccw_range(VertexHandle _vh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like voh_ccw_range(VertexHandle _heh.from()) but starts iteration at _heh + */ + ConstVertexOHalfedgeCCWRange voh_ccw_range(HalfedgeHandle _heh) const; + + /** + * @return The edges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexEdgeCCWRange ve_ccw_range(VertexHandle _vh) const ; + + /** + * @return The faces incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexFaceCCWRange vf_ccw_range(VertexHandle _vh) const; + + /** + * @return The vertices incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceVertexCCWRange fv_ccw_range(FaceHandle _fh) const; + + /** + * @return The halfedges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceHalfedgeCCWRange fh_ccw_range(FaceHandle _fh) const; + + /** + * @return The edges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceEdgeCCWRange fe_ccw_range(FaceHandle _fh) const; + + /** + * @return The faces adjacent to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceFaceCCWRange ff_ccw_range(FaceHandle _fh) const; + + + /** + * @return The halfedges in the face + * as a range object suitable for C++11 range based for loops. + */ + ConstHalfedgeLoopCCWRange hl_ccw_range(HalfedgeHandle _heh) const; + + //@} + + //=========================================================================== + /** @name Boundary and manifold tests + * @{ */ + //=========================================================================== + + /** \brief Check if the halfedge is at the boundary + * + * The halfedge is at the boundary, if no face is incident to it. + * + * @param _heh HalfedgeHandle to test + * @return boundary? + */ + bool is_boundary(HalfedgeHandle _heh) const + { return ArrayKernel::is_boundary(_heh); } + + /** \brief Is the edge a boundary edge? + * + * Checks it the edge _eh is a boundary edge, i.e. is one of its halfedges + * a boundary halfedge. + * + * @param _eh Edge handle to test + * @return boundary? + */ + bool is_boundary(EdgeHandle _eh) const + { + return (is_boundary(halfedge_handle(_eh, 0)) || + is_boundary(halfedge_handle(_eh, 1))); + } + + /** \brief Is vertex _vh a boundary vertex ? + * + * Checks if the associated halfedge (which would on a boundary be the outside + * halfedge), is connected to a face. Which is equivalent, if the vertex is + * at the boundary of the mesh, as OpenMesh will make sure, that if there is a + * boundary halfedge at the vertex, the halfedge will be the one which is associated + * to the vertex. + * + * @param _vh VertexHandle to test + * @return boundary? + */ + bool is_boundary(VertexHandle _vh) const + { + HalfedgeHandle heh(halfedge_handle(_vh)); + return (!(heh.is_valid() && face_handle(heh).is_valid())); + } + + /** \brief Check if face is at the boundary + * + * Is face _fh at boundary, i.e. is one of its edges (or vertices) + * a boundary edge? + * + * @param _fh Check this face + * @param _check_vertex If \c true, check the corner vertices of the face, too. + * @return boundary? + */ + bool is_boundary(FaceHandle _fh, bool _check_vertex=false) const; + + /** \brief Is (the mesh at) vertex _vh two-manifold ? + * + * The vertex is non-manifold if more than one gap exists, i.e. + * more than one outgoing boundary halfedge. If (at least) one + * boundary halfedge exists, the vertex' halfedge must be a + * boundary halfedge. + * + * @param _vh VertexHandle to test + * @return manifold? + */ + bool is_manifold(VertexHandle _vh) const; + + /** @} */ + + // --- misc --- + + /** Adjust outgoing halfedge handle for vertices, so that it is a + boundary halfedge whenever possible. + */ + void adjust_outgoing_halfedge(VertexHandle _vh); + + /// Find halfedge from _vh0 to _vh1. Returns invalid handle if not found. + SmartHalfedgeHandle find_halfedge(VertexHandle _start_vh, VertexHandle _end_vh) const; + /// Vertex valence + uint valence(VertexHandle _vh) const; + /// Face valence + uint valence(FaceHandle _fh) const; + + // --- connectivity operattions + + /** Halfedge collapse: collapse the from-vertex of halfedge _heh + into its to-vertex. + + \attention Needs vertex/edge/face status attribute in order to + delete the items that degenerate. + + \note The from vertex is marked as deleted while the to vertex will still exist. + + \note This function does not perform a garbage collection. It + only marks degenerate items as deleted. + + \attention A halfedge collapse may lead to topological inconsistencies. + Therefore you should check this using is_collapse_ok(). + */ + void collapse(HalfedgeHandle _heh); + /** return true if the this the only link between the faces adjacent to _eh. + _eh is allowed to be boundary, in which case true is returned iff _eh is + the only boundary edge of its ajdacent face. + */ + bool is_simple_link(EdgeHandle _eh) const; + /** return true if _fh shares only one edge with all of its adjacent faces. + Boundary is treated as one face, i.e., the function false if _fh has more + than one boundary edge. + */ + bool is_simply_connected(FaceHandle _fh) const; + /** Removes the edge _eh. Its adjacent faces are merged. _eh and one of the + adjacent faces are set deleted. The handle of the remaining face is + returned (InvalidFaceHandle is returned if _eh is a boundary edge). + + \pre is_simple_link(_eh). This ensures that there are no hole faces + or isolated vertices appearing in result of the operation. + + \attention Needs the Attributes::Status attribute for edges and faces. + + \note This function does not perform a garbage collection. It + only marks items as deleted. + */ + FaceHandle remove_edge(EdgeHandle _eh); + /** Inverse of remove_edge. _eh should be the handle of the edge and the + vertex and halfedge handles pointed by edge(_eh) should be valid. + */ + void reinsert_edge(EdgeHandle _eh); + /** Inserts an edge between to_vh(_prev_heh) and from_vh(_next_heh). + A new face is created started at heh0 of the inserted edge and + its halfedges loop includes both _prev_heh and _next_heh. If an + old face existed which includes the argument halfedges, it is + split at the new edge. heh0 is returned. + + \note assumes _prev_heh and _next_heh are either boundary or pointed + to the same face + */ + HalfedgeHandle insert_edge(HalfedgeHandle _prev_heh, HalfedgeHandle _next_heh); + + /** \brief Face split (= 1-to-n split). + * + * Split an arbitrary face into triangles by connecting each vertex of fh to vh. + * + * \note fh will remain valid (it will become one of the triangles) + * \note the halfedge handles of the new triangles will point to the old halfeges + * + * \note The properties of the new faces and all other new primitives will be undefined! + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle of the new vertex that will be inserted in the face + */ + void split(FaceHandle _fh, VertexHandle _vh); + + /** \brief Face split (= 1-to-n split). + * + * Split an arbitrary face into triangles by connecting each vertex of fh to vh. + * + * \note fh will remain valid (it will become one of the triangles) + * \note the halfedge handles of the new triangles will point to the old halfeges + * + * \note The properties of the new faces will be adjusted to the properties of the original faces + * \note Properties of the new edges and halfedges will be undefined + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle of the new vertex that will be inserted in the face + */ + void split_copy(FaceHandle _fh, VertexHandle _vh); + + /** \brief Triangulate the face _fh + + Split an arbitrary face into triangles by connecting + each vertex of fh after its second to vh. + + \note _fh will remain valid (it will become one of the + triangles) + + \note The halfedge handles of the new triangles will + point to the old halfedges + + @param _fh Handle of the face that should be triangulated + */ + void triangulate(FaceHandle _fh); + + /** \brief triangulate the entire mesh + */ + void triangulate(); + + /** Edge split (inserts a vertex on the edge only) + * + * This edge split only splits the edge without introducing new faces! + * As this is for polygonal meshes, we can have valence 2 vertices here. + * + * \note The properties of the new edges and halfedges will be undefined! + * + * @param _eh Handle of the edge, that will be splitted + * @param _vh Handle of the vertex that will be inserted at the edge + */ + void split_edge(EdgeHandle _eh, VertexHandle _vh); + + /** Edge split (inserts a vertex on the edge only) + * + * This edge split only splits the edge without introducing new faces! + * As this is for polygonal meshes, we can have valence 2 vertices here. + * + * \note The properties of the new edge will be copied from the splitted edge + * \note Properties of the new halfedges will be undefined + * + * @param _eh Handle of the edge, that will be splitted + * @param _vh Handle of the vertex that will be inserted at the edge + */ + void split_edge_copy(EdgeHandle _eh, VertexHandle _vh); + + + /** \name Generic handle derefertiation. + Calls the respective vertex(), halfedge(), edge(), face() + method of the mesh kernel. + */ + //@{ + /// Get item from handle + const Vertex& deref(VertexHandle _h) const { return vertex(_h); } + Vertex& deref(VertexHandle _h) { return vertex(_h); } + const Halfedge& deref(HalfedgeHandle _h) const { return halfedge(_h); } + Halfedge& deref(HalfedgeHandle _h) { return halfedge(_h); } + const Edge& deref(EdgeHandle _h) const { return edge(_h); } + Edge& deref(EdgeHandle _h) { return edge(_h); } + const Face& deref(FaceHandle _h) const { return face(_h); } + Face& deref(FaceHandle _h) { return face(_h); } + //@} + +protected: + /// Helper for halfedge collapse + void collapse_edge(HalfedgeHandle _hh); + /// Helper for halfedge collapse + void collapse_loop(HalfedgeHandle _hh); + + + +private: // Working storage for add_face() + struct AddFaceEdgeInfo + { + HalfedgeHandle halfedge_handle; + bool is_new; + bool needs_adjust; + }; + std::vector edgeData_; // + std::vector > next_cache_; // cache for set_next_halfedge and vertex' set_halfedge + +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstVertexRange; + using RangeSkipping = ConstVertexRangeSkipping; +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstHalfedgeRange; + using RangeSkipping = ConstHalfedgeRangeSkipping; +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstEdgeRange; + using RangeSkipping = ConstEdgeRangeSkipping; +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstFaceRange; + using RangeSkipping = ConstFaceRangeSkipping; +}; + +}//namespace OpenMesh + +#define OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE +#include +#include +#undef OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE + +#endif//OPENMESH_POLYCONNECTIVITY_HH diff --git a/Sources/OpenMeshCore/Core/Mesh/PolyConnectivity_inline_impl.hh b/Sources/OpenMeshCore/Core/Mesh/PolyConnectivity_inline_impl.hh new file mode 100644 index 0000000..c876b2c --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/PolyConnectivity_inline_impl.hh @@ -0,0 +1,1031 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#ifndef OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE +#error Do not include this directly, include instead PolyConnectivity.hh +#endif // OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE + +#include // To help some IDEs +#include +#include + +namespace OpenMesh { + + +inline SmartVertexHandle PolyConnectivity::add_vertex() { return make_smart(new_vertex(), *this); } + +inline SmartHalfedgeHandle PolyConnectivity::next_halfedge_handle(SmartHalfedgeHandle _heh) const { return make_smart(next_halfedge_handle(HalfedgeHandle(_heh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::prev_halfedge_handle(SmartHalfedgeHandle _heh) const { return make_smart(prev_halfedge_handle(HalfedgeHandle(_heh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::opposite_halfedge_handle(SmartHalfedgeHandle _heh) const { return make_smart(opposite_halfedge_handle(HalfedgeHandle(_heh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::ccw_rotated_halfedge_handle(SmartHalfedgeHandle _heh) const { return make_smart(ccw_rotated_halfedge_handle(HalfedgeHandle(_heh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::cw_rotated_halfedge_handle(SmartHalfedgeHandle _heh) const { return make_smart(cw_rotated_halfedge_handle(HalfedgeHandle(_heh)), *this); } + +inline SmartHalfedgeHandle PolyConnectivity::s_halfedge_handle(SmartEdgeHandle _eh, unsigned int _i) { return make_smart(ArrayKernel::s_halfedge_handle(EdgeHandle(_eh), _i), _eh.mesh()); } +inline SmartEdgeHandle PolyConnectivity::s_edge_handle(SmartHalfedgeHandle _heh) { return make_smart(ArrayKernel::s_edge_handle(HalfedgeHandle(_heh)), _heh.mesh()); } + +inline SmartHalfedgeHandle PolyConnectivity::halfedge_handle(SmartEdgeHandle _eh, unsigned int _i) const { return make_smart(halfedge_handle(EdgeHandle(_eh), _i), *this); } +inline SmartEdgeHandle PolyConnectivity::edge_handle(SmartHalfedgeHandle _heh) const { return make_smart(edge_handle(HalfedgeHandle(_heh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::halfedge_handle(SmartFaceHandle _fh) const { return make_smart(halfedge_handle(FaceHandle(_fh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::halfedge_handle(SmartVertexHandle _vh) const { return make_smart(halfedge_handle(VertexHandle(_vh)), *this); } + +inline SmartFaceHandle PolyConnectivity::face_handle(SmartHalfedgeHandle _heh) const { return make_smart(face_handle(HalfedgeHandle(_heh)), *this); } + +inline SmartFaceHandle PolyConnectivity::opposite_face_handle(HalfedgeHandle _heh) const { return make_smart(face_handle(opposite_halfedge_handle(_heh)), *this); } + + +/// Generic class for vertex/halfedge/edge/face ranges. +template +class EntityRange : public SmartRangeT, typename RangeTraitT::ITER_TYPE::SmartHandle> { + public: + typedef typename RangeTraitT::ITER_TYPE iterator; + typedef typename RangeTraitT::ITER_TYPE const_iterator; + + explicit EntityRange(typename RangeTraitT::CONTAINER_TYPE &container) : container_(container) {} + typename RangeTraitT::ITER_TYPE begin() const { return RangeTraitT::begin(container_); } + typename RangeTraitT::ITER_TYPE end() const { return RangeTraitT::end(container_); } + + private: + typename RangeTraitT::CONTAINER_TYPE &container_; +}; + +/// Generic class for iterator ranges. +template +//class CirculatorRange : public SmartRangeT, decltype (make_smart(std::declval(), std::declval()))>{ +class CirculatorRange : public SmartRangeT, typename SmartHandle::type>{ + public: + typedef typename CirculatorRangeTraitT::ITER_TYPE ITER_TYPE; + typedef typename CirculatorRangeTraitT::CENTER_ENTITY_TYPE CENTER_ENTITY_TYPE; + typedef typename CirculatorRangeTraitT::CONTAINER_TYPE CONTAINER_TYPE; + typedef ITER_TYPE iterator; + typedef ITER_TYPE const_iterator; + + CirculatorRange( + const CONTAINER_TYPE &container, + CENTER_ENTITY_TYPE center) : + container_(container), heh_() + { + auto it = CirculatorRangeTraitT::begin(container_, center); + heh_ = it.heh_; + } + + CirculatorRange( + const CONTAINER_TYPE &container, + HalfedgeHandle heh, int) : + container_(container), heh_(heh) {} + + ITER_TYPE begin() const { return CirculatorRangeTraitT::begin(container_, heh_, 1); } + ITER_TYPE end() const { return CirculatorRangeTraitT::end(container_, heh_, 1); } + + private: + const CONTAINER_TYPE &container_; + HalfedgeHandle heh_; +}; + + +inline PolyConnectivity::ConstVertexRangeSkipping PolyConnectivity::vertices() const { return ConstVertexRangeSkipping(*this); } +inline PolyConnectivity::ConstVertexRange PolyConnectivity::all_vertices() const { return ConstVertexRange(*this); } +inline PolyConnectivity::ConstHalfedgeRangeSkipping PolyConnectivity::halfedges() const { return ConstHalfedgeRangeSkipping(*this); } +inline PolyConnectivity::ConstHalfedgeRange PolyConnectivity::all_halfedges() const { return ConstHalfedgeRange(*this); } +inline PolyConnectivity::ConstEdgeRangeSkipping PolyConnectivity::edges() const { return ConstEdgeRangeSkipping(*this); } +inline PolyConnectivity::ConstEdgeRange PolyConnectivity::all_edges() const { return ConstEdgeRange(*this); } +inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::faces() const { return ConstFaceRangeSkipping(*this); } +inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_faces() const { return ConstFaceRange(*this); } + +template <> inline PolyConnectivity::ConstVertexRangeSkipping PolyConnectivity::elements() const { return vertices(); } +template <> inline PolyConnectivity::ConstVertexRange PolyConnectivity::all_elements() const { return all_vertices(); } +template <> inline PolyConnectivity::ConstHalfedgeRangeSkipping PolyConnectivity::elements() const { return halfedges(); } +template <> inline PolyConnectivity::ConstHalfedgeRange PolyConnectivity::all_elements() const { return all_halfedges(); } +template <> inline PolyConnectivity::ConstEdgeRangeSkipping PolyConnectivity::elements() const { return edges(); } +template <> inline PolyConnectivity::ConstEdgeRange PolyConnectivity::all_elements() const { return all_edges(); } +template <> inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::elements() const { return faces(); } +template <> inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_elements() const { return all_faces(); } + + +inline PolyConnectivity::ConstVertexVertexRange PolyConnectivity::vv_range(VertexHandle _vh) const { + return ConstVertexVertexRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeRange PolyConnectivity::vih_range(VertexHandle _vh) const { + return ConstVertexIHalfedgeRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeRange PolyConnectivity::vih_range(HalfedgeHandle _heh) const { + return ConstVertexIHalfedgeRange(*this, opposite_halfedge_handle(_heh), 1); +} + +inline PolyConnectivity::ConstVertexOHalfedgeRange PolyConnectivity::voh_range(VertexHandle _vh) const { + return ConstVertexOHalfedgeRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexOHalfedgeRange PolyConnectivity::voh_range(HalfedgeHandle _heh) const { + return ConstVertexOHalfedgeRange(*this, _heh, 1); +} + +inline PolyConnectivity::ConstVertexEdgeRange PolyConnectivity::ve_range(VertexHandle _vh) const { + return ConstVertexEdgeRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexFaceRange PolyConnectivity::vf_range(VertexHandle _vh) const { + return ConstVertexFaceRange(*this, _vh); +} + +inline PolyConnectivity::ConstFaceVertexRange PolyConnectivity::fv_range(FaceHandle _fh) const { + return ConstFaceVertexRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceHalfedgeRange PolyConnectivity::fh_range(FaceHandle _fh) const { + return ConstFaceHalfedgeRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceEdgeRange PolyConnectivity::fe_range(FaceHandle _fh) const { + return ConstFaceEdgeRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceFaceRange PolyConnectivity::ff_range(FaceHandle _fh) const { + return ConstFaceFaceRange(*this, _fh); +} + +inline PolyConnectivity::ConstEdgeVertexRange PolyConnectivity::ev_range(EdgeHandle _eh) const { + return ConstEdgeVertexRange(*this, _eh); +} + +inline PolyConnectivity::ConstEdgeHalfedgeRange PolyConnectivity::eh_range(EdgeHandle _eh) const { + return ConstEdgeHalfedgeRange(*this, _eh); +} + +inline PolyConnectivity::ConstEdgeHalfedgeRange PolyConnectivity::eh_range(HalfedgeHandle _heh) const { + return ConstEdgeHalfedgeRange(*this, _heh, 1); +} + +inline PolyConnectivity::ConstEdgeFaceRange PolyConnectivity::ef_range(EdgeHandle _eh) const { + return ConstEdgeFaceRange(*this, _eh); +} + +inline PolyConnectivity::ConstHalfedgeLoopRange PolyConnectivity::hl_range(HalfedgeHandle _heh) const { + return ConstHalfedgeLoopRange(*this, _heh); +} + + +inline PolyConnectivity::ConstVertexVertexCWRange PolyConnectivity::vv_cw_range(VertexHandle _vh) const { + return ConstVertexVertexCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeCWRange PolyConnectivity::vih_cw_range(VertexHandle _vh) const { + return ConstVertexIHalfedgeCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeCWRange PolyConnectivity::vih_cw_range(HalfedgeHandle _heh) const { + return ConstVertexIHalfedgeCWRange(*this, opposite_halfedge_handle(_heh), 1); +} + +inline PolyConnectivity::ConstVertexOHalfedgeCWRange PolyConnectivity::voh_cw_range(VertexHandle _vh) const { + return ConstVertexOHalfedgeCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexOHalfedgeCWRange PolyConnectivity::voh_cw_range(HalfedgeHandle _heh) const { + return ConstVertexOHalfedgeCWRange(*this, _heh, 1); +} + +inline PolyConnectivity::ConstVertexEdgeCWRange PolyConnectivity::ve_cw_range(VertexHandle _vh) const { + return ConstVertexEdgeCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexFaceCWRange PolyConnectivity::vf_cw_range(VertexHandle _vh) const { + return ConstVertexFaceCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstFaceVertexCWRange PolyConnectivity::fv_cw_range(FaceHandle _fh) const { + return ConstFaceVertexCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceHalfedgeCWRange PolyConnectivity::fh_cw_range(FaceHandle _fh) const { + return ConstFaceHalfedgeCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceEdgeCWRange PolyConnectivity::fe_cw_range(FaceHandle _fh) const { + return ConstFaceEdgeCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceFaceCWRange PolyConnectivity::ff_cw_range(FaceHandle _fh) const { + return ConstFaceFaceCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstHalfedgeLoopCWRange PolyConnectivity::hl_cw_range(HalfedgeHandle _heh) const { + return ConstHalfedgeLoopCWRange(*this, _heh); +} + + + +inline PolyConnectivity::ConstVertexVertexCCWRange PolyConnectivity::vv_ccw_range(VertexHandle _vh) const { + return ConstVertexVertexCCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeCCWRange PolyConnectivity::vih_ccw_range(VertexHandle _vh) const { + return ConstVertexIHalfedgeCCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeCCWRange PolyConnectivity::vih_ccw_range(HalfedgeHandle _heh) const { + return ConstVertexIHalfedgeCCWRange(*this, opposite_halfedge_handle(_heh), 1); +} + +inline PolyConnectivity::ConstVertexOHalfedgeCCWRange PolyConnectivity::voh_ccw_range(VertexHandle _vh) const { + return ConstVertexOHalfedgeCCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexOHalfedgeCCWRange PolyConnectivity::voh_ccw_range(HalfedgeHandle _heh) const { + return ConstVertexOHalfedgeCCWRange(*this, _heh, 1); +} + +inline PolyConnectivity::ConstVertexEdgeCCWRange PolyConnectivity::ve_ccw_range(VertexHandle _vh) const { + return ConstVertexEdgeCCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexFaceCCWRange PolyConnectivity::vf_ccw_range(VertexHandle _vh) const { + return ConstVertexFaceCCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstFaceVertexCCWRange PolyConnectivity::fv_ccw_range(FaceHandle _fh) const { + return ConstFaceVertexCCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceHalfedgeCCWRange PolyConnectivity::fh_ccw_range(FaceHandle _fh) const { + return ConstFaceHalfedgeCCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceEdgeCCWRange PolyConnectivity::fe_ccw_range(FaceHandle _fh) const { + return ConstFaceEdgeCCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceFaceCCWRange PolyConnectivity::ff_ccw_range(FaceHandle _fh) const { + return ConstFaceFaceCCWRange(*this, _fh); +} + + +inline PolyConnectivity::ConstHalfedgeLoopCCWRange PolyConnectivity::hl_ccw_range(HalfedgeHandle _heh) const { + return ConstHalfedgeLoopCCWRange(*this, _heh); +} + + + +inline PolyConnectivity::VertexIter PolyConnectivity::vertices_begin() +{ return VertexIter(*this, VertexHandle(0)); } + +inline PolyConnectivity::ConstVertexIter PolyConnectivity::vertices_begin() const +{ return ConstVertexIter(*this, VertexHandle(0)); } + +inline PolyConnectivity::VertexIter PolyConnectivity::vertices_end() +{ return VertexIter(*this, VertexHandle( int(n_vertices() ) )); } + +inline PolyConnectivity::ConstVertexIter PolyConnectivity::vertices_end() const +{ return ConstVertexIter(*this, VertexHandle( int(n_vertices()) )); } + +inline PolyConnectivity::HalfedgeIter PolyConnectivity::halfedges_begin() +{ return HalfedgeIter(*this, HalfedgeHandle(0)); } + +inline PolyConnectivity::ConstHalfedgeIter PolyConnectivity::halfedges_begin() const +{ return ConstHalfedgeIter(*this, HalfedgeHandle(0)); } + +inline PolyConnectivity::HalfedgeIter PolyConnectivity::halfedges_end() +{ return HalfedgeIter(*this, HalfedgeHandle(int(n_halfedges()))); } + +inline PolyConnectivity::ConstHalfedgeIter PolyConnectivity::halfedges_end() const +{ return ConstHalfedgeIter(*this, HalfedgeHandle(int(n_halfedges()))); } + +inline PolyConnectivity::EdgeIter PolyConnectivity::edges_begin() +{ return EdgeIter(*this, EdgeHandle(0)); } + +inline PolyConnectivity::ConstEdgeIter PolyConnectivity::edges_begin() const +{ return ConstEdgeIter(*this, EdgeHandle(0)); } + +inline PolyConnectivity::EdgeIter PolyConnectivity::edges_end() +{ return EdgeIter(*this, EdgeHandle(int(n_edges()))); } + +inline PolyConnectivity::ConstEdgeIter PolyConnectivity::edges_end() const +{ return ConstEdgeIter(*this, EdgeHandle(int(n_edges()))); } + +inline PolyConnectivity::FaceIter PolyConnectivity::faces_begin() +{ return FaceIter(*this, FaceHandle(0)); } + +inline PolyConnectivity::ConstFaceIter PolyConnectivity::faces_begin() const +{ return ConstFaceIter(*this, FaceHandle(0)); } + +inline PolyConnectivity::FaceIter PolyConnectivity::faces_end() +{ return FaceIter(*this, FaceHandle(int(n_faces()))); } + + +inline PolyConnectivity::ConstFaceIter PolyConnectivity::faces_end() const +{ return ConstFaceIter(*this, FaceHandle(int(n_faces()))); } + +inline PolyConnectivity::VertexIter PolyConnectivity::vertices_sbegin() +{ return VertexIter(*this, VertexHandle(0), true); } + +inline PolyConnectivity::ConstVertexIter PolyConnectivity::vertices_sbegin() const +{ return ConstVertexIter(*this, VertexHandle(0), true); } + +inline PolyConnectivity::HalfedgeIter PolyConnectivity::halfedges_sbegin() +{ return HalfedgeIter(*this, HalfedgeHandle(0), true); } + +inline PolyConnectivity::ConstHalfedgeIter PolyConnectivity::halfedges_sbegin() const +{ return ConstHalfedgeIter(*this, HalfedgeHandle(0), true); } + +inline PolyConnectivity::EdgeIter PolyConnectivity::edges_sbegin() +{ return EdgeIter(*this, EdgeHandle(0), true); } + +inline PolyConnectivity::ConstEdgeIter PolyConnectivity::edges_sbegin() const +{ return ConstEdgeIter(*this, EdgeHandle(0), true); } + +inline PolyConnectivity::FaceIter PolyConnectivity::faces_sbegin() +{ return FaceIter(*this, FaceHandle(0), true); } + +inline PolyConnectivity::ConstFaceIter PolyConnectivity::faces_sbegin() const +{ return ConstFaceIter(*this, FaceHandle(0), true); } + +inline PolyConnectivity::VertexVertexIter PolyConnectivity::vv_iter(ArrayKernel::VertexHandle _vh) +{ return VertexVertexIter(*this, _vh); } + +inline PolyConnectivity::VertexVertexCWIter PolyConnectivity::vv_cwiter(ArrayKernel::VertexHandle _vh) +{ return VertexVertexCWIter(*this, _vh); } + +inline PolyConnectivity::VertexVertexCCWIter PolyConnectivity::vv_ccwiter(ArrayKernel::VertexHandle _vh) +{ return VertexVertexCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeIter PolyConnectivity::vih_iter(ArrayKernel::VertexHandle _vh) +{ return VertexIHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeCWIter PolyConnectivity::vih_cwiter(ArrayKernel::VertexHandle _vh) +{ return VertexIHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeCCWIter PolyConnectivity::vih_ccwiter(ArrayKernel::VertexHandle _vh) +{ return VertexIHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeIter PolyConnectivity::voh_iter(ArrayKernel::VertexHandle _vh) +{ return VertexOHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeCWIter PolyConnectivity::voh_cwiter(ArrayKernel::VertexHandle _vh) +{ return VertexOHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeCCWIter PolyConnectivity::voh_ccwiter(ArrayKernel::VertexHandle _vh) +{ return VertexOHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeIter PolyConnectivity::ve_iter(ArrayKernel::VertexHandle _vh) +{ return VertexEdgeIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeCWIter PolyConnectivity::ve_cwiter(ArrayKernel::VertexHandle _vh) +{ return VertexEdgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeCCWIter PolyConnectivity::ve_ccwiter(ArrayKernel::VertexHandle _vh) +{ return VertexEdgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceIter PolyConnectivity::vf_iter(ArrayKernel::VertexHandle _vh) +{ return VertexFaceIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceCWIter PolyConnectivity::vf_cwiter(ArrayKernel::VertexHandle _vh) +{ return VertexFaceCWIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceCCWIter PolyConnectivity::vf_ccwiter(ArrayKernel::VertexHandle _vh) +{ return VertexFaceCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexVertexIter PolyConnectivity::cvv_iter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexVertexIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexVertexCWIter PolyConnectivity::cvv_cwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexVertexCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexVertexCCWIter PolyConnectivity::cvv_ccwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexVertexCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeIter PolyConnectivity::cvih_iter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexIHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeCWIter PolyConnectivity::cvih_cwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexIHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeCCWIter PolyConnectivity::cvih_ccwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexIHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeIter PolyConnectivity::cvoh_iter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexOHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeCWIter PolyConnectivity::cvoh_cwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexOHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeCCWIter PolyConnectivity::cvoh_ccwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexOHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeIter PolyConnectivity::cve_iter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexEdgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeCWIter PolyConnectivity::cve_cwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexEdgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeCCWIter PolyConnectivity::cve_ccwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexEdgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceIter PolyConnectivity::cvf_iter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexFaceIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceCWIter PolyConnectivity::cvf_cwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexFaceCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceCCWIter PolyConnectivity::cvf_ccwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexFaceCCWIter(*this, _vh); } + +inline PolyConnectivity::FaceVertexIter PolyConnectivity::fv_iter(ArrayKernel::FaceHandle _fh) +{ return FaceVertexIter(*this, _fh); } + +inline PolyConnectivity::FaceVertexCWIter PolyConnectivity::fv_cwiter(ArrayKernel::FaceHandle _fh) +{ return FaceVertexCWIter(*this, _fh); } + +inline PolyConnectivity::FaceVertexCCWIter PolyConnectivity::fv_ccwiter(ArrayKernel::FaceHandle _fh) +{ return FaceVertexCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeIter PolyConnectivity::fh_iter(ArrayKernel::FaceHandle _fh) +{ return FaceHalfedgeIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeCWIter PolyConnectivity::fh_cwiter(ArrayKernel::FaceHandle _fh) +{ return FaceHalfedgeCWIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeCCWIter PolyConnectivity::fh_ccwiter(ArrayKernel::FaceHandle _fh) +{ return FaceHalfedgeCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeIter PolyConnectivity::fe_iter(ArrayKernel::FaceHandle _fh) +{ return FaceEdgeIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeCWIter PolyConnectivity::fe_cwiter(ArrayKernel::FaceHandle _fh) +{ return FaceEdgeCWIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeCCWIter PolyConnectivity::fe_ccwiter(ArrayKernel::FaceHandle _fh) +{ return FaceEdgeCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceIter PolyConnectivity::ff_iter(ArrayKernel::FaceHandle _fh) +{ return FaceFaceIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceCWIter PolyConnectivity::ff_cwiter(ArrayKernel::FaceHandle _fh) +{ return FaceFaceCWIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceCCWIter PolyConnectivity::ff_ccwiter(ArrayKernel::FaceHandle _fh) +{ return FaceFaceCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceVertexIter PolyConnectivity::cfv_iter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceVertexIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceVertexCWIter PolyConnectivity::cfv_cwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceVertexCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceVertexCCWIter PolyConnectivity::cfv_ccwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceVertexCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeIter PolyConnectivity::cfh_iter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceHalfedgeIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeCWIter PolyConnectivity::cfh_cwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceHalfedgeCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeCCWIter PolyConnectivity::cfh_ccwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceHalfedgeCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeIter PolyConnectivity::cfe_iter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceEdgeIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeCWIter PolyConnectivity::cfe_cwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceEdgeCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeCCWIter PolyConnectivity::cfe_ccwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceEdgeCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceIter PolyConnectivity::cff_iter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceFaceIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceCWIter PolyConnectivity::cff_cwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceFaceCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceCCWIter PolyConnectivity::cff_ccwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceFaceCCWIter(*this, _fh); } + +inline PolyConnectivity::EdgeVertexIter PolyConnectivity::ev_iter(ArrayKernel::EdgeHandle _eh) +{ return EdgeVertexIter(*this, _eh); } + +inline PolyConnectivity::EdgeHalfedgeIter PolyConnectivity::eh_iter(ArrayKernel::EdgeHandle _eh) +{ return EdgeHalfedgeIter(*this, _eh); } + +inline PolyConnectivity::EdgeFaceIter PolyConnectivity::ef_iter(ArrayKernel::EdgeHandle _eh) +{ return EdgeFaceIter(*this, _eh); } + +inline PolyConnectivity::ConstEdgeVertexIter PolyConnectivity::cev_iter(ArrayKernel::EdgeHandle _eh) const +{ return ConstEdgeVertexIter(*this, _eh); } + +inline PolyConnectivity::ConstEdgeHalfedgeIter PolyConnectivity::ceh_iter(ArrayKernel::EdgeHandle _eh) const +{ return ConstEdgeHalfedgeIter(*this, _eh); } + +inline PolyConnectivity::ConstEdgeFaceIter PolyConnectivity::cef_iter(ArrayKernel::EdgeHandle _eh) const +{ return ConstEdgeFaceIter(*this, _eh); } + + +inline PolyConnectivity::VertexVertexIter PolyConnectivity::vv_begin(VertexHandle _vh) +{ return VertexVertexIter(*this, _vh); } + +inline PolyConnectivity::VertexVertexCWIter PolyConnectivity::vv_cwbegin(VertexHandle _vh) +{ return VertexVertexCWIter(*this, _vh); } + +inline PolyConnectivity::VertexVertexCCWIter PolyConnectivity::vv_ccwbegin(VertexHandle _vh) +{ return VertexVertexCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeIter PolyConnectivity::vih_begin(VertexHandle _vh) +{ return VertexIHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeCWIter PolyConnectivity::vih_cwbegin(VertexHandle _vh) +{ return VertexIHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeCCWIter PolyConnectivity::vih_ccwbegin(VertexHandle _vh) +{ return VertexIHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeIter PolyConnectivity::voh_begin(VertexHandle _vh) +{ return VertexOHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeCWIter PolyConnectivity::voh_cwbegin(VertexHandle _vh) +{ return VertexOHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeCCWIter PolyConnectivity::voh_ccwbegin(VertexHandle _vh) +{ return VertexOHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeIter PolyConnectivity::ve_begin(VertexHandle _vh) +{ return VertexEdgeIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeCWIter PolyConnectivity::ve_cwbegin(VertexHandle _vh) +{ return VertexEdgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeCCWIter PolyConnectivity::ve_ccwbegin(VertexHandle _vh) +{ return VertexEdgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceIter PolyConnectivity::vf_begin(VertexHandle _vh) +{ return VertexFaceIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceCWIter PolyConnectivity::vf_cwbegin(VertexHandle _vh) +{ return VertexFaceCWIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceCCWIter PolyConnectivity::vf_ccwbegin(VertexHandle _vh) +{ return VertexFaceCCWIter(*this, _vh); } + + +inline PolyConnectivity::ConstVertexVertexIter PolyConnectivity::cvv_begin(VertexHandle _vh) const +{ return ConstVertexVertexIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexVertexCWIter PolyConnectivity::cvv_cwbegin(VertexHandle _vh) const +{ return ConstVertexVertexCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexVertexCCWIter PolyConnectivity::cvv_ccwbegin(VertexHandle _vh) const +{ return ConstVertexVertexCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeIter PolyConnectivity::cvih_begin(VertexHandle _vh) const +{ return ConstVertexIHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeCWIter PolyConnectivity::cvih_cwbegin(VertexHandle _vh) const +{ return ConstVertexIHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeCCWIter PolyConnectivity::cvih_ccwbegin(VertexHandle _vh) const +{ return ConstVertexIHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeIter PolyConnectivity::cvoh_begin(VertexHandle _vh) const +{ return ConstVertexOHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeCWIter PolyConnectivity::cvoh_cwbegin(VertexHandle _vh) const +{ return ConstVertexOHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeCCWIter PolyConnectivity::cvoh_ccwbegin(VertexHandle _vh) const +{ return ConstVertexOHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeIter PolyConnectivity::cve_begin(VertexHandle _vh) const +{ return ConstVertexEdgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeCWIter PolyConnectivity::cve_cwbegin(VertexHandle _vh) const +{ return ConstVertexEdgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeCCWIter PolyConnectivity::cve_ccwbegin(VertexHandle _vh) const +{ return ConstVertexEdgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceIter PolyConnectivity::cvf_begin(VertexHandle _vh) const +{ return ConstVertexFaceIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceCWIter PolyConnectivity::cvf_cwbegin(VertexHandle _vh) const +{ return ConstVertexFaceCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceCCWIter PolyConnectivity::cvf_ccwbegin(VertexHandle _vh) const +{ return ConstVertexFaceCCWIter(*this, _vh); } + + +inline PolyConnectivity::FaceVertexIter PolyConnectivity::fv_begin(FaceHandle _fh) +{ return FaceVertexIter(*this, _fh); } + +inline PolyConnectivity::FaceVertexCWIter PolyConnectivity::fv_cwbegin(FaceHandle _fh) +{ return FaceVertexCWIter(*this, _fh); } + +inline PolyConnectivity::FaceVertexCCWIter PolyConnectivity::fv_ccwbegin(FaceHandle _fh) +{ return FaceVertexCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeIter PolyConnectivity::fh_begin(FaceHandle _fh) +{ return FaceHalfedgeIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeCWIter PolyConnectivity::fh_cwbegin(FaceHandle _fh) +{ return FaceHalfedgeCWIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeCCWIter PolyConnectivity::fh_ccwbegin(FaceHandle _fh) +{ return FaceHalfedgeCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeIter PolyConnectivity::fe_begin(FaceHandle _fh) +{ return FaceEdgeIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeCWIter PolyConnectivity::fe_cwbegin(FaceHandle _fh) +{ return FaceEdgeCWIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeCCWIter PolyConnectivity::fe_ccwbegin(FaceHandle _fh) +{ return FaceEdgeCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceIter PolyConnectivity::ff_begin(FaceHandle _fh) +{ return FaceFaceIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceCWIter PolyConnectivity::ff_cwbegin(FaceHandle _fh) +{ return FaceFaceCWIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceCCWIter PolyConnectivity::ff_ccwbegin(FaceHandle _fh) +{ return FaceFaceCCWIter(*this, _fh); } + +inline PolyConnectivity::HalfedgeLoopIter PolyConnectivity::hl_begin(HalfedgeHandle _heh) +{ return HalfedgeLoopIter(*this, _heh); } + +inline PolyConnectivity::HalfedgeLoopCWIter PolyConnectivity::hl_cwbegin(HalfedgeHandle _heh) +{ return HalfedgeLoopCWIter(*this, _heh); } + +inline PolyConnectivity::HalfedgeLoopCCWIter PolyConnectivity::hl_ccwbegin(HalfedgeHandle _heh) +{ return HalfedgeLoopCCWIter(*this, _heh); } + + +inline PolyConnectivity::ConstFaceVertexIter PolyConnectivity::cfv_begin(FaceHandle _fh) const +{ return ConstFaceVertexIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceVertexCWIter PolyConnectivity::cfv_cwbegin(FaceHandle _fh) const +{ return ConstFaceVertexCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceVertexCCWIter PolyConnectivity::cfv_ccwbegin(FaceHandle _fh) const +{ return ConstFaceVertexCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeIter PolyConnectivity::cfh_begin(FaceHandle _fh) const +{ return ConstFaceHalfedgeIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeCWIter PolyConnectivity::cfh_cwbegin(FaceHandle _fh) const +{ return ConstFaceHalfedgeCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeCCWIter PolyConnectivity::cfh_ccwbegin(FaceHandle _fh) const +{ return ConstFaceHalfedgeCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeIter PolyConnectivity::cfe_begin(FaceHandle _fh) const +{ return ConstFaceEdgeIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeCWIter PolyConnectivity::cfe_cwbegin(FaceHandle _fh) const +{ return ConstFaceEdgeCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeCCWIter PolyConnectivity::cfe_ccwbegin(FaceHandle _fh) const +{ return ConstFaceEdgeCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceIter PolyConnectivity::cff_begin(FaceHandle _fh) const +{ return ConstFaceFaceIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceCWIter PolyConnectivity::cff_cwbegin(FaceHandle _fh) const +{ return ConstFaceFaceCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceCCWIter PolyConnectivity::cff_ccwbegin(FaceHandle _fh) const +{ return ConstFaceFaceCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstHalfedgeLoopIter PolyConnectivity::chl_begin(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopIter(*this, _heh); } + +inline PolyConnectivity::ConstHalfedgeLoopCWIter PolyConnectivity::chl_cwbegin(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopCWIter(*this, _heh); } + +inline PolyConnectivity::ConstHalfedgeLoopCCWIter PolyConnectivity::chl_ccwbegin(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopCCWIter(*this, _heh); } + + +inline PolyConnectivity::EdgeVertexIter PolyConnectivity::ev_begin(EdgeHandle _eh) +{ return EdgeVertexIter(*this, _eh); } + +inline PolyConnectivity::EdgeHalfedgeIter PolyConnectivity::eh_begin(EdgeHandle _eh) +{ return EdgeHalfedgeIter(*this, _eh); } + +inline PolyConnectivity::EdgeFaceIter PolyConnectivity::ef_begin(EdgeHandle _eh) +{ return EdgeFaceIter(*this, _eh); } + + +inline PolyConnectivity::ConstEdgeVertexIter PolyConnectivity::cev_begin(EdgeHandle _eh) const +{ return ConstEdgeVertexIter(*this, _eh); } + +inline PolyConnectivity::ConstEdgeHalfedgeIter PolyConnectivity::ceh_begin(EdgeHandle _eh) const +{ return ConstEdgeHalfedgeIter(*this, _eh); } + +inline PolyConnectivity::ConstEdgeFaceIter PolyConnectivity::cef_begin(EdgeHandle _eh) const +{ return ConstEdgeFaceIter(*this, _eh); } + + +// 'end' circulators + +inline PolyConnectivity::VertexVertexIter PolyConnectivity::vv_end(VertexHandle _vh) +{ return VertexVertexIter(*this, _vh, true); } + +inline PolyConnectivity::VertexVertexCWIter PolyConnectivity::vv_cwend(VertexHandle _vh) +{ return VertexVertexCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexVertexCCWIter PolyConnectivity::vv_ccwend(VertexHandle _vh) +{ return VertexVertexCCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexIHalfedgeIter PolyConnectivity::vih_end(VertexHandle _vh) +{ return VertexIHalfedgeIter(*this, _vh, true); } + +inline PolyConnectivity::VertexIHalfedgeCWIter PolyConnectivity::vih_cwend(VertexHandle _vh) +{ return VertexIHalfedgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexIHalfedgeCCWIter PolyConnectivity::vih_ccwend(VertexHandle _vh) +{ return VertexIHalfedgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexOHalfedgeIter PolyConnectivity::voh_end(VertexHandle _vh) +{ return VertexOHalfedgeIter(*this, _vh, true); } + +inline PolyConnectivity::VertexOHalfedgeCWIter PolyConnectivity::voh_cwend(VertexHandle _vh) +{ return VertexOHalfedgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexOHalfedgeCCWIter PolyConnectivity::voh_ccwend(VertexHandle _vh) +{ return VertexOHalfedgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexEdgeIter PolyConnectivity::ve_end(VertexHandle _vh) +{ return VertexEdgeIter(*this, _vh, true); } + +inline PolyConnectivity::VertexEdgeCWIter PolyConnectivity::ve_cwend(VertexHandle _vh) +{ return VertexEdgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexEdgeCCWIter PolyConnectivity::ve_ccwend(VertexHandle _vh) +{ return VertexEdgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexFaceIter PolyConnectivity::vf_end(VertexHandle _vh) +{ return VertexFaceIter(*this, _vh, true); } + +inline PolyConnectivity::VertexFaceCWIter PolyConnectivity::vf_cwend(VertexHandle _vh) +{ return VertexFaceCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexFaceCCWIter PolyConnectivity::vf_ccwend(VertexHandle _vh) +{ return VertexFaceCCWIter(*this, _vh, true); } + + +inline PolyConnectivity::ConstVertexVertexIter PolyConnectivity::cvv_end(VertexHandle _vh) const +{ return ConstVertexVertexIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexVertexCWIter PolyConnectivity::cvv_cwend(VertexHandle _vh) const +{ return ConstVertexVertexCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexVertexCCWIter PolyConnectivity::cvv_ccwend(VertexHandle _vh) const +{ return ConstVertexVertexCCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexIHalfedgeIter PolyConnectivity::cvih_end(VertexHandle _vh) const +{ return ConstVertexIHalfedgeIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexIHalfedgeCWIter PolyConnectivity::cvih_cwend(VertexHandle _vh) const +{ return ConstVertexIHalfedgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexIHalfedgeCCWIter PolyConnectivity::cvih_ccwend(VertexHandle _vh) const +{ return ConstVertexIHalfedgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexOHalfedgeIter PolyConnectivity::cvoh_end(VertexHandle _vh) const +{ return ConstVertexOHalfedgeIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexOHalfedgeCWIter PolyConnectivity::cvoh_cwend(VertexHandle _vh) const +{ return ConstVertexOHalfedgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexOHalfedgeCCWIter PolyConnectivity::cvoh_ccwend(VertexHandle _vh) const +{ return ConstVertexOHalfedgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexEdgeIter PolyConnectivity::cve_end(VertexHandle _vh) const +{ return ConstVertexEdgeIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexEdgeCWIter PolyConnectivity::cve_cwend(VertexHandle _vh) const +{ return ConstVertexEdgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexEdgeCCWIter PolyConnectivity::cve_ccwend(VertexHandle _vh) const +{ return ConstVertexEdgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexFaceIter PolyConnectivity::cvf_end(VertexHandle _vh) const +{ return ConstVertexFaceIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexFaceCWIter PolyConnectivity::cvf_cwend(VertexHandle _vh) const +{ return ConstVertexFaceCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexFaceCCWIter PolyConnectivity::cvf_ccwend(VertexHandle _vh) const +{ return ConstVertexFaceCCWIter(*this, _vh, true); } + + +inline PolyConnectivity::FaceVertexIter PolyConnectivity::fv_end(FaceHandle _fh) +{ return FaceVertexIter(*this, _fh, true); } + +inline PolyConnectivity::FaceVertexCWIter PolyConnectivity::fv_cwend(FaceHandle _fh) +{ return FaceVertexCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceVertexCCWIter PolyConnectivity::fv_ccwend(FaceHandle _fh) +{ return FaceVertexCCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceHalfedgeIter PolyConnectivity::fh_end(FaceHandle _fh) +{ return FaceHalfedgeIter(*this, _fh, true); } + +inline PolyConnectivity::FaceHalfedgeCWIter PolyConnectivity::fh_cwend(FaceHandle _fh) +{ return FaceHalfedgeCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceHalfedgeCCWIter PolyConnectivity::fh_ccwend(FaceHandle _fh) +{ return FaceHalfedgeCCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceEdgeIter PolyConnectivity::fe_end(FaceHandle _fh) +{ return FaceEdgeIter(*this, _fh, true); } + +inline PolyConnectivity::FaceEdgeCWIter PolyConnectivity::fe_cwend(FaceHandle _fh) +{ return FaceEdgeCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceEdgeCCWIter PolyConnectivity::fe_ccwend(FaceHandle _fh) +{ return FaceEdgeCCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceFaceIter PolyConnectivity::ff_end(FaceHandle _fh) +{ return FaceFaceIter(*this, _fh, true); } + +inline PolyConnectivity::FaceFaceCWIter PolyConnectivity::ff_cwend(FaceHandle _fh) +{ return FaceFaceCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceFaceCCWIter PolyConnectivity::ff_ccwend(FaceHandle _fh) +{ return FaceFaceCCWIter(*this, _fh, true); } + +inline PolyConnectivity::HalfedgeLoopIter PolyConnectivity::hl_end(HalfedgeHandle _heh) +{ return HalfedgeLoopIter(*this, _heh, true); } + +inline PolyConnectivity::HalfedgeLoopCWIter PolyConnectivity::hl_cwend(HalfedgeHandle _heh) +{ return HalfedgeLoopCWIter(*this, _heh, true); } + +inline PolyConnectivity::HalfedgeLoopCCWIter PolyConnectivity::hl_ccwend(HalfedgeHandle _heh) +{ return HalfedgeLoopCCWIter(*this, _heh, true); } + + +inline PolyConnectivity::ConstFaceVertexIter PolyConnectivity::cfv_end(FaceHandle _fh) const +{ return ConstFaceVertexIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceVertexCWIter PolyConnectivity::cfv_cwend(FaceHandle _fh) const +{ return ConstFaceVertexCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceVertexCCWIter PolyConnectivity::cfv_ccwend(FaceHandle _fh) const +{ return ConstFaceVertexCCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceHalfedgeIter PolyConnectivity::cfh_end(FaceHandle _fh) const +{ return ConstFaceHalfedgeIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceHalfedgeCWIter PolyConnectivity::cfh_cwend(FaceHandle _fh) const +{ return ConstFaceHalfedgeCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceHalfedgeCCWIter PolyConnectivity::cfh_ccwend(FaceHandle _fh) const +{ return ConstFaceHalfedgeCCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceEdgeIter PolyConnectivity::cfe_end(FaceHandle _fh) const +{ return ConstFaceEdgeIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceEdgeCWIter PolyConnectivity::cfe_cwend(FaceHandle _fh) const +{ return ConstFaceEdgeCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceEdgeCCWIter PolyConnectivity::cfe_ccwend(FaceHandle _fh) const +{ return ConstFaceEdgeCCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceFaceIter PolyConnectivity::cff_end(FaceHandle _fh) const +{ return ConstFaceFaceIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceFaceCWIter PolyConnectivity::cff_cwend(FaceHandle _fh) const +{ return ConstFaceFaceCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceFaceCCWIter PolyConnectivity::cff_ccwend(FaceHandle _fh) const +{ return ConstFaceFaceCCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstHalfedgeLoopIter PolyConnectivity::chl_end(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopIter(*this, _heh, true); } + +inline PolyConnectivity::ConstHalfedgeLoopCWIter PolyConnectivity::chl_cwend(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopCWIter(*this, _heh, true); } + +inline PolyConnectivity::ConstHalfedgeLoopCCWIter PolyConnectivity::chl_ccwend(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopCCWIter(*this, _heh, true); } + + +inline PolyConnectivity::EdgeVertexIter PolyConnectivity::ev_end(EdgeHandle _eh) +{ return EdgeVertexIter(*this, _eh, true); } + +inline PolyConnectivity::EdgeHalfedgeIter PolyConnectivity::eh_end(EdgeHandle _eh) +{ return EdgeHalfedgeIter(*this, _eh, true); } + +inline PolyConnectivity::EdgeFaceIter PolyConnectivity::ef_end(EdgeHandle _eh) +{ return EdgeFaceIter(*this, _eh, true); } + + +inline PolyConnectivity::ConstEdgeVertexIter PolyConnectivity::cev_end(EdgeHandle _eh) const +{ return ConstEdgeVertexIter(*this, _eh, true); } + +inline PolyConnectivity::ConstEdgeHalfedgeIter PolyConnectivity::ceh_end(EdgeHandle _eh) const +{ return ConstEdgeHalfedgeIter(*this, _eh, true); } + +inline PolyConnectivity::ConstEdgeFaceIter PolyConnectivity::cef_end(EdgeHandle _eh) const +{ return ConstEdgeFaceIter(*this, _eh, true); } + + +inline PolyConnectivity::ConstVertexFaceRange SmartVertexHandle::faces() const { assert(mesh() != nullptr); return mesh()->vf_range (*this); } +inline PolyConnectivity::ConstVertexFaceCWRange SmartVertexHandle::faces_cw() const { assert(mesh() != nullptr); return mesh()->vf_cw_range (*this); } +inline PolyConnectivity::ConstVertexFaceCCWRange SmartVertexHandle::faces_ccw() const { assert(mesh() != nullptr); return mesh()->vf_ccw_range(*this); } + +inline PolyConnectivity::ConstVertexEdgeRange SmartVertexHandle::edges() const { assert(mesh() != nullptr); return mesh()->ve_range (*this); } +inline PolyConnectivity::ConstVertexEdgeCWRange SmartVertexHandle::edges_cw() const { assert(mesh() != nullptr); return mesh()->ve_cw_range (*this); } +inline PolyConnectivity::ConstVertexEdgeCCWRange SmartVertexHandle::edges_ccw() const { assert(mesh() != nullptr); return mesh()->ve_ccw_range(*this); } + +inline PolyConnectivity::ConstVertexVertexRange SmartVertexHandle::vertices() const { assert(mesh() != nullptr); return mesh()->vv_range (*this); } +inline PolyConnectivity::ConstVertexVertexCWRange SmartVertexHandle::vertices_cw() const { assert(mesh() != nullptr); return mesh()->vv_cw_range (*this); } +inline PolyConnectivity::ConstVertexVertexCCWRange SmartVertexHandle::vertices_ccw() const { assert(mesh() != nullptr); return mesh()->vv_ccw_range (*this); } + +inline PolyConnectivity::ConstVertexIHalfedgeRange SmartVertexHandle::incoming_halfedges() const { assert(mesh() != nullptr); return mesh()->vih_range (*this); } +inline PolyConnectivity::ConstVertexIHalfedgeCWRange SmartVertexHandle::incoming_halfedges_cw() const { assert(mesh() != nullptr); return mesh()->vih_cw_range (*this); } +inline PolyConnectivity::ConstVertexIHalfedgeCCWRange SmartVertexHandle::incoming_halfedges_ccw() const { assert(mesh() != nullptr); return mesh()->vih_ccw_range(*this); } + +inline PolyConnectivity::ConstVertexIHalfedgeRange SmartVertexHandle::incoming_halfedges (HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->vih_range (_heh); } +inline PolyConnectivity::ConstVertexIHalfedgeCWRange SmartVertexHandle::incoming_halfedges_cw (HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->vih_cw_range (_heh); } +inline PolyConnectivity::ConstVertexIHalfedgeCCWRange SmartVertexHandle::incoming_halfedges_ccw(HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->vih_ccw_range(_heh); } + +inline PolyConnectivity::ConstVertexOHalfedgeRange SmartVertexHandle::outgoing_halfedges() const { assert(mesh() != nullptr); return mesh()->voh_range (*this); } +inline PolyConnectivity::ConstVertexOHalfedgeCWRange SmartVertexHandle::outgoing_halfedges_cw() const { assert(mesh() != nullptr); return mesh()->voh_cw_range (*this); } +inline PolyConnectivity::ConstVertexOHalfedgeCCWRange SmartVertexHandle::outgoing_halfedges_ccw() const { assert(mesh() != nullptr); return mesh()->voh_ccw_range(*this); } + +inline PolyConnectivity::ConstVertexOHalfedgeRange SmartVertexHandle::outgoing_halfedges (HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->voh_range (_heh); } +inline PolyConnectivity::ConstVertexOHalfedgeCWRange SmartVertexHandle::outgoing_halfedges_cw (HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->voh_cw_range (_heh); } +inline PolyConnectivity::ConstVertexOHalfedgeCCWRange SmartVertexHandle::outgoing_halfedges_ccw(HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->voh_ccw_range(_heh); } + + +inline PolyConnectivity::ConstHalfedgeLoopRange SmartHalfedgeHandle::loop() const { assert(mesh() != nullptr); return mesh()->hl_range (*this); } +inline PolyConnectivity::ConstHalfedgeLoopCWRange SmartHalfedgeHandle::loop_cw() const { assert(mesh() != nullptr); return mesh()->hl_cw_range (*this); } +inline PolyConnectivity::ConstHalfedgeLoopCCWRange SmartHalfedgeHandle::loop_ccw() const { assert(mesh() != nullptr); return mesh()->hl_ccw_range (*this); } + + +inline PolyConnectivity::ConstFaceVertexRange SmartFaceHandle::vertices() const { assert(mesh() != nullptr); return mesh()->fv_range (*this); } +inline PolyConnectivity::ConstFaceVertexCWRange SmartFaceHandle::vertices_cw() const { assert(mesh() != nullptr); return mesh()->fv_cw_range (*this); } +inline PolyConnectivity::ConstFaceVertexCCWRange SmartFaceHandle::vertices_ccw() const { assert(mesh() != nullptr); return mesh()->fv_ccw_range(*this); } + +inline PolyConnectivity::ConstFaceHalfedgeRange SmartFaceHandle::halfedges() const { assert(mesh() != nullptr); return mesh()->fh_range (*this); } +inline PolyConnectivity::ConstFaceHalfedgeCWRange SmartFaceHandle::halfedges_cw() const { assert(mesh() != nullptr); return mesh()->fh_cw_range (*this); } +inline PolyConnectivity::ConstFaceHalfedgeCCWRange SmartFaceHandle::halfedges_ccw() const { assert(mesh() != nullptr); return mesh()->fh_ccw_range(*this); } + +inline PolyConnectivity::ConstFaceEdgeRange SmartFaceHandle::edges() const { assert(mesh() != nullptr); return mesh()->fe_range (*this); } +inline PolyConnectivity::ConstFaceEdgeCWRange SmartFaceHandle::edges_cw() const { assert(mesh() != nullptr); return mesh()->fe_cw_range (*this); } +inline PolyConnectivity::ConstFaceEdgeCCWRange SmartFaceHandle::edges_ccw() const { assert(mesh() != nullptr); return mesh()->fe_ccw_range(*this); } + +inline PolyConnectivity::ConstFaceFaceRange SmartFaceHandle::faces() const { assert(mesh() != nullptr); return mesh()->ff_range (*this); } +inline PolyConnectivity::ConstFaceFaceCWRange SmartFaceHandle::faces_cw() const { assert(mesh() != nullptr); return mesh()->ff_cw_range (*this); } +inline PolyConnectivity::ConstFaceFaceCCWRange SmartFaceHandle::faces_ccw() const { assert(mesh() != nullptr); return mesh()->ff_ccw_range(*this); } + + +inline PolyConnectivity::ConstEdgeVertexRange SmartEdgeHandle::vertices() const { assert(mesh() != nullptr); return mesh()->ev_range (*this); } + +inline PolyConnectivity::ConstEdgeHalfedgeRange SmartEdgeHandle::halfedges() const { assert(mesh() != nullptr); return mesh()->eh_range (*this); } + +inline PolyConnectivity::ConstEdgeHalfedgeRange SmartEdgeHandle::halfedges(HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->eh_range (_heh); } + +inline PolyConnectivity::ConstEdgeFaceRange SmartEdgeHandle::faces() const { assert(mesh() != nullptr); return mesh()->ef_range (*this); } + +}//namespace OpenMesh diff --git a/Sources/OpenMeshCore/Core/Mesh/PolyMeshT.hh b/Sources/OpenMeshCore/Core/Mesh/PolyMeshT.hh new file mode 100644 index 0000000..757c58e --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/PolyMeshT.hh @@ -0,0 +1,664 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS PolyMeshT +// +//============================================================================= + + +#ifndef OPENMESH_POLYMESHT_HH +#define OPENMESH_POLYMESHT_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + + +/** \class PolyMeshT PolyMeshT.hh + + Base type for a polygonal mesh. + + This is the base class for a polygonal mesh. It is parameterized + by a mesh kernel that is given as a template argument. This class + inherits all methods from its mesh kernel. + + \param Kernel: template argument for the mesh kernel + \note You should use the predefined mesh-kernel combinations in + \ref mesh_types_group + \see \ref mesh_type +*/ + +template +class PolyMeshT : public Kernel +{ +public: + + /// Self type. Used to specify iterators/circulators. + typedef PolyMeshT This; + //--- item types --- + + //@{ + /// Determine whether this is a PolyMeshT or TriMeshT (This function does not check the per face vertex count! It only checks if the datatype is PolyMeshT or TriMeshT) + static constexpr bool is_polymesh() { return true; } + static constexpr bool is_trimesh() { return false; } + using ConnectivityTag = PolyConnectivityTag; + enum { IsPolyMesh = 1 }; + enum { IsTriMesh = 0 }; + //@} + + /// \name Mesh Items + //@{ + /// Scalar type + typedef typename Kernel::Scalar Scalar; + /// Coordinate type + typedef typename Kernel::Point Point; + /// Normal type + typedef typename Kernel::Normal Normal; + /// Color type + typedef typename Kernel::Color Color; + /// TexCoord1D type + typedef typename Kernel::TexCoord1D TexCoord1D; + /// TexCoord2D type + typedef typename Kernel::TexCoord2D TexCoord2D; + /// TexCoord3D type + typedef typename Kernel::TexCoord3D TexCoord3D; + /// Vertex type + typedef typename Kernel::Vertex Vertex; + /// Halfedge type + typedef typename Kernel::Halfedge Halfedge; + /// Edge type + typedef typename Kernel::Edge Edge; + /// Face type + typedef typename Kernel::Face Face; + //@} + + //--- handle types --- + + /// Handle for referencing the corresponding item + typedef typename Kernel::VertexHandle VertexHandle; + typedef typename Kernel::HalfedgeHandle HalfedgeHandle; + typedef typename Kernel::EdgeHandle EdgeHandle; + typedef typename Kernel::FaceHandle FaceHandle; + + + + typedef typename Kernel::VertexIter VertexIter; + typedef typename Kernel::HalfedgeIter HalfedgeIter; + typedef typename Kernel::EdgeIter EdgeIter; + typedef typename Kernel::FaceIter FaceIter; + + typedef typename Kernel::ConstVertexIter ConstVertexIter; + typedef typename Kernel::ConstHalfedgeIter ConstHalfedgeIter; + typedef typename Kernel::ConstEdgeIter ConstEdgeIter; + typedef typename Kernel::ConstFaceIter ConstFaceIter; + //@} + + //--- circulators --- + + /** \name Mesh Circulators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators + for documentation. + */ + //@{ + /// Circulator + typedef typename Kernel::VertexVertexIter VertexVertexIter; + typedef typename Kernel::VertexOHalfedgeIter VertexOHalfedgeIter; + typedef typename Kernel::VertexIHalfedgeIter VertexIHalfedgeIter; + typedef typename Kernel::VertexEdgeIter VertexEdgeIter; + typedef typename Kernel::VertexFaceIter VertexFaceIter; + typedef typename Kernel::FaceVertexIter FaceVertexIter; + typedef typename Kernel::FaceHalfedgeIter FaceHalfedgeIter; + typedef typename Kernel::FaceEdgeIter FaceEdgeIter; + typedef typename Kernel::FaceFaceIter FaceFaceIter; + + typedef typename Kernel::ConstVertexVertexIter ConstVertexVertexIter; + typedef typename Kernel::ConstVertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef typename Kernel::ConstVertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef typename Kernel::ConstVertexEdgeIter ConstVertexEdgeIter; + typedef typename Kernel::ConstVertexFaceIter ConstVertexFaceIter; + typedef typename Kernel::ConstFaceVertexIter ConstFaceVertexIter; + typedef typename Kernel::ConstFaceHalfedgeIter ConstFaceHalfedgeIter; + typedef typename Kernel::ConstFaceEdgeIter ConstFaceEdgeIter; + typedef typename Kernel::ConstFaceFaceIter ConstFaceFaceIter; + //@} + + + // --- constructor/destructor + PolyMeshT() {} + template + explicit PolyMeshT(const T& t) : Kernel(t) {} + virtual ~PolyMeshT() {} + + /** Uses default copy and assignment operator. + Use them to assign two meshes of \b equal type. + If the mesh types vary, use PolyMeshT::assign() instead. */ + + // --- creation --- + + /** + * \brief Adds a new default-initialized vertex. + * + * \sa new_vertex(const Point&), new_vertex_dirty() + */ + inline SmartVertexHandle new_vertex() + { return make_smart(Kernel::new_vertex(), this); } + + /** + * \brief Adds a new vertex initialized to a custom position. + * + * \sa new_vertex(), new_vertex_dirty() + * + */ + inline SmartVertexHandle new_vertex(const Point _p) + { + VertexHandle vh(Kernel::new_vertex()); + this->set_point(vh, _p); + return make_smart(vh, this); + } + + /** + * Same as new_vertex(const Point&) but never shrinks, only enlarges the + * vertex property vectors. + * + * If you are rebuilding a mesh that you erased with ArrayKernel::clean() or + * ArrayKernel::clean_keep_reservation() using this method instead of + * new_vertex(const Point &) saves reallocation and reinitialization of + * property memory. + * + * \sa new_vertex(const Point ) + */ + inline SmartVertexHandle new_vertex_dirty(const Point _p) + { + VertexHandle vh(Kernel::new_vertex_dirty()); + this->set_point(vh, _p); + return make_smart(vh, this); + } + + /** Alias for new_vertex(const Point&). + * + */ + inline SmartVertexHandle add_vertex(const Point _p) + { return new_vertex(_p); } + + /// Alias for new_vertex_dirty(). + inline SmartVertexHandle add_vertex_dirty(const Point _p) + { return make_smart(new_vertex_dirty(_p), this); } + + // --- normal vectors --- + + /** \name Normal vector computation + */ + //@{ + + /** \brief Compute normals for all primitives + * + * Calls update_face_normals() , update_halfedge_normals() and update_vertex_normals() if + * the normals (i.e. the properties) exist. + * + * \note Face normals are required to compute vertex and halfedge normals! + */ + void update_normals(); + + /// Update normal for face _fh + void update_normal(FaceHandle _fh) + { this->set_normal(_fh, calc_face_normal(_fh)); } + + /** \brief Update normal vectors for all faces. + * + * \attention Needs the Attributes::Normal attribute for faces. + * Call request_face_normals() before using it! + */ + void update_face_normals(); + + /** Calculate normal vector for face _fh. */ + virtual Normal calc_face_normal(FaceHandle _fh) const; + + /** Calculate normal vector for face (_p0, _p1, _p2). */ + Normal calc_face_normal(const Point& _p0, const Point& _p1, + const Point& _p2) const; + + /// same as calc_face_normal + Normal calc_normal(FaceHandle _fh) const; + + /// calculates the average of the vertices defining _fh + void calc_face_centroid(FaceHandle _fh, Point& _pt) const { + _pt = calc_face_centroid(_fh); + } + + /// Computes and returns the average of the vertices defining _fh + Point calc_face_centroid(FaceHandle _fh) const; + + /// Computes and returns the average of the vertices defining _fh (same as calc_face_centroid) + Point calc_centroid(FaceHandle _fh) const; + + /// Computes and returns the average of the vertices defining _eh (same as calc_edge_midpoint) + Point calc_centroid(EdgeHandle _eh) const; + + /// Computes and returns the average of the vertices defining _heh (same as calc_edge_midpoint for edge of halfedge) + Point calc_centroid(HalfedgeHandle _heh) const; + + /// Returns the point of _vh + Point calc_centroid(VertexHandle _vh) const; + + /// Computes and returns the average of the vertices defining the mesh + Point calc_centroid(MeshHandle _mh) const; + + /// Update normal for halfedge _heh + void update_normal(HalfedgeHandle _heh, const double _feature_angle = 0.8) + { this->set_normal(_heh, calc_halfedge_normal(_heh,_feature_angle)); } + + /** \brief Update normal vectors for all halfedges. + * + * Uses the existing face normals to compute halfedge normals + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and halfedges. + * Call request_face_normals() and request_halfedge_normals() before using it! + */ + void update_halfedge_normals(const double _feature_angle = 0.8); + + /** \brief Calculate halfedge normal for one specific halfedge + * + * Calculate normal vector for halfedge _heh. + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and vertices. + * Call request_face_normals() and request_halfedge_normals() before using it! + * + * @param _heh Handle of the halfedge + * @param _feature_angle If the dihedral angle across this edge is greater than this value, the edge is considered as a feature edge (angle in radians) + */ + virtual Normal calc_halfedge_normal(HalfedgeHandle _heh, const double _feature_angle = 0.8) const; + + /// same as calc_halfedge_normal + Normal calc_normal(HalfedgeHandle, const double _feature_angle = 0.8) const; + + /** identifies feature edges w.r.t. the minimal dihedral angle for feature edges (in radians) */ + /** and the status feature tag */ + bool is_estimated_feature_edge(HalfedgeHandle _heh, const double _feature_angle) const; + + /// Update normal for vertex _vh + void update_normal(VertexHandle _vh) + { this->set_normal(_vh, calc_vertex_normal(_vh)); } + + /** \brief Update normal vectors for all vertices. + * + * Uses existing face normals to calculate new vertex normals. + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and vertices. + * Call request_face_normals() and request_vertex_normals() before using it! + */ + void update_vertex_normals(); + + /** \brief Calculate vertex normal for one specific vertex + * + * Calculate normal vector for vertex _vh by averaging normals + * of adjacent faces. + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and vertices. + * Call request_face_normals() and request_vertex_normals() before using it! + * + * @param _vh Handle of the vertex + */ + Normal calc_vertex_normal(VertexHandle _vh) const; + + /** Different methods for calculation of the normal at _vh: + - ..._fast - the default one - the same as calc vertex_normal() + - needs the Attributes::Normal attribute for faces + - ..._correct - works properly for non-triangular meshes + - does not need any attributes + - ..._loop - calculates loop surface normals + - does not need any attributes */ + void calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const; + void calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const; + void calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const; + + /// same as calc_vertex_normal_correct + Normal calc_normal(VertexHandle _vh) const; + + //@} + + // --- Geometry API - still in development --- + + /** Calculates the edge vector as the vector defined by + the halfedge with id #0 (see below) */ + void calc_edge_vector(EdgeHandle _eh, Normal& _edge_vec) const + { + _edge_vec = calc_edge_vector(_eh); + } + + /** Calculates the edge vector as the vector defined by + the halfedge with id #0 (see below) */ + Normal calc_edge_vector(EdgeHandle _eh) const + { + return calc_edge_vector(this->halfedge_handle(_eh,0)); + } + + /** Calculates the edge vector as the difference of the + the points defined by to_vertex_handle() and from_vertex_handle() */ + void calc_edge_vector(HalfedgeHandle _heh, Normal& _edge_vec) const + { + _edge_vec = calc_edge_vector(_heh); + } + + /** Calculates the edge vector as the difference of the + the points defined by to_vertex_handle() and from_vertex_handle() */ + Normal calc_edge_vector(HalfedgeHandle _heh) const + { + return this->point(this->to_vertex_handle(_heh)) - + this->point(this->from_vertex_handle(_heh)); + } + + // Calculates the length of the edge _eh + Scalar calc_edge_length(EdgeHandle _eh) const + { return calc_edge_length(this->halfedge_handle(_eh,0)); } + + /** Calculates the length of the edge _heh + */ + Scalar calc_edge_length(HalfedgeHandle _heh) const + { return (Scalar)sqrt(calc_edge_sqr_length(_heh)); } + + Scalar calc_edge_sqr_length(EdgeHandle _eh) const + { return calc_edge_sqr_length(this->halfedge_handle(_eh,0)); } + + Scalar calc_edge_sqr_length(HalfedgeHandle _heh) const + { + Normal edge_vec; + calc_edge_vector(_heh, edge_vec); + return sqrnorm(edge_vec); + } + + /** Calculates the midpoint of the halfedge _heh, defined by the positions of + the two incident vertices */ + Point calc_edge_midpoint(HalfedgeHandle _heh) const + { + VertexHandle vh0 = this->from_vertex_handle(_heh); + VertexHandle vh1 = this->to_vertex_handle(_heh); + return 0.5 * (this->point(vh0) + this->point(vh1)); + } + + /** Calculates the midpoint of the edge _eh, defined by the positions of the + two incident vertices */ + Point calc_edge_midpoint(EdgeHandle _eh) const + { + return calc_edge_midpoint(this->halfedge_handle(_eh, 0)); + } + + /// calculated and returns the average of the two vertex normals + Normal calc_normal(EdgeHandle _eh) const; + + /** defines a consistent representation of a sector geometry: + the halfedge _in_heh defines the sector orientation + the vertex pointed by _in_heh defines the sector center + _vec0 and _vec1 are resp. the first and the second vectors defining the sector */ + void calc_sector_vectors(HalfedgeHandle _in_heh, Normal& _vec0, Normal& _vec1) const + { + calc_edge_vector(this->next_halfedge_handle(_in_heh), _vec0);//p2 - p1 + calc_edge_vector(this->opposite_halfedge_handle(_in_heh), _vec1);//p0 - p1 + } + + /** calculates the sector angle.\n + * The vertex pointed by _in_heh defines the sector center + * The angle will be calculated between the given halfedge and the next halfedge.\n + * Seen from the center vertex this will be the next halfedge in clockwise direction.\n + NOTE: only boundary concave sectors are treated correctly */ + Scalar calc_sector_angle(HalfedgeHandle _in_heh) const + { + Normal v0, v1; + calc_sector_vectors(_in_heh, v0, v1); + Scalar denom = norm(v0)*norm(v1); + if ( denom == Scalar(0)) + { + return 0; + } + Scalar cos_a = dot(v0 , v1) / denom; + if (this->is_boundary(_in_heh)) + {//determine if the boundary sector is concave or convex + FaceHandle fh(this->face_handle(this->opposite_halfedge_handle(_in_heh))); + Normal f_n(calc_face_normal(fh));//this normal is (for convex fh) OK + Scalar sign_a = dot(cross(v0, v1), f_n); + return angle(cos_a, sign_a); + } + else + { + return acos(sane_aarg(cos_a)); + } + } + + // calculate the cos and the sin of angle <(_in_heh,next_halfedge(_in_heh)) + /* + void calc_sector_angle_cos_sin(HalfedgeHandle _in_heh, Scalar& _cos_a, Scalar& _sin_a) const + { + Normal in_vec, out_vec; + calc_edge_vector(_in_heh, in_vec); + calc_edge_vector(next_halfedge_handle(_in_heh), out_vec); + Scalar denom = norm(in_vec)*norm(out_vec); + if (is_zero(denom)) + { + _cos_a = 1; + _sin_a = 0; + } + else + { + _cos_a = dot(in_vec, out_vec)/denom; + _sin_a = norm(cross(in_vec, out_vec))/denom; + } + } + */ + /** calculates the normal (non-normalized) of the face sector defined by + the angle <(_in_heh,next_halfedge(_in_heh)) */ + void calc_sector_normal(HalfedgeHandle _in_heh, Normal& _sector_normal) const + { + Normal vec0, vec1; + calc_sector_vectors(_in_heh, vec0, vec1); + _sector_normal = cross(vec0, vec1);//(p2-p1)^(p0-p1) + } + + /** calculates the area of the face sector defined by + the angle <(_in_heh,next_halfedge(_in_heh)) + NOTE: special cases (e.g. concave sectors) are not handled correctly */ + Scalar calc_sector_area(HalfedgeHandle _in_heh) const + { + Normal sector_normal; + calc_sector_normal(_in_heh, sector_normal); + return norm(sector_normal)/2; + } + + /** calculates the dihedral angle on the halfedge _heh + \attention Needs the Attributes::Normal attribute for faces */ + Scalar calc_dihedral_angle_fast(HalfedgeHandle _heh) const + { + // Make sure that we have face normals on the mesh + assert(Kernel::has_face_normals()); + + if (this->is_boundary(this->edge_handle(_heh))) + {//the dihedral angle at a boundary edge is 0 + return 0; + } + const Normal& n0 = this->normal(this->face_handle(_heh)); + const Normal& n1 = this->normal(this->face_handle(this->opposite_halfedge_handle(_heh))); + Normal he; + calc_edge_vector(_heh, he); + Scalar da_cos = dot(n0, n1); + //should be normalized, but we need only the sign + Scalar da_sin_sign = dot(cross(n0, n1), he); + return angle(da_cos, da_sin_sign); + } + + /** calculates the dihedral angle on the edge _eh + \attention Needs the Attributes::Normal attribute for faces */ + Scalar calc_dihedral_angle_fast(EdgeHandle _eh) const + { return calc_dihedral_angle_fast(this->halfedge_handle(_eh,0)); } + + // calculates the dihedral angle on the halfedge _heh + Scalar calc_dihedral_angle(HalfedgeHandle _heh) const + { + if (this->is_boundary(this->edge_handle(_heh))) + {//the dihedral angle at a boundary edge is 0 + return 0; + } + Normal n0, n1, he; + calc_sector_normal(_heh, n0); + calc_sector_normal(this->opposite_halfedge_handle(_heh), n1); + calc_edge_vector(_heh, he); + Scalar denom = norm(n0)*norm(n1); + if (denom == Scalar(0)) + { + return 0; + } + Scalar da_cos = dot(n0, n1)/denom; + //should be normalized, but we need only the sign + Scalar da_sin_sign = dot(cross(n0, n1), he); + return angle(da_cos, da_sin_sign); + } + + // calculates the dihedral angle on the edge _eh + Scalar calc_dihedral_angle(EdgeHandle _eh) const + { return calc_dihedral_angle(this->halfedge_handle(_eh,0)); } + + /** tags an edge as a feature if its dihedral angle is larger than _angle_tresh + returns the number of the found feature edges, requires edge_status property*/ + unsigned int find_feature_edges(Scalar _angle_tresh = OpenMesh::deg_to_rad(44.0)); + // --- misc --- + + /// Face split (= 1-to-n split) + inline void split(FaceHandle _fh, const Point& _p) + { Kernel::split(_fh, add_vertex(_p)); } + + inline void split(FaceHandle _fh, VertexHandle _vh) + { Kernel::split(_fh, _vh); } + + inline void split(EdgeHandle _eh, const Point& _p) + { Kernel::split_edge(_eh, add_vertex(_p)); } + + inline void split(EdgeHandle _eh, VertexHandle _vh) + { Kernel::split_edge(_eh, _vh); } + +private: + struct PointIs3DTag {}; + struct PointIsNot3DTag {}; + Normal calc_face_normal_impl(FaceHandle, PointIs3DTag) const; + Normal calc_face_normal_impl(FaceHandle, PointIsNot3DTag) const; + Normal calc_face_normal_impl(const Point&, const Point&, const Point&, PointIs3DTag) const; + Normal calc_face_normal_impl(const Point&, const Point&, const Point&, PointIsNot3DTag) const; +}; + +/** + * @brief Cast a mesh with different but identical traits into each other. + * + * Example: + * @code{.cpp} + * struct TriTraits1 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits2 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits3 : public OpenMesh::DefaultTraits { + * typedef Vec3f Point; + * }; + * + * TriMesh_ArrayKernelT a; + * TriMesh_ArrayKernelT &b = mesh_cast&>(a); // OK + * TriMesh_ArrayKernelT &c = mesh_cast&>(a); // ERROR + * @endcode + * + * @see MeshCast + * + * @param rhs + * @return + */ +template +LHS mesh_cast(PolyMeshT &rhs) { + return MeshCast&>::cast(rhs); +} + +template +LHS mesh_cast(PolyMeshT *rhs) { + return MeshCast*>::cast(rhs); +} + +template +const LHS mesh_cast(const PolyMeshT &rhs) { + return MeshCast&>::cast(rhs); +} + +template +const LHS mesh_cast(const PolyMeshT *rhs) { + return MeshCast*>::cast(rhs); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_POLYMESH_C) +# define OPENMESH_POLYMESH_TEMPLATES +# include "PolyMeshT_impl.hh" +#endif +//============================================================================= +#endif // OPENMESH_POLYMESHT_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/PolyMeshT_impl.hh b/Sources/OpenMeshCore/Core/Mesh/PolyMeshT_impl.hh new file mode 100644 index 0000000..5026a36 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/PolyMeshT_impl.hh @@ -0,0 +1,582 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS PolyMeshT - IMPLEMENTATION +// +//============================================================================= + + +#define OPENMESH_POLYMESH_C + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +//== IMPLEMENTATION ========================================================== + +template +uint PolyMeshT::find_feature_edges(Scalar _angle_tresh) +{ + assert(Kernel::has_edge_status());//this function needs edge status property + uint n_feature_edges = 0; + for (EdgeIter e_it = Kernel::edges_begin(); e_it != Kernel::edges_end(); ++e_it) + { + if (fabs(calc_dihedral_angle(*e_it)) > _angle_tresh) + {//note: could be optimized by comparing cos(dih_angle) vs. cos(_angle_tresh) + this->status(*e_it).set_feature(true); + n_feature_edges++; + } + else + { + this->status(*e_it).set_feature(false); + } + } + return n_feature_edges; +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal(FaceHandle _fh) const +{ + return calc_face_normal_impl(_fh, typename GenProg::IF< + vector_traits::Point>::size_ == 3, + PointIs3DTag, + PointIsNot3DTag + >::Result()); +} + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal_impl(FaceHandle _fh, PointIs3DTag) const +{ + assert(this->halfedge_handle(_fh).is_valid()); + ConstFaceVertexIter fv_it(this->cfv_iter(_fh)); + + // Safeguard for 1-gons + if (!(++fv_it).is_valid()) return Normal(0, 0, 0); + + // Safeguard for 2-gons + if (!(++fv_it).is_valid()) return Normal(0, 0, 0); + + // use Newell's Method to compute the surface normal + Normal n(0,0,0); + for(fv_it = this->cfv_iter(_fh); fv_it.is_valid(); ++fv_it) + { + // next vertex + ConstFaceVertexIter fv_itn = fv_it; + ++fv_itn; + + if (!fv_itn.is_valid()) + fv_itn = this->cfv_iter(_fh); + + // http://www.opengl.org/wiki/Calculating_a_Surface_Normal + const Point a = this->point(*fv_it) - this->point(*fv_itn); + const Point b = this->point(*fv_it) + this->point(*fv_itn); + + + // Due to traits, the value types of normals and points can be different. + // Therefore we cast them here. + n[0] += static_cast::value_type>(a[1] * b[2]); + n[1] += static_cast::value_type>(a[2] * b[0]); + n[2] += static_cast::value_type>(a[0] * b[1]); + } + + const typename vector_traits::value_type length = norm(n); + + // The expression ((n *= (1.0/norm)),n) is used because the OpenSG + // vector class does not return self after component-wise + // self-multiplication with a scalar!!! + return (length != typename vector_traits::value_type(0)) + ? ((n *= (typename vector_traits::value_type(1)/length)), n) + : Normal(0, 0, 0); +} + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal_impl(FaceHandle, PointIsNot3DTag) const +{ + // Dummy fallback implementation + // Returns just an initialized all 0 normal + // This function is only used if we don't have a matching implementation + // for normal computation with the current vector type defined in the mesh traits + + assert(false); + + Normal normal; + vectorize(normal,Scalar(0)); + return normal; +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_face_normal(const Point& _p0, + const Point& _p1, + const Point& _p2) const +{ + return calc_face_normal_impl(_p0, _p1, _p2, typename GenProg::IF< + vector_traits::Point>::size_ == 3, + PointIs3DTag, + PointIsNot3DTag + >::Result()); +} + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_normal(FaceHandle _fh) const +{ + return calc_face_normal(_fh); +} + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_face_normal_impl(const Point& _p0, + const Point& _p1, + const Point& _p2, + PointIs3DTag) const +{ +#if 1 + // The OpenSG ::operator -= () does not support the type Point + // as rhs. Therefore use vector_cast at this point!!! + // Note! OpenSG distinguishes between Normal and Point!!! + Normal p1p0(vector_cast(_p0)); p1p0 -= vector_cast(_p1); + Normal p1p2(vector_cast(_p2)); p1p2 -= vector_cast(_p1); + + Normal n = cross(p1p2, p1p0); + typename vector_traits::value_type length = norm(n); + + // The expression ((n *= (1.0/norm)),n) is used because the OpenSG + // vector class does not return self after component-wise + // self-multiplication with a scalar!!! + return (length != typename vector_traits::value_type(0)) + ? ((n *= (typename vector_traits::value_type(1)/length)),n) + : Normal(0,0,0); +#else + Point p1p0 = _p0; p1p0 -= _p1; + Point p1p2 = _p2; p1p2 -= _p1; + + Normal n = vector_cast(cross(p1p2, p1p0)); + typename vector_traits::value_type length = norm(n); + + return (length != 0.0) ? n *= (1.0/length) : Normal(0,0,0); +#endif +} + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal_impl(const Point&, const Point&, const Point&, PointIsNot3DTag) const +{ + + // Dummy fallback implementation + // Returns just an initialized all 0 normal + // This function is only used if we don't have a matching implementation + // for normal computation with the current vector type defined in the mesh traits + + assert(false); + + Normal normal; + vectorize(normal,Scalar(0)); + return normal; +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_face_centroid(FaceHandle _fh) const +{ + Point _pt; + vectorize(_pt, Scalar(0)); + Scalar valence = 0.0; + for (ConstFaceVertexIter cfv_it = this->cfv_iter(_fh); cfv_it.is_valid(); ++cfv_it, valence += 1.0) + { + _pt += this->point(*cfv_it); + } + _pt /= valence; + return _pt; +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_centroid(FaceHandle _fh) const +{ + return calc_face_centroid(_fh); +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_centroid(EdgeHandle _eh) const +{ + return this->calc_edge_midpoint(_eh); +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_centroid(HalfedgeHandle _heh) const +{ + return this->calc_edge_midpoint(this->edge_handle(_heh)); +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_centroid(VertexHandle _vh) const +{ + return this->point(_vh); +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_centroid(MeshHandle /*_mh*/) const +{ + return this->vertices().avg([this](VertexHandle vh) { return this->point(vh); }); +} + +//----------------------------------------------------------------------------- + +template +void +PolyMeshT:: +update_normals() +{ + // Face normals are required to compute the vertex and the halfedge normals + if (Kernel::has_face_normals() ) { + update_face_normals(); + + if (Kernel::has_vertex_normals() ) update_vertex_normals(); + if (Kernel::has_halfedge_normals()) update_halfedge_normals(); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_face_normals() +{ + FaceIter f_it(Kernel::faces_sbegin()), f_end(Kernel::faces_end()); + + for (; f_it != f_end; ++f_it) + this->set_normal(*f_it, calc_face_normal(*f_it)); +} + + +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_halfedge_normals(const double _feature_angle) +{ + HalfedgeIter h_it(Kernel::halfedges_begin()), h_end(Kernel::halfedges_end()); + + for (; h_it != h_end; ++h_it) + this->set_normal(*h_it, calc_halfedge_normal(*h_it, _feature_angle)); +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_halfedge_normal(HalfedgeHandle _heh, const double _feature_angle) const +{ + if(Kernel::is_boundary(_heh)) + return Normal(0,0,0); + else + { + std::vector fhs; fhs.reserve(10); + + HalfedgeHandle heh = _heh; + + // collect CW face-handles + do + { + fhs.push_back(Kernel::face_handle(heh)); + + heh = Kernel::next_halfedge_handle(heh); + heh = Kernel::opposite_halfedge_handle(heh); + } + while(heh != _heh && !Kernel::is_boundary(heh) && !is_estimated_feature_edge(heh, _feature_angle)); + + // collect CCW face-handles + if(heh != _heh && !is_estimated_feature_edge(_heh, _feature_angle)) + { + heh = Kernel::opposite_halfedge_handle(_heh); + + if ( !Kernel::is_boundary(heh) ) { + do + { + + fhs.push_back(Kernel::face_handle(heh)); + + heh = Kernel::prev_halfedge_handle(heh); + heh = Kernel::opposite_halfedge_handle(heh); + } + while(!Kernel::is_boundary(heh) && !is_estimated_feature_edge(heh, _feature_angle)); + } + } + + Normal n(0,0,0); + for (unsigned int i = 0; i < fhs.size(); ++i) + n += Kernel::has_face_normals() ? Kernel::normal(fhs[i]) : calc_face_normal(fhs[i]); + + return normalize(n); + } +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_normal(HalfedgeHandle _heh, const double _feature_angle) const +{ + return calc_halfedge_normal(_heh, _feature_angle); +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_normal(EdgeHandle _eh) const +{ + Normal n(0, 0, 0); + for (int i = 0; i < 2; ++i) + { + const auto heh = this->halfedge_handle(_eh, i); + const auto fh = this->face_handle(heh); + if (fh.is_valid()) + n += calc_normal(fh); + } + const auto length = norm(n); + if (length != 0) + n /= length; + return n; +} + +//----------------------------------------------------------------------------- + + +template +bool +PolyMeshT:: +is_estimated_feature_edge(HalfedgeHandle _heh, const double _feature_angle) const +{ + EdgeHandle eh = Kernel::edge_handle(_heh); + + if(Kernel::has_edge_status()) + { + if(Kernel::status(eh).feature()) + return true; + } + + if(Kernel::is_boundary(eh)) + return false; + + // compute angle between faces + FaceHandle fh0 = Kernel::face_handle(_heh); + FaceHandle fh1 = Kernel::face_handle(Kernel::opposite_halfedge_handle(_heh)); + + Normal fn0 = Kernel::has_face_normals() ? Kernel::normal(fh0) : calc_face_normal(fh0); + Normal fn1 = Kernel::has_face_normals() ? Kernel::normal(fh1) : calc_face_normal(fh1); + + // dihedral angle above angle threshold + return ( dot(fn0,fn1) < cos(_feature_angle) ); +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_vertex_normal(VertexHandle _vh) const +{ + Normal n; + calc_vertex_normal_fast(_vh,n); + + Scalar length = norm(n); + if (length != 0.0) n *= (Scalar(1.0)/length); + + return n; +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const +{ + vectorize(_n, Scalar(0)); + for (ConstVertexFaceIter vf_it = this->cvf_iter(_vh); vf_it.is_valid(); ++vf_it) + _n += this->normal(*vf_it); +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const +{ + vectorize(_n, Scalar(0)); + ConstVertexIHalfedgeIter cvih_it = this->cvih_iter(_vh); + if (! cvih_it.is_valid() ) + {//don't crash on isolated vertices + return; + } + Normal in_he_vec; + calc_edge_vector(*cvih_it, in_he_vec); + for ( ; cvih_it.is_valid(); ++cvih_it) + {//calculates the sector normal defined by cvih_it and adds it to _n + if (this->is_boundary(*cvih_it)) + { + continue; + } + HalfedgeHandle out_heh(this->next_halfedge_handle(*cvih_it)); + Normal out_he_vec; + calc_edge_vector(out_heh, out_he_vec); + _n += cross(in_he_vec, out_he_vec);//sector area is taken into account + in_he_vec = out_he_vec; + in_he_vec *= -1;//change the orientation + } + Scalar length = norm(_n); + if (length != 0.0) + _n *= (Scalar(1.0)/length); +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const +{ + static const LoopSchemeMaskDouble& loop_scheme_mask__ = + LoopSchemeMaskDoubleSingleton::Instance(); + + Normal t_v(0.0,0.0,0.0), t_w(0.0,0.0,0.0); + unsigned int vh_val = this->valence(_vh); + unsigned int i = 0; + for (ConstVertexOHalfedgeIter cvoh_it = this->cvoh_iter(_vh); cvoh_it.is_valid(); ++cvoh_it, ++i) + { + VertexHandle r1_v( this->to_vertex_handle(*cvoh_it) ); + t_v += (typename vector_traits::value_type)(loop_scheme_mask__.tang0_weight(vh_val, i))*this->point(r1_v); + t_w += (typename vector_traits::value_type)(loop_scheme_mask__.tang1_weight(vh_val, i))*this->point(r1_v); + } + _n = cross(t_w, t_v);//hack: should be cross(t_v, t_w), but then the normals are reversed? +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_normal(VertexHandle _vh) const +{ + Normal n; + calc_vertex_normal_correct(_vh, n); + return n; +} + +//----------------------------------------------------------------------------- + +template +void +PolyMeshT:: +update_vertex_normals() +{ + VertexIter v_it(Kernel::vertices_begin()), v_end(Kernel::vertices_end()); + + for (; v_it!=v_end; ++v_it) + this->set_normal(*v_it, calc_vertex_normal(*v_it)); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/PolyMesh_ArrayKernelT.hh b/Sources/OpenMeshCore/Core/Mesh/PolyMesh_ArrayKernelT.hh new file mode 100644 index 0000000..bb20234 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/PolyMesh_ArrayKernelT.hh @@ -0,0 +1,113 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS PolyMesh_ArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_POLY_MESH_ARRAY_KERNEL_HH +#define OPENMESH_POLY_MESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +template +class TriMesh_ArrayKernelT; +//== CLASS DEFINITION ========================================================= + +/// Helper class to build a PolyMesh-type +template +struct PolyMesh_ArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef PolyMeshT Mesh; +}; + + +/** \class PolyMesh_ArrayKernelT PolyMesh_ArrayKernelT.hh + + \ingroup mesh_types_group + Polygonal mesh based on the ArrayKernel. + \see OpenMesh::PolyMeshT + \see OpenMesh::ArrayKernel +*/ +template +class PolyMesh_ArrayKernelT + : public PolyMesh_ArrayKernel_GeneratorT::Mesh +{ +public: + PolyMesh_ArrayKernelT() {} + template + explicit PolyMesh_ArrayKernelT( const TriMesh_ArrayKernelT & t) + { + //assign the connectivity and standard properties + this->assign(t, true); + + } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_POLY_MESH_ARRAY_KERNEL_HH +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/SmartHandles.hh b/Sources/OpenMeshCore/Core/Mesh/SmartHandles.hh new file mode 100644 index 0000000..409b685 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/SmartHandles.hh @@ -0,0 +1,484 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#ifndef OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE +#error Do not include this directly, include instead PolyConnectivity.hh +#endif//OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== FORWARD DECLARATION ====================================================== + +struct SmartVertexHandle; +struct SmartHalfedgeHandle; +struct SmartEdgeHandle; +struct SmartFaceHandle; + + +//== CLASS DEFINITION ========================================================= + +/// Base class for all smart handle types +class OPENMESHDLLEXPORT SmartBaseHandle +{ +public: + explicit SmartBaseHandle(const PolyConnectivity* _mesh = nullptr) : mesh_(_mesh) {} + + /// Get the underlying mesh of this handle + const PolyConnectivity* mesh() const { return mesh_; } + + // TODO: should operators ==, !=, < look at mesh_? + +private: + const PolyConnectivity* mesh_; + +}; + +/// Base class for all smart handle types that contains status related methods +template +class SmartHandleStatusPredicates +{ +public: + /// Returns true iff the handle is marked as feature + bool feature() const; + /// Returns true iff the handle is marked as selected + bool selected() const; + /// Returns true iff the handle is marked as tagged + bool tagged() const; + /// Returns true iff the handle is marked as tagged2 + bool tagged2() const; + /// Returns true iff the handle is marked as locked + bool locked() const; + /// Returns true iff the handle is marked as hidden + bool hidden() const; + /// Returns true iff the handle is marked as deleted + bool deleted() const; +}; + +/// Base class for all smart handle types that contains status related methods +template +class SmartHandleBoundaryPredicate +{ +public: + /// Returns true iff the handle is boundary + bool is_boundary() const; +}; + +/// Smart version of VertexHandle contains a pointer to the corresponding mesh and allows easier access to navigation methods +struct OPENMESHDLLEXPORT SmartVertexHandle : public SmartBaseHandle, VertexHandle, SmartHandleStatusPredicates, SmartHandleBoundaryPredicate +{ + explicit SmartVertexHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), VertexHandle(_idx) {} + + /// Returns an outgoing halfedge + SmartHalfedgeHandle out() const; + /// Returns an outgoing halfedge + SmartHalfedgeHandle halfedge() const; // alias for out + /// Returns an incoming halfedge + SmartHalfedgeHandle in() const; + + /// Returns a range of faces incident to the vertex (PolyConnectivity::vf_range()) + PolyConnectivity::ConstVertexFaceRange faces() const; + /// Returns a range of faces incident to the vertex (PolyConnectivity::vf_cw_range()) + PolyConnectivity::ConstVertexFaceCWRange faces_cw() const; + /// Returns a range of faces incident to the vertex (PolyConnectivity::vf_ccw_range()) + PolyConnectivity::ConstVertexFaceCCWRange faces_ccw() const; + /// Returns a range of edges incident to the vertex (PolyConnectivity::ve_range()) + PolyConnectivity::ConstVertexEdgeRange edges() const; + /// Returns a range of edges incident to the vertex (PolyConnectivity::ve_cw_range()) + PolyConnectivity::ConstVertexEdgeCWRange edges_cw() const; + /// Returns a range of edges incident to the vertex (PolyConnectivity::ve_ccw_range()) + PolyConnectivity::ConstVertexEdgeCCWRange edges_ccw() const; + /// Returns a range of vertices adjacent to the vertex (PolyConnectivity::vv_range()) + PolyConnectivity::ConstVertexVertexRange vertices() const; + /// Returns a range of vertices adjacent to the vertex (PolyConnectivity::vv_cw_range()) + PolyConnectivity::ConstVertexVertexCWRange vertices_cw() const; + /// Returns a range of vertices adjacent to the vertex (PolyConnectivity::vv_ccw_range()) + PolyConnectivity::ConstVertexVertexCCWRange vertices_ccw() const; + /// Returns a range of outgoing halfedges incident to the vertex (PolyConnectivity::voh_range()) + PolyConnectivity::ConstVertexIHalfedgeRange incoming_halfedges() const; + /// Returns a range of outgoing halfedges incident to the vertex (PolyConnectivity::voh_cw_range()) + PolyConnectivity::ConstVertexIHalfedgeCWRange incoming_halfedges_cw() const; + /// Returns a range of outgoing halfedges incident to the vertex (PolyConnectivity::voh_ccw_range()) + PolyConnectivity::ConstVertexIHalfedgeCCWRange incoming_halfedges_ccw() const; + /// Returns a range of outgoing halfedges incident to the vertex (PolyConnectivity::vih_range()) + PolyConnectivity::ConstVertexIHalfedgeRange incoming_halfedges(HalfedgeHandle _heh) const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::vih_cw_range()) + PolyConnectivity::ConstVertexIHalfedgeCWRange incoming_halfedges_cw(HalfedgeHandle _heh) const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::vih_ccw_range()) + PolyConnectivity::ConstVertexIHalfedgeCCWRange incoming_halfedges_ccw(HalfedgeHandle _heh) const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_range()) + PolyConnectivity::ConstVertexOHalfedgeRange outgoing_halfedges() const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_cw_range()) + PolyConnectivity::ConstVertexOHalfedgeCWRange outgoing_halfedges_cw() const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_ccw_range()) + PolyConnectivity::ConstVertexOHalfedgeCCWRange outgoing_halfedges_ccw() const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_range()) + PolyConnectivity::ConstVertexOHalfedgeRange outgoing_halfedges(HalfedgeHandle _heh) const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_cw_range()) + PolyConnectivity::ConstVertexOHalfedgeCWRange outgoing_halfedges_cw(HalfedgeHandle _heh) const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_ccw_range()) + PolyConnectivity::ConstVertexOHalfedgeCCWRange outgoing_halfedges_ccw(HalfedgeHandle _heh) const; + + /// Returns valence of the vertex + uint valence() const; + /// Returns true iff (the mesh at) the vertex is two-manifold ? + bool is_manifold() const; +}; + +struct OPENMESHDLLEXPORT SmartHalfedgeHandle : public SmartBaseHandle, HalfedgeHandle, SmartHandleStatusPredicates, SmartHandleBoundaryPredicate +{ + explicit SmartHalfedgeHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), HalfedgeHandle(_idx) {} + + /// Returns next halfedge handle + SmartHalfedgeHandle next() const; + /// Returns previous halfedge handle + SmartHalfedgeHandle prev() const; + /// Returns opposite halfedge handle + SmartHalfedgeHandle opp() const; + /// Returns vertex pointed to by halfedge + SmartVertexHandle to() const; + /// Returns vertex at start of halfedge + SmartVertexHandle from() const; + /// Returns incident edge of halfedge + SmartEdgeHandle edge() const; + /// Returns incident face of halfedge + SmartFaceHandle face() const; + + /// Returns a range of halfedges in the face of the halfedge (or along the boundary) (PolyConnectivity::hl_range()) + PolyConnectivity::ConstHalfedgeLoopRange loop() const; + /// Returns a range of halfedges in the face of the halfedge (or along the boundary) (PolyConnectivity::hl_cw_range()) + PolyConnectivity::ConstHalfedgeLoopCWRange loop_cw() const; + /// Returns a range of halfedges in the face of the halfedge (or along the boundary) (PolyConnectivity::hl_ccw_range()) + PolyConnectivity::ConstHalfedgeLoopCCWRange loop_ccw() const; +}; + +struct OPENMESHDLLEXPORT SmartEdgeHandle : public SmartBaseHandle, EdgeHandle, SmartHandleStatusPredicates, SmartHandleBoundaryPredicate +{ + explicit SmartEdgeHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), EdgeHandle(_idx) {} + + /// Returns one of the two halfedges of the edge + SmartHalfedgeHandle halfedge(unsigned int _i) const; + /// Shorthand for halfedge() + SmartHalfedgeHandle h(unsigned int _i) const; + /// Shorthand for halfedge(0) + SmartHalfedgeHandle h0() const; + /// Shorthand for halfedge(1) + SmartHalfedgeHandle h1() const; + /// Returns one of the two incident vertices of the edge + SmartVertexHandle vertex(unsigned int _i) const; + /// Shorthand for vertex() + SmartVertexHandle v(unsigned int _i) const; + /// Shorthand for vertex(0) + SmartVertexHandle v0() const; + /// Shorthand for vertex(1) + SmartVertexHandle v1() const; + + /// Returns a range of vertices incident to the edge (PolyConnectivity::ev_range()) + PolyConnectivity::ConstEdgeVertexRange vertices() const; + /// Returns a range of halfedges of the edge (PolyConnectivity::eh_range()) + PolyConnectivity::ConstEdgeHalfedgeRange halfedges() const; + /// Returns a range of halfedges of the edge (PolyConnectivity::eh_range()) + PolyConnectivity::ConstEdgeHalfedgeRange halfedges(HalfedgeHandle _heh) const; + /// Returns a range of faces incident to the edge (PolyConnectivity::ef_range()) + PolyConnectivity::ConstEdgeFaceRange faces() const; +}; + +struct OPENMESHDLLEXPORT SmartFaceHandle : public SmartBaseHandle, FaceHandle, SmartHandleStatusPredicates, SmartHandleBoundaryPredicate +{ + explicit SmartFaceHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), FaceHandle(_idx) {} + + /// Returns one of the halfedges of the face + SmartHalfedgeHandle halfedge() const; + + /// Returns a range of vertices incident to the face (PolyConnectivity::fv_range()) + PolyConnectivity::ConstFaceVertexRange vertices() const; + /// Returns a range of vertices incident to the face (PolyConnectivity::fv_cw_range()) + PolyConnectivity::ConstFaceVertexCWRange vertices_cw() const; + /// Returns a range of vertices incident to the face (PolyConnectivity::fv_ccw_range()) + PolyConnectivity::ConstFaceVertexCCWRange vertices_ccw() const; + /// Returns a range of halfedges of the face (PolyConnectivity::fh_range()) + PolyConnectivity::ConstFaceHalfedgeRange halfedges() const; + /// Returns a range of halfedges of the face (PolyConnectivity::fh_cw_range()) + PolyConnectivity::ConstFaceHalfedgeCWRange halfedges_cw() const; + /// Returns a range of halfedges of the face (PolyConnectivity::fh_ccw_range()) + PolyConnectivity::ConstFaceHalfedgeCCWRange halfedges_ccw() const; + /// Returns a range of edges of the face (PolyConnectivity::fv_range()) + PolyConnectivity::ConstFaceEdgeRange edges() const; + /// Returns a range of edges of the face (PolyConnectivity::fv_cw_range()) + PolyConnectivity::ConstFaceEdgeCWRange edges_cw() const; + /// Returns a range of edges of the face (PolyConnectivity::fv_ccw_range()) + PolyConnectivity::ConstFaceEdgeCCWRange edges_ccw() const; + /// Returns a range adjacent faces of the face (PolyConnectivity::ff_range()) + PolyConnectivity::ConstFaceFaceRange faces() const; + /// Returns a range adjacent faces of the face (PolyConnectivity::ff_cw_range()) + PolyConnectivity::ConstFaceFaceCWRange faces_cw() const; + /// Returns a range adjacent faces of the face (PolyConnectivity::ff_ccw_range()) + PolyConnectivity::ConstFaceFaceCCWRange faces_ccw() const; + + /// Returns the valence of the face + uint valence() const; +}; + + +/// Creats a SmartVertexHandle from a VertexHandle and a Mesh +inline SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity* _mesh) { return SmartVertexHandle (_vh.idx(), _mesh); } +/// Creats a SmartHalfedgeHandle from a HalfedgeHandle and a Mesh +inline SmartHalfedgeHandle make_smart(HalfedgeHandle _hh, const PolyConnectivity* _mesh) { return SmartHalfedgeHandle(_hh.idx(), _mesh); } +/// Creats a SmartEdgeHandle from an EdgeHandle and a Mesh +inline SmartEdgeHandle make_smart(EdgeHandle _eh, const PolyConnectivity* _mesh) { return SmartEdgeHandle (_eh.idx(), _mesh); } +/// Creats a SmartFaceHandle from a FaceHandle and a Mesh +inline SmartFaceHandle make_smart(FaceHandle _fh, const PolyConnectivity* _mesh) { return SmartFaceHandle (_fh.idx(), _mesh); } + +/// Creats a SmartVertexHandle from a VertexHandle and a Mesh +inline SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity& _mesh) { return SmartVertexHandle (_vh.idx(), &_mesh); } +/// Creats a SmartHalfedgeHandle from a HalfedgeHandle and a Mesh +inline SmartHalfedgeHandle make_smart(HalfedgeHandle _hh, const PolyConnectivity& _mesh) { return SmartHalfedgeHandle(_hh.idx(), &_mesh); } +/// Creats a SmartEdgeHandle from an EdgeHandle and a Mesh +inline SmartEdgeHandle make_smart(EdgeHandle _eh, const PolyConnectivity& _mesh) { return SmartEdgeHandle (_eh.idx(), &_mesh); } +/// Creats a SmartFaceHandle from a FaceHandle and a Mesh +inline SmartFaceHandle make_smart(FaceHandle _fh, const PolyConnectivity& _mesh) { return SmartFaceHandle (_fh.idx(), &_mesh); } + + +// helper to convert Handle Types to Smarthandle Types +template +struct SmartHandle; + +template <> struct SmartHandle { using type = SmartVertexHandle; }; +template <> struct SmartHandle { using type = SmartHalfedgeHandle; }; +template <> struct SmartHandle { using type = SmartEdgeHandle; }; +template <> struct SmartHandle { using type = SmartFaceHandle; }; + + +template +inline bool SmartHandleStatusPredicates::feature() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).feature(); +} + +template +inline bool SmartHandleStatusPredicates::selected() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).selected(); +} + +template +inline bool SmartHandleStatusPredicates::tagged() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).tagged(); +} + +template +inline bool SmartHandleStatusPredicates::tagged2() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).tagged2(); +} + +template +inline bool SmartHandleStatusPredicates::locked() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).locked(); +} + +template +inline bool SmartHandleStatusPredicates::hidden() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).hidden(); +} + +template +inline bool SmartHandleStatusPredicates::deleted() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).deleted(); +} + +template +inline bool SmartHandleBoundaryPredicate::is_boundary() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->is_boundary(handle); +} + +inline SmartHalfedgeHandle SmartVertexHandle::out() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->halfedge_handle(*this), mesh()); +} + +inline SmartHalfedgeHandle SmartVertexHandle::halfedge() const +{ + return out(); +} + +inline SmartHalfedgeHandle SmartVertexHandle::in() const +{ + return out().opp(); +} + +inline uint SmartVertexHandle::valence() const +{ + assert(mesh() != nullptr); + return mesh()->valence(*this); +} + +inline bool SmartVertexHandle::is_manifold() const +{ + assert(mesh() != nullptr); + return mesh()->is_manifold(*this); +} + +inline SmartHalfedgeHandle SmartHalfedgeHandle::next() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->next_halfedge_handle(*this), mesh()); +} + +inline SmartHalfedgeHandle SmartHalfedgeHandle::prev() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->prev_halfedge_handle(*this), mesh()); +} + +inline SmartHalfedgeHandle SmartHalfedgeHandle::opp() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->opposite_halfedge_handle(*this), mesh()); +} + +inline SmartVertexHandle SmartHalfedgeHandle::to() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->to_vertex_handle(*this), mesh()); +} + +inline SmartVertexHandle SmartHalfedgeHandle::from() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->from_vertex_handle(*this), mesh()); +} + +inline SmartEdgeHandle SmartHalfedgeHandle::edge() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->edge_handle(*this), mesh()); +} + +inline SmartFaceHandle SmartHalfedgeHandle::face() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->face_handle(*this), mesh()); +} + +inline SmartHalfedgeHandle SmartEdgeHandle::halfedge(unsigned int _i = 0) const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->halfedge_handle(*this, _i), mesh()); +} + +inline SmartHalfedgeHandle SmartEdgeHandle::h(unsigned int _i = 0) const +{ + return halfedge(_i); +} + +inline SmartHalfedgeHandle SmartEdgeHandle::h0() const +{ + return h(0); +} + +inline SmartHalfedgeHandle SmartEdgeHandle::h1() const +{ + return h(1); +} + +inline SmartVertexHandle SmartEdgeHandle::vertex(unsigned int _i) const +{ + return halfedge(_i).from(); +} + +inline SmartVertexHandle SmartEdgeHandle::v(unsigned int _i) const +{ + return vertex(_i); +} + +inline SmartVertexHandle SmartEdgeHandle::v0() const +{ + return v(0); +} + +inline SmartVertexHandle SmartEdgeHandle::v1() const +{ + return v(1); +} + +inline SmartHalfedgeHandle SmartFaceHandle::halfedge() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->halfedge_handle(*this), mesh()); +} + +inline uint SmartFaceHandle::valence() const +{ + assert(mesh() != nullptr); + return mesh()->valence(*this); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/SmartRange.hh b/Sources/OpenMeshCore/Core/Mesh/SmartRange.hh new file mode 100644 index 0000000..00c121f --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/SmartRange.hh @@ -0,0 +1,496 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#pragma once + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== FORWARD DECLARATION ====================================================== + +//== CLASS DEFINITION ========================================================= + +namespace { + +struct Identity +{ + template + T operator()(const T& _t) const { return _t; } +}; + +} + +template +struct FilteredSmartRangeT; + +/// Base class for all smart range types +template +struct SmartRangeT +{ + using Handle = HandleT; + using SmartRange = SmartRangeT; + using Range = RangeT; + + // TODO: Someone with better c++ knowledge may improve the code below. + + /** @brief Computes the sum of elements. + * + * Computes the sum of all elements in the range after applying the functor \p f. + * + * @param f Functor that is applied to all elements before computing the sum + */ + template + auto sum(Functor&& f) -> typename std::decay()))>::type + { + auto range = static_cast(this); + auto begin = range->begin(); + auto end = range->end(); + assert(begin != end); + typename std::decay::type result = f(*begin); + auto it = begin; + ++it; + for (; it != end; ++it) + result += f(*it); + return result; + } + + /** @brief Computes the average of elements. + * + * Computes the average of all elements in the range after applying the functor \p f. + * + * @param f Functor that is applied to all elements before computing the average. + */ + template + auto avg(Functor&& f) -> typename std::decay()))>::type + { + auto range = static_cast(this); + auto begin = range->begin(); + auto end = range->end(); + assert(begin != end); + typename std::decay::type result = f(*begin); + auto it = begin; + ++it; + int n_elements = 1; + for (; it != end; ++it) + { + result += f(*it); + ++n_elements; + } + return (1.0 / n_elements) * result; + } + + /** @brief Computes the weighted average of elements. + * + * Computes the weighted average of all elements in the range after applying the functor \p f. + * + * @param f Functor that is applied to all elements before computing the average. + * @param w Functor returning element weight. + */ + template + auto avg(Functor&& f, WeightFunctor&& w) -> typename std::decay())+w(std::declval())))*f(std::declval()))>::type + { + auto range = static_cast(this); + auto begin = range->begin(); + auto end = range->end(); + assert(begin != end); + typename std::decay::type weight = w(*begin); + typename std::decay::type result = weight * f(*begin); + typename std::decay::type weight_sum = weight; + auto it = begin; + ++it; + for (; it != end; ++it) + { + weight = w(*it); + result += weight*f(*it); + weight_sum += weight; + } + return (1.0 / weight_sum) * result; + } + + /** @brief Check if any element fulfils condition. + * + * Checks if functor \p f returns true for any of the elements in the range. + * Returns true if that is the case, false otherwise. + * + * @param f Functor that is evaluated for all elements. + */ + template + auto any_of(Functor&& f) -> bool + { + auto range = static_cast(this); + for (auto e : *range) + if (f(e)) + return true; + return false; + } + + /** @brief Check if all elements fulfil condition. + * + * Checks if functor \p f returns true for all of the elements in the range. + * Returns true if that is the case, false otherwise. + * + * @param f Functor that is evaluated for all elements. + */ + template + auto all_of(Functor&& f) -> bool + { + auto range = static_cast(this); + for (auto e : *range) + if (!f(e)) + return false; + return true; + } + + /** @brief Convert range to array. + * + * Converts the range of elements into an array of objects returned by functor \p f. + * The size of the array needs to be provided by the user. If the size is larger than the number of + * elements in the range, the remaining entries of the array will be uninitialized. + * + * @param f Functor that is applied to all elements before putting them into the array. If no functor is provided + * the array will contain the handles. + */ + template + auto to_array(Functor&& f = {}) -> std::array()))>::type, n> + { + auto range = static_cast(this); + std::array()))>::type, n> res; + auto it = range->begin(); + auto end = range->end(); + int i = 0; + while (i < n && it != end) + res[i++] = f(*(it++)); + return res; + } + + /** @brief Convert range to vector. + * + * Converts the range of elements into a vector of objects returned by functor \p f. + * + * @param f Functor that is applied to all elements before putting them into the vector. If no functor is provided + * the vector will contain the handles. + */ + template + auto to_vector(Functor&& f = {}) -> std::vector()))>::type> + { + auto range = static_cast(this); + std::vector()))>::type> res; + for (const auto& e : *range) + res.push_back(f(e)); + return res; + } + + /** @brief Convert range to set. + * + * Converts the range of elements into a set of objects returned by functor \p f. + * + * @param f Functor that is applied to all elements before putting them into the set. If no functor is provided + * the set will contain the handles. + */ + template + auto to_set(Functor&& f = {}) -> std::set()))>::type> + { + auto range = static_cast(this); + std::set()))>::type> res; + for (const auto& e : *range) + res.insert(f(e)); + return res; + } + + /** @brief Get the first element that fulfills a condition. + * + * Finds the first element of the range for which the functor \p f evaluates to true. + * Returns an invalid handle if none evaluates to true + * + * @param f Functor that is applied to all elements before putting them into the set. If no functor is provided + * the set will contain the handles. + */ + template + auto first(Functor&& f = {}) -> HandleT + { + auto range = static_cast(this); + for (const auto& e : *range) + if (f(e)) + return e; + return HandleT(); + } + + /** @brief Compute minimum. + * + * Computes the minimum of all objects returned by functor \p f. + * + * @param f Functor that is applied to all elements before computing minimum. + */ + template + auto min(Functor&& f) -> typename std::decay()))>::type + { + using std::min; + + auto range = static_cast(this); + auto it = range->begin(); + auto end = range->end(); + assert(it != end); + + typename std::decay()))>::type res = f(*it); + ++it; + + for (; it != end; ++it) + res = min(res, f(*it)); + + return res; + } + + /** @brief Compute minimal element. + * + * Computes the element that minimizes \p f. + * + * @param f Functor that is applied to all elements before comparing. + */ + template + auto argmin(Functor&& f) -> HandleT + { + auto range = static_cast(this); + auto it = range->begin(); + auto min_it = it; + auto end = range->end(); + assert(it != end); + + typename std::decay()))>::type curr_min = f(*it); + ++it; + + for (; it != end; ++it) + { + auto val = f(*it); + if (val < curr_min) + { + curr_min = val; + min_it = it; + } + } + + return *min_it; + } + + /** @brief Compute maximum. + * + * Computes the maximum of all objects returned by functor \p f. + * + * @param f Functor that is applied to all elements before computing maximum. + */ + template + auto max(Functor&& f) -> typename std::decay()))>::type + { + using std::max; + + auto range = static_cast(this); + auto it = range->begin(); + auto end = range->end(); + assert(it != end); + + typename std::decay()))>::type res = f(*it); + ++it; + + for (; it != end; ++it) + res = max(res, f(*it)); + + return res; + } + + + /** @brief Compute maximal element. + * + * Computes the element that maximizes \p f. + * + * @param f Functor that is applied to all elements before comparing. + */ + template + auto argmax(Functor&& f) -> HandleT + { + auto range = static_cast(this); + auto it = range->begin(); + auto max_it = it; + auto end = range->end(); + assert(it != end); + + typename std::decay()))>::type curr_max = f(*it); + ++it; + + for (; it != end; ++it) + { + auto val = f(*it); + if (val > curr_max) + { + curr_max = val; + max_it = it; + } + } + + return *max_it; + } + + /** @brief Computes minimum and maximum. + * + * Computes the minimum and maximum of all objects returned by functor \p f. Result is returned as std::pair + * containing minimum as first and maximum as second element. + * + * @param f Functor that is applied to all elements before computing maximum. + */ + template + auto minmax(Functor&& f) -> std::pair()))>::type, + typename std::decay()))>::type> + { + return std::make_pair(this->min(f), this->max(f)); + } + + + /** @brief Compute number of elements that satisfy a given predicate. + * + * Computes the numer of elements which satisfy functor \p f. + * + * @param f Predicate that elements have to satisfy in order to be counted. + */ + template + auto count_if(Functor&& f) -> int + { + int count = 0; + auto range = static_cast(this); + for (const auto& e : *range) + if (f(e)) + ++count; + return count; + } + + + /** @brief Apply a functor to each element. + * + * Calls functor \p f with each element as parameter + * + * @param f Functor that is called for each element. + */ + template + auto for_each(Functor&& f) -> void + { + auto range = static_cast(this); + for (const auto& e : *range) + f(e); + } + + + /** @brief Only iterate over a subset of elements + * + * Returns a smart range which skips all elements that do not satisfy functor \p f + * + * @param f Functor that needs to be evaluated to true if the element should not be skipped. + */ + template + auto filtered(Functor&& f) -> FilteredSmartRangeT + { + auto range = static_cast(this); + return FilteredSmartRangeT(std::forward(f), (*range).begin(), (*range).end()); + } +}; + + +/// Class which applies a filter when iterating over elements +template +struct FilteredSmartRangeT : public SmartRangeT, HandleT> +{ + using BaseRange = SmartRangeT, HandleT>; + using BaseIterator = decltype((std::declval().begin())); + + struct FilteredIterator : public BaseIterator + { + + FilteredIterator(Functor f, BaseIterator it, BaseIterator end): BaseIterator(it), f_(f), end_(end) + { + if (!BaseIterator::operator==(end_) && !f_(*(*this))) // if start is not valid go to first valid one + operator++(); + } + + FilteredIterator(const FilteredIterator& other) = default; + + FilteredIterator& operator=(const FilteredIterator& other) + { + BaseIterator::operator=(other); + end_ = other.end_; + return *this; + } + + FilteredIterator& operator++() + { + if (BaseIterator::operator==(end_)) // don't go past end + return *this; + + // go to next valid one + do + BaseIterator::operator++(); + while (BaseIterator::operator!=(end_) && !f_(*(*this))); + return *this; + } + + Functor f_; // Should iterators always get a reference to filter stored in range? + // Should iterators stay valid after range goes out of scope? + BaseIterator end_; + }; + + FilteredSmartRangeT(Functor&& f, BaseIterator begin, BaseIterator end) : f_(std::forward(f)), begin_(std::move(begin)), end_(std::move(end)){} + FilteredIterator begin() const { return FilteredIterator(f_, begin_, end_); } + FilteredIterator end() const { return FilteredIterator(f_, end_, end_); } + + Functor f_; + BaseIterator begin_; + BaseIterator end_; +}; + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/Status.hh b/Sources/OpenMeshCore/Core/Mesh/Status.hh new file mode 100644 index 0000000..73f992a --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/Status.hh @@ -0,0 +1,178 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS Status +// +//============================================================================= + + +#ifndef OPENMESH_ATTRIBUTE_STATUS_HH +#define OPENMESH_ATTRIBUTE_STATUS_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Attributes { + + +//== CLASS DEFINITION ======================================================== + + +/** Status bits used by the Status class. + * \see OpenMesh::Attributes::StatusInfo + */ +enum StatusBits { + + DELETED = 1, ///< Item has been deleted + LOCKED = 2, ///< Item is locked. + SELECTED = 4, ///< Item is selected. + HIDDEN = 8, ///< Item is hidden. + FEATURE = 16, ///< Item is a feature or belongs to a feature. + TAGGED = 32, ///< Item is tagged. + TAGGED2 = 64, ///< Alternate bit for tagging an item. + FIXEDNONMANIFOLD = 128, ///< Item was non-two-manifold and had to be fixed + UNUSED = 256 ///< Unused +}; + + +/** \class StatusInfo Status.hh + * + * Add status information to a base class. + * + * \see StatusBits + */ +class StatusInfo +{ +public: + + typedef unsigned int value_type; + + StatusInfo() : status_(0) {} + + /// is deleted ? + bool deleted() const { return is_bit_set(DELETED); } + /// set deleted + void set_deleted(bool _b) { change_bit(DELETED, _b); } + + + /// is locked ? + bool locked() const { return is_bit_set(LOCKED); } + /// set locked + void set_locked(bool _b) { change_bit(LOCKED, _b); } + + + /// is selected ? + bool selected() const { return is_bit_set(SELECTED); } + /// set selected + void set_selected(bool _b) { change_bit(SELECTED, _b); } + + + /// is hidden ? + bool hidden() const { return is_bit_set(HIDDEN); } + /// set hidden + void set_hidden(bool _b) { change_bit(HIDDEN, _b); } + + + /// is feature ? + bool feature() const { return is_bit_set(FEATURE); } + /// set feature + void set_feature(bool _b) { change_bit(FEATURE, _b); } + + + /// is tagged ? + bool tagged() const { return is_bit_set(TAGGED); } + /// set tagged + void set_tagged(bool _b) { change_bit(TAGGED, _b); } + + + /// is tagged2 ? This is just one more tag info. + bool tagged2() const { return is_bit_set(TAGGED2); } + /// set tagged + void set_tagged2(bool _b) { change_bit(TAGGED2, _b); } + + + /// is fixed non-manifold ? + bool fixed_nonmanifold() const { return is_bit_set(FIXEDNONMANIFOLD); } + /// set fixed non-manifold + void set_fixed_nonmanifold(bool _b) { change_bit(FIXEDNONMANIFOLD, _b); } + + + /// return whole status + unsigned int bits() const { return status_; } + /// set whole status at once + void set_bits(unsigned int _bits) { status_ = _bits; } + + + /// is a certain bit set ? + bool is_bit_set(unsigned int _s) const { return (status_ & _s) > 0; } + /// set a certain bit + void set_bit(unsigned int _s) { status_ |= _s; } + /// unset a certain bit + void unset_bit(unsigned int _s) { status_ &= ~_s; } + /// set or unset a certain bit + void change_bit(unsigned int _s, bool _b) { + if (_b) status_ |= _s; else status_ &= ~_s; } + + +private: + + value_type status_; +}; + + +//============================================================================= +} // namespace Attributes +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBUTE_STATUS_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/Tags.hh b/Sources/OpenMeshCore/Core/Mesh/Tags.hh new file mode 100644 index 0000000..f71b6b6 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/Tags.hh @@ -0,0 +1,52 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#pragma once + +namespace OpenMesh { + +/// Connectivity tag indicating that the tagged mesh has polygon connectivity. +struct PolyConnectivityTag {}; +/// Connectivity tag indicating that the tagged mesh has triangle connectivity. +struct TriConnectivityTag {}; + +} // namespace OpenMesh + diff --git a/Sources/OpenMeshCore/Core/Mesh/Traits.hh b/Sources/OpenMeshCore/Core/Mesh/Traits.hh new file mode 100644 index 0000000..f30a3a8 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/Traits.hh @@ -0,0 +1,258 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +/** \file Core/Mesh/Traits.hh + This file defines the default traits and some convenience macros. +*/ + + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_TRAITS_HH +#define OPENMESH_TRAITS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/// Macro for defining the vertex attributes. See \ref mesh_type. +#define VertexAttributes(_i) enum { VertexAttributes = _i } + +/// Macro for defining the halfedge attributes. See \ref mesh_type. +#define HalfedgeAttributes(_i) enum { HalfedgeAttributes = _i } + +/// Macro for defining the edge attributes. See \ref mesh_type. +#define EdgeAttributes(_i) enum { EdgeAttributes = _i } + +/// Macro for defining the face attributes. See \ref mesh_type. +#define FaceAttributes(_i) enum { FaceAttributes = _i } + +/// Macro for defining the vertex traits. See \ref mesh_type. +#define VertexTraits \ + template struct VertexT : public Base + +/// Macro for defining the halfedge traits. See \ref mesh_type. +#define HalfedgeTraits \ + template struct HalfedgeT : public Base + +/// Macro for defining the edge traits. See \ref mesh_type. +#define EdgeTraits \ + template struct EdgeT : public Base + +/// Macro for defining the face traits. See \ref mesh_type. +#define FaceTraits \ + template struct FaceT : public Base + + + +//== CLASS DEFINITION ========================================================= + + +/** \class DefaultTraits Traits.hh + + Base class for all traits. All user traits should be derived from + this class. You may enrich all basic items by additional + properties or define one or more of the types \c Point, \c Normal, + \c TexCoord, or \c Color. + + \see The Mesh docu section on \ref mesh_type. + \see Traits.hh for a list of macros for traits classes. +*/ +struct DefaultTraits +{ + /// The default coordinate type is OpenMesh::Vec3f. + typedef Vec3f Point; + + /// The default normal type is OpenMesh::Vec3f. + typedef Vec3f Normal; + + /// The default 1D texture coordinate type is float. + typedef float TexCoord1D; + /// The default 2D texture coordinate type is OpenMesh::Vec2f. + typedef Vec2f TexCoord2D; + /// The default 3D texture coordinate type is OpenMesh::Vec3f. + typedef Vec3f TexCoord3D; + + /// The default texture index type + typedef int TextureIndex; + + /// The default color type is OpenMesh::Vec3uc. + typedef Vec3uc Color; + +#ifndef DOXY_IGNORE_THIS + VertexTraits {}; + HalfedgeTraits {}; + EdgeTraits {}; + FaceTraits {}; +#endif + + VertexAttributes(0); + HalfedgeAttributes(Attributes::PrevHalfedge); + EdgeAttributes(0); + FaceAttributes(0); +}; + +/** \class DefaultTraitsDouble Traits.hh + + Version of Default Traits that uses double precision for points and + normals as well as floating point vectors for colors + + \see The Mesh docu section on \ref mesh_type. + \see Traits.hh for a list of macros for traits classes. +*/ +struct DefaultTraitsDouble : public DefaultTraits +{ + /// Use double precision points + typedef OpenMesh::Vec3d Point; + /// Use double precision Normals + typedef OpenMesh::Vec3d Normal; + /// Use RGBA Color + typedef OpenMesh::Vec4f Color; +}; + + +//== CLASS DEFINITION ========================================================= + + +/** Helper class to merge two mesh traits. + * \internal + * + * With the help of this class it's possible to merge two mesh traits. + * Whereby \c _Traits1 overrides equally named symbols of \c _Traits2. + * + * For your convenience use the provided defines \c OM_Merge_Traits + * and \c OM_Merge_Traits_In_Template instead. + * + * \see OM_Merge_Traits, OM_Merge_Traits_In_Template + */ +template struct MergeTraits +{ +#ifndef DOXY_IGNORE_THIS + struct Result + { + // Mipspro needs this (strange) typedef + typedef _Traits1 T1; + typedef _Traits2 T2; + + + VertexAttributes ( T1::VertexAttributes | T2::VertexAttributes ); + HalfedgeAttributes ( T1::HalfedgeAttributes | T2::HalfedgeAttributes ); + EdgeAttributes ( T1::EdgeAttributes | T2::EdgeAttributes ); + FaceAttributes ( T1::FaceAttributes | T2::FaceAttributes ); + + + typedef typename T1::Point Point; + typedef typename T1::Normal Normal; + typedef typename T1::Color Color; + typedef typename T1::TexCoord TexCoord; + + template class VertexT : + public T1::template VertexT< + typename T2::template VertexT, Refs> + {}; + + template class HalfedgeT : + public T1::template HalfedgeT< + typename T2::template HalfedgeT, Refs> + {}; + + + template class EdgeT : + public T1::template EdgeT< + typename T2::template EdgeT, Refs> + {}; + + + template class FaceT : + public T1::template FaceT< + typename T2::template FaceT, Refs> + {}; + }; +#endif +}; + + +/** + Macro for merging two traits classes _S1 and _S2 into one traits class _D. + Note that in case of ambiguities class _S1 overrides _S2, especially + the point/normal/color/texcoord type to be used is taken from _S1::Point / + _S1::Normal / _S1::Color / _S1::TexCoord +*/ +#define OM_Merge_Traits(_S1, _S2, _D) \ + typedef OpenMesh::MergeTraits<_S1, _S2>::Result _D; + + +/** + Macro for merging two traits classes _S1 and _S2 into one traits class _D. + Same as OM_Merge_Traits, but this can be used inside template classes. +*/ +#define OM_Merge_Traits_In_Template(_S1, _S2, _D) \ + typedef typename OpenMesh::MergeTraits<_S1, _S2>::Result _D; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_TRAITS_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/Mesh/TriConnectivity.cc b/Sources/OpenMeshCore/Core/Mesh/TriConnectivity.cc new file mode 100644 index 0000000..cfae830 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/TriConnectivity.cc @@ -0,0 +1,524 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +// CLASS TriMeshT - IMPLEMENTATION + +#include + +namespace OpenMesh +{ + +SmartFaceHandle +TriConnectivity::add_face(const VertexHandle* _vertex_handles, size_t _vhs_size) +{ + // need at least 3 vertices + if (_vhs_size < 3) return make_smart(InvalidFaceHandle, this); + + /// face is triangle -> ok + if (_vhs_size == 3) + return PolyConnectivity::add_face(_vertex_handles, _vhs_size); + + /// face is not a triangle -> triangulate + else + { + //omlog() << "triangulating " << _vhs_size << "_gon\n"; + + VertexHandle vhandles[3]; + vhandles[0] = _vertex_handles[0]; + + FaceHandle fh; + unsigned int i(1); + --_vhs_size; + + while (i < _vhs_size) + { + vhandles[1] = _vertex_handles[i]; + vhandles[2] = _vertex_handles[++i]; + fh = PolyConnectivity::add_face(vhandles, 3); + } + + return make_smart(fh, this); + } +} + +//----------------------------------------------------------------------------- + +SmartFaceHandle TriConnectivity::add_face(const std::vector& _vhandles) +{ + return add_face(&_vhandles.front(), _vhandles.size()); +} + +//----------------------------------------------------------------------------- + +SmartFaceHandle TriConnectivity::add_face(const std::vector& _vhandles) +{ + std::vector vhandles(_vhandles.begin(), _vhandles.end()); + return add_face(&vhandles.front(), vhandles.size()); +} + +//----------------------------------------------------------------------------- + + +SmartFaceHandle TriConnectivity::add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2) +{ + VertexHandle vhs[3] = { _vh0, _vh1, _vh2 }; + return PolyConnectivity::add_face(vhs, 3); +} + +//----------------------------------------------------------------------------- + +bool TriConnectivity::is_collapse_ok(HalfedgeHandle v0v1) +{ + // is the edge already deleted? + if ( status(edge_handle(v0v1)).deleted() ) + return false; + + HalfedgeHandle v1v0(opposite_halfedge_handle(v0v1)); + VertexHandle v0(to_vertex_handle(v1v0)); + VertexHandle v1(to_vertex_handle(v0v1)); + + // are vertices already deleted ? + if (status(v0).deleted() || status(v1).deleted()) + return false; + + VertexHandle vl, vr; + HalfedgeHandle h1, h2; + + // the edges v1-vl and vl-v0 must not be both boundary edges + if (!is_boundary(v0v1)) + { + + h1 = next_halfedge_handle(v0v1); + h2 = next_halfedge_handle(h1); + + vl = to_vertex_handle(h1); + + if (is_boundary(opposite_halfedge_handle(h1)) && + is_boundary(opposite_halfedge_handle(h2))) + { + return false; + } + } + + + // the edges v0-vr and vr-v1 must not be both boundary edges + if (!is_boundary(v1v0)) + { + + h1 = next_halfedge_handle(v1v0); + h2 = next_halfedge_handle(h1); + + vr = to_vertex_handle(h1); + + if (is_boundary(opposite_halfedge_handle(h1)) && + is_boundary(opposite_halfedge_handle(h2))) + return false; + } + + // if vl and vr are equal or both invalid -> fail + if (vl == vr) return false; + + VertexVertexIter vv_it; + + // test intersection of the one-rings of v0 and v1 + for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it) + status(*vv_it).set_tagged(false); + + for (vv_it = vv_iter(v1); vv_it.is_valid(); ++vv_it) + status(*vv_it).set_tagged(true); + + for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it) + if (status(*vv_it).tagged() && *vv_it != vl && *vv_it != vr) + return false; + + + // edge between two boundary vertices should be a boundary edge + if ( is_boundary(v0) && is_boundary(v1) && + !is_boundary(v0v1) && !is_boundary(v1v0)) + return false; + + // passed all tests + return true; +} + +//----------------------------------------------------------------------------- +TriConnectivity::HalfedgeHandle +TriConnectivity::vertex_split(VertexHandle v0, VertexHandle v1, + VertexHandle vl, VertexHandle vr) +{ + HalfedgeHandle v1vl, vlv1, vrv1, v0v1; + + // build loop from halfedge v1->vl + if (vl.is_valid()) + { + v1vl = find_halfedge(v1, vl); + assert(v1vl.is_valid()); + vlv1 = insert_loop(v1vl); + } + + // build loop from halfedge vr->v1 + if (vr.is_valid()) + { + vrv1 = find_halfedge(vr, v1); + assert(vrv1.is_valid()); + insert_loop(vrv1); + } + + // handle boundary cases + if (!vl.is_valid()) + vlv1 = prev_halfedge_handle(halfedge_handle(v1)); + if (!vr.is_valid()) + vrv1 = prev_halfedge_handle(halfedge_handle(v1)); + + + // split vertex v1 into edge v0v1 + v0v1 = insert_edge(v0, vlv1, vrv1); + + + return v0v1; +} + +//----------------------------------------------------------------------------- +TriConnectivity::HalfedgeHandle +TriConnectivity::insert_loop(HalfedgeHandle _hh) +{ + HalfedgeHandle h0(_hh); + HalfedgeHandle o0(opposite_halfedge_handle(h0)); + + VertexHandle v0(to_vertex_handle(o0)); + VertexHandle v1(to_vertex_handle(h0)); + + HalfedgeHandle h1 = new_edge(v1, v0); + HalfedgeHandle o1 = opposite_halfedge_handle(h1); + + FaceHandle f0 = face_handle(h0); + FaceHandle f1 = new_face(); + + // halfedge -> halfedge + set_next_halfedge_handle(prev_halfedge_handle(h0), o1); + set_next_halfedge_handle(o1, next_halfedge_handle(h0)); + set_next_halfedge_handle(h1, h0); + set_next_halfedge_handle(h0, h1); + + // halfedge -> face + set_face_handle(o1, f0); + set_face_handle(h0, f1); + set_face_handle(h1, f1); + + // face -> halfedge + set_halfedge_handle(f1, h0); + if (f0.is_valid()) + set_halfedge_handle(f0, o1); + + + // vertex -> halfedge + adjust_outgoing_halfedge(v0); + adjust_outgoing_halfedge(v1); + + return h1; +} + +//----------------------------------------------------------------------------- +TriConnectivity::HalfedgeHandle +TriConnectivity::insert_edge(VertexHandle _vh, HalfedgeHandle _h0, HalfedgeHandle _h1) +{ + assert(_h0.is_valid() && _h1.is_valid()); + + VertexHandle v0 = _vh; + VertexHandle v1 = to_vertex_handle(_h0); + + assert( v1 == to_vertex_handle(_h1)); + + HalfedgeHandle v0v1 = new_edge(v0, v1); + HalfedgeHandle v1v0 = opposite_halfedge_handle(v0v1); + + + + // vertex -> halfedge + set_halfedge_handle(v0, v0v1); + set_halfedge_handle(v1, v1v0); + + + // halfedge -> halfedge + set_next_halfedge_handle(v0v1, next_halfedge_handle(_h0)); + set_next_halfedge_handle(_h0, v0v1); + set_next_halfedge_handle(v1v0, next_halfedge_handle(_h1)); + set_next_halfedge_handle(_h1, v1v0); + + + // halfedge -> vertex + for (VertexIHalfedgeIter vih_it(vih_iter(v0)); vih_it.is_valid(); ++vih_it) + set_vertex_handle(*vih_it, v0); + + + // halfedge -> face + set_face_handle(v0v1, face_handle(_h0)); + set_face_handle(v1v0, face_handle(_h1)); + + + // face -> halfedge + if (face_handle(v0v1).is_valid()) + set_halfedge_handle(face_handle(v0v1), v0v1); + if (face_handle(v1v0).is_valid()) + set_halfedge_handle(face_handle(v1v0), v1v0); + + + // vertex -> halfedge + adjust_outgoing_halfedge(v0); + adjust_outgoing_halfedge(v1); + + + return v0v1; +} + +//----------------------------------------------------------------------------- +bool TriConnectivity::is_flip_ok(EdgeHandle _eh) const +{ + // boundary edges cannot be flipped + if (is_boundary(_eh)) return false; + + + HalfedgeHandle hh = halfedge_handle(_eh, 0); + HalfedgeHandle oh = halfedge_handle(_eh, 1); + + + // check if the flipped edge is already present + // in the mesh + + VertexHandle ah = to_vertex_handle(next_halfedge_handle(hh)); + VertexHandle bh = to_vertex_handle(next_halfedge_handle(oh)); + + if (ah == bh) // this is generally a bad sign !!! + return false; + + for (ConstVertexVertexIter vvi(*this, ah); vvi.is_valid(); ++vvi) + if (*vvi == bh) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +void TriConnectivity::flip(EdgeHandle _eh) +{ + // CAUTION : Flipping a halfedge may result in + // a non-manifold mesh, hence check for yourself + // whether this operation is allowed or not! + assert(is_flip_ok(_eh));//let's make it sure it is actually checked + assert(!is_boundary(_eh)); + + HalfedgeHandle a0 = halfedge_handle(_eh, 0); + HalfedgeHandle b0 = halfedge_handle(_eh, 1); + + HalfedgeHandle a1 = next_halfedge_handle(a0); + HalfedgeHandle a2 = next_halfedge_handle(a1); + + HalfedgeHandle b1 = next_halfedge_handle(b0); + HalfedgeHandle b2 = next_halfedge_handle(b1); + + VertexHandle va0 = to_vertex_handle(a0); + VertexHandle va1 = to_vertex_handle(a1); + + VertexHandle vb0 = to_vertex_handle(b0); + VertexHandle vb1 = to_vertex_handle(b1); + + FaceHandle fa = face_handle(a0); + FaceHandle fb = face_handle(b0); + + set_vertex_handle(a0, va1); + set_vertex_handle(b0, vb1); + + set_next_halfedge_handle(a0, a2); + set_next_halfedge_handle(a2, b1); + set_next_halfedge_handle(b1, a0); + + set_next_halfedge_handle(b0, b2); + set_next_halfedge_handle(b2, a1); + set_next_halfedge_handle(a1, b0); + + set_face_handle(a1, fb); + set_face_handle(b1, fa); + + set_halfedge_handle(fa, a0); + set_halfedge_handle(fb, b0); + + if (halfedge_handle(va0) == b0) + set_halfedge_handle(va0, a1); + if (halfedge_handle(vb0) == a0) + set_halfedge_handle(vb0, b1); +} + + +//----------------------------------------------------------------------------- + +void TriConnectivity::split(EdgeHandle _eh, VertexHandle _vh) +{ + HalfedgeHandle h0 = halfedge_handle(_eh, 0); + HalfedgeHandle o0 = halfedge_handle(_eh, 1); + + VertexHandle v2 = to_vertex_handle(o0); + + HalfedgeHandle e1 = new_edge(_vh, v2); + HalfedgeHandle t1 = opposite_halfedge_handle(e1); + + FaceHandle f0 = face_handle(h0); + FaceHandle f3 = face_handle(o0); + + set_halfedge_handle(_vh, h0); + set_vertex_handle(o0, _vh); + + if (!is_boundary(h0)) + { + HalfedgeHandle h1 = next_halfedge_handle(h0); + HalfedgeHandle h2 = next_halfedge_handle(h1); + + VertexHandle v1 = to_vertex_handle(h1); + + HalfedgeHandle e0 = new_edge(_vh, v1); + HalfedgeHandle t0 = opposite_halfedge_handle(e0); + + FaceHandle f1 = new_face(); + set_halfedge_handle(f0, h0); + set_halfedge_handle(f1, h2); + + set_face_handle(h1, f0); + set_face_handle(t0, f0); + set_face_handle(h0, f0); + + set_face_handle(h2, f1); + set_face_handle(t1, f1); + set_face_handle(e0, f1); + + set_next_halfedge_handle(h0, h1); + set_next_halfedge_handle(h1, t0); + set_next_halfedge_handle(t0, h0); + + set_next_halfedge_handle(e0, h2); + set_next_halfedge_handle(h2, t1); + set_next_halfedge_handle(t1, e0); + } + else + { + set_next_halfedge_handle(prev_halfedge_handle(h0), t1); + set_next_halfedge_handle(t1, h0); + // halfedge handle of _vh already is h0 + } + + + if (!is_boundary(o0)) + { + HalfedgeHandle o1 = next_halfedge_handle(o0); + HalfedgeHandle o2 = next_halfedge_handle(o1); + + VertexHandle v3 = to_vertex_handle(o1); + + HalfedgeHandle e2 = new_edge(_vh, v3); + HalfedgeHandle t2 = opposite_halfedge_handle(e2); + + FaceHandle f2 = new_face(); + set_halfedge_handle(f2, o1); + set_halfedge_handle(f3, o0); + + set_face_handle(o1, f2); + set_face_handle(t2, f2); + set_face_handle(e1, f2); + + set_face_handle(o2, f3); + set_face_handle(o0, f3); + set_face_handle(e2, f3); + + set_next_halfedge_handle(e1, o1); + set_next_halfedge_handle(o1, t2); + set_next_halfedge_handle(t2, e1); + + set_next_halfedge_handle(o0, e2); + set_next_halfedge_handle(e2, o2); + set_next_halfedge_handle(o2, o0); + } + else + { + set_next_halfedge_handle(e1, next_halfedge_handle(o0)); + set_next_halfedge_handle(o0, e1); + set_halfedge_handle(_vh, e1); + } + + if (halfedge_handle(v2) == h0) + set_halfedge_handle(v2, t1); +} + +//----------------------------------------------------------------------------- + +void TriConnectivity::split_copy(EdgeHandle _eh, VertexHandle _vh) +{ + const VertexHandle v0 = to_vertex_handle(halfedge_handle(_eh, 0)); + const VertexHandle v1 = to_vertex_handle(halfedge_handle(_eh, 1)); + + const size_t nf = n_faces(); + + // Split the halfedge ( handle will be preserved) + split(_eh, _vh); + + // Copy the properties of the original edge to all neighbor edges that + // have been created + for(VEIter ve_it = ve_iter(_vh); ve_it.is_valid(); ++ve_it) + copy_all_properties(_eh, *ve_it, true); + + for (auto vh : {v0, v1}) + { + // get the halfedge pointing from new vertex to old vertex + const HalfedgeHandle h = find_halfedge(_vh, vh); + if (!is_boundary(h)) // for boundaries there are no faces whose properties need to be copied + { + FaceHandle fh0 = face_handle(h); + FaceHandle fh1 = face_handle(opposite_halfedge_handle(prev_halfedge_handle(h))); + if (static_cast(fh0.idx()) >= nf) // is fh0 the new face? + std::swap(fh0, fh1); + + // copy properties from old face to new face + copy_all_properties(fh0, fh1, true); + } + } +} + +}// namespace OpenMesh diff --git a/Sources/OpenMeshCore/Core/Mesh/TriConnectivity.hh b/Sources/OpenMeshCore/Core/Mesh/TriConnectivity.hh new file mode 100644 index 0000000..ddd90e0 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/TriConnectivity.hh @@ -0,0 +1,252 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_TRICONNECTIVITY_HH +#define OPENMESH_TRICONNECTIVITY_HH + +#include + +namespace OpenMesh { + +/** \brief Connectivity Class for Triangle Meshes +*/ +class OPENMESHDLLEXPORT TriConnectivity : public PolyConnectivity +{ +public: + + TriConnectivity() {} + virtual ~TriConnectivity() {} + + inline static bool is_triangles() + { return true; } + + /** assign_connectivity() methods. See ArrayKernel::assign_connectivity() + for more details. When the source connectivity is not triangles, in + addition "fan" connectivity triangulation is performed*/ + inline void assign_connectivity(const TriConnectivity& _other) + { PolyConnectivity::assign_connectivity(_other); } + + inline void assign_connectivity(const PolyConnectivity& _other) + { + PolyConnectivity::assign_connectivity(_other); + triangulate(); + } + + /** \name Addding items to a mesh + */ + + //@{ + + /** \brief Add a face with arbitrary valence to the triangle mesh + * + * Override OpenMesh::Mesh::PolyMeshT::add_face(). Faces that aren't + * triangles will be triangulated and added. In this case an + * invalid face handle will be returned. + * + * + * */ + SmartFaceHandle add_face(const VertexHandle* _vhandles, size_t _vhs_size); + + /** \brief Add a face with arbitrary valence to the triangle mesh + * + * Override OpenMesh::Mesh::PolyMeshT::add_face(). Faces that aren't + * triangles will be triangulated and added. In this case an + * invalid face handle will be returned. + * + * + * */ + SmartFaceHandle add_face(const std::vector& _vhandles); + + /** \brief Add a face with arbitrary valence to the triangle mesh + * + * Override OpenMesh::Mesh::PolyMeshT::add_face(). Faces that aren't + * triangles will be triangulated and added. In this case an + * invalid face handle will be returned. + * + * + * */ + SmartFaceHandle add_face(const std::vector& _vhandles); + + /** \brief Add a face to the mesh (triangle) + * + * This function adds a triangle to the mesh. The triangle is passed directly + * to the underlying PolyConnectivity as we don't explicitly need to triangulate something. + * + * @param _vh0 VertexHandle 1 + * @param _vh1 VertexHandle 2 + * @param _vh2 VertexHandle 3 + * @return FaceHandle of the added face (invalid, if the operation failed) + */ + SmartFaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2); + + //@} + + /** Returns the opposite vertex to the halfedge _heh in the face + referenced by _heh returns InvalidVertexHandle if the _heh is + boundary */ + inline VertexHandle opposite_vh(HalfedgeHandle _heh) const + { + return is_boundary(_heh) ? InvalidVertexHandle : + to_vertex_handle(next_halfedge_handle(_heh)); + } + + /** Returns the opposite vertex to the opposite halfedge of _heh in + the face referenced by it returns InvalidVertexHandle if the + opposite halfedge is boundary */ + VertexHandle opposite_he_opposite_vh(HalfedgeHandle _heh) const + { return opposite_vh(opposite_halfedge_handle(_heh)); } + + /** \name Topology modifying operators + */ + //@{ + + + /** Returns whether collapsing halfedge _heh is ok or would lead to + topological inconsistencies. + \attention This method need the Attributes::Status attribute and + changes the \em tagged bit. */ + bool is_collapse_ok(HalfedgeHandle _heh); + + /// Vertex Split: inverse operation to collapse(). + HalfedgeHandle vertex_split(VertexHandle v0, VertexHandle v1, + VertexHandle vl, VertexHandle vr); + + /// Check whether flipping _eh is topologically correct. + bool is_flip_ok(EdgeHandle _eh) const; + + /** Flip edge _eh. + Check for topological correctness first using is_flip_ok(). */ + void flip(EdgeHandle _eh); + + + /** \brief Edge split (= 2-to-4 split) + * + * + * The function will introduce two new faces ( non-boundary case) or + * one additional face (if edge is boundary) + * + * \note The properties of the new edges, halfedges, and faces will be undefined! + * + * @param _eh Edge handle that should be split + * @param _vh Vertex handle that will be inserted at the edge + */ + void split(EdgeHandle _eh, VertexHandle _vh); + + /** \brief Edge split (= 2-to-4 split) + * + * + * The function will introduce two new faces ( non-boundary case) or + * one additional face (if edge is boundary) + * + * \note The properties of the new edges, halfedges, and faces will be undefined! + * + * \note This is an override to prevent a direct call to PolyConnectivity split_edge, + * which would introduce a singular vertex with valence 2 which is not allowed + * on TriMeshes + * + * @param _eh Edge handle that should be split + * @param _vh Vertex handle that will be inserted at the edge + */ + inline void split_edge(EdgeHandle _eh, VertexHandle _vh) { TriConnectivity::split(_eh, _vh); } + + /** \brief Edge split (= 2-to-4 split) + * + * The function will introduce two new faces ( non-boundary case) or + * one additional face (if edge is boundary) + * + * \note The properties of the new edges and faces will be adjusted to the + * properties of the original edge and face + * \note The properties of the new halfedges will be undefined + * + * @param _eh Edge handle that should be split + * @param _vh Vertex handle that will be inserted at the edge + */ + void split_copy(EdgeHandle _eh, VertexHandle _vh); + + /** \brief Edge split (= 2-to-4 split) + * + * The function will introduce two new faces ( non-boundary case) or + * one additional face (if edge is boundary) + * + * \note The properties of the new edges and faces will be adjusted to the + * properties of the original edge and face + * \note The properties of the new halfedges will be undefined + * + * \note This is an override to prevent a direct call to PolyConnectivity split_edge_copy, + * which would introduce a singular vertex with valence 2 which is not allowed + * on TriMeshes + * + * @param _eh Edge handle that should be split + * @param _vh Vertex handle that will be inserted at the edge + */ + inline void split_edge_copy(EdgeHandle _eh, VertexHandle _vh) { TriConnectivity::split_copy(_eh, _vh); } + + /** \brief Face split (= 1-to-3) split, calls corresponding PolyMeshT function). + * + * @param _fh Face handle that should be split + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split(FaceHandle _fh, VertexHandle _vh) + { PolyConnectivity::split(_fh, _vh); } + + /** \brief Face split (= 1-to-3) split, calls corresponding PolyMeshT function). + * + * @param _fh Face handle that should be split + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split_copy(FaceHandle _fh, VertexHandle _vh) + { PolyConnectivity::split_copy(_fh, _vh); } + + //@} + +private: + /// Helper for vertex split + HalfedgeHandle insert_loop(HalfedgeHandle _hh); + /// Helper for vertex split + HalfedgeHandle insert_edge(VertexHandle _vh, + HalfedgeHandle _h0, HalfedgeHandle _h1); +}; + +} + +#endif//OPENMESH_TRICONNECTIVITY_HH diff --git a/Sources/OpenMeshCore/Core/Mesh/TriMeshT.hh b/Sources/OpenMeshCore/Core/Mesh/TriMeshT.hh new file mode 100644 index 0000000..0b7909f --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/TriMeshT.hh @@ -0,0 +1,453 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS TriMeshT +// +//============================================================================= + + +#ifndef OPENMESH_TRIMESH_HH +#define OPENMESH_TRIMESH_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class TriMeshT TriMeshT.hh + + Base type for a triangle mesh. + + Base type for a triangle mesh, parameterized by a mesh kernel. The + mesh inherits all methods from the kernel class and the + more general polygonal mesh PolyMeshT. Therefore it provides + the same types for items, handles, iterators and so on. + + \param Kernel: template argument for the mesh kernel + \note You should use the predefined mesh-kernel combinations in + \ref mesh_types_group + \see \ref mesh_type + \see OpenMesh::PolyMeshT +*/ + +template +class TriMeshT : public PolyMeshT +{ + +public: + + + // self + typedef TriMeshT This; + typedef PolyMeshT PolyMesh; + + //@{ + /// Determine whether this is a PolyMeshT or TriMeshT (This function does not check the per face vertex count! It only checks if the datatype is PolyMeshT or TriMeshT) + static constexpr bool is_polymesh() { return false; } + static constexpr bool is_trimesh() { return true; } + using ConnectivityTag = TriConnectivityTag; + enum { IsPolyMesh = 0 }; + enum { IsTriMesh = 1 }; + //@} + + //--- items --- + + typedef typename PolyMesh::Scalar Scalar; + typedef typename PolyMesh::Point Point; + typedef typename PolyMesh::Normal Normal; + typedef typename PolyMesh::Color Color; + typedef typename PolyMesh::TexCoord1D TexCoord1D; + typedef typename PolyMesh::TexCoord2D TexCoord2D; + typedef typename PolyMesh::TexCoord3D TexCoord3D; + typedef typename PolyMesh::Vertex Vertex; + typedef typename PolyMesh::Halfedge Halfedge; + typedef typename PolyMesh::Edge Edge; + typedef typename PolyMesh::Face Face; + + + //--- handles --- + + typedef typename PolyMesh::VertexHandle VertexHandle; + typedef typename PolyMesh::HalfedgeHandle HalfedgeHandle; + typedef typename PolyMesh::EdgeHandle EdgeHandle; + typedef typename PolyMesh::FaceHandle FaceHandle; + + + //--- iterators --- + + typedef typename PolyMesh::VertexIter VertexIter; + typedef typename PolyMesh::ConstVertexIter ConstVertexIter; + typedef typename PolyMesh::EdgeIter EdgeIter; + typedef typename PolyMesh::ConstEdgeIter ConstEdgeIter; + typedef typename PolyMesh::FaceIter FaceIter; + typedef typename PolyMesh::ConstFaceIter ConstFaceIter; + + + + //--- circulators --- + + typedef typename PolyMesh::VertexVertexIter VertexVertexIter; + typedef typename PolyMesh::VertexOHalfedgeIter VertexOHalfedgeIter; + typedef typename PolyMesh::VertexIHalfedgeIter VertexIHalfedgeIter; + typedef typename PolyMesh::VertexEdgeIter VertexEdgeIter; + typedef typename PolyMesh::VertexFaceIter VertexFaceIter; + typedef typename PolyMesh::FaceVertexIter FaceVertexIter; + typedef typename PolyMesh::FaceHalfedgeIter FaceHalfedgeIter; + typedef typename PolyMesh::FaceEdgeIter FaceEdgeIter; + typedef typename PolyMesh::FaceFaceIter FaceFaceIter; + typedef typename PolyMesh::ConstVertexVertexIter ConstVertexVertexIter; + typedef typename PolyMesh::ConstVertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef typename PolyMesh::ConstVertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef typename PolyMesh::ConstVertexEdgeIter ConstVertexEdgeIter; + typedef typename PolyMesh::ConstVertexFaceIter ConstVertexFaceIter; + typedef typename PolyMesh::ConstFaceVertexIter ConstFaceVertexIter; + typedef typename PolyMesh::ConstFaceHalfedgeIter ConstFaceHalfedgeIter; + typedef typename PolyMesh::ConstFaceEdgeIter ConstFaceEdgeIter; + typedef typename PolyMesh::ConstFaceFaceIter ConstFaceFaceIter; + + // --- constructor/destructor + + /// Default constructor + TriMeshT() : PolyMesh() {} + explicit TriMeshT(PolyMesh rhs) : PolyMesh((rhs.triangulate(), rhs)) + { + } + + /// Destructor + virtual ~TriMeshT() {} + + //--- halfedge collapse / vertex split --- + + /** \brief Vertex Split: inverse operation to collapse(). + * + * Insert the new vertex at position v0. The vertex will be added + * as the inverse of the edge collapse. The faces above the split + * will be correctly attached to the two new edges + * + *
+   *
+   * Before:
+   * v_l     v0     v_r
+   *  x      x      x
+   *   \           /
+   *    \         /
+   *     \       /
+   *      \     /
+   *       \   /
+   *        \ /
+   *         x
+   *         v1
+   *
+   * After:
+   * v_l    v0      v_r
+   *  x------x------x
+   *   \     |     /
+   *    \    |    /
+   *     \   |   /
+   *      \  |  /
+   *       \ | /
+   *        \|/
+   *         x
+   *         v1
+   *
+   * 
+ * + * @param _v0_point Point position for the new point + * @param _v1 Vertex that will be split + * @param _vl Left vertex handle + * @param _vr Right vertex handle + * @return Newly inserted halfedge + */ + inline HalfedgeHandle vertex_split(Point _v0_point, VertexHandle _v1, + VertexHandle _vl, VertexHandle _vr) + { return PolyMesh::vertex_split(this->add_vertex(_v0_point), _v1, _vl, _vr); } + + /** \brief Vertex Split: inverse operation to collapse(). + * + * Insert the new vertex at position v0. The vertex will be added + * as the inverse of the edge collapse. The faces above the split + * will be correctly attached to the two new edges + * + *
+   *
+   * Before:
+   * v_l     v0     v_r
+   *  x      x      x
+   *   \           /
+   *    \         /
+   *     \       /
+   *      \     /
+   *       \   /
+   *        \ /
+   *         x
+   *         v1
+   *
+   * After:
+   * v_l    v0      v_r
+   *  x------x------x
+   *   \     |     /
+   *    \    |    /
+   *     \   |   /
+   *      \  |  /
+   *       \ | /
+   *        \|/
+   *         x
+   *         v1
+   *
+   * 
+ * + * @param _v0 Vertex handle for the newly inserted point (Input has to be unconnected!) + * @param _v1 Vertex that will be split + * @param _vl Left vertex handle + * @param _vr Right vertex handle + * @return Newly inserted halfedge + */ + inline HalfedgeHandle vertex_split(VertexHandle _v0, VertexHandle _v1, + VertexHandle _vl, VertexHandle _vr) + { return PolyMesh::vertex_split(_v0, _v1, _vl, _vr); } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be undefined! + * + * + * @param _eh Edge handle that should be splitted + * @param _p New point position that will be inserted at the edge + * @return Vertex handle of the newly added vertex + */ + inline SmartVertexHandle split(EdgeHandle _eh, const Point& _p) + { + //Do not call PolyMeshT function below as this does the wrong operation + const SmartVertexHandle vh = this->add_vertex(_p); Kernel::split(_eh, vh); return vh; + } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be adjusted to the properties of the original edge + * + * @param _eh Edge handle that should be splitted + * @param _p New point position that will be inserted at the edge + * @return Vertex handle of the newly added vertex + */ + inline SmartVertexHandle split_copy(EdgeHandle _eh, const Point& _p) + { + //Do not call PolyMeshT function below as this does the wrong operation + const SmartVertexHandle vh = this->add_vertex(_p); Kernel::split_copy(_eh, vh); return vh; + } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be undefined! + * + * @param _eh Edge handle that should be splitted + * @param _vh Vertex handle that will be inserted at the edge + */ + inline void split(EdgeHandle _eh, VertexHandle _vh) + { + //Do not call PolyMeshT function below as this does the wrong operation + Kernel::split(_eh, _vh); + } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be adjusted to the properties of the original edge + * + * @param _eh Edge handle that should be splitted + * @param _vh Vertex handle that will be inserted at the edge + */ + inline void split_copy(EdgeHandle _eh, VertexHandle _vh) + { + //Do not call PolyMeshT function below as this does the wrong operation + Kernel::split_copy(_eh, _vh); + } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be undefined! + * + * @param _fh Face handle that should be splitted + * @param _p New point position that will be inserted in the face + * + * @return Vertex handle of the new vertex + */ + inline SmartVertexHandle split(FaceHandle _fh, const Point& _p) + { const SmartVertexHandle vh = this->add_vertex(_p); PolyMesh::split(_fh, vh); return vh; } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be adjusted to the properties of the original face + * + * @param _fh Face handle that should be splitted + * @param _p New point position that will be inserted in the face + * + * @return Vertex handle of the new vertex + */ + inline SmartVertexHandle split_copy(FaceHandle _fh, const Point& _p) + { const SmartVertexHandle vh = this->add_vertex(_p); PolyMesh::split_copy(_fh, vh); return vh; } + + + /** \brief Face split (= 1-to-4) split, splits edges at midpoints and adds 4 new faces in the interior). + * + * @param _fh Face handle that should be splitted + */ + inline void split(FaceHandle _fh) + { + // Collect halfedges of face + HalfedgeHandle he0 = this->halfedge_handle(_fh); + HalfedgeHandle he1 = this->next_halfedge_handle(he0); + HalfedgeHandle he2 = this->next_halfedge_handle(he1); + + EdgeHandle eh0 = this->edge_handle(he0); + EdgeHandle eh1 = this->edge_handle(he1); + EdgeHandle eh2 = this->edge_handle(he2); + + // Collect points of face + VertexHandle p0 = this->to_vertex_handle(he0); + VertexHandle p1 = this->to_vertex_handle(he1); + VertexHandle p2 = this->to_vertex_handle(he2); + + // Calculate midpoint coordinates + const Point new0 = (this->point(p0) + this->point(p2)) * static_cast::value_type >(0.5); + const Point new1 = (this->point(p0) + this->point(p1)) * static_cast::value_type >(0.5); + const Point new2 = (this->point(p1) + this->point(p2)) * static_cast::value_type >(0.5); + + // Add vertices at midpoint coordinates + VertexHandle v0 = this->add_vertex(new0); + VertexHandle v1 = this->add_vertex(new1); + VertexHandle v2 = this->add_vertex(new2); + + const bool split0 = !this->is_boundary(eh0); + const bool split1 = !this->is_boundary(eh1); + const bool split2 = !this->is_boundary(eh2); + + // delete original face + this->delete_face(_fh); + + // split boundary edges of deleted face ( if not boundary ) + if ( split0 ) { + this->split(eh0,v0); + } + + if ( split1 ) { + this->split(eh1,v1); + } + + if ( split2 ) { + this->split(eh2,v2); + } + + // Retriangulate + this->add_face(v0 , p0, v1); + this->add_face(p2, v0 , v2); + this->add_face(v2,v1,p1); + this->add_face(v2 , v0, v1); + } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be undefined! + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split(FaceHandle _fh, VertexHandle _vh) + { PolyMesh::split(_fh, _vh); } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be adjusted to the properties of the original face + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split_copy(FaceHandle _fh, VertexHandle _vh) + { PolyMesh::split_copy(_fh, _vh); } + + /** \brief Calculates the area of a face + * + * @param _fh Handle of the face to calculate the area of + */ + Scalar calc_face_area(FaceHandle _fh) const + { + const HalfedgeHandle heh = this->halfedge_handle(_fh); + return this->calc_sector_area(heh); + } + + /** \name Normal vector computation + */ + //@{ + + /** Calculate normal vector for face _fh (specialized for TriMesh). */ + Normal calc_face_normal(FaceHandle _fh) const; + + //@} +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_TRIMESH_C) +#define OPENMESH_TRIMESH_TEMPLATES +#include "TriMeshT_impl.hh" +#endif +//============================================================================= +#endif // OPENMESH_TRIMESH_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/TriMeshT_impl.hh b/Sources/OpenMeshCore/Core/Mesh/TriMeshT_impl.hh new file mode 100644 index 0000000..b6392ba --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/TriMeshT_impl.hh @@ -0,0 +1,88 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS TriMeshT - IMPLEMENTATION +// +//============================================================================= + + +#define OPENMESH_TRIMESH_C + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + +template +typename TriMeshT::Normal +TriMeshT:: +calc_face_normal(FaceHandle _fh) const +{ + assert(this->halfedge_handle(_fh).is_valid()); + ConstFaceVertexIter fv_it(this->cfv_iter(_fh)); + + const Point& p0(this->point(*fv_it)); ++fv_it; + const Point& p1(this->point(*fv_it)); ++fv_it; + const Point& p2(this->point(*fv_it)); + + return PolyMesh::calc_face_normal(p0, p1, p2); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/TriMesh_ArrayKernelT.hh b/Sources/OpenMeshCore/Core/Mesh/TriMesh_ArrayKernelT.hh new file mode 100644 index 0000000..bb7f235 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/TriMesh_ArrayKernelT.hh @@ -0,0 +1,112 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS TriMesh_ArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_TRIMESH_ARRAY_KERNEL_HH +#define OPENMESH_TRIMESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +template +class PolyMesh_ArrayKernelT; +//== CLASS DEFINITION ========================================================= + + +/// Helper class to create a TriMesh-type based on ArrayKernelT +template +struct TriMesh_ArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef TriMeshT Mesh; +}; + + + +/** \ingroup mesh_types_group + Triangle mesh based on the ArrayKernel. + \see OpenMesh::TriMeshT + \see OpenMesh::ArrayKernelT +*/ +template +class TriMesh_ArrayKernelT + : public TriMesh_ArrayKernel_GeneratorT::Mesh +{ +public: + TriMesh_ArrayKernelT() {} + template + explicit TriMesh_ArrayKernelT( const PolyMesh_ArrayKernelT & t) + { + //assign the connectivity and standard properties + this->assign(t,true); + } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_TRIMESH_ARRAY_KERNEL_HH +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/gen/circulators_header.hh b/Sources/OpenMeshCore/Core/Mesh/gen/circulators_header.hh new file mode 100644 index 0000000..b795a00 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/gen/circulators_header.hh @@ -0,0 +1,93 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_CIRCULATORS_HH +#define OPENMESH_CIRCULATORS_HH + +//============================================================================= +// +// Vertex and Face circulators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class VertexVertexIterT; +template class VertexIHalfedgeIterT; +template class VertexOHalfedgeIterT; +template class VertexEdgeIterT; +template class VertexFaceIterT; + +template class ConstVertexVertexIterT; +template class ConstVertexIHalfedgeIterT; +template class ConstVertexOHalfedgeIterT; +template class ConstVertexEdgeIterT; +template class ConstVertexFaceIterT; + +template class FaceVertexIterT; +template class FaceHalfedgeIterT; +template class FaceEdgeIterT; +template class FaceFaceIterT; + +template class ConstFaceVertexIterT; +template class ConstFaceHalfedgeIterT; +template class ConstFaceEdgeIterT; +template class ConstFaceFaceIterT; + + + diff --git a/Sources/OpenMeshCore/Core/Mesh/gen/circulators_template.hh b/Sources/OpenMeshCore/Core/Mesh/gen/circulators_template.hh new file mode 100644 index 0000000..97a2171 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/gen/circulators_template.hh @@ -0,0 +1,190 @@ +//== CLASS DEFINITION ========================================================= + + +/** \class CirculatorT CirculatorsT.hh + Circulator. +*/ + +template +class CirculatorT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef TargetType value_type; + typedef TargetHandle value_handle; + +#if IsConst + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const TargetType& reference; + typedef const TargetType* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef TargetType& reference; + typedef TargetType* pointer; +#endif + + + + /// Default constructor + CirculatorT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a SourceHandle + CirculatorT(mesh_ref _mesh, SourceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { post_init; } + + + /// Construct with mesh and start halfedge + CirculatorT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { post_init; } + + + /// Copy constructor + CirculatorT(const CirculatorT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { post_init; } + + + /// Assignment operator + CirculatorT& operator=(const CirculatorT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if IsConst + /// construct from non-const circulator type + CirculatorT(const NonConstCircT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { post_init; } + + + /// assign from non-const circulator + CirculatorT& operator=(const NonConstCircT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstCircT; +#endif + + + /// Equal ? + bool operator==(const CirculatorT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const CirculatorT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + CirculatorT& operator++() { + assert(mesh_); + active_ = true; + increment; + return *this; + } + + + /// Pre-Decrement (next ccw target) + CirculatorT& operator--() { + assert(mesh_); + active_ = true; + decrement; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + TargetHandle handle() const { + assert(mesh_); + return get_handle; + } + + + /// Cast to the handle of the current target. + operator TargetHandle() const { + assert(mesh_); + return get_handle; + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +private: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + diff --git a/Sources/OpenMeshCore/Core/Mesh/gen/footer.hh b/Sources/OpenMeshCore/Core/Mesh/gen/footer.hh new file mode 100644 index 0000000..8e2a9c1 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/gen/footer.hh @@ -0,0 +1,6 @@ +//============================================================================= +} // namespace Iterators +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Mesh/gen/generate.sh b/Sources/OpenMeshCore/Core/Mesh/gen/generate.sh new file mode 100644 index 0000000..3bcaffd --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/gen/generate.sh @@ -0,0 +1,175 @@ +#!/bin/bash + +#------------------------------------------------------------------------------ + + +# generate_iterator( TargetType, n_elements, has_element_status ) +function generate_iterator +{ + NonConstIter=$1"IterT" + ConstIter="Const"$NonConstIter + TargetType="typename Mesh::"$1 + TargetHandle="typename Mesh::"$1"Handle" + + + cat iterators_template.hh \ + | sed -e "s/IteratorT/$NonConstIter/; s/IteratorT/$NonConstIter/; + s/NonConstIterT/$NonConstIter/; + s/ConstIterT/$ConstIter/; + s/TargetType/$TargetType/; + s/TargetHandle/$TargetHandle/; + s/IsConst/0/; + s/n_elements/$2/; + s/has_element_status/$3/;" + + + cat iterators_template.hh \ + | sed -e "s/IteratorT/$ConstIter/; s/IteratorT/$ConstIter/; + s/NonConstIterT/$NonConstIter/; + s/ConstIterT/$ConstIter/; + s/TargetType/$TargetType/; + s/TargetHandle/$TargetHandle/; + s/IsConst/1/; + s/n_elements/$2/; + s/has_element_status/$3/;" +} + + +#------------------------------------------------------------------------------ + + +# generate_circulator( NonConstName, SourceType, TargetType, +# post_init, +# increment, decrement, +# get_handle, +# [Name] ) +function generate_circulator +{ + NonConstCirc=$1 + ConstCirc="Const"$NonConstCirc + SourceHandle="typename Mesh::"$2"Handle" + TargetHandle="typename Mesh::"$3"Handle" + TargetType="typename Mesh::"$3 + + + cat circulators_template.hh \ + | sed -e "s/CirculatorT/$NonConstCirc/; s/CirculatorT/$NonConstCirc/; + s/NonConstCircT/$NonConstCirc/; + s/ConstCircT/$ConstCirc/; + s/SourceHandle/$SourceHandle/; + s/TargetHandle/$TargetHandle/; + s/TargetType/$TargetType/; + s/IsConst/0/; + s/post_init/$4/; + s/increment/$5/; + s/decrement/$6/; + s/get_handle/$7/;" + + + cat circulators_template.hh \ + | sed -e "s/CirculatorT/$ConstCirc/; s/CirculatorT/$ConstCirc/; + s/NonConstCircT/$NonConstCirc/; + s/ConstCircT/$ConstCirc/; + s/SourceHandle/$SourceHandle/; + s/TargetHandle/$TargetHandle/; + s/TargetType/$TargetType/; + s/IsConst/1/; + s/post_init/$4/; + s/increment/$5/; + s/decrement/$6/; + s/get_handle/$7/;" +} + + +#------------------------------------------------------------------------------ + + +### Generate IteratorsT.hh + +cat iterators_header.hh > IteratorsT.hh + +generate_iterator Vertex n_vertices has_vertex_status >> IteratorsT.hh +generate_iterator Halfedge n_halfedges has_halfedge_status >> IteratorsT.hh +generate_iterator Edge n_edges has_edge_status >> IteratorsT.hh +generate_iterator Face n_faces has_face_status >> IteratorsT.hh + +cat footer.hh >> IteratorsT.hh + + +#------------------------------------------------------------------------------ + + +### Generate CirculatorsT.hh + +cat circulators_header.hh > CirculatorsT.hh + + +generate_circulator VertexVertexIterT Vertex Vertex \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "mesh_->to_vertex_handle(heh_);" \ + >> CirculatorsT.hh + +generate_circulator VertexOHalfedgeIterT Vertex Halfedge \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "heh_" \ + >> CirculatorsT.hh + +generate_circulator VertexIHalfedgeIterT Vertex Halfedge \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "mesh_->opposite_halfedge_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator VertexEdgeIterT Vertex Edge \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "mesh_->edge_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator VertexFaceIterT Vertex Face \ + "if (heh_.is_valid() \&\& !handle().is_valid()) operator++();" \ + "do heh_=mesh_->cw_rotated_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "do heh_=mesh_->ccw_rotated_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "mesh_->face_handle(heh_)" \ + >> CirculatorsT.hh + + +generate_circulator FaceVertexIterT Face Vertex \ + " " \ + "heh_=mesh_->next_halfedge_handle(heh_);" \ + "heh_=mesh_->prev_halfedge_handle(heh_);" \ + "mesh_->to_vertex_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator FaceHalfedgeIterT Face Halfedge \ + " " \ + "heh_=mesh_->next_halfedge_handle(heh_);" \ + "heh_=mesh_->prev_halfedge_handle(heh_);" \ + "heh_" \ + >> CirculatorsT.hh + +generate_circulator FaceEdgeIterT Face Edge \ + " " \ + "heh_=mesh_->next_halfedge_handle(heh_);" \ + "heh_=mesh_->prev_halfedge_handle(heh_);" \ + "mesh_->edge_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator FaceFaceIterT Face Face \ + "if (heh_.is_valid() \&\& !handle().is_valid()) operator++();" \ + "do heh_=mesh_->next_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "do heh_=mesh_->prev_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "mesh_->face_handle(mesh_->opposite_halfedge_handle(heh_))" \ + >> CirculatorsT.hh + + +cat footer.hh >> CirculatorsT.hh + + +#------------------------------------------------------------------------------ diff --git a/Sources/OpenMeshCore/Core/Mesh/gen/iterators_header.hh b/Sources/OpenMeshCore/Core/Mesh/gen/iterators_header.hh new file mode 100644 index 0000000..afdaca6 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/gen/iterators_header.hh @@ -0,0 +1,82 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_ITERATORS_HH +#define OPENMESH_ITERATORS_HH + +//============================================================================= +// +// Iterators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class VertexIterT; +template class ConstVertexIterT; +template class HalfedgeIterT; +template class ConstHalfedgeIterT; +template class EdgeIterT; +template class ConstEdgeIterT; +template class FaceIterT; +template class ConstFaceIterT; + + + + diff --git a/Sources/OpenMeshCore/Core/Mesh/gen/iterators_template.hh b/Sources/OpenMeshCore/Core/Mesh/gen/iterators_template.hh new file mode 100644 index 0000000..99f54e0 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Mesh/gen/iterators_template.hh @@ -0,0 +1,162 @@ +//== CLASS DEFINITION ========================================================= + + +/** \class IteratorT IteratorsT.hh + Linear iterator. +*/ + +template +class IteratorT +{ +public: + + + //--- Typedefs --- + + typedef TargetType value_type; + typedef TargetHandle value_handle; + +#if IsConst + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + IteratorT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + IteratorT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + IteratorT(const IteratorT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + IteratorT& operator=(const IteratorT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if IsConst + + /// Construct from a non-const iterator + IteratorT(const NonConstIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + IteratorT& operator=(const NonConstIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const IteratorT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const IteratorT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + IteratorT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + IteratorT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_element_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_elements()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + diff --git a/Sources/OpenMeshCore/Core/System/OpenMeshDLLMacros.hh b/Sources/OpenMeshCore/Core/System/OpenMeshDLLMacros.hh new file mode 100644 index 0000000..4c1e804 --- /dev/null +++ b/Sources/OpenMeshCore/Core/System/OpenMeshDLLMacros.hh @@ -0,0 +1,65 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +// Disable the warnings about needs to have DLL interface as we have tons of vector templates +#ifdef _MSC_VER + #pragma warning( disable: 4251 ) +#endif + +#ifndef OPENMESHDLLEXPORT + #ifdef WIN32 + #ifdef OPENMESHDLL + #ifdef BUILDOPENMESHDLL + #define OPENMESHDLLEXPORT __declspec(dllexport) + #define OPENMESHDLLEXPORTONLY __declspec(dllexport) + #else + #define OPENMESHDLLEXPORT __declspec(dllimport) + #define OPENMESHDLLEXPORTONLY + #endif + #else + #define OPENMESHDLLEXPORT + #define OPENMESHDLLEXPORTONLY + #endif + #else + #define OPENMESHDLLEXPORT + #define OPENMESHDLLEXPORTONLY + #endif +#endif diff --git a/Sources/OpenMeshCore/Core/System/compiler.hh b/Sources/OpenMeshCore/Core/System/compiler.hh new file mode 100644 index 0000000..3abf35f --- /dev/null +++ b/Sources/OpenMeshCore/Core/System/compiler.hh @@ -0,0 +1,167 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef OPENMESH_COMPILER_H +#define OPENMESH_COMPILER_H + +//============================================================================= + +#if defined(_DEBUG) || defined(DEBUG) +# define OM_DEBUG +#endif + +//============================================================================= + +// Workaround for Intel Compiler with MS VC++ 6 +#if defined(_MSC_VER) && \ + ( defined(__ICL) || defined(__INTEL_COMPILER) || defined(__ICC) ) +# if !defined(__INTEL_COMPILER) +# define __INTEL_COMPILER __ICL +# endif +# define OM_USE_INTEL_COMPILER 1 +#endif + +// --------------------------------------------------------- MS Visual C++ ---- +// Compiler _MSC_VER +// .NET 2002 1300 +// .NET 2003 1310 +// .NET 2005 1400 +#if defined(_MSC_VER) && !defined(OM_USE_INTEL_COMPILER) +# if (_MSC_VER == 1300) +# define OM_CC_MSVC +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 0 +# define OM_PARTIAL_SPECIALIZATION 0 +# define OM_INCLUDE_TEMPLATES 1 +# elif (_MSC_VER == 1310) +# define OM_CC_MSVC +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# elif (_MSC_VER >= 1400) // settings for .NET 2005 (NOTE: not fully tested) +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# else +# error "Version 7 (.NET 2002) or higher of the MS VC++ is required!" +# endif +// currently no windows dll supported +# define OM_STATIC_BUILD 1 +# if defined(_MT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "MSVC++" +# define OM_CC_VERSION _MSC_VER +// Does not work stable because the define _CPPRTTI sometimes does not exist, +// though the option /GR is set!? +# if defined(__cplusplus) && !defined(_CPPRTTI) +# error "Enable Runtime Type Information (Compiler Option /GR)!" +# endif +# if !defined(_USE_MATH_DEFINES) +# error "You have to define _USE_MATH_DEFINES in the compiler settings!" +# endif +// ------------------------------------------------------------- Borland C ---- +#elif defined(__BORLANDC__) +# error "Borland Compiler are not supported yet!" +// ------------------------------------------------------------- GNU C/C++ ---- +#elif defined(__GNUC__) && !defined(__ICC) +# define OM_CC_GCC +# define OM_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 ) +# define OM_GCC_MAJOR __GNUC__ +# define OM_GCC_MINOR __GNUC_MINOR__ +# if (OM_GCC_VERSION >= 30200) +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# else +# error "Version 3.2.0 or better of the GNU Compiler is required!" +# endif +# if defined(_REENTRANT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "GCC" +# define OM_CC_VERSION OM_GCC_VERSION +// ------------------------------------------------------------- Intel icc ---- +#elif defined(__ICC) || defined(__INTEL_COMPILER) +# define OM_CC_ICC +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# if defined(_REENTRANT) || defined(_MT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "ICC" +# define OM_CC_VERSION __INTEL_COMPILER +// currently no windows dll supported +# if defined(_MSC_VER) || defined(WIN32) +# define OM_STATIC_BUILD 1 +# endif +// ------------------------------------------------------ MIPSpro Compiler ---- +#elif defined(__MIPS_ISA) || defined(__mips) +// _MIPS_ISA +// _COMPILER_VERSION e.g. 730, 7 major, 3 minor +// _MIPS_FPSET 32|64 +// _MIPS_SZINT 32|64 +// _MIPS_SZLONG 32|64 +// _MIPS_SZPTR 32|64 +# define OM_CC_MIPS +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 0 +# define OM_CC "MIPS" +# define OM_CC_VERSION _COMPILER_VERSION +// ------------------------------------------------------------------ ???? ---- +#else +# error "You're using an unsupported compiler!" +#endif + +//============================================================================= +#endif // OPENMESH_COMPILER_H defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/System/config.h b/Sources/OpenMeshCore/Core/System/config.h new file mode 100644 index 0000000..342caab --- /dev/null +++ b/Sources/OpenMeshCore/Core/System/config.h @@ -0,0 +1,106 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/** \file config.h + * \todo Move content to config.hh and include it to be compatible with old + * source. + */ + +//============================================================================= + +#ifndef OPENMESH_CONFIG_H +#define OPENMESH_CONFIG_H + +//============================================================================= + +#include +#include +#include + +// ---------------------------------------------------------------------------- + + +#define OM_VERSION 0x0B0000 +//#define OM_VERSION 0x70200 + +#define OM_GET_VER ((OM_VERSION & 0xf0000) >> 16) +#define OM_GET_MAJ ((OM_VERSION & 0x0ff00) >> 8) +#define OM_GET_MIN (OM_VERSION & 0x000ff) + +#ifdef WIN32 +# ifdef min +# pragma message("Detected min macro! OpenMesh does not compile with min/max macros active! Please add a define NOMINMAX to your compiler flags or add #undef min before including OpenMesh headers !") +# error min macro active +# endif +# ifdef max +# pragma message("Detected max macro! OpenMesh does not compile with min/max macros active! Please add a define NOMINMAX to your compiler flags or add #undef max before including OpenMesh headers !") +# error max macro active +# endif +#endif + +//! define OM_SUPPRESS_DEPRECATED to suppress deprecated code warnings +#if defined(OM_SUPPRESS_DEPRECATED) +#pragma message( \ + "OpenMesh deprecated code warnings suppressed, please fix your code soon") +# define OM_DEPRECATED(msg) +#elif defined(_MSC_VER) +# define OM_DEPRECATED(msg) __declspec(deprecated(msg)) +#elif defined(__GNUC__) +# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40500 /* Test for GCC >= 4.5.0 */ +# define OM_DEPRECATED(msg) __attribute__ ((deprecated(msg))) +# else +# define OM_DEPRECATED(msg) __attribute__ ((deprecated)) +# endif +#elif defined(__clang__) +# define OM_DEPRECATED(msg) __attribute__ ((deprecated(msg))) +#else +# define OM_DEPRECATED(msg) +#endif + +typedef unsigned int uint; + +#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) +#define OM_HAS_HASH +#endif + +//============================================================================= +#endif // OPENMESH_CONFIG_H defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/System/config.hh b/Sources/OpenMeshCore/Core/System/config.hh new file mode 100644 index 0000000..4073290 --- /dev/null +++ b/Sources/OpenMeshCore/Core/System/config.hh @@ -0,0 +1,44 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#include diff --git a/Sources/OpenMeshCore/Core/System/mostream.hh b/Sources/OpenMeshCore/Core/System/mostream.hh new file mode 100644 index 0000000..2b7e08e --- /dev/null +++ b/Sources/OpenMeshCore/Core/System/mostream.hh @@ -0,0 +1,325 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// multiplex streams & ultilities +// +//============================================================================= + +#ifndef OPENMESH_MOSTREAM_HH +#define OPENMESH_MOSTREAM_HH + + +//== INCLUDES ================================================================= + +#include +#include +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 +# include +#else +# include +#endif +#include +#include +#include +#include + +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + #include +#endif + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +#ifndef DOXY_IGNORE_THIS + + +//== CLASS DEFINITION ========================================================= + + +class basic_multiplex_target +{ +public: + virtual ~basic_multiplex_target() {} + virtual void operator<<(const std::string& _s) = 0; +}; + + +template +class multiplex_target : public basic_multiplex_target +{ +public: + explicit multiplex_target(T& _t) : target_(_t) {} + virtual void operator<<(const std::string& _s) override { target_ << _s; } +private: + T& target_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 +# define STREAMBUF streambuf +# define INT_TYPE int +# define TRAITS_TYPE +#else +# define STREAMBUF std::basic_streambuf +#endif + +class multiplex_streambuf : public STREAMBUF +{ +public: + + typedef STREAMBUF base_type; +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 + typedef int int_type; + struct traits_type + { + static int_type eof() { return -1; } + static char to_char_type(int_type c) { return char(c); } + }; +#else + typedef base_type::int_type int_type; + typedef base_type::traits_type traits_type; +#endif + + // Constructor + multiplex_streambuf() : enabled_(true) { buffer_.reserve(100); } + + // Destructor + ~multiplex_streambuf() + { + tmap_iter t_it(target_map_.begin()), t_end(target_map_.end()); + for (; t_it!=t_end; ++t_it) + delete t_it->second; + } + + + // buffer enable/disable + bool is_enabled() const { return enabled_; } + void enable() { enabled_ = true; } + void disable() { enabled_ = false; } + + + // construct multiplex_target and add it to targets + template bool connect(T& _target) + { + void* key = (void*) &_target; + + if (target_map_.find(key) != target_map_.end()) + return false; + + target_type* mtarget = new multiplex_target(_target); + target_map_[key] = mtarget; + + __connect(mtarget); + return true; + } + + + // disconnect target from multiplexer + template bool disconnect(T& _target) + { + void* key = (void*) &_target; + tmap_iter t_it = target_map_.find(key); + + if (t_it != target_map_.end()) + { + __disconnect(t_it->second); + target_map_.erase(t_it); + return true; + } + + return false; + } + + +protected: + + // output what's in buffer_ + virtual int sync() + { + // If working on multiple threads, we need to serialize the output correctly (requires c++11 headers) + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + std::lock_guard lck (serializer_); + #endif + + if (!buffer_.empty()) + { + if (enabled_) multiplex(); +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 + buffer_ = ""; // member clear() not available! +#else + buffer_.clear(); +#endif + } + return base_type::sync(); + } + + + // take on char and add it to buffer_ + // if '\n' is encountered, trigger a sync() + virtual + int_type overflow(int_type _c = multiplex_streambuf::traits_type::eof()) + { + char c = traits_type::to_char_type(_c); + + // If working on multiple threads, we need to serialize the output correctly (requires c++11 headers) + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + { + std::lock_guard lck (serializer_); + buffer_.push_back(c); + } + #else + buffer_.push_back(c); + #endif + + if (c == '\n') sync(); + return 0; + } + + +private: + + typedef basic_multiplex_target target_type; + typedef std::vector target_list; + typedef target_list::iterator tlist_iter; + typedef std::map target_map; + typedef target_map::iterator tmap_iter; + + + // add _target to list of multiplex targets + void __connect(target_type* _target) { targets_.push_back(_target); } + + + // remove _target from list of multiplex targets + void __disconnect(target_type* _target) { + targets_.erase(std::find(targets_.begin(), targets_.end(), _target)); + } + + + // multiplex output of buffer_ to all targets + void multiplex() + { + tlist_iter t_it(targets_.begin()), t_end(targets_.end()); + for (; t_it!=t_end; ++t_it) + **t_it << buffer_; + } + + +private: + + target_list targets_; + target_map target_map_; + std::string buffer_; + bool enabled_; + + // If working on multiple threads, we need to serialize the output correctly (requires c++11 headers) + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + std::mutex serializer_; + #endif + +}; + +#undef STREAMBUF + + +//== CLASS DEFINITION ========================================================= + + +/** \class mostream mostream.hh + + This class provides streams that can easily be multiplexed (using + the connect() method) and toggled on/off (using enable() / + disable()). + + \see omlog, omout, omerr +*/ + +class mostream : public std::ostream +{ +public: + + /// Explicit constructor + explicit mostream() : std::ostream(nullptr) { init(&streambuffer_); } + + + /// Connect target to multiplexer + template bool connect(T& _target) + { + return streambuffer_.connect(_target); + } + + + /// Disconnect target from multiplexer + template bool disconnect(T& _target) + { + return streambuffer_.disconnect(_target); + } + + + /// is buffer enabled + bool is_enabled() const { return streambuffer_.is_enabled(); } + + /// enable this buffer + void enable() { streambuffer_.enable(); } + + /// disable this buffer + void disable() { streambuffer_.disable(); } + + +private: + multiplex_streambuf streambuffer_; +}; + + +//============================================================================= +#endif +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MOSTREAM_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/System/omstream.cc b/Sources/OpenMeshCore/Core/System/omstream.cc new file mode 100644 index 0000000..786ada2 --- /dev/null +++ b/Sources/OpenMeshCore/Core/System/omstream.cc @@ -0,0 +1,102 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// CLASS mostream - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include +#include + + +//== IMPLEMENTATION ========================================================== + + +OpenMesh::mostream& omlog() +{ + static bool initialized = false; + static OpenMesh::mostream mystream; + if (!initialized) + { + mystream.connect(std::clog); +#ifdef NDEBUG + mystream.disable(); +#endif + initialized = true; + } + return mystream; +} + + +OpenMesh::mostream& omout() +{ + static bool initialized = false; + static OpenMesh::mostream mystream; + if (!initialized) + { + mystream.connect(std::cout); + initialized = true; + } + return mystream; +} + + +OpenMesh::mostream& omerr() +{ + static bool initialized = false; + static OpenMesh::mostream mystream; + if (!initialized) + { + mystream.connect(std::cerr); + initialized = true; + } + return mystream; +} + + +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/System/omstream.hh b/Sources/OpenMeshCore/Core/System/omstream.hh new file mode 100644 index 0000000..18712f9 --- /dev/null +++ b/Sources/OpenMeshCore/Core/System/omstream.hh @@ -0,0 +1,78 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// OpenMesh streams: omlog, omout, omerr +// +//============================================================================= + +#ifndef OPENMESH_OMSTREAMS_HH +#define OPENMESH_OMSTREAMS_HH + + +//== INCLUDES ================================================================= + +#include + + +//== CLASS DEFINITION ========================================================= + +/** \file omstream.hh + This file provides the streams omlog, omout, and omerr. +*/ + +/** \name stream replacements + These stream provide replacements for clog, cout, and cerr. They have + the advantage that they can easily be multiplexed. + \see OpenMesh::mostream +*/ +//@{ +OPENMESHDLLEXPORT OpenMesh::mostream& omlog(); +OPENMESHDLLEXPORT OpenMesh::mostream& omout(); +OPENMESHDLLEXPORT OpenMesh::mostream& omerr(); +//@} + +//============================================================================= +#endif // OPENMESH_OMSTREAMS_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Templates/bla.hh b/Sources/OpenMeshCore/Core/Templates/bla.hh new file mode 100644 index 0000000..7340366 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Templates/bla.hh @@ -0,0 +1,110 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// CLASS bla +// +//============================================================================= +#ifndef DOXY_IGNORE_THIS +#ifndef OPENMESH_NEWCLASST_HH +#define OPENMESH_NEWCLASST_HH + + +//== INCLUDES ================================================================= + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + + + +/** \class blaT blaT.hh + + Brief Description. + + A more elaborate description follows. +*/ + +template <> +class blaT +{ +public: + + /// Default constructor + blaT() {} + + /// Destructor + ~blaT() {} + + +private: + + /// Copy constructor (not used) + blaT(const blaT& _rhs); + + /// Assignment operator (not used) + blaT& operator=(const blaT& _rhs); + +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_BLA_C) +#define OPENMESH_BLA_TEMPLATES +#include "blaT_impl.hh" +#endif +//============================================================================= +#endif // OPENMESH_NEWCLASST_HH defined +#endif // DOXY_IGNORE_THIS +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Templates/blaT_impl.hh b/Sources/OpenMeshCore/Core/Templates/blaT_impl.hh new file mode 100644 index 0000000..64c3b6d --- /dev/null +++ b/Sources/OpenMeshCore/Core/Templates/blaT_impl.hh @@ -0,0 +1,72 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// CLASS bla - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_BLA_C + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + + + +//----------------------------------------------------------------------------- + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/AutoPropertyHandleT.hh b/Sources/OpenMeshCore/Core/Utils/AutoPropertyHandleT.hh new file mode 100644 index 0000000..1b2734c --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/AutoPropertyHandleT.hh @@ -0,0 +1,133 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_AutoPropertyHandleT_HH +#define OPENMESH_AutoPropertyHandleT_HH + +//== INCLUDES ================================================================= +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +template +class AutoPropertyHandleT : public PropertyHandle_ +{ +public: + typedef Mesh_ Mesh; + typedef PropertyHandle_ PropertyHandle; + typedef PropertyHandle Base; + typedef typename PropertyHandle::Value Value; + typedef AutoPropertyHandleT + Self; +protected: + Mesh* m_; + bool own_property_;//ref counting? + +public: + AutoPropertyHandleT() + : m_(nullptr), own_property_(false) + {} + + AutoPropertyHandleT(const Self& _other) + : Base(_other.idx()), m_(_other.m_), own_property_(false) + {} + + explicit AutoPropertyHandleT(Mesh& _m, const std::string& _pp_name = std::string()) + { add_property(_m, _pp_name); } + + AutoPropertyHandleT(Mesh& _m, PropertyHandle _pph) + : Base(_pph.idx()), m_(&_m), own_property_(false) + {} + + ~AutoPropertyHandleT() + { + if (own_property_) + { + m_->remove_property(*this); + } + } + + inline void add_property(Mesh& _m, const std::string& _pp_name = std::string()) + { + assert(!is_valid()); + m_ = &_m; + own_property_ = _pp_name.empty() || !m_->get_property_handle(*this, _pp_name); + if (own_property_) + { + m_->add_property(*this, _pp_name); + } + } + + inline void remove_property() + { + assert(own_property_);//only the owner can delete the property + m_->remove_property(*this); + own_property_ = false; + invalidate(); + } + + template + inline Value& operator [] (_Handle _hnd) + { return m_->property(*this, _hnd); } + + template + inline const Value& operator [] (_Handle _hnd) const + { return m_->property(*this, _hnd); } + + inline bool own_property() const + { return own_property_; } + + inline void free_property() + { own_property_ = false; } +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_AutoPropertyHandleT_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/BaseProperty.cc b/Sources/OpenMeshCore/Core/Utils/BaseProperty.cc new file mode 100644 index 0000000..a432101 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/BaseProperty.cc @@ -0,0 +1,54 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#include + +namespace OpenMesh +{ + +void BaseProperty::stats(std::ostream& _ostr) const +{ + _ostr << " " << name() << (persistent() ? ", persistent " : "") << "\n"; +} + +} diff --git a/Sources/OpenMeshCore/Core/Utils/BaseProperty.hh b/Sources/OpenMeshCore/Core/Utils/BaseProperty.hh new file mode 100644 index 0000000..252d2b7 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/BaseProperty.hh @@ -0,0 +1,191 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_BASEPROPERTY_HH +#define OPENMESH_BASEPROPERTY_HH + +#include +#include +#include + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +/** \class BaseProperty Property.hh + + Abstract class defining the basic interface of a dynamic property. +**/ + +class OPENMESHDLLEXPORT BaseProperty +{ +public: + + /// Indicates an error when a size is returned by a member. + static const size_t UnknownSize = size_t(-1); + +public: + + /// \brief Default constructor. + /// + /// In %OpenMesh all mesh data is stored in so-called properties. + /// We distinuish between standard properties, which can be defined at + /// compile time using the Attributes in the traits definition and + /// at runtime using the request property functions defined in one of + /// the kernels. + /// + /// If the property should be stored along with the default properties + /// in the OM-format one must name the property and enable the persistant + /// flag with set_persistent(). + /// + /// \param _name Optional textual name for the property. + /// \param _internal_type_name Internal type name which will be used when storing the data in OM format + /// + BaseProperty(const std::string& _name = "", const std::string& _internal_type_name = "" ) + : name_(_name), internal_type_name_(_internal_type_name), persistent_(false) + {} + + /// \brief Copy constructor + BaseProperty(const BaseProperty & _rhs) + : name_( _rhs.name_ ), internal_type_name_(_rhs.internal_type_name_), persistent_( _rhs.persistent_ ) {} + + /// Destructor. + virtual ~BaseProperty() {} + +public: // synchronized array interface + + /// Reserve memory for n elements. + virtual void reserve(size_t _n) = 0; + + /// Resize storage to hold n elements. + virtual void resize(size_t _n) = 0; + + /// Clear all elements and free memory. + virtual void clear() = 0; + + /// Extend the number of elements by one. + virtual void push_back() = 0; + + /// Let two elements swap their storage place. + virtual void swap(size_t _i0, size_t _i1) = 0; + + /// Copy one element to another + virtual void copy(size_t _io, size_t _i1) = 0; + + /// Return a deep copy of self. + virtual BaseProperty* clone () const = 0; + +public: // named property interface + + /// Return the name of the property + const std::string& name() const { return name_; } + + /// Return internal type name of the property for type safe casting alternative to runtime information + const std::string& internal_type_name() const { return internal_type_name_; } + + virtual void stats(std::ostream& _ostr) const; + +public: // I/O support + + /// Returns true if the persistent flag is enabled else false. + bool persistent(void) const { return persistent_; } + + /// Enable or disable persistency. Self must be a named property to enable + /// persistency. + virtual void set_persistent( bool _yn ) = 0; + + ///returns a unique string for the type of the elements + virtual std::string get_storage_name() const = 0; + + /// Number of elements in property + virtual size_t n_elements() const = 0; + + /// Size of one element in bytes or UnknownSize if not known. + virtual size_t element_size() const = 0; + + /// Return size of property in bytes + virtual size_t size_of() const + { + return size_of( n_elements() ); + } + + /// Estimated size of property if it has _n_elem elements. + /// The member returns UnknownSize if the size cannot be estimated. + virtual size_t size_of(size_t _n_elem) const + { + return (element_size()!=UnknownSize) + ? (_n_elem*element_size()) + : UnknownSize; + } + + /// Store self as one binary block + virtual size_t store( std::ostream& _ostr, bool _swap ) const = 0; + + /** Restore self from a binary block. Uses reserve() to set the + size of self before restoring. + **/ + virtual size_t restore( std::istream& _istr, bool _swap ) = 0; + +protected: + + // To be used in a derived class, when overloading set_persistent() + template < typename T > + void check_and_set_persistent( bool _yn ) + { + if ( _yn && !IO::is_streamable() ) + omerr() << "Warning! Type of property value is not binary storable!\n"; + persistent_ = IO::is_streamable() && _yn; + } + +private: + + std::string name_; + std::string internal_type_name_; + bool persistent_; +}; + +}//namespace OpenMesh + +#endif //OPENMESH_BASEPROPERTY_HH + + diff --git a/Sources/OpenMeshCore/Core/Utils/Endian.cc b/Sources/OpenMeshCore/Core/Utils/Endian.cc new file mode 100644 index 0000000..9acef83 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/Endian.cc @@ -0,0 +1,81 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +//== INCLUDES ================================================================= + + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION =========================================================== + +//----------------------------------------------------------------------------- + +int Endian::one_ = 1; + +const Endian::Type Endian::local_ = *((unsigned char*)&Endian::one_) + ? Endian::LSB + : Endian::MSB; + +const char * Endian::as_string(Type _t) +{ + return _t == LSB ? "LSB" : "MSB"; +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/Endian.hh b/Sources/OpenMeshCore/Core/Utils/Endian.hh new file mode 100644 index 0000000..414142b --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/Endian.hh @@ -0,0 +1,98 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_UTILS_ENDIAN_HH +#define OPENMESH_UTILS_ENDIAN_HH + + +//== INCLUDES ================================================================= + + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** Determine byte order of host system. + */ +class OPENMESHDLLEXPORT Endian +{ +public: + + enum Type { + LSB = 1, ///< Little endian (Intel family and clones) + MSB ///< big endian (Motorola's 68x family, DEC Alpha, MIPS) + }; + + /// Return endian type of host system. + static Type local() { return local_; } + + /// Return type _t as string. + static const char * as_string(Type _t); + +private: + static int one_; + static const Type local_; +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/Utils/GenProg.hh b/Sources/OpenMeshCore/Core/Utils/GenProg.hh new file mode 100644 index 0000000..12264cd --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/GenProg.hh @@ -0,0 +1,160 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Utils for generic/generative programming +// +//============================================================================= + +#ifndef OPENMESH_GENPROG_HH +#define OPENMESH_GENPROG_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +namespace GenProg { +#ifndef DOXY_IGNORE_THIS + +//== IMPLEMENTATION =========================================================== + + +/// This type maps \c true or \c false to different types. +template struct Bool2Type { enum { my_bool = b }; }; + +/// This class generates different types from different \c int 's. +template struct Int2Type { enum { my_int = i }; }; + +/// Handy typedef for Bool2Type classes +typedef Bool2Type TrueType; + +/// Handy typedef for Bool2Type classes +typedef Bool2Type FalseType; + +//----------------------------------------------------------------------------- +/// compile time assertions +template struct AssertCompile; +template <> struct AssertCompile {}; + + + +//--- Template "if" w/ partial specialization --------------------------------- +#if OM_PARTIAL_SPECIALIZATION + + +template +struct IF { typedef Then Result; }; + +/** Template \c IF w/ partial specialization +\code +typedef IF::Result ResultType; +\endcode +*/ +template +struct IF { typedef Else Result; }; + + + + + +//--- Template "if" w/o partial specialization -------------------------------- +#else + + +struct SelectThen +{ + template struct Select { + typedef Then Result; + }; +}; + +struct SelectElse +{ + template struct Select { + typedef Else Result; + }; +}; + +template struct ChooseSelector { + typedef SelectThen Result; +}; + +template <> struct ChooseSelector { + typedef SelectElse Result; +}; + + +/** Template \c IF w/o partial specialization. Use it like +\code +typedef IF::Result ResultType; +\endcode +*/ + +template +class IF +{ + typedef typename ChooseSelector::Result Selector; +public: + typedef typename Selector::template Select::Result Result; +}; + +#endif + +//============================================================================= +#endif +} // namespace GenProg +} // namespace OpenMesh + +#define assert_compile(EXPR) GenProg::AssertCompile<(EXPR)>(); + +//============================================================================= +#endif // OPENMESH_GENPROG_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/HandleToPropHandle.hh b/Sources/OpenMeshCore/Core/Utils/HandleToPropHandle.hh new file mode 100644 index 0000000..6e5f639 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/HandleToPropHandle.hh @@ -0,0 +1,45 @@ +#ifndef HANDLETOPROPHANDLE_HH_ +#define HANDLETOPROPHANDLE_HH_ + +#include +#include + +namespace OpenMesh { + + template + struct HandleToPropHandle { + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::VPropHandleT; + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::HPropHandleT; + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::EPropHandleT; + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::FPropHandleT; + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::MPropHandleT; + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::MPropHandleT; + }; + +} // namespace OpenMesh + +#endif // HANDLETOPROPHANDLE_HH_ diff --git a/Sources/OpenMeshCore/Core/Utils/Noncopyable.hh b/Sources/OpenMeshCore/Core/Utils/Noncopyable.hh new file mode 100644 index 0000000..928761c --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/Noncopyable.hh @@ -0,0 +1,89 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the Non-Copyable metapher +// +//============================================================================= + +#ifndef OPENMESH_NONCOPYABLE_HH +#define OPENMESH_NONCOPYABLE_HH + + +//----------------------------------------------------------------------------- + +#include + +//----------------------------------------------------------------------------- + +namespace OpenMesh { +namespace Utils { + +//----------------------------------------------------------------------------- + +/** This class demonstrates the non copyable idiom. In some cases it is + important an object can't be copied. Deriving from Noncopyable makes sure + all relevant constructor and operators are made inaccessable, for public + AND derived classes. +**/ +class Noncopyable +{ +public: + Noncopyable() { } + +private: + /// Prevent access to copy constructor + Noncopyable( const Noncopyable& ); + + /// Prevent access to assignment operator + const Noncopyable& operator=( const Noncopyable& ); +}; + +//============================================================================= +} // namespace Utils +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_NONCOPYABLE_HH +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/Predicates.hh b/Sources/OpenMeshCore/Core/Utils/Predicates.hh new file mode 100644 index 0000000..8d7f0fe --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/Predicates.hh @@ -0,0 +1,293 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +namespace Predicates { + +//== FORWARD DECLARATION ====================================================== + +//== CLASS DEFINITION ========================================================= + +template +struct PredicateBase +{ +}; + +template +struct Predicate : public PredicateBase> +{ + Predicate(PredicateT _p) + : + p_(_p) + {} + + template + bool operator()(const T& _t) const { return p_(_t); } + + PredicateT p_; +}; + +template +Predicate make_predicate(PredicateT& _p) { return { _p }; } + +template +Predicate make_predicate(PredicateT&& _p) { return { _p }; } + +template +struct Disjunction : public PredicateBase> +{ + Disjunction(Predicate1T _p1, Predicate2T _p2) + : + p1_(_p1), + p2_(_p2) + {} + + template + bool operator()(const T& _t) const { return p1_( _t) || p2_( _t); } + + Predicate1T p1_; + Predicate2T p2_; +}; + +template +struct Conjunction : public PredicateBase> +{ + Conjunction(Predicate1T _p1, Predicate2T _p2) + : + p1_(_p1), + p2_(_p2) + {} + + template + bool operator()(const T& _t) const { return p1_( _t) && p2_( _t); } + + Predicate1T p1_; + Predicate2T p2_; +}; + + +template +struct Negation : public PredicateBase> +{ + Negation(const PredicateT& _p1) + : + p1_(_p1) + {} + + template + bool operator()(const T& _t) const { return !p1_( _t); } + + PredicateT p1_; +}; + +template +Disjunction operator||(PredicateBase& p1, PredicateBase& p2) +{ + return Disjunction(static_cast(p1), static_cast(p2)); +} + +template +Disjunction operator||(PredicateBase& p1, PredicateBase&& p2) +{ + return Disjunction(static_cast(p1), static_cast(p2)); +} + +template +Disjunction operator||(PredicateBase&& p1, PredicateBase& p2) +{ + return Disjunction(static_cast(p1), static_cast(p2)); +} + +template +Disjunction operator||(PredicateBase&& p1, PredicateBase&& p2) +{ + return Disjunction(static_cast(p1), static_cast(p2)); +} + +template +Conjunction operator&&(PredicateBase& p1, PredicateBase& p2) +{ + return Conjunction(static_cast(p1), static_cast(p2)); +} + +template +Conjunction operator&&(PredicateBase& p1, PredicateBase&& p2) +{ + return Conjunction(static_cast(p1), static_cast(p2)); +} + +template +Conjunction operator&&(PredicateBase&& p1, PredicateBase& p2) +{ + return Conjunction(static_cast(p1), static_cast(p2)); +} + +template +Conjunction operator&&(PredicateBase&& p1, PredicateBase&& p2) +{ + return Conjunction(static_cast(p1), static_cast(p2)); +} + +template +Negation operator!(PredicateBase

& p) +{ + return Negation(static_cast(p)); +} + +template +Negation

operator!(PredicateBase

&& p) +{ + return Negation

(static_cast(p)); +} + +struct Feature : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.feature(); } +}; + +struct Selected : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.selected(); } +}; + +struct Tagged : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.tagged(); } +}; + +struct Tagged2 : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.tagged2(); } +}; + +struct Locked : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.locked(); } +}; + +struct Hidden : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.hidden(); } +}; + +struct Deleted : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.deleted(); } +}; + +struct Boundary : public PredicateBase +{ + template + bool operator()(const SmartHandleBoundaryPredicate& _h) const { return _h.is_boundary(); } +}; + +template +struct Regular: public PredicateBase> +{ + bool operator()(const SmartVertexHandle& _vh) const { return _vh.valence() == (_vh.is_boundary() ? boundary_reg : inner_reg); } +}; + +using RegularQuad = Regular<4,3>; +using RegularTri = Regular<6,4>; + + +/// Wrapper object to hold an object and a member function pointer, +/// and provides operator() to call that member function for that object with one argument +template +struct MemberFunctionWrapper +{ + T t_; // Objects whose member function we want to call + MF mf_; // pointer to member function + + MemberFunctionWrapper(T _t, MF _mf) + : + t_(_t), + mf_(_mf) + {} + + template + auto operator()(const O& _o) -> decltype ((t_.*mf_)(_o)) + { + return (t_.*mf_)(_o); + } +}; + +/// Helper to create a MemberFunctionWrapper without explicitely naming the types +template +MemberFunctionWrapper make_member_function_wrapper(T&& _t, MF _mf) +{ + return MemberFunctionWrapper(std::forward(_t), _mf); +} + +/// Convenience macro to create a MemberFunctionWrapper for *this object +#define OM_MFW(member_function) OpenMesh::Predicates::make_member_function_wrapper(*this, &std::decay::type::member_function) + + + +//============================================================================= +} // namespace Predicates + +} // namespace OpenMesh +//============================================================================= + +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/Property.hh b/Sources/OpenMeshCore/Core/Utils/Property.hh new file mode 100644 index 0000000..26bcb99 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/Property.hh @@ -0,0 +1,522 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//#ifndef OPENMESH_PROPERTY_HH +//#define OPENMESH_PROPERTY_HH +#pragma once + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +/** \class PropertyT Property.hh + * + * \brief Default property class for any type T. + * + * The default property class for any type T. + * + * The property supports persistency if T is a "fundamental" type: + * - integer fundamental types except bool: + * char, short, int, long, long long (__int64 for MS VC++) and + * their unsigned companions. + * - float fundamentals except long double: + * float, double + * - %OpenMesh vector types + * + * Persistency of non-fundamental types is supported if and only if a + * specialization of struct IO::binary<> exists for the wanted type. + */ + +// TODO: it might be possible to define Property using kind of a runtime info +// structure holding the size of T. Then reserve, swap, resize, etc can be written +// in pure malloc() style w/o virtual overhead. Template member function proved per +// element access to the properties, asserting dynamic_casts in debug + +template +class PropertyT : public BaseProperty +{ +public: + + typedef T Value; + typedef std::vector vector_type; + typedef T value_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + +public: + + /// Default constructor + explicit PropertyT( + const std::string& _name = "", + const std::string& _internal_type_name = "") + : BaseProperty(_name, _internal_type_name) + {} + + /// Copy constructor + PropertyT(const PropertyT & _rhs) + : BaseProperty( _rhs ), data_( _rhs.data_ ) {} + +public: // inherited from BaseProperty + + virtual void reserve(size_t _n) override { data_.reserve(_n); } + virtual void resize(size_t _n) override { data_.resize(_n); } + virtual void clear() override { data_.clear(); vector_type().swap(data_); } + virtual void push_back() override { data_.emplace_back(); } + virtual void swap(size_t _i0, size_t _i1) override + { std::swap(data_[_i0], data_[_i1]); } + virtual void copy(size_t _i0, size_t _i1) override + { data_[_i1] = data_[_i0]; } + +public: + + virtual void set_persistent( bool _yn ) override + { check_and_set_persistent( _yn ); } + + virtual size_t n_elements() const override { return data_.size(); } + virtual size_t element_size() const override { return IO::size_of(); } + +#ifndef DOXY_IGNORE_THIS + struct plus { + size_t operator () ( size_t _b, const T& _v ) + { return _b + IO::size_of(_v); } + }; +#endif + + virtual size_t size_of(void) const override + { + if (element_size() != IO::UnknownSize) + return this->BaseProperty::size_of(n_elements()); + return std::accumulate(data_.begin(), data_.end(), size_t(0), plus()); + } + + virtual size_t size_of(size_t _n_elem) const override + { return this->BaseProperty::size_of(_n_elem); } + + virtual size_t store( std::ostream& _ostr, bool _swap ) const override + { + if (IO::is_streamable() && element_size() != IO::UnknownSize) + return IO::store(_ostr, data_, _swap, false); //does not need to store its length + + size_t bytes = 0; + for (size_t i=0; i() && element_size() != IO::UnknownSize) + return IO::restore(_istr, data_, _swap, false); //does not need to restore its length + + size_t bytes = 0; + for (size_t i=0; i* clone() const override + { + PropertyT* p = new PropertyT( *this ); + return p; + } + + std::string get_storage_name() const override + { + return OpenMesh::IO::binary::type_identifier(); + } + +private: + + vector_type data_; +}; + +//----------------------------------------------------------------------------- + + +/** Property specialization for bool type. + + The data will be stored as a bitset. + */ +template <> +class PropertyT : public BaseProperty +{ +public: + + typedef std::vector vector_type; + typedef bool value_type; + typedef vector_type::reference reference; + typedef vector_type::const_reference const_reference; + +public: + + explicit PropertyT(const std::string& _name = "", const std::string& _internal_type_name="" ) + : BaseProperty(_name, _internal_type_name) + { } + +public: // inherited from BaseProperty + + virtual void reserve(size_t _n) override { data_.reserve(_n); } + virtual void resize(size_t _n) override { data_.resize(_n); } + virtual void clear() override { data_.clear(); vector_type().swap(data_); } + virtual void push_back() override { data_.push_back(bool()); } + virtual void swap(size_t _i0, size_t _i1) override + { bool t(data_[_i0]); data_[_i0]=data_[_i1]; data_[_i1]=t; } + virtual void copy(size_t _i0, size_t _i1) override + { data_[_i1] = data_[_i0]; } + +public: + + virtual void set_persistent( bool _yn ) override + { + check_and_set_persistent( _yn ); + } + + virtual size_t n_elements() const override { return data_.size(); } + virtual size_t element_size() const override { return UnknownSize; } + virtual size_t size_of() const override { return size_of( n_elements() ); } + virtual size_t size_of(size_t _n_elem) const override + { + return _n_elem / 8 + ((_n_elem % 8)!=0); + } + + size_t store( std::ostream& _ostr, bool /* _swap */ ) const override + { + size_t bytes = 0; + + size_t N = data_.size() / 8; + size_t R = data_.size() % 8; + + size_t idx; // element index + size_t bidx; + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + bits = static_cast(data_[bidx]) + | (static_cast(data_[bidx+1]) << 1) + | (static_cast(data_[bidx+2]) << 2) + | (static_cast(data_[bidx+3]) << 3) + | (static_cast(data_[bidx+4]) << 4) + | (static_cast(data_[bidx+5]) << 5) + | (static_cast(data_[bidx+6]) << 6) + | (static_cast(data_[bidx+7]) << 7); + _ostr << bits; + } + bytes = N; + + if (R) + { + bits = 0; + for (idx=0; idx < R; ++idx) + bits |= static_cast(data_[bidx+idx]) << idx; + _ostr << bits; + ++bytes; + } + + assert( bytes == size_of() ); + + return bytes; + } + + size_t restore( std::istream& _istr, bool /* _swap */ ) override + { + size_t bytes = 0; + + size_t N = data_.size() / 8; + size_t R = data_.size() % 8; + + size_t idx; // element index + size_t bidx; // + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + _istr >> bits; + data_[bidx+0] = (bits & 0x01) != 0; + data_[bidx+1] = (bits & 0x02) != 0; + data_[bidx+2] = (bits & 0x04) != 0; + data_[bidx+3] = (bits & 0x08) != 0; + data_[bidx+4] = (bits & 0x10) != 0; + data_[bidx+5] = (bits & 0x20) != 0; + data_[bidx+6] = (bits & 0x40) != 0; + data_[bidx+7] = (bits & 0x80) != 0; + } + bytes = N; + + if (R) + { + _istr >> bits; + for (idx=0; idx < R; ++idx) + data_[bidx+idx] = (bits & (1<* clone() const override + { + PropertyT* p = new PropertyT( *this ); + return p; + } + + std::string get_storage_name() const override + { + return OpenMesh::IO::binary::type_identifier(); + } + + +private: + + vector_type data_; +}; + + +//----------------------------------------------------------------------------- + + +/// Base property handle. +template +struct BasePropHandleT : public BaseHandle +{ + typedef T Value; + typedef std::vector vector_type; + typedef T value_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + + explicit BasePropHandleT(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a vertex property + */ +template +struct VPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + typedef VertexHandle Handle; + + explicit VPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit VPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a halfedge property + */ +template +struct HPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + typedef HalfedgeHandle Handle; + + explicit HPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit HPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing an edge property + */ +template +struct EPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + typedef EdgeHandle Handle; + + explicit EPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit EPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a face property + */ +template +struct FPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + typedef FaceHandle Handle; + + explicit FPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit FPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a mesh property + */ +template +struct MPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + typedef MeshHandle Handle; + + explicit MPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit MPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + +template +struct PropHandle; + +template <> +struct PropHandle { + template + using type = VPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = HPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = EPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = FPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = MPropHandleT; +}; + +} // namespace OpenMesh +//============================================================================= +//#endif // OPENMESH_PROPERTY_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/PropertyContainer.hh b/Sources/OpenMeshCore/Core/Utils/PropertyContainer.hh new file mode 100644 index 0000000..6460413 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/PropertyContainer.hh @@ -0,0 +1,357 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_PROPERTYCONTAINER +#define OPENMESH_PROPERTYCONTAINER + +#include +#include + +//----------------------------------------------------------------------------- +namespace OpenMesh +{ +//== FORWARDDECLARATIONS ====================================================== + class BaseKernel; + +//== CLASS DEFINITION ========================================================= +/// A a container for properties. +class PropertyContainer +{ +public: + + //-------------------------------------------------- constructor / destructor + + PropertyContainer() {} + virtual ~PropertyContainer() { std::for_each(properties_.begin(), properties_.end(), Delete()); } + + + //------------------------------------------------------------- info / access + + typedef std::vector Properties; + const Properties& properties() const { return properties_; } + size_t size() const { return properties_.size(); } + + + + //--------------------------------------------------------- copy / assignment + + PropertyContainer(const PropertyContainer& _rhs) { operator=(_rhs); } + + PropertyContainer& operator=(const PropertyContainer& _rhs) + { + // The assignment below relies on all previous BaseProperty* elements having been deleted + std::for_each(properties_.begin(), properties_.end(), Delete()); + properties_ = _rhs.properties_; + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + for (; p_it!=p_end; ++p_it) + if (*p_it) + *p_it = (*p_it)->clone(); + return *this; + } + + + + //--------------------------------------------------------- manage properties + + template + BasePropHandleT add(const T&, const std::string& _name="") + { + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + int idx=0; + for ( ; p_it!=p_end && *p_it!=nullptr; ++p_it, ++idx ) {}; + if (p_it==p_end) properties_.push_back(nullptr); + properties_[idx] = new PropertyT(_name, get_type_name() ); // create a new property with requested name and given (system dependent) internal typename + return BasePropHandleT(idx); + } + + + template + BasePropHandleT handle(const T&, const std::string& _name) const + { + Properties::const_iterator p_it = properties_.begin(); + for (int idx=0; p_it != properties_.end(); ++p_it, ++idx) + { + if (*p_it != nullptr && + (*p_it)->name() == _name //skip deleted properties + && (*p_it)->internal_type_name() == get_type_name() // new check type + ) + { + return BasePropHandleT(idx); + } + } + return BasePropHandleT(); + } + + BaseProperty* property( const std::string& _name ) const + { + Properties::const_iterator p_it = properties_.begin(); + for (int idx=0; p_it != properties_.end(); ++p_it, ++idx) + { + if (*p_it != nullptr && (*p_it)->name() == _name) //skip deleted properties + { + return *p_it; + } + } + return nullptr; + } + + template PropertyT& property(BasePropHandleT _h) + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + assert(properties_[_h.idx()] != nullptr); + assert( properties_[_h.idx()]->internal_type_name() == get_type_name() ); + PropertyT *p = static_cast< PropertyT* > (properties_[_h.idx()]); + assert(p != nullptr); + return *p; + } + + + template const PropertyT& property(BasePropHandleT _h) const + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + assert(properties_[_h.idx()] != nullptr); + assert( properties_[_h.idx()]->internal_type_name() == get_type_name() ); + PropertyT *p = static_cast< PropertyT* > (properties_[_h.idx()]); + assert(p != nullptr); + return *p; + } + + + template void remove(BasePropHandleT _h) + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + delete properties_[_h.idx()]; + properties_[_h.idx()] = nullptr; + } + + + void clear() + { + // Clear properties vector: + // Replaced the old version with new one + // which performs a swap to clear values and + // deallocate memory. + + // Old version (changed 22.07.09) { + // std::for_each(properties_.begin(), properties_.end(), Delete()); + // } + + std::for_each(properties_.begin(), properties_.end(), ClearAll()); + } + + + //---------------------------------------------------- synchronize properties + +/* + * In C++11 an beyond we can introduce more efficient and more legible + * implementations of the following methods. + */ +#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) + /** + * Reserves space for \p _n elements in all property vectors. + */ + void reserve(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p) p->reserve(_n); }); + } + + /** + * Resizes all property vectors to the specified size. + */ + void resize(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p) p->resize(_n); }); + } + + /** + * Same as resize() but ignores property vectors that have a size larger + * than \p _n. + * + * Use this method instead of resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ + void resize_if_smaller(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p && p->n_elements() < _n) p->resize(_n); }); + } + + /** + * Swaps the items with index \p _i0 and index \p _i1 in all property + * vectors. + */ + void swap(size_t _i0, size_t _i1) const { + std::for_each(properties_.begin(), properties_.end(), + [_i0, _i1](BaseProperty* p) { if (p) p->swap(_i0, _i1); }); + } +#else + /** + * Reserves space for \p _n elements in all property vectors. + */ + void reserve(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), Reserve(_n)); + } + + /** + * Resizes all property vectors to the specified size. + */ + void resize(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), Resize(_n)); + } + + /** + * Same as \sa resize() but ignores property vectors that have a size + * larger than \p _n. + * + * Use this method instead of \sa resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ + void resize_if_smaller(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), ResizeIfSmaller(_n)); + } + + /** + * Swaps the items with index \p _i0 and index \p _i1 in all property + * vectors. + */ + void swap(size_t _i0, size_t _i1) const { + std::for_each(properties_.begin(), properties_.end(), Swap(_i0, _i1)); + } +#endif + + + +protected: // generic add/get + + size_t _add( BaseProperty* _bp ) + { + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + size_t idx=0; + for (; p_it!=p_end && *p_it!=nullptr; ++p_it, ++idx) {}; + if (p_it==p_end) properties_.push_back(nullptr); + properties_[idx] = _bp; + return idx; + } + + BaseProperty& _property( size_t _idx ) + { + assert( _idx < properties_.size()); + assert( properties_[_idx] != nullptr); + BaseProperty *p = properties_[_idx]; + assert( p != nullptr ); + return *p; + } + + const BaseProperty& _property( size_t _idx ) const + { + assert( _idx < properties_.size()); + assert( properties_[_idx] != nullptr); + BaseProperty *p = properties_[_idx]; + assert( p != nullptr ); + return *p; + } + + + typedef Properties::iterator iterator; + typedef Properties::const_iterator const_iterator; + iterator begin() { return properties_.begin(); } + iterator end() { return properties_.end(); } + const_iterator begin() const { return properties_.begin(); } + const_iterator end() const { return properties_.end(); } + + friend class BaseKernel; + +private: + + //-------------------------------------------------- synchronization functors + +#ifndef DOXY_IGNORE_THIS + struct Reserve + { + explicit Reserve(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p) _p->reserve(n_); } + size_t n_; + }; + + struct Resize + { + explicit Resize(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p) _p->resize(n_); } + size_t n_; + }; + + struct ResizeIfSmaller + { + explicit ResizeIfSmaller(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p && _p->n_elements() < n_) _p->resize(n_); } + size_t n_; + }; + + struct ClearAll + { + ClearAll() {} + void operator()(BaseProperty* _p) const { if (_p) _p->clear(); } + }; + + struct Swap + { + Swap(size_t _i0, size_t _i1) : i0_(_i0), i1_(_i1) {} + void operator()(BaseProperty* _p) const { if (_p) _p->swap(i0_, i1_); } + size_t i0_, i1_; + }; + + struct Delete + { + Delete() {} + void operator()(BaseProperty* _p) const { if (_p) delete _p; } + }; +#endif + + Properties properties_; +}; + +}//namespace OpenMesh + +#endif//OPENMESH_PROPERTYCONTAINER + diff --git a/Sources/OpenMeshCore/Core/Utils/PropertyCreator.cc b/Sources/OpenMeshCore/Core/Utils/PropertyCreator.cc new file mode 100644 index 0000000..f75f742 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/PropertyCreator.cc @@ -0,0 +1,153 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#include "PropertyCreator.hh" + +#include +#include +#include +#include + + +namespace OpenMesh { + +PropertyCreationManager& PropertyCreationManager::instance() +{ + static PropertyCreationManager manager; + return manager; +} + +bool PropertyCreator::can_you_create(const std::string& _type_name) +{ + return _type_name == type_string(); +} + + +} /* namespace OpenMesh */ + +OM_REGISTER_PROPERTY_TYPE(FaceHandle) +OM_REGISTER_PROPERTY_TYPE(EdgeHandle) +OM_REGISTER_PROPERTY_TYPE(HalfedgeHandle) +OM_REGISTER_PROPERTY_TYPE(VertexHandle) +OM_REGISTER_PROPERTY_TYPE(MeshHandle) + +OM_REGISTER_PROPERTY_TYPE(bool) +OM_REGISTER_PROPERTY_TYPE(float) +OM_REGISTER_PROPERTY_TYPE(double) +OM_REGISTER_PROPERTY_TYPE(long double) +OM_REGISTER_PROPERTY_TYPE(char) +OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::int8_t ) +OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::int16_t ) +OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::int32_t ) +//OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::int64_t ) +OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::uint8_t ) +OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::uint16_t) +OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::uint32_t) +OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::uint64_t) +OM_REGISTER_PROPERTY_TYPE(std::string) + +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) +OM_REGISTER_PROPERTY_TYPE(std::vector) + +OM_REGISTER_PROPERTY_TYPE(Vec1c); +OM_REGISTER_PROPERTY_TYPE(Vec1uc); +OM_REGISTER_PROPERTY_TYPE(Vec1s); +OM_REGISTER_PROPERTY_TYPE(Vec1us); +OM_REGISTER_PROPERTY_TYPE(Vec1i); +OM_REGISTER_PROPERTY_TYPE(Vec1ui); +OM_REGISTER_PROPERTY_TYPE(Vec1f); +OM_REGISTER_PROPERTY_TYPE(Vec1d); + +OM_REGISTER_PROPERTY_TYPE(Vec2c); +OM_REGISTER_PROPERTY_TYPE(Vec2uc); +OM_REGISTER_PROPERTY_TYPE(Vec2s); +OM_REGISTER_PROPERTY_TYPE(Vec2us); +OM_REGISTER_PROPERTY_TYPE(Vec2i); +OM_REGISTER_PROPERTY_TYPE(Vec2ui); +OM_REGISTER_PROPERTY_TYPE(Vec2f); +OM_REGISTER_PROPERTY_TYPE(Vec2d); + +OM_REGISTER_PROPERTY_TYPE(Vec3c); +OM_REGISTER_PROPERTY_TYPE(Vec3uc); +OM_REGISTER_PROPERTY_TYPE(Vec3s); +OM_REGISTER_PROPERTY_TYPE(Vec3us); +OM_REGISTER_PROPERTY_TYPE(Vec3i); +OM_REGISTER_PROPERTY_TYPE(Vec3ui); +OM_REGISTER_PROPERTY_TYPE(Vec3f); +OM_REGISTER_PROPERTY_TYPE(Vec3d); + +OM_REGISTER_PROPERTY_TYPE(Vec4c); +OM_REGISTER_PROPERTY_TYPE(Vec4uc); +OM_REGISTER_PROPERTY_TYPE(Vec4s); +OM_REGISTER_PROPERTY_TYPE(Vec4us); +OM_REGISTER_PROPERTY_TYPE(Vec4i); +OM_REGISTER_PROPERTY_TYPE(Vec4ui); +OM_REGISTER_PROPERTY_TYPE(Vec4f); +OM_REGISTER_PROPERTY_TYPE(Vec4d); + +OM_REGISTER_PROPERTY_TYPE(Vec5c); +OM_REGISTER_PROPERTY_TYPE(Vec5uc); +OM_REGISTER_PROPERTY_TYPE(Vec5s); +OM_REGISTER_PROPERTY_TYPE(Vec5us); +OM_REGISTER_PROPERTY_TYPE(Vec5i); +OM_REGISTER_PROPERTY_TYPE(Vec5ui); +OM_REGISTER_PROPERTY_TYPE(Vec5f); +OM_REGISTER_PROPERTY_TYPE(Vec5d); + +OM_REGISTER_PROPERTY_TYPE(Vec6c); +OM_REGISTER_PROPERTY_TYPE(Vec6uc); +OM_REGISTER_PROPERTY_TYPE(Vec6s); +OM_REGISTER_PROPERTY_TYPE(Vec6us); +OM_REGISTER_PROPERTY_TYPE(Vec6i); +OM_REGISTER_PROPERTY_TYPE(Vec6ui); +OM_REGISTER_PROPERTY_TYPE(Vec6f); +OM_REGISTER_PROPERTY_TYPE(Vec6d); diff --git a/Sources/OpenMeshCore/Core/Utils/PropertyCreator.hh b/Sources/OpenMeshCore/Core/Utils/PropertyCreator.hh new file mode 100644 index 0000000..459452d --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/PropertyCreator.hh @@ -0,0 +1,242 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace OpenMesh { + +#define OM_CONCAT_IMPL(a, b) a##b +#define OM_CONCAT(a, b) OM_CONCAT_IMPL(a, b) + +/** \brief Base class for property creators + * + * A PropertyCreator can add a named property to a mesh. + * The type of the property is specified in the classes derived from this class. + * + * */ +class OPENMESHDLLEXPORT PropertyCreator +{ +public: + + /// The string that corresponds to the type this property creator can create + virtual std::string type_string() = 0; + + virtual std::string type_id_string() = 0; + + /// Returns true iff the given _type_name corresponds to the string the derived class can create a property for + bool can_you_create(const std::string &_type_name); + + /// Create a vertex property on _mesh with name _property_name + virtual void create_vertex_property (BaseKernel& _mesh, const std::string& _property_name) = 0; + + /// Create a halfedge property on _mesh with name _property_name + virtual void create_halfedge_property(BaseKernel& _mesh, const std::string& _property_name) = 0; + + /// Create an edge property on _mesh with name _property_name + virtual void create_edge_property (BaseKernel& _mesh, const std::string& _property_name) = 0; + + /// Create a face property on _mesh with name _property_name + virtual void create_face_property (BaseKernel& _mesh, const std::string& _property_name) = 0; + + /// Create a mesh property on _mesh with name _property_name + virtual void create_mesh_property (BaseKernel& _mesh, const std::string& _property_name) = 0; + + + /// Create a property for the element of type HandleT on _mesh with name _property_name + template + void create_property(BaseKernel& _mesh, const std::string& _property_name); + + virtual ~PropertyCreator() {} + +protected: + PropertyCreator() {} + +}; + +template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_vertex_property (_mesh, _property_name); } +template <> inline void PropertyCreator::create_property(BaseKernel& _mesh, const std::string& _property_name) { create_halfedge_property(_mesh, _property_name); } +template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_edge_property (_mesh, _property_name); } +template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_face_property (_mesh, _property_name); } +template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_mesh_property (_mesh, _property_name); } + +/// Helper class that contains the implementation of the create__property methods. +/// Implementation is injected into PropertyCreatorT. +template +class PropertyCreatorImpl : public PropertyCreator +{ +public: + std::string type_id_string() override { return get_type_name(); } + + template + void create_prop(BaseKernel& _mesh, const std::string& _property_name) + { + using PHandle = typename PropHandle::template type; + PHandle prop; + if (!_mesh.get_property_handle(prop, _property_name)) + _mesh.add_property(prop, _property_name); + } + + void create_vertex_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name); } + void create_halfedge_property(BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} + void create_edge_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} + void create_face_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} + void create_mesh_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} + + ~PropertyCreatorImpl() override {} +protected: + PropertyCreatorImpl() {} +}; + +/// Actual PropertyCreators specialize this class in order to add properties of type T +namespace { +template +class PropertyCreatorT : public PropertyCreatorImpl> +{ +}; +} + +///used to register custom type, where typename.hh does provide a string for type recognition + +#define OM_REGISTER_PROPERTY_TYPE(ClassName) \ +namespace OpenMesh { \ +namespace { /* ensure internal linkage of class */ \ +template <> \ +class PropertyCreatorT : public PropertyCreatorImpl> \ +{ \ +public: \ + using type = ClassName; \ + std::string type_string() override { return OpenMesh::IO::binary::type_identifier(); } \ + \ + PropertyCreatorT() \ + { \ + PropertyCreationManager::instance().register_property_creator(this); \ + } \ + ~PropertyCreatorT() override {} \ +}; \ +} \ +/* static to ensure internal linkage of object */ \ +static PropertyCreatorT OM_CONCAT(property_creator_registration_object_, __LINE__); \ +} + +/** \brief Class for adding properties based on strings + * + * The PropertyCreationManager holds all PropertyCreators and dispatches the property creation + * to them if they are able to create a property for a given string. + * + * If you want to be able to store your custom properties into a file and automatically load + * them without manually adding the property yourself you can register your type by calling the + * OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString) + * */ +class OPENMESHDLLEXPORT PropertyCreationManager +{ +public: + + static PropertyCreationManager& instance(); + + template + void create_property(BaseKernel& _mesh, const std::string& _type_name, const std::string& _property_name) + { + + auto can_create = [_type_name](OpenMesh::PropertyCreator* pc){ + return pc->can_you_create(_type_name); + }; + + std::vector::iterator pc_iter = std::find_if(property_creators_.begin(), + property_creators_.end(), can_create); + if (pc_iter != property_creators_.end()) + { + const auto& pc = *pc_iter; + pc->create_property(_mesh, _property_name); + return; + } + + omerr() << "No property creator registered that can create a property of type " << _type_name << std::endl; + omerr() << "You need to register your custom type using OM_REGISTER_PROPERTY_TYPE(ClassName) and declare the struct binary.\ + See documentation for more details." << std::endl; + omerr() << "Adding property failed." << std::endl; + } + + void register_property_creator(PropertyCreator* _property_creator) + { + for (auto pc : property_creators_) + if (pc->type_string() == _property_creator->type_string()) + { + if (pc->type_id_string() != _property_creator->type_id_string()) + { + omerr() << "And it looks like you are trying to add a different type with an already existing string identification." << std::endl; + omerr() << "Type id of existing type is " << pc->type_id_string() << " trying to add for " << _property_creator->type_id_string() << std::endl; + } + return; + } + property_creators_.push_back(_property_creator); + } + +private: + + PropertyCreationManager() {} + ~PropertyCreationManager() {} + + std::vector property_creators_; +}; + +/** \brief Create a property with type corresponding to _type_name on _mesh with name _property_name + * + * For user defined types you need to register the type using OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString) + * */ +template +void create_property_from_string(BaseKernel& _mesh, const std::string& _type_name, const std::string& _property_name) +{ + PropertyCreationManager::instance().create_property(_mesh, _type_name, _property_name); +} + +} /* namespace OpenMesh */ diff --git a/Sources/OpenMeshCore/Core/Utils/PropertyManager.hh b/Sources/OpenMeshCore/Core/Utils/PropertyManager.hh new file mode 100644 index 0000000..7145230 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/PropertyManager.hh @@ -0,0 +1,955 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#ifndef PROPERTYMANAGER_HH_ +#define PROPERTYMANAGER_HH_ + +#include +#include +#include +#include +#include +#include + +namespace OpenMesh { + +/** + * This class is intended to manage the lifecycle of properties. + * It also defines convenience operators to access the encapsulated + * property's value. + * + * Note that the second template parameter is depcretated. + * + * \code + * { + * TriMesh mesh; + * auto visited = makeTemporaryProperty(mesh); + * + * for (auto vh : mesh.vertices()) { + * if (!visited[vh]) { + * visitComponent(mesh, vh, visited); + * } + * } + * // The property is automatically removed at the end of the scope + * } + * \endcode + */ +template +class PropertyManager { + + public: + using Value = typename PROPTYPE::Value; + using value_type = typename PROPTYPE::value_type; + using Handle = typename PROPTYPE::Handle; + using Self = PropertyManager; + using Reference = typename PROPTYPE::reference; + using ConstReference = typename PROPTYPE::const_reference; + + private: + // Mesh properties (MPropHandleT<...>) are stored differently than the other properties. + // This class implements different behavior when initializing a property or when + // copying or swapping data from one property manager to a another one. + template + struct StorageT; + + // specialization for Mesh Properties + template + struct StorageT> { + static void initialize(PropertyManager& pm, const Value& initial_value ) { + pm() = initial_value; + } + static void copy(const PropertyManager& from, PropertyManager2& to) { + *to = *from; + } + static void swap(PropertyManager& from, PropertyManager2& to) { + std::swap(*to, *from); + } + static ConstReference access_property_const(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle&) { + return mesh.property(prop_handle); + } + static Reference access_property(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle&) { + return mesh.property(prop_handle); + } + }; + + // definition for other Mesh Properties + template + struct StorageT { + static void initialize(PropertyManager& pm, const Value& initial_value ) { + pm.set_range(pm.mesh_.template all_elements(), initial_value); + } + static void copy(const PropertyManager& from, PropertyManager2& to) { + from.copy_to(from.mesh_.template all_elements(), to, to.mesh_.template all_elements()); + } + static void swap(PropertyManager& lhs, PropertyManager2& rhs) { + std::swap(lhs.mesh().property(lhs.prop_).data_vector(), rhs.mesh().property(rhs.prop_).data_vector()); + // resize the property to the correct size + lhs.mesh().property(lhs.prop_).resize(lhs.mesh().template n_elements()); + rhs.mesh().property(rhs.prop_).resize(rhs.mesh().template n_elements()); + } + static ConstReference access_property_const(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle& handle) { + return mesh.property(prop_handle, handle); + } + static Reference access_property(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle& handle) { + return mesh.property(prop_handle, handle); + } + }; + + using Storage = StorageT; + + public: + + /** + * @deprecated Use a constructor without \p existing and check existance with hasProperty() instead. + * + * Constructor. + * + * Throws an \p std::runtime_error if \p existing is true and + * no property named \p propname of the appropriate property type + * exists. + * + * @param mesh The mesh on which to create the property. + * @param propname The name of the property. + * @param existing If false, a new property is created and its lifecycle is managed (i.e. + * the property is deleted upon destruction of the PropertyManager instance). If true, + * the instance merely acts as a convenience wrapper around an existing property with no + * lifecycle management whatsoever. + * + * @see PropertyManager::getOrMakeProperty, PropertyManager::getProperty, + * PropertyManager::makeTemporaryProperty + */ + OM_DEPRECATED("Use the constructor without parameter 'existing' instead. Check for existance with hasProperty") // As long as this overload exists, initial value must be first parameter due to ambiguity for properties of type bool + PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing) : mesh_(mesh), retain_(existing), name_(propname) { + if (existing) { + if (!PropertyManager::mesh().get_property_handle(prop_, propname)) { + std::ostringstream oss; + oss << "Requested property handle \"" << propname << "\" does not exist."; + throw std::runtime_error(oss.str()); + } + } else { + PropertyManager::mesh().add_property(prop_, propname); + } + } + + /** + * Constructor. + * + * Asks for a property with name propname and creates one if none exists. Lifetime is not managed. + * + * @param mesh The mesh on which to create the property. + * @param propname The name of the property. + */ + PropertyManager(PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) { + if (!PropertyManager::mesh().get_property_handle(prop_, propname)) { + PropertyManager::mesh().add_property(prop_, propname); + } + } + + /** + * Constructor. + * + * Asks for a property with name propname and creates one if none exists. Lifetime is not managed. + * + * @param initial_value If the proeprty is newly created, it will be initialized with initial_value. + * If the property already existed, nothing is changes. + * @param mesh The mesh on which to create the property. + * @param propname The name of the property. + */ + PropertyManager(const Value& initial_value, PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) { + if (!mesh_.get_property_handle(prop_, propname)) { + PropertyManager::mesh().add_property(prop_, propname); + Storage::initialize(*this, initial_value); + } + } + + /** + * Constructor. + * + * Create an anonymous property. Lifetime is managed. + * + * @param mesh The mesh on which to create the property. + */ + explicit PropertyManager(const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { + PropertyManager::mesh().add_property(prop_, name_); + } + + /** + * Constructor. + * + * Create an anonymous property. Lifetime is managed. + * + * @param initial_value The property will be initialized with initial_value. + * @param mesh The mesh on which to create the property. + */ + PropertyManager(const Value& initial_value, const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { + PropertyManager::mesh().add_property(prop_, name_); + Storage::initialize(*this, initial_value); + } + + /** + * Constructor. + * + * Create a wrapper around an existing property. Lifetime is not managed. + * + * @param mesh The mesh on which to create the property. + * @param property_handle Handle to an existing property that should be wrapped. + */ + PropertyManager(PolyConnectivity& mesh, PROPTYPE property_handle) : mesh_(mesh), prop_(property_handle), retain_(true), name_() { + } + + PropertyManager() = delete; + + PropertyManager(const PropertyManager& rhs) + : + mesh_(rhs.mesh_), + prop_(), + retain_(rhs.retain_), + name_(rhs.name_) + { + if (rhs.retain_) // named property -> create a property manager referring to the same + { + prop_ = rhs.prop_; + } + else // unnamed property -> create a property manager refering to a new property and copy the contents + { + PropertyManager::mesh().add_property(prop_, name_); + Storage::copy(rhs, *this); + } + } + + + /** + * Create property manager referring to a copy of the current property. + * This can be used to explicitely create a copy of a named property. The cloned property + * will be unnamed. + */ + PropertyManager clone() + { + PropertyManager result(this->mesh()); + Storage::copy(*this, result); + return result; + } + + PropertyManager& operator=(const PropertyManager& rhs) + { + if (&mesh_ == &rhs.mesh_ && prop_ == rhs.prop_) + ; // nothing to do + else + Storage::copy(rhs, *this); + return *this; + } + + ~PropertyManager() { + deleteProperty(); + } + + void swap(PropertyManager &rhs) { + // swap the data stored in the properties + Storage::swap(rhs, *this); + } + + static bool propertyExists(const PolyConnectivity &mesh, const char *propname) { + PROPTYPE dummy; + return mesh.get_property_handle(dummy, propname); + } + + bool isValid() const { return prop_.is_valid(); } + operator bool() const { return isValid(); } + + const PROPTYPE &getRawProperty() const { return prop_; } + + const std::string &getName() const { return name_; } + + /** + * Get the mesh corresponding to the property. + * + * If you use PropertyManager without second template parameter (recommended) + * you need to specify the actual mesh type when using this function, e.g.: + * \code + * { + * TriMesh mesh; + * auto visited = VProp(mesh); + * TriMesh& mesh_ref = visited.getMesh(); + * } + * + */ + template + const MeshType& getMesh() const { return dynamic_cast(mesh_); } + + const MeshT& getMesh() const { return dynamic_cast(mesh_); } + + + /** + * @deprecated This method no longer has any effect. Instead, named properties are always retained, while unnamed ones are not + * + * Tells the PropertyManager whether lifetime should be managed or not. + */ + OM_DEPRECATED("retain no longer has any effect. Instead, named properties are always retained, while unnamed ones are not.") + void retain(bool = true) {} + + /** + * Move constructor. Transfers ownership (delete responsibility). + */ + PropertyManager(PropertyManager &&rhs) + : + mesh_(rhs.mesh_), + prop_(rhs.prop_), + retain_(rhs.retain_), + name_(rhs.name_) + { + if (!rhs.retain_) + rhs.prop_.invalidate(); // only invalidate unnamed properties + } + + /** + * Move assignment. Transfers ownership (delete responsibility). + */ + PropertyManager& operator=(PropertyManager&& rhs) + { + if ((&mesh_ != &rhs.mesh_) || (prop_ != rhs.prop_)) + { + if (rhs.retain_) + { + // retained properties cannot be invalidated. Copy instead + Storage::copy(rhs, *this); + } + else + { + // swap the data stored in the properties + Storage::swap(rhs, *this); + // remove the property from rhs + rhs.mesh().remove_property(rhs.prop_); + // invalidate prop_ + rhs.prop_.invalidate(); + } + } + return *this; + } + + /** + * Create a property manager for the supplied property and mesh. + * If the property doesn't exist, it is created. In any case, + * lifecycle management is disabled. + * + * @see makePropertyManagerFromExistingOrNew + */ + static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname) { + return PropertyManager(mesh, propname); + } + + /** + * Like createIfNotExists() with two parameters except, if the property + * doesn't exist, it is initialized with the supplied value over + * the supplied range after creation. If the property already exists, + * this method has the exact same effect as the two parameter version. + * Lifecycle management is disabled in any case. + * + * @see makePropertyManagerFromExistingOrNew + */ + template + static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname, + const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, + const PROP_VALUE &init_value) { + const bool exists = propertyExists(mesh, propname); + PropertyManager pm(mesh, propname, exists); + pm.retain(); + if (!exists) + pm.set_range(begin, end, init_value); + return std::move(pm); + } + + /** + * Like createIfNotExists() with two parameters except, if the property + * doesn't exist, it is initialized with the supplied value over + * the supplied range after creation. If the property already exists, + * this method has the exact same effect as the two parameter version. + * Lifecycle management is disabled in any case. + * + * @see makePropertyManagerFromExistingOrNew + */ + template + static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname, + const ITERATOR_RANGE &range, const PROP_VALUE &init_value) { + return createIfNotExists( + mesh, propname, range.begin(), range.end(), init_value); + } + + + /** + * Access the value of the encapsulated mesh property. + * + * Example: + * @code + * PolyMesh m; + * auto description = getOrMakeProperty(m, "description"); + * *description = "This is a very nice mesh."; + * @endcode + * + * @note This method is only used for mesh properties. + */ + typename PROPTYPE::reference& operator*() { + return mesh().mproperty(prop_)[0]; + } + + /** + * Access the value of the encapsulated mesh property. + * + * Example: + * @code + * PolyMesh m; + * auto description = getProperty(m, "description"); + * std::cout << *description << std::endl; + * @endcode + * + * @note This method is only used for mesh properties. + */ + typename PROPTYPE::const_reference& operator*() const { + return mesh().mproperty(prop_)[0]; + } + + /** + * Enables convenient access to the encapsulated property. + * + * For a usage example see this class' documentation. + * + * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) + */ + inline typename PROPTYPE::reference operator[] (Handle handle) { + return mesh().property(prop_, handle); + } + + /** + * Enables convenient access to the encapsulated property. + * + * For a usage example see this class' documentation. + * + * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) + */ + inline typename PROPTYPE::const_reference operator[] (const Handle& handle) const { + return mesh().property(prop_, handle); + } + + /** + * Enables convenient access to the encapsulated property. + * + * For a usage example see this class' documentation. + * + * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) + */ + inline typename PROPTYPE::reference operator() (const Handle& handle = Handle()) { +// return mesh().property(prop_, handle); + return Storage::access_property(mesh(), prop_, handle); + } + + /** + * Enables convenient access to the encapsulated property. + * + * For a usage example see this class' documentation. + * + * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) + */ + inline typename PROPTYPE::const_reference operator() (const Handle& handle = Handle()) const { +// return mesh().property(prop_, handle); + return Storage::access_property_const(mesh(), prop_, handle); + } + + /** + * Conveniently set the property for an entire range of values. + * + * Examples: + * \code + * MeshT mesh; + * PropertyManager> distance( + * mesh, "distance.plugin-example.i8.informatik.rwth-aachen.de"); + * distance.set_range( + * mesh.vertices_begin(), mesh.vertices_end(), + * std::numeric_limits::infinity()); + * \endcode + * or + * \code + * MeshT::VertexHandle vh; + * distance.set_range( + * mesh.vv_begin(vh), mesh.vv_end(vh), + * std::numeric_limits::infinity()); + * \endcode + * + * @param begin Start iterator. Needs to dereference to HandleType. + * @param end End iterator. (Exclusive.) + * @param value The value the range will be set to. + */ + template + void set_range(HandleTypeIterator begin, HandleTypeIterator end, + const PROP_VALUE &value) { + for (; begin != end; ++begin) + (*this)[*begin] = value; + } + +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) + template + void set_range(const HandleTypeIteratorRange &range, + const PROP_VALUE &value) { + set_range(range.begin(), range.end(), value); + } +#endif + + /** + * Conveniently transfer the values managed by one property manager + * onto the values managed by a different property manager. + * + * @param begin Start iterator. Needs to dereference to HandleType. Will + * be used with this property manager. + * @param end End iterator. (Exclusive.) Will be used with this property + * manager. + * @param dst_propmanager The destination property manager. + * @param dst_begin Start iterator. Needs to dereference to the + * HandleType of dst_propmanager. Will be used with dst_propmanager. + * @param dst_end End iterator. (Exclusive.) + * Will be used with dst_propmanager. Used to double check the bounds. + */ + template + void copy_to(HandleTypeIterator begin, HandleTypeIterator end, + PropertyManager2 &dst_propmanager, + HandleTypeIterator2 dst_begin, HandleTypeIterator2 dst_end) const { + + for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) { + dst_propmanager[*dst_begin] = (*this)[*begin]; + } + } + + template + void copy_to(const RangeType &range, + PropertyManager2 &dst_propmanager, + const RangeType2 &dst_range) const { + copy_to(range.begin(), range.end(), dst_propmanager, + dst_range.begin(), dst_range.end()); + } + + + /** + * Copy the values of a property from a source range to + * a target range. The source range must not be smaller than the + * target range. + * + * @param prop_name Name of the property to copy. Must exist on the + * source mesh. Will be created on the target mesh if it doesn't exist. + * + * @param src_mesh Source mesh from which to copy. + * @param src_range Source range which to copy. Must not be smaller than + * dst_range. + * @param dst_mesh Destination mesh on which to copy. + * @param dst_range Destination range. + */ + template + static void copy(const char *prop_name, + PolyConnectivity &src_mesh, const RangeType &src_range, + PolyConnectivity &dst_mesh, const RangeType2 &dst_range) { + + typedef OpenMesh::PropertyManager DstPM; + DstPM dst(DstPM::createIfNotExists(dst_mesh, prop_name)); + + typedef OpenMesh::PropertyManager SrcPM; + SrcPM src(src_mesh, prop_name, true); + + src.copy_to(src_range, dst, dst_range); + } + + /** + * Mark whether this property should be stored when mesh is written + * to a file + * + * @param _persistence Property will be stored iff _persistence is true + */ + void set_persistent(bool _persistence = true) + { + mesh().property(getRawProperty()).set_persistent(_persistence); + } + + private: + void deleteProperty() { + if (!retain_ && prop_.is_valid()) + mesh().remove_property(prop_); + } + + PolyConnectivity& mesh() const + { + return const_cast(mesh_); + } + + private: + const PolyConnectivity& mesh_; + PROPTYPE prop_; + bool retain_; + std::string name_; +}; + +template +class ConstPropertyViewer +{ +public: + using Value = typename PropertyT::Value; + using value_type = typename PropertyT::value_type; + using Handle = typename PropertyT::Handle; + + ConstPropertyViewer(const PolyConnectivity& mesh, const PropertyT& property_handle) + : + mesh_(mesh), + prop_(property_handle) + {} + + inline const typename PropertyT::const_reference operator() (const Handle& handle) + { + return mesh_.property(prop_, handle); + } + + inline const typename PropertyT::const_reference operator[] (const Handle& handle) + { + return mesh_.property(prop_, handle); + } + +private: + const PolyConnectivity& mesh_; + PropertyT prop_; +}; + +/** @relates PropertyManager + * + * @deprecated Temporary properties should not have a name. + * + * Creates a new property whose lifetime is limited to the current scope. + * + * Used for temporary properties. Shadows any existing properties of + * matching name and type. + * + * Example: + * @code + * PolyMesh m; + * { + * auto is_quad = makeTemporaryProperty(m); + * for (auto& fh : m.faces()) { + * is_quad[fh] = (m.valence(fh) == 4); + * } + * // The property is automatically removed from the mesh at the end of the scope. + * } + * @endcode + * + * @param mesh The mesh on which the property is created + * @param propname (optional) The name of the created property + * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the created property, e.g., \p double, \p int, etc. + * @returns A PropertyManager handling the lifecycle of the property + */ +template +PropertyManager::type> +OM_DEPRECATED("Named temporary properties are deprecated. Either create a temporary without name or a non-temporary with name") +makeTemporaryProperty(PolyConnectivity &mesh, const char *propname) { + return PropertyManager::type>(mesh, propname, false); +} + +/** @relates PropertyManager + * + * Creates a new property whose lifetime is limited to the current scope. + * + * Used for temporary properties. Shadows any existing properties of + * matching name and type. + * + * Example: + * @code + * PolyMesh m; + * { + * auto is_quad = makeTemporaryProperty(m); + * for (auto& fh : m.faces()) { + * is_quad[fh] = (m.valence(fh) == 4); + * } + * // The property is automatically removed from the mesh at the end of the scope. + * } + * @endcode + * + * @param mesh The mesh on which the property is created + * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the created property, e.g., \p double, \p int, etc. + * @returns A PropertyManager handling the lifecycle of the property + */ +template +PropertyManager::type> +makeTemporaryProperty(PolyConnectivity &mesh) { + return PropertyManager::type>(mesh); +} + + +/** @relates PropertyManager + * + * Tests whether a property with the given element type, value type, and name is + * present on the given mesh. + * + * * Example: + * @code + * PolyMesh m; + * if (hasProperty(m, "is_quad")) { + * // We now know the property exists: getProperty won't throw. + * auto is_quad = getProperty(m, "is_quad"); + * // Use is_quad here. + * } + * @endcode + * + * @param mesh The mesh in question + * @param propname The property name of the expected property + * @tparam ElementT Element type of the expected property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the expected property, e.g., \p double, \p int, etc. + * @tparam MeshT Type of the mesh. Can often be inferred from \p mesh + */ +template +bool +hasProperty(const PolyConnectivity &mesh, const char *propname) { + typename HandleToPropHandle::type ph; + return mesh.get_property_handle(ph, propname); +} + +/** @relates PropertyManager + * + * Obtains a handle to a named property. + * + * Example: + * @code + * PolyMesh m; + * { + * try { + * auto is_quad = getProperty(m, "is_quad"); + * // Use is_quad here. + * } + * catch (const std::runtime_error& e) { + * // There is no is_quad face property on the mesh. + * } + * } + * @endcode + * + * @pre Property with the name \p propname of matching type exists. + * @throws std::runtime_error if no property with the name \p propname of + * matching type exists. + * @param mesh The mesh on which the property is created + * @param propname The name of the created property + * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the created property, e.g., \p double, \p int, etc. + * @returns A PropertyManager wrapping the property + */ +template +PropertyManager::type> +getProperty(PolyConnectivity &mesh, const char *propname) { + if (!hasProperty(mesh, propname)) + { + std::ostringstream oss; + oss << "Requested property handle \"" << propname << "\" does not exist."; + throw std::runtime_error(oss.str()); + } + return PropertyManager::type>(mesh, propname); +} + +/** @relates PropertyManager + * + * Obtains a handle to a named property if it exists or creates a new one otherwise. + * + * Used for creating or accessing permanent properties. + * + * Example: + * @code + * PolyMesh m; + * { + * auto is_quad = getOrMakeProperty(m, "is_quad"); + * for (auto& fh : m.faces()) { + * is_quad[fh] = (m.valence(fh) == 4); + * } + * // The property remains on the mesh after the end of the scope. + * } + * { + * // Retrieve the property from the previous scope. + * auto is_quad = getOrMakeProperty(m, "is_quad"); + * // Use is_quad here. + * } + * @endcode + * + * @param mesh The mesh on which the property is created + * @param propname The name of the created property + * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the created property, e.g., \p double, \p int, etc. + * @returns A PropertyManager wrapping the property + */ +template +PropertyManager::type> +getOrMakeProperty(PolyConnectivity &mesh, const char *propname) { + return PropertyManager::type>::createIfNotExists(mesh, propname); +} + +/** @relates PropertyManager + * @deprecated Use makeTemporaryProperty() instead. + * + * Creates a new property whose lifecycle is managed by the returned + * PropertyManager. + * + * Intended for temporary properties. Shadows any existing properties of + * matching name and type. + */ +template +OM_DEPRECATED("Use makeTemporaryProperty instead.") +PropertyManager makePropertyManagerFromNew(PolyConnectivity &mesh, const char *propname) +{ + return PropertyManager(mesh, propname, false); +} + +/** \relates PropertyManager + * @deprecated Use getProperty() instead. + * + * Creates a non-owning wrapper for an existing mesh property (no lifecycle + * management). + * + * Intended for convenient access. + * + * @pre Property with the name \p propname of matching type exists. + * @throws std::runtime_error if no property with the name \p propname of + * matching type exists. + */ +template +OM_DEPRECATED("Use getProperty instead.") +PropertyManager makePropertyManagerFromExisting(PolyConnectivity &mesh, const char *propname) +{ + return PropertyManager(mesh, propname, true); +} + +/** @relates PropertyManager + * @deprecated Use getOrMakeProperty() instead. + * + * Creates a non-owning wrapper for a mesh property (no lifecycle management). + * If the given property does not exist, it is created. + * + * Intended for creating or accessing persistent properties. + */ +template +OM_DEPRECATED("Use getOrMakeProperty instead.") +PropertyManager makePropertyManagerFromExistingOrNew(PolyConnectivity &mesh, const char *propname) +{ + return PropertyManager::createIfNotExists(mesh, propname); +} + +/** @relates PropertyManager + * Like the two parameter version of makePropertyManagerFromExistingOrNew() + * except it initializes the property with the specified value over the + * specified range if it needs to be created. If the property already exists, + * this function has the exact same effect as the two parameter version. + * + * Creates a non-owning wrapper for a mesh property (no lifecycle management). + * If the given property does not exist, it is created. + * + * Intended for creating or accessing persistent properties. + */ +template +OM_DEPRECATED("Use getOrMakeProperty instead.") +PropertyManager makePropertyManagerFromExistingOrNew( + PolyConnectivity &mesh, const char *propname, + const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, + const PROP_VALUE &init_value) { + return PropertyManager::createIfNotExists( + mesh, propname, begin, end, init_value); +} + +/** @relates PropertyManager + * Like the two parameter version of makePropertyManagerFromExistingOrNew() + * except it initializes the property with the specified value over the + * specified range if it needs to be created. If the property already exists, + * this function has the exact same effect as the two parameter version. + * + * Creates a non-owning wrapper for a mesh property (no lifecycle management). + * If the given property does not exist, it is created. + * + * Intended for creating or accessing persistent properties. + */ +template +OM_DEPRECATED("Use getOrMakeProperty instead.") +PropertyManager makePropertyManagerFromExistingOrNew( + PolyConnectivity &mesh, const char *propname, + const ITERATOR_RANGE &range, + const PROP_VALUE &init_value) { + return makePropertyManagerFromExistingOrNew( + mesh, propname, range.begin(), range.end(), init_value); +} + + +/** @relates PropertyManager + * Returns a convenience wrapper around the points property of a mesh. + */ +template +PropertyManager> +getPointsProperty(MeshT &mesh) { + return PropertyManager>(mesh, mesh.points_property_handle()); +} + +/** @relates PropertyManager + * Returns a convenience wrapper around the points property of a mesh that only allows const access. + */ +template +ConstPropertyViewer> +getPointsProperty(const MeshT &mesh) { + using PropType = OpenMesh::VPropHandleT; + return ConstPropertyViewer(mesh, mesh.points_property_handle()); +} + +template +using Prop = PropertyManager::template type>; + +template +using VProp = PropertyManager>; + +template +using HProp = PropertyManager>; + +template +using EProp = PropertyManager>; + +template +using FProp = PropertyManager>; + +template +using MProp = PropertyManager>; + + +} /* namespace OpenMesh */ +#endif /* PROPERTYMANAGER_HH_ */ diff --git a/Sources/OpenMeshCore/Core/Utils/RandomNumberGenerator.cc b/Sources/OpenMeshCore/Core/Utils/RandomNumberGenerator.cc new file mode 100644 index 0000000..2941160 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/RandomNumberGenerator.cc @@ -0,0 +1,98 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +//============================================================================= +// +// Helper Functions for generating a random number between 0.0 and 1.0 with +// a garantueed resolution +// +//============================================================================= + + +//== INCLUDES ================================================================= + + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION =========================================================== + +RandomNumberGenerator::RandomNumberGenerator(const size_t _resolution) : + resolution_(_resolution), + iterations_(1), + maxNum_(RAND_MAX + 1.0) +{ + double tmp = double(resolution_); + while (tmp > (double(RAND_MAX) + 1.0) ) { + iterations_++; + tmp /= (double(RAND_MAX) + 1.0); + } + + for ( unsigned int i = 0 ; i < iterations_ - 1; ++i ) { + maxNum_ *= (RAND_MAX + 1.0); + } +} + +//----------------------------------------------------------------------------- + +double RandomNumberGenerator::getRand() const { + double randNum = 0.0; + for ( unsigned int i = 0 ; i < iterations_; ++i ) { + randNum *= (RAND_MAX + 1.0); + randNum += rand(); + } + + return randNum / maxNum_; +} + +double RandomNumberGenerator::resolution() const { + return maxNum_; +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/RandomNumberGenerator.hh b/Sources/OpenMeshCore/Core/Utils/RandomNumberGenerator.hh new file mode 100644 index 0000000..3861f14 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/RandomNumberGenerator.hh @@ -0,0 +1,109 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +//============================================================================= +// +// Helper Functions for generating a random number between 0.0 and 1.0 with +// a guaranteed resolution +// +//============================================================================= + + +#ifndef OPENMESH_UTILS_RANDOMNUMBERGENERATOR_HH +#define OPENMESH_UTILS_RANDOMNUMBERGENERATOR_HH + + +//== INCLUDES ================================================================= + + +#include +#include + + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** Generate a random number between 0.0 and 1.0 with a guaranteed resolution + * ( Number of possible values ) + * + * Especially useful on windows, as there MAX_RAND is often only 32k which is + * not enough resolution for a lot of applications + */ +class OPENMESHDLLEXPORT RandomNumberGenerator +{ +public: + + /** \brief Constructor + * + * @param _resolution specifies the desired resolution for the random number generated + */ + explicit RandomNumberGenerator(const size_t _resolution); + + /// returns a random double between 0.0 and 1.0 with a guaranteed resolution + double getRand() const; + + double resolution() const; + +private: + + /// desired resolution + const size_t resolution_; + + /// number of "blocks" of RAND_MAX that make up the desired _resolution + size_t iterations_; + + /// maximum random number generated, which is used for normalization + double maxNum_; +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_UTILS_RANDOMNUMBERGENERATOR_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/Utils/SingletonT.hh b/Sources/OpenMeshCore/Core/Utils/SingletonT.hh new file mode 100644 index 0000000..67a113e --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/SingletonT.hh @@ -0,0 +1,144 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a simple singleton template +// +//============================================================================= + +#pragma once + +//=== INCLUDES ================================================================ + +// OpenMesh +#include + +// STL +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//=== IMPLEMENTATION ========================================================== + + +/** A simple singleton template. + Encapsulates an arbitrary class and enforces its uniqueness. +*/ + +template +class SingletonT +{ +public: + + /** Singleton access function. + Use this function to obtain a reference to the instance of the + encapsulated class. Note that this instance is unique and created + on the first call to Instance(). + */ + + static T& Instance() + { + if (!pInstance__) + { + // check if singleton alive + if (destroyed__) + { + OnDeadReference(); + } + // first time request -> initialize + else + { + Create(); + } + } + return *pInstance__; + } + + +private: + + // Disable constructors/assignment to enforce uniqueness + SingletonT(); + SingletonT(const SingletonT&); + SingletonT& operator=(const SingletonT&); + + // Create a new singleton and store its pointer + static void Create() + { + static T theInstance; + pInstance__ = &theInstance; + } + + // Will be called if instance is accessed after its lifetime has expired + static void OnDeadReference() + { + throw std::runtime_error("[Singelton error] - Dead reference detected!\n"); + } + + virtual ~SingletonT() + { + pInstance__ = 0; + destroyed__ = true; + } + + static T* pInstance__; + static bool destroyed__; +}; + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SINGLETON_C) +# define OPENMESH_SINGLETON_TEMPLATES +# include "SingletonT_impl.hh" +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/SingletonT_impl.hh b/Sources/OpenMeshCore/Core/Utils/SingletonT_impl.hh new file mode 100644 index 0000000..dd5cc4c --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/SingletonT_impl.hh @@ -0,0 +1,80 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a simple singleton template +// +//============================================================================= + + +#define OPENMESH_SINGLETON_C + + +//== INCLUDES ================================================================= + + +// header +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== SINGLETON'S DATA ========================================================= + + +template +T* SingletonT::pInstance__ = 0; + +template +bool SingletonT::destroyed__ = false; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/color_cast.hh b/Sources/OpenMeshCore/Core/Utils/color_cast.hh new file mode 100644 index 0000000..e6a1dfb --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/color_cast.hh @@ -0,0 +1,394 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_COLOR_CAST_HH +#define OPENMESH_COLOR_CAST_HH + + +//== INCLUDES ================================================================= + + +#include +#include + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Cast vector type to another vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- +#ifndef DOXY_IGNORE_THIS + +/// Cast one color vector to another. +template +struct color_caster +{ + typedef dst_t return_type; + + inline static return_type cast(const src_t& _src) + { + dst_t dst; + vector_cast(_src, dst, GenProg::Int2Type::size_>()); + return dst; + } +}; + + +template <> +struct color_caster +{ + typedef Vec3uc return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec3uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3uc return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec3uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3i return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec3i( (int)(_src[0]* 255.0f + 0.5f), + (int)(_src[1]* 255.0f + 0.5f), + (int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3i return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec3i( (int)(_src[0]* 255.0f + 0.5f), + (int)(_src[1]* 255.0f + 0.5f), + (int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4i return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec4i( (int)(_src[0]* 255.0f + 0.5f), + (int)(_src[1]* 255.0f + 0.5f), + (int)(_src[2]* 255.0f + 0.5f), + (int)(_src[3]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3ui return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec3ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3ui return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec3ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4ui return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec4ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f), + (unsigned int)(_src[3]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec4uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f), + (unsigned char)(255) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4ui return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec4ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f), + (unsigned int)(255) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec4f( _src[0], + _src[1], + _src[2], + 1.0f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4ui return_type; + + inline static return_type cast(const Vec3uc& _src) + { + return Vec4ui(_src[0], + _src[1], + _src[2], + 255 ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec3i& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0]*f, _src[1]*f, _src[2]*f, 1.0f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec4uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f), + (unsigned char)(_src[3]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec4i& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f( _src[0] * f, _src[1] * f, _src[2] * f , _src[3] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec3uc& _src) + { + return Vec4uc( _src[0], _src[1], _src[2], 255 ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3f return_type; + + inline static return_type cast(const Vec3uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec3f(_src[0] * f, _src[1] * f, _src[2] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3f return_type; + + inline static return_type cast(const Vec4uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec3f(_src[0] * f, _src[1] * f, _src[2] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec3uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0] * f, _src[1] * f, _src[2] * f, 1.0f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec4uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0] * f, _src[1] * f, _src[2] * f, _src[3] * f ); + } +}; + +// ---------------------------------------------------------------------------- + + +#ifndef DOXY_IGNORE_THIS + +#if !defined(OM_CC_MSVC) +template +struct color_caster +{ + typedef const dst_t& return_type; + + inline static return_type cast(const dst_t& _src) + { + return _src; + } +}; +#endif + +#endif + +//----------------------------------------------------------------------------- + + +template +inline +typename color_caster::return_type +color_cast(const src_t& _src ) +{ + return color_caster::cast(_src); +} + +#endif +//----------------------------------------------------------------------------- + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_COLOR_CAST_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Core/Utils/typename.hh b/Sources/OpenMeshCore/Core/Utils/typename.hh new file mode 100644 index 0000000..0ac7c3c --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/typename.hh @@ -0,0 +1,29 @@ +#pragma once + +/// Get an internal name for a type +/// Important, this is depends on compilers and versions, do NOT use in file formats! +/// This provides property type safety when only limited RTTI is available +/// Solution adapted from OpenVolumeMesh + +#include +#include +#include +#include +#include + +namespace OpenMesh { + +template +std::string get_type_name() +{ +#ifdef _MSC_VER + // MSVC'S type_name returns only a friendly name with name() method, + // to get a unique name use raw_name() method instead + return typeid(T).raw_name(); +#else + // GCC and clang curently return mangled name as name(), there is no raw_name() method + return typeid(T).name(); +#endif +} + +}//namespace OpenMesh diff --git a/Sources/OpenMeshCore/Core/Utils/vector_cast.hh b/Sources/OpenMeshCore/Core/Utils/vector_cast.hh new file mode 100644 index 0000000..35d1e08 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/vector_cast.hh @@ -0,0 +1,158 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_VECTORCAST_HH +#define OPENMESH_VECTORCAST_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Cast vector type to another vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- + +template +inline void vector_cast( const src_t &_src, dst_t &_dst, GenProg::Int2Type ) +{ + assert_compile(vector_traits::size_ <= vector_traits::size_) + vector_cast(_src,_dst, GenProg::Int2Type()); + _dst[n-1] = static_cast::value_type >(_src[n-1]); +} + +template +inline void vector_cast( const src_t & /*_src*/, dst_t & /*_dst*/, GenProg::Int2Type<0> ) +{ +} + +template +inline void vector_copy( const src_t &_src, dst_t &_dst, GenProg::Int2Type ) +{ + assert_compile(vector_traits::size_ <= vector_traits::size_) + vector_copy(_src,_dst, GenProg::Int2Type()); + _dst[n-1] = _src[n-1]; +} + +template +inline void vector_copy( const src_t & /*_src*/, dst_t & /*_dst*/ , GenProg::Int2Type<0> ) +{ +} + + + +//----------------------------------------------------------------------------- +#ifndef DOXY_IGNORE_THIS + +template +struct vector_caster +{ + typedef dst_t return_type; + + inline static return_type cast(const src_t& _src) + { + dst_t dst; + vector_cast(_src, dst, GenProg::Int2Type::size_>()); + return dst; + } +}; + +#if !defined(OM_CC_MSVC) +template +struct vector_caster +{ + typedef const dst_t& return_type; + + inline static return_type cast(const dst_t& _src) + { + return _src; + } +}; +#endif + +#endif +//----------------------------------------------------------------------------- + + +/// Cast vector type to another vector type by copying the vector elements +template +inline +typename vector_caster::return_type +vector_cast(const src_t& _src ) +{ + return vector_caster::cast(_src); +} + + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Core/Utils/vector_traits.hh b/Sources/OpenMeshCore/Core/Utils/vector_traits.hh new file mode 100644 index 0000000..430e9e5 --- /dev/null +++ b/Sources/OpenMeshCore/Core/Utils/vector_traits.hh @@ -0,0 +1,110 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_VECTOR_TRAITS_HH +#define OPENMESH_VECTOR_TRAITS_HH + + +//== INCLUDES ================================================================= + +#include +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Provide a standardized access to relevant information about a + vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- + +/** Helper class providing information about a vector type. + * + * If want to use a different vector type than the one provided %OpenMesh + * you need to supply a specialization of this class for the new vector type. + */ +template +struct vector_traits +{ + /// Type of the vector class + typedef typename T::vector_type vector_type; + + /// Type of the scalar value + typedef typename T::value_type value_type; + + /// size/dimension of the vector + static const size_t size_ = T::size_; + + /// size/dimension of the vector + static size_t size() { return size_; } +}; + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/Config.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/Config.hh new file mode 100644 index 0000000..772a9df --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/Config.hh @@ -0,0 +1,70 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + + +//============================================================================= +// +// Defines +// +//============================================================================= + +#ifndef OPENMESH_GEOMETRY_CONFIG_HH +#define OPENMESH_GEOMETRY_CONFIG_HH + + +//== INCLUDES ================================================================= + +// OpenMesh Namespace Defines +#include + + +//== NAMESPACES =============================================================== + +#define BEGIN_NS_GEOMETRY namespace geometry { +#define END_NS_GEOMETRY } + + +//============================================================================= +#endif // OPENMESH_GEOMETRY_CONFIG_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/EigenVectorT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/EigenVectorT.hh new file mode 100644 index 0000000..5ae86e9 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/EigenVectorT.hh @@ -0,0 +1,104 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/** This file contains all code required to use Eigen3 vectors as Mesh + * vectors + */ +#pragma once + +#include +#include +#include + + +namespace OpenMesh { + template + struct vector_traits> { + static_assert(_Rows != Eigen::Dynamic && _Cols != Eigen::Dynamic, + "Should not use dynamic vectors."); + static_assert(_Rows == 1 || _Cols == 1, "Should not use matrices."); + + using vector_type = Eigen::Matrix<_Scalar, _Rows, _Cols, _Options>; + using value_type = _Scalar; + static const size_t size_ = _Rows * _Cols; + static size_t size() { return size_; } +}; + +} // namespace OpenMesh + +namespace Eigen { + + template + typename Derived::Scalar dot(const MatrixBase &x, + const MatrixBase &y) { + return x.dot(y); + } + + template + typename MatrixBase< Derived >::PlainObject cross(const MatrixBase &x, const MatrixBase &y) { + return x.cross(y); + } + + template + typename Derived::Scalar norm(const MatrixBase &x) { + return x.norm(); + } + + template + typename Derived::Scalar sqrnorm(const MatrixBase &x) { + return x.dot(x); + } + + template + MatrixBase &normalize(MatrixBase &x) { + x /= x.norm(); + return x; + } + + template + MatrixBase &vectorize(MatrixBase &x, + typename Derived::Scalar const &val) { + x.fill(val); + return x; + } + +} // namespace Eigen + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/LoopSchemeMaskT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/LoopSchemeMaskT.hh new file mode 100644 index 0000000..329365b --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/LoopSchemeMaskT.hh @@ -0,0 +1,191 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef LOOPSCHEMEMASKT_HH +#define LOOPSCHEMEMASKT_HH + +#include +#include + +#include +#include + +namespace OpenMesh +{ + +/** implements cache for the weights of the original Loop scheme + supported: + - vertex projection rule on the next level + - vertex projection rule on the limit surface + - vertex projection rule on the k-th (level) step (Barthe, Kobbelt'2003) + - vertex tangents on the limit surface +*/ + +template +class LoopSchemeMaskT +{ +public: + enum { cache_size = cache_size_ }; + typedef T_ Scalar; + +protected: + + Scalar proj_weights_[cache_size]; + Scalar limit_weights_[cache_size]; + Scalar step_weights_[cache_size]; + std::vector tang0_weights_[cache_size]; + std::vector tang1_weights_[cache_size]; + +protected: + + inline static Scalar compute_proj_weight(uint _valence) + { + //return pow(3.0 / 2.0 + cos(2.0 * M_PI / _valence), 2) / 2.0 - 1.0; + double denom = (3.0 + 2.0*cos(2.0*M_PI/(double)_valence)); + double weight = (64.0*_valence)/(40.0 - denom*denom) - _valence; + return (Scalar) weight; + } + + inline static Scalar compute_limit_weight(uint _valence) + { + double proj_weight_value = compute_proj_weight(_valence); + proj_weight_value = proj_weight_value/(proj_weight_value + _valence);//normalize the proj_weight + double weight = (3.0/8.0)/(1.0 - proj_weight_value + (3.0/8.0)); + return (Scalar)weight; + } + + inline static Scalar compute_step_weight(uint _valence) + { + double proj_weight_value = compute_proj_weight(_valence); + proj_weight_value = proj_weight_value/(proj_weight_value + _valence);//normalize the proj_weight + double weight = proj_weight_value - (3.0/8.0); + return (Scalar)weight; + } + + inline static Scalar compute_tang0_weight(uint _valence, uint _ver_id) + { + return (Scalar)cos(2.0*M_PI*(double)_ver_id/(double)_valence); + } + + inline static Scalar compute_tang1_weight(uint _valence, uint _ver_id) + { + return (Scalar)sin(2.0*M_PI*(double)_ver_id/(double)_valence); + } + + void cache_weights() + { + proj_weights_[0] = 1; + for (uint k = 1; k < cache_size; ++k) + { + proj_weights_[k] = compute_proj_weight(k); + limit_weights_[k] = compute_limit_weight(k); + step_weights_[k] = compute_step_weight(k); + tang0_weights_[k].resize(k); + tang1_weights_[k].resize(k); + for (uint i = 0; i < k; ++i) + { + tang0_weights_[k][i] = compute_tang0_weight(k,i); + tang1_weights_[k][i] = compute_tang1_weight(k,i); + } + } + } + +public: + + LoopSchemeMaskT() + { + cache_weights(); + } + + inline Scalar proj_weight(uint _valence) const + { + assert(_valence < cache_size ); + return proj_weights_[_valence]; + } + + inline Scalar limit_weight(uint _valence) const + { + assert(_valence < cache_size ); + return limit_weights_[_valence]; + } + + inline Scalar step_weight(uint _valence, uint _step) const + { + assert(_valence < cache_size); + return pow(step_weights_[_valence], (int)_step);//can be precomputed + } + + inline Scalar tang0_weight(uint _valence, uint _ver_id) const + { + assert(_valence < cache_size ); + assert(_ver_id < _valence); + return tang0_weights_[_valence][_ver_id]; + } + + inline Scalar tang1_weight(uint _valence, uint _ver_id) const + { + assert(_valence < cache_size ); + assert(_ver_id < _valence); + return tang1_weights_[_valence][_ver_id]; + } + + void dump(uint _max_valency = cache_size - 1) const + { + assert(_max_valency <= cache_size - 1); + //CConsole::printf("(k : pw_k, lw_k): "); + for (uint i = 0; i <= _max_valency; ++i) + { + //CConsole::stream() << "(" << i << " : " << proj_weight(i) << ", " << limit_weight(i) << ", " << step_weight(i,1) << "), "; + } + //CConsole::printf("\n"); + } +}; + +typedef LoopSchemeMaskT LoopSchemeMaskDouble; +typedef SingletonT LoopSchemeMaskDoubleSingleton; + +}//namespace OpenMesh + +#endif//LOOPSCHEMEMASKT_HH + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/MathDefs.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/MathDefs.hh new file mode 100644 index 0000000..c7a77fc --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/MathDefs.hh @@ -0,0 +1,167 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef MATHDEFS_HH +#define MATHDEFS_HH + +#include +#include + +#ifndef M_PI + #define M_PI 3.14159265359 +#endif + +namespace OpenMesh +{ + +/** comparison operators with user-selected precision control +*/ +template +inline bool is_zero(const T& _a, Real _eps) +{ return fabs(_a) < _eps; } + +template +inline bool is_eq(const T1& a, const T2& b, Real _eps) +{ return is_zero(a-b, _eps); } + +template +inline bool is_gt(const T1& a, const T2& b, Real _eps) +{ return (a > b) && !is_eq(a,b,_eps); } + +template +inline bool is_ge(const T1& a, const T2& b, Real _eps) +{ return (a > b) || is_eq(a,b,_eps); } + +template +inline bool is_lt(const T1& a, const T2& b, Real _eps) +{ return (a < b) && !is_eq(a,b,_eps); } + +template +inline bool is_le(const T1& a, const T2& b, Real _eps) +{ return (a < b) || is_eq(a,b,_eps); } + +/*const float flt_eps__ = 10*FLT_EPSILON; +const double dbl_eps__ = 10*DBL_EPSILON;*/ +const float flt_eps__ = (float)1e-05; +const double dbl_eps__ = 1e-09; + +inline float eps__(float) +{ return flt_eps__; } + +inline double eps__(double) +{ return dbl_eps__; } + +template +inline bool is_zero(const T& a) +{ return is_zero(a, eps__(a)); } + +template +inline bool is_eq(const T1& a, const T2& b) +{ return is_zero(a-b); } + +template +inline bool is_gt(const T1& a, const T2& b) +{ return (a > b) && !is_eq(a,b); } + +template +inline bool is_ge(const T1& a, const T2& b) +{ return (a > b) || is_eq(a,b); } + +template +inline bool is_lt(const T1& a, const T2& b) +{ return (a < b) && !is_eq(a,b); } + +template +inline bool is_le(const T1& a, const T2& b) +{ return (a < b) || is_eq(a,b); } + +/// Trigonometry/angles - related + +template +inline T sane_aarg(T _aarg) +{ + if (_aarg < -1) + { + _aarg = -1; + } + else if (_aarg > 1) + { + _aarg = 1; + } + return _aarg; +} + +/** returns the angle determined by its cos and the sign of its sin + result is positive if the angle is in [0:pi] + and negative if it is in [pi:2pi] +*/ +template +T angle(T _cos_angle, T _sin_angle) +{//sanity checks - otherwise acos will return nan + _cos_angle = sane_aarg(_cos_angle); + return (T) _sin_angle >= 0 ? acos(_cos_angle) : -acos(_cos_angle); +} + +template +inline T positive_angle(T _angle) +{ return _angle < 0 ? (2*M_PI + _angle) : _angle; } + +template +inline T positive_angle(T _cos_angle, T _sin_angle) +{ return positive_angle(angle(_cos_angle, _sin_angle)); } + +template +inline T deg_to_rad(const T& _angle) +{ return M_PI*(_angle/180); } + +template +inline T rad_to_deg(const T& _angle) +{ return 180*(_angle/M_PI); } + +inline double log_(double _value) +{ return log(_value); } + +}//namespace OpenMesh + +#endif//MATHDEFS_HH diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/NormalConeT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/NormalConeT.hh new file mode 100644 index 0000000..c146c59 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/NormalConeT.hh @@ -0,0 +1,124 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +//============================================================================= +// +// CLASS NormalCone +// +//============================================================================= + + +#ifndef OPENMESH_NORMALCONE_HH +#define OPENMESH_NORMALCONE_HH + + +//== INCLUDES ================================================================= + + +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** /class NormalCone NormalCone.hh + + NormalCone that can be merged with other normal cones. Provides + the center normal and the opening angle. +**/ + +template +class NormalConeT +{ +public: + + // typedefs + typedef typename vector_traits::value_type Scalar; + typedef Vector Vec3; + + + //! default constructor (not initialized) + NormalConeT() : angle_(0.0) {} + + //! Initialize cone with center (unit vector) and angle (radius in radians) + explicit NormalConeT(const Vec3& _center_normal, Scalar _angle=0.0); + + //! return max. distance (radians) unit vector to cone (distant side) + Scalar max_angle(const Vec3&) const; + + //! return max. distance (radians) cone to cone (distant sides) + Scalar max_angle(const NormalConeT&) const; + + //! merge _cone; this instance will then enclose both former cones + void merge(const NormalConeT&); + + //! returns center normal + const Vec3& center_normal() const { return center_normal_; } + + //! returns size of cone (radius in radians) + inline Scalar angle() const { return angle_; } + +private: + + Vec3 center_normal_; + Scalar angle_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_NORMALCONE_C) +#define OPENMESH_NORMALCONE_TEMPLATES +#include "NormalConeT_impl.hh" +#endif +//============================================================================= +#endif // OPENMESH_NORMALCONE_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/NormalConeT_impl.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/NormalConeT_impl.hh new file mode 100644 index 0000000..d09fc42 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/NormalConeT_impl.hh @@ -0,0 +1,151 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +//============================================================================= +// +// CLASS NormalConeT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_NORMALCONE_C + +//== INCLUDES ================================================================= + +#include +#include "NormalConeT.hh" + +#ifdef max +# undef max +#endif + +#ifdef min +# undef min +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + +template +NormalConeT:: +NormalConeT(const Vec3& _center_normal, Scalar _angle) + : center_normal_(_center_normal), angle_(_angle) +{ +} + + +//---------------------------------------------------------------------------- + + +template +typename NormalConeT::Scalar +NormalConeT:: +max_angle(const Vec3& _norm) const +{ + Scalar dotp = (center_normal_ | _norm); + return (dotp >= 1.0 ? 0.0 : (dotp <= -1.0 ? M_PI : acos(dotp))) + + angle_; +} + + +//---------------------------------------------------------------------------- + + +template +typename NormalConeT::Scalar +NormalConeT:: +max_angle(const NormalConeT& _cone) const +{ + Scalar dotp = (center_normal_ | _cone.center_normal_); + Scalar centerAngle = dotp >= 1.0 ? 0.0 : (dotp <= -1.0 ? M_PI : acos(dotp)); + Scalar sideAngle0 = std::max(angle_-centerAngle, _cone.angle_); + Scalar sideAngle1 = std::max(_cone.angle_-centerAngle, angle_); + + return centerAngle + sideAngle0 + sideAngle1; +} + + +//---------------------------------------------------------------------------- + + +template +void +NormalConeT:: +merge(const NormalConeT& _cone) +{ + Scalar dotp = dot(center_normal_, _cone.center_normal_); + + if (fabs(dotp) < 0.99999f) + { + // new angle + Scalar centerAngle = acos(dotp); + Scalar minAngle = std::min(-angle(), centerAngle - _cone.angle()); + Scalar maxAngle = std::max( angle(), centerAngle + _cone.angle()); + angle_ = (maxAngle - minAngle) * Scalar(0.5f); + + // axis by SLERP + Scalar axisAngle = Scalar(0.5f) * (minAngle + maxAngle); + center_normal_ = ((center_normal_ * sin(centerAngle-axisAngle) + + _cone.center_normal_ * sin(axisAngle)) + / sin(centerAngle)); + } + else + { + // axes point in same direction + if (dotp > 0.0f) + angle_ = std::max(angle_, _cone.angle_); + + // axes point in opposite directions + else + angle_ = Scalar(2.0f * M_PI); + } +} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/Plane3d.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/Plane3d.hh new file mode 100644 index 0000000..42e4c4a --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/Plane3d.hh @@ -0,0 +1,119 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + + +//============================================================================= +// +// CLASS Plane3D +// +//============================================================================= + + +#ifndef OPENMESH_PLANE3D_HH +#define OPENMESH_PLANE3D_HH + + +//== INCLUDES ================================================================= + +#include + + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** \class Plane3d Plane3d.hh + + ax + by + cz + d = 0 +*/ + + +class OPENMESHDLLEXPORT Plane3d +{ +public: + + typedef OpenMesh::Vec3f vector_type; + typedef vector_type::value_type value_type; + +public: + + Plane3d() + : d_(0) + { } + + Plane3d(const vector_type &_dir, const vector_type &_pnt) + : n_(_dir), d_(0) + { + n_.normalize(); + d_ = -dot(n_,_pnt); + } + + value_type signed_distance(const OpenMesh::Vec3f &_p) + { + return dot(n_ , _p) + d_; + } + + // back compatibility + value_type singed_distance(const OpenMesh::Vec3f &point) + { return signed_distance( point ); } + +public: + + vector_type n_; + value_type d_; + +}; + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_PLANE3D_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/QuadricT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/QuadricT.hh new file mode 100644 index 0000000..7e21257 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/QuadricT.hh @@ -0,0 +1,286 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + + +/** \file Core/Geometry/QuadricT.hh + + */ + +//============================================================================= +// +// CLASS QuadricT +// +//============================================================================= + +#ifndef OPENMESH_GEOMETRY_QUADRIC_HH +#define OPENMESH_GEOMETRY_QUADRIC_HH + + +//== INCLUDES ================================================================= + +#include "Config.hh" +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { //BEGIN_NS_OPENMESH +namespace Geometry { //BEGIN_NS_GEOMETRY + + +//== CLASS DEFINITION ========================================================= + + +/** /class QuadricT Geometry/QuadricT.hh + + Stores a quadric as a 4x4 symmetrix matrix. Used by the + error quadric based mesh decimation algorithms. +**/ + +template +class QuadricT +{ +public: + typedef Scalar value_type; + typedef QuadricT type; + typedef QuadricT Self; + // typedef VectorInterface > Vec3; + // typedef VectorInterface > Vec4; + //typedef Vector3Elem Vec3; + //typedef Vector4Elem Vec4; + + /// construct with upper triangle of symmetrix 4x4 matrix + QuadricT(Scalar _a, Scalar _b, Scalar _c, Scalar _d, + Scalar _e, Scalar _f, Scalar _g, + Scalar _h, Scalar _i, + Scalar _j) + : a_(_a), b_(_b), c_(_c), d_(_d), + e_(_e), f_(_f), g_(_g), + h_(_h), i_(_i), + j_(_j) + { + } + + + /// constructor from given plane equation: ax+by+cz+d_=0 + QuadricT( Scalar _a=0.0, Scalar _b=0.0, Scalar _c=0.0, Scalar _d=0.0 ) + : a_(_a*_a), b_(_a*_b), c_(_a*_c), d_(_a*_d), + e_(_b*_b), f_(_b*_c), g_(_b*_d), + h_(_c*_c), i_(_c*_d), + j_(_d*_d) + {} + + template + explicit QuadricT(const _Point& _pt) + { + set_distance_to_point(_pt); + } + + template + QuadricT(const _Normal& _n, const _Point& _p) + { + set_distance_to_plane(_n,_p); + } + + //set operator + void set(Scalar _a, Scalar _b, Scalar _c, Scalar _d, + Scalar _e, Scalar _f, Scalar _g, + Scalar _h, Scalar _i, + Scalar _j) + { + a_ = _a; b_ = _b; c_ = _c; d_ = _d; + e_ = _e; f_ = _f; g_ = _g; + h_ = _h; i_ = _i; + j_ = _j; + } + + //sets the quadric representing the squared distance to _pt + template + void set_distance_to_point(const _Point& _pt) + { + set(1, 0, 0, -_pt[0], + 1, 0, -_pt[1], + 1, -_pt[2], + dot(_pt,_pt)); + } + + //sets the quadric representing the squared distance to the plane [_a,_b,_c,_d] + void set_distance_to_plane(Scalar _a, Scalar _b, Scalar _c, Scalar _d) + { + a_ = _a*_a; b_ = _a*_b; c_ = _a*_c; d_ = _a*_d; + e_ = _b*_b; f_ = _b*_c; g_ = _b*_d; + h_ = _c*_c; i_ = _c*_d; + j_ = _d*_d; + } + + //sets the quadric representing the squared distance to the plane + //determined by the normal _n and the point _p + template + void set_distance_to_plane(const _Normal& _n, const _Point& _p) + { + set_distance_to_plane(_n[0], _n[1], _n[2], -dot(_n,_p)); + } + + /// set all entries to zero + void clear() { a_ = b_ = c_ = d_ = e_ = f_ = g_ = h_ = i_ = j_ = 0.0; } + + /// add quadrics + QuadricT& operator+=( const QuadricT& _q ) + { + a_ += _q.a_; b_ += _q.b_; c_ += _q.c_; d_ += _q.d_; + e_ += _q.e_; f_ += _q.f_; g_ += _q.g_; + h_ += _q.h_; i_ += _q.i_; + j_ += _q.j_; + return *this; + } + + QuadricT operator+(const QuadricT& _other ) const + { + QuadricT result = *this; + return result += _other; + } + + + /// multiply by scalar + QuadricT& operator*=( Scalar _s) + { + a_ *= _s; b_ *= _s; c_ *= _s; d_ *= _s; + e_ *= _s; f_ *= _s; g_ *= _s; + h_ *= _s; i_ *= _s; + j_ *= _s; + return *this; + } + + QuadricT operator*(Scalar _s) const + { + QuadricT result = *this; + return result *= _s; + } + + /// multiply 4D vector from right: Q*v + template + _Vec4 operator*(const _Vec4& _v) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]), w(_v[3]); + return _Vec4(x*a_ + y*b_ + z*c_ + w*d_, + x*b_ + y*e_ + z*f_ + w*g_, + x*c_ + y*f_ + z*h_ + w*i_, + x*d_ + y*g_ + z*i_ + w*j_); + } + + /// evaluate quadric Q at (3D or 4D) vector v: v*Q*v + template + Scalar operator()(const _Vec& _v) const + { + return evaluate(_v, GenProg::Int2Type::size_>()); + } + + Scalar a() const { return a_; } + Scalar b() const { return b_; } + Scalar c() const { return c_; } + Scalar d() const { return d_; } + Scalar e() const { return e_; } + Scalar f() const { return f_; } + Scalar g() const { return g_; } + Scalar h() const { return h_; } + Scalar i() const { return i_; } + Scalar j() const { return j_; } + + Scalar xx() const { return a_; } + Scalar xy() const { return b_; } + Scalar xz() const { return c_; } + Scalar xw() const { return d_; } + Scalar yy() const { return e_; } + Scalar yz() const { return f_; } + Scalar yw() const { return g_; } + Scalar zz() const { return h_; } + Scalar zw() const { return i_; } + Scalar ww() const { return j_; } + +protected: + + /// evaluate quadric Q at 3D vector v: v*Q*v + template + Scalar evaluate(const _Vec3& _v, GenProg::Int2Type<3>/*_dimension*/) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]); + return a_*x*x + 2.0*b_*x*y + 2.0*c_*x*z + 2.0*d_*x + + e_*y*y + 2.0*f_*y*z + 2.0*g_*y + + h_*z*z + 2.0*i_*z + + j_; + } + + /// evaluate quadric Q at 4D vector v: v*Q*v + template + Scalar evaluate(const _Vec4& _v, GenProg::Int2Type<4>/*_dimension*/) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]), w(_v[3]); + return a_*x*x + 2.0*b_*x*y + 2.0*c_*x*z + 2.0*d_*x*w + + e_*y*y + 2.0*f_*y*z + 2.0*g_*y*w + + h_*z*z + 2.0*i_*z*w + + j_*w*w; + } + +private: + + Scalar a_, b_, c_, d_, + e_, f_, g_, + h_, i_, + j_; +}; + + +/// Quadric using floats +typedef QuadricT Quadricf; + +/// Quadric using double +typedef QuadricT Quadricd; + + +//============================================================================= +} // END_NS_GEOMETRY +} // END_NS_OPENMESH +//============================================================================ +#endif // OPENMESH_GEOMETRY_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/Vector11T.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/Vector11T.hh new file mode 100644 index 0000000..7a6c93b --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/Vector11T.hh @@ -0,0 +1,926 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#ifndef OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ +#define OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// This header is not needed by this file but expected by others including +// this file. +#include + + +/* + * Helpers for VectorT + */ +namespace { + +template +struct are_convertible_to; + +template +struct are_convertible_to { + static constexpr bool value = std::is_convertible::value + && are_convertible_to::value; +}; + +template +struct are_convertible_to : public std::is_convertible { +}; +} + +namespace OpenMesh { + +template +class VectorT { + + static_assert(DIM >= 1, "VectorT requires positive dimensionality."); + + private: + using container = std::array; + container values_; + + public: + + //---------------------------------------------------------------- class info + + /// the type of the scalar used in this template + typedef Scalar value_type; + + /// type of this vector + typedef VectorT vector_type; + + /// returns dimension of the vector (deprecated) + static constexpr int dim() { + return DIM; + } + + /// returns dimension of the vector + static constexpr size_t size() { + return DIM; + } + + static constexpr const size_t size_ = DIM; + + //-------------------------------------------------------------- constructors + + // Converting constructor: Constructs the vector from DIM values (of + // potentially heterogenous types) which are all convertible to Scalar. + template::type, + typename = typename std::enable_if< + are_convertible_to::value>::type> + constexpr VectorT(T v, Ts... vs) : values_ { {static_cast(v), static_cast(vs)...} } { + static_assert(sizeof...(Ts)+1 == DIM, + "Invalid number of components specified in constructor."); + static_assert(are_convertible_to::value, + "Not all components are convertible to Scalar."); + } + + /// default constructor creates uninitialized values. + constexpr VectorT() {} + + /** + * Creates a vector with all components set to v. + */ + explicit VectorT(const Scalar &v) { + vectorize(v); + } + + VectorT(const VectorT &rhs) = default; + VectorT(VectorT &&rhs) = default; + VectorT &operator=(const VectorT &rhs) = default; + VectorT &operator=(VectorT &&rhs) = default; + + /** + * Only for 4-component vectors with division operator on their + * Scalar: Dehomogenization. + */ + template + auto homogenized() const -> + typename std::enable_if()/std::declval()), DIM>>::type { + static_assert(D == DIM, "D and DIM need to be identical. (Never " + "override the default template arguments.)"); + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return VectorT( + values_[0]/values_[3], + values_[1]/values_[3], + values_[2]/values_[3], + 1); + } + + /// construct from a value array or any other iterator + template(), void(), + ++std::declval(), void())> + explicit VectorT(Iterator it) { + std::copy_n(it, DIM, values_.begin()); + } + + /// construct from an array + explicit VectorT(container&& _array) : + values_(_array) + { + } + + /// copy & cast constructor (explicit) + template::value>> + explicit VectorT(const VectorT& _rhs) { + operator=(_rhs); + } + + //--------------------------------------------------------------------- casts + + /// cast from vector with a different scalar type + template::value>> + vector_type& operator=(const VectorT& _rhs) { + std::transform(_rhs.cbegin(), _rhs.cend(), + this->begin(), [](OtherScalar rhs) { + return static_cast(std::move(rhs)); + }); + return *this; + } + + /// access to Scalar array + Scalar* data() { return values_.data(); } + + /// access to const Scalar array + const Scalar* data() const { return values_.data(); } + + //----------------------------------------------------------- element access + + /// get i'th element read-write + Scalar& operator[](size_t _i) { + assert(_i < DIM); + return values_[_i]; + } + + /// get i'th element read-only + const Scalar& operator[](size_t _i) const { + assert(_i < DIM); + return values_[_i]; + } + + //---------------------------------------------------------------- comparsion + + /// component-wise comparison + bool operator==(const vector_type& _rhs) const { + return std::equal(_rhs.values_.cbegin(), _rhs.values_.cend(), values_.cbegin()); + } + + /// component-wise comparison + bool operator!=(const vector_type& _rhs) const { + return !std::equal(_rhs.values_.cbegin(), _rhs.values_.cend(), values_.cbegin()); + } + + //---------------------------------------------------------- scalar operators + + /// component-wise self-multiplication with scalar + template + auto operator*=(const OtherScalar& _s) -> + typename std::enable_ifvalues_[0] * _s), Scalar>::value, + VectorT&>::type { + for (auto& e : *this) { + e *= _s; + } + return *this; + } + + /// component-wise self-division by scalar + template + auto operator/=(const OtherScalar& _s) -> + typename std::enable_ifvalues_[0] / _s), Scalar>::value, + VectorT&>::type { + for (auto& e : *this) { + e /= _s; + } + return *this; + } + + /// component-wise multiplication with scalar + template + typename std::enable_if() * std::declval()), + Scalar>::value, + VectorT>::type + operator*(const OtherScalar& _s) const { + return vector_type(*this) *= _s; + } + + /// component-wise division by with scalar + template + typename std::enable_if() / std::declval()), + Scalar>::value, + VectorT>::type + operator/(const OtherScalar& _s) const { + return vector_type(*this) /= _s; + } + + //---------------------------------------------------------- vector operators + + /// component-wise self-multiplication + template + auto operator*=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] *= _rhs.data()[i]; + } + return *this; + } + + /// component-wise self-division + template + auto operator/=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] /= _rhs.data()[i]; + } + return *this; + } + + /// vector difference from this + template + auto operator-=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] -= _rhs.data()[i]; + } + return *this; + } + + /// vector self-addition + template + auto operator+=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0, + vector_type&>::type { + for (int i = 0; i < DIM; ++i) { + data()[i] += _rhs.data()[i]; + } + return *this; + } + + /// component-wise vector multiplication + template + auto operator*(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) *= _rhs; + } + + /// component-wise vector division + template + auto operator/(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) /= _rhs; + } + + /// component-wise vector addition + template + auto operator+(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) += _rhs; + } + + /// component-wise vector difference + template + auto operator-(const VectorT& _rhs) const -> + typename std::enable_if< + sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0, + vector_type>::type { + return vector_type(*this) -= _rhs; + } + + /// unary minus + vector_type operator-(void) const { + vector_type v; + std::transform(values_.begin(), values_.end(), v.values_.begin(), + [](const Scalar &s) { return -s; }); + return v; + } + + /// cross product: only defined for Vec3* as specialization + /// \see OpenMesh::cross and .cross() + template + auto operator% (const VectorT &_rhs) const -> + typename std::enable_if>::type { + return { + values_[1] * _rhs[2] - values_[2] * _rhs[1], + values_[2] * _rhs[0] - values_[0] * _rhs[2], + values_[0] * _rhs[1] - values_[1] * _rhs[0] + }; + } + + /// cross product: only defined for Vec3* as specialization + /// \see OpenMesh::cross and .operator% + template + auto cross (const VectorT &_rhs) const -> + decltype(*this % _rhs) + { + return *this % _rhs; + } + + + /// compute scalar product + /// \see OpenMesh::dot and .dot() + template + auto operator|(const VectorT& _rhs) const -> + decltype(*this->data() * *_rhs.data()) { + + return std::inner_product(begin() + 1, begin() + DIM, _rhs.begin() + 1, + *begin() * *_rhs.begin()); + } + + /// compute scalar product + /// \see OpenMesh::dot and .operator| + template + auto dot(const VectorT& _rhs) const -> + decltype(*this | _rhs) + { + return *this | _rhs; + } + + //------------------------------------------------------------ euclidean norm + + /// \name Euclidean norm calculations + //@{ + + /// compute squared euclidean norm + template + decltype(std::declval() * std::declval()) sqrnorm() const { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + typedef decltype(values_[0] * values_[0]) RESULT; + return std::accumulate(values_.cbegin() + 1, values_.cend(), + values_[0] * values_[0], + [](const RESULT &l, const Scalar &r) { return l + r * r; }); + } + + /// compute euclidean norm + template + auto norm() const -> + decltype(std::sqrt(std::declval>().sqrnorm())) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return std::sqrt(sqrnorm()); + } + + template + auto length() const -> + decltype(std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return norm(); + } + + /** normalize vector, return normalized vector + */ + template + auto normalize() -> + decltype(*this /= std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return *this /= norm(); + } + + /** return normalized vector + */ + template + auto normalized() const -> + decltype(*this / std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return *this / norm(); + } + + /** normalize vector, return normalized vector and avoids div by zero + */ + template + typename std::enable_if< + sizeof(decltype( + static_cast(0), + std::declval>().norm())) >= 0, + vector_type&>::type + normalize_cond() { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + auto n = norm(); + if (n != static_cast(0)) { + *this /= n; + } + return *this; + } + + //@} + + //------------------------------------------------------------ euclidean norm + + /// \name Non-Euclidean norm calculations + //@{ + + /// compute L1 (Manhattan) norm + Scalar l1_norm() const { + return std::accumulate( + values_.cbegin() + 1, values_.cend(), values_[0]); + } + + /// compute l8_norm + Scalar l8_norm() const { + return max_abs(); + } + + //@} + + //------------------------------------------------------------ max, min, mean + + /// \name Minimum maximum and mean + //@{ + + /// return the maximal component + Scalar max() const { + return *std::max_element(values_.cbegin(), values_.cend()); + } + + /// return the maximal absolute component + Scalar max_abs() const { + return std::abs( + *std::max_element(values_.cbegin(), values_.cend(), + [](const Scalar &a, const Scalar &b) { + return std::abs(a) < std::abs(b); + })); + } + + /// return the minimal component + Scalar min() const { + return *std::min_element(values_.cbegin(), values_.cend()); + } + + /// return the minimal absolute component + Scalar min_abs() const { + return std::abs( + *std::min_element(values_.cbegin(), values_.cend(), + [](const Scalar &a, const Scalar &b) { + return std::abs(a) < std::abs(b); + })); + } + + /// return arithmetic mean + Scalar mean() const { + return l1_norm()/DIM; + } + + /// return absolute arithmetic mean + Scalar mean_abs() const { + return std::accumulate(values_.cbegin() + 1, values_.cend(), + std::abs(values_[0]), + [](const Scalar &l, const Scalar &r) { + return l + std::abs(r); + }) / DIM; + } + + /// minimize values: same as *this = min(*this, _rhs), but faster + vector_type& minimize(const vector_type& _rhs) { + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [](const Scalar &l, const Scalar &r) { + return std::min(l, r); + }); + return *this; + } + + /// minimize values and signalize coordinate minimization + bool minimized(const vector_type& _rhs) { + bool result = false; + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [&result](const Scalar &l, const Scalar &r) { + if (l < r) { + return l; + } else { + result = true; + return r; + } + }); + return result; + } + + /// maximize values: same as *this = max(*this, _rhs), but faster + vector_type& maximize(const vector_type& _rhs) { + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [](const Scalar &l, const Scalar &r) { + return std::max(l, r); + }); + return *this; + } + + /// maximize values and signalize coordinate maximization + bool maximized(const vector_type& _rhs) { + bool result = false; + std::transform(values_.cbegin(), values_.cend(), + _rhs.values_.cbegin(), + values_.begin(), + [&result](const Scalar &l, const Scalar &r) { + if (l > r) { + return l; + } else { + result = true; + return r; + } + }); + return result; + } + + /// component-wise min + inline vector_type min(const vector_type& _rhs) const { + return vector_type(*this).minimize(_rhs); + } + + /// component-wise max + inline vector_type max(const vector_type& _rhs) const { + return vector_type(*this).maximize(_rhs); + } + + //@} + + //------------------------------------------------------------ misc functions + + /// component-wise apply function object with Scalar operator()(Scalar). + template + inline vector_type apply(const Functor& _func) const { + vector_type result; + std::transform(result.values_.cbegin(), result.values_.cend(), + result.values_.begin(), _func); + return result; + } + + /// store the same value in each component (e.g. to clear all entries) + vector_type& vectorize(const Scalar& _s) { + std::fill(values_.begin(), values_.end(), _s); + return *this; + } + + /// store the same value in each component + static vector_type vectorized(const Scalar& _s) { + return vector_type().vectorize(_s); + } + + /// lexicographical comparison + bool operator<(const vector_type& _rhs) const { + return std::lexicographical_compare( + values_.begin(), values_.end(), + _rhs.values_.begin(), _rhs.values_.end()); + } + + /// swap with another vector + void swap(VectorT& _other) + noexcept(noexcept(std::swap(values_, _other.values_))) { + std::swap(values_, _other.values_); + } + + //------------------------------------------------------------ component iterators + + /// \name Component iterators + //@{ + + using iterator = typename container::iterator; + using const_iterator = typename container::const_iterator; + using reverse_iterator = typename container::reverse_iterator; + using const_reverse_iterator = typename container::const_reverse_iterator; + + iterator begin() noexcept { return values_.begin(); } + const_iterator begin() const noexcept { return values_.cbegin(); } + const_iterator cbegin() const noexcept { return values_.cbegin(); } + + iterator end() noexcept { return values_.end(); } + const_iterator end() const noexcept { return values_.cend(); } + const_iterator cend() const noexcept { return values_.cend(); } + + reverse_iterator rbegin() noexcept { return values_.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return values_.crbegin(); } + const_reverse_iterator crbegin() const noexcept { return values_.crbegin(); } + + reverse_iterator rend() noexcept { return values_.rend(); } + const_reverse_iterator rend() const noexcept { return values_.crend(); } + const_reverse_iterator crend() const noexcept { return values_.crend(); } + + //@} +}; + +/// Component wise multiplication from the left +template +auto operator*(const OtherScalar& _s, const VectorT &rhs) -> + decltype(rhs.operator*(_s)) { + + return rhs * _s; +} + +/// output a vector by printing its space-separated compontens +template +auto operator<<(std::ostream& os, const VectorT &_vec) -> + typename std::enable_if< + sizeof(decltype(os << _vec[0])) >= 0, std::ostream&>::type { + + os << _vec[0]; + for (int i = 1; i < DIM; ++i) { + os << " " << _vec[i]; + } + return os; +} + +/// read the space-separated components of a vector from a stream +template +auto operator>> (std::istream& is, VectorT &_vec) -> + typename std::enable_if< + sizeof(decltype(is >> _vec[0])) >= 0, std::istream &>::type { + for (int i = 0; i < DIM; ++i) + is >> _vec[i]; + return is; +} + +/// \relates OpenMesh::VectorT +/// symmetric version of the dot product +template +Scalar dot(const VectorT& _v1, const VectorT& _v2) { + return (_v1 | _v2); +} + +/// \relates OpenMesh::VectorT +/// symmetric version of the cross product +template +auto +cross(const VectorT& _v1, const VectorT& _v2) -> + decltype(_v1 % _v2) { + return (_v1 % _v2); +} + +/// \relates OpenMesh::VectorT +/// non-member swap +template +void swap(VectorT& _v1, VectorT& _v2) +noexcept(noexcept(_v1.swap(_v2))) { + _v1.swap(_v2); +} + +/// \relates OpenMesh::VectorT +/// non-member norm +template +Scalar norm(const VectorT& _v) { + return _v.norm(); +} + +/// \relates OpenMesh::VectorT +/// non-member sqrnorm +template +Scalar sqrnorm(const VectorT& _v) { + return _v.sqrnorm(); +} +/// \relates OpenMesh::VectorT +/// non-member vectorize +template +VectorT& vectorize(VectorT& _v, OtherScalar const& _val) { + return _v.vectorize(_val); +} + +/// \relates OpenMesh::VectorT +/// non-member normalize +template +VectorT& normalize(VectorT& _v) { + return _v.normalize(); +} + +/// \relates OpenMesh::VectorT +/// non-member maximize +template +VectorT& maximize(VectorT& _v1, VectorT& _v2) { + return _v1.maximize(_v2); +} + +/// \relates OpenMesh::VectorT +/// non-member minimize +template +VectorT& minimize(VectorT& _v1, VectorT& _v2) { + return _v1.minimize(_v2); +} + +/// \relates OpenMesh::VectorT +/// non-member max +template +VectorT max(const VectorT& _v1, const VectorT& _v2) { + return _v1.max(_v2); +} + +/// \relates OpenMesh::VectorT +/// non-member min +template +VectorT min(const VectorT& _v1, const VectorT& _v2) { + return _v1.min(_v2); +} + + +//== TYPEDEFS ================================================================= + +/** 1-byte signed vector */ +typedef VectorT Vec1c; +/** 1-byte unsigned vector */ +typedef VectorT Vec1uc; +/** 1-short signed vector */ +typedef VectorT Vec1s; +/** 1-short unsigned vector */ +typedef VectorT Vec1us; +/** 1-int signed vector */ +typedef VectorT Vec1i; +/** 1-int unsigned vector */ +typedef VectorT Vec1ui; +/** 1-float vector */ +typedef VectorT Vec1f; +/** 1-double vector */ +typedef VectorT Vec1d; + +/** 2-byte signed vector */ +typedef VectorT Vec2c; +/** 2-byte unsigned vector */ +typedef VectorT Vec2uc; +/** 2-short signed vector */ +typedef VectorT Vec2s; +/** 2-short unsigned vector */ +typedef VectorT Vec2us; +/** 2-int signed vector */ +typedef VectorT Vec2i; +/** 2-int unsigned vector */ +typedef VectorT Vec2ui; +/** 2-float vector */ +typedef VectorT Vec2f; +/** 2-double vector */ +typedef VectorT Vec2d; + +/** 3-byte signed vector */ +typedef VectorT Vec3c; +/** 3-byte unsigned vector */ +typedef VectorT Vec3uc; +/** 3-short signed vector */ +typedef VectorT Vec3s; +/** 3-short unsigned vector */ +typedef VectorT Vec3us; +/** 3-int signed vector */ +typedef VectorT Vec3i; +/** 3-int unsigned vector */ +typedef VectorT Vec3ui; +/** 3-float vector */ +typedef VectorT Vec3f; +/** 3-double vector */ +typedef VectorT Vec3d; +/** 3-bool vector */ +typedef VectorT Vec3b; + +/** 4-byte signed vector */ +typedef VectorT Vec4c; +/** 4-byte unsigned vector */ +typedef VectorT Vec4uc; +/** 4-short signed vector */ +typedef VectorT Vec4s; +/** 4-short unsigned vector */ +typedef VectorT Vec4us; +/** 4-int signed vector */ +typedef VectorT Vec4i; +/** 4-int unsigned vector */ +typedef VectorT Vec4ui; +/** 4-float vector */ +typedef VectorT Vec4f; +/** 4-double vector */ +typedef VectorT Vec4d; + +/** 5-byte signed vector */ +typedef VectorT Vec5c; +/** 5-byte unsigned vector */ +typedef VectorT Vec5uc; +/** 5-short signed vector */ +typedef VectorT Vec5s; +/** 5-short unsigned vector */ +typedef VectorT Vec5us; +/** 5-int signed vector */ +typedef VectorT Vec5i; +/** 5-int unsigned vector */ +typedef VectorT Vec5ui; +/** 5-float vector */ +typedef VectorT Vec5f; +/** 5-double vector */ +typedef VectorT Vec5d; + +/** 6-byte signed vector */ +typedef VectorT Vec6c; +/** 6-byte unsigned vector */ +typedef VectorT Vec6uc; +/** 6-short signed vector */ +typedef VectorT Vec6s; +/** 6-short unsigned vector */ +typedef VectorT Vec6us; +/** 6-int signed vector */ +typedef VectorT Vec6i; +/** 6-int unsigned vector */ +typedef VectorT Vec6ui; +/** 6-float vector */ +typedef VectorT Vec6f; +/** 6-double vector */ +typedef VectorT Vec6d; + +} // namespace OpenMesh + +/** + * Literal operator for inline specification of colors in HTML syntax. + * + * Example: + * \code{.cpp} + * OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor; + * \endcode + */ +constexpr OpenMesh::Vec4f operator"" _htmlColor(unsigned long long raw_color) { + return OpenMesh::Vec4f( + ((raw_color >> 24) & 0xFF) / 255.0f, + ((raw_color >> 16) & 0xFF) / 255.0f, + ((raw_color >> 8) & 0xFF) / 255.0f, + ((raw_color >> 0) & 0xFF) / 255.0f); +} + +#endif /* OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ */ diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/VectorT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/VectorT.hh new file mode 100644 index 0000000..c2676c7 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/VectorT.hh @@ -0,0 +1,451 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + + +//============================================================================= +// +// CLASS VectorT +// +//============================================================================= + +// Don't parse this header file with doxygen since +// for some reason (obviously due to a bug in doxygen, +// bugreport: https://bugzilla.gnome.org/show_bug.cgi?id=629182) +// macro expansion and preprocessor defines +// don't work properly. + +#if ((defined(_MSC_VER) && (_MSC_VER >= 1900)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) +#include "Vector11T.hh" +#else +#ifndef DOXYGEN + +#ifndef OPENMESH_VECTOR_HH +#define OPENMESH_VECTOR_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + +#if defined(__GNUC__) && defined(__SSE__) +#include +#endif + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** The N values of the template Scalar type are the only data members + of the class VectorT. This guarantees 100% compatibility + with arrays of type Scalar and size N, allowing us to define the + cast operators to and from arrays and array pointers. + + In addition, this class will be specialized for Vec4f to be 16 bit + aligned, so that aligned SSE instructions can be used on these + vectors. +*/ +template class VectorDataT { + public: + Scalar values_[N]; +}; + + +#if defined(__GNUC__) && defined(__SSE__) + +/// This specialization enables us to use aligned SSE instructions. +template<> class VectorDataT { + public: + union { + __m128 m128; + float values_[4]; + }; +}; + +#endif + + + + +//== CLASS DEFINITION ========================================================= + + +#define DIM N +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT +#define unroll(expr) for (int i=0; i + A vector is an array of \ values of type \. + The actual data is stored in an VectorDataT, this class just adds + the necessary operators. +*/ +#include "VectorT_inc.hh" + +#undef DIM +#undef TEMPLATE_HEADER +#undef CLASSNAME +#undef DERIVED +#undef unroll + + + + +//== PARTIAL TEMPLATE SPECIALIZATIONS ========================================= +#if OM_PARTIAL_SPECIALIZATION + + +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT + + +#define DIM 2 +#define unroll(expr) expr(0) expr(1) +#define unroll_comb(expr, op) expr(0) op expr(1) +#define unroll_csv(expr) expr(0), expr(1) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#define DIM 3 +#define unroll(expr) expr(0) expr(1) expr(2) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) +#define unroll_csv(expr) expr(0), expr(1), expr(2) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#define DIM 4 +#define unroll(expr) expr(0) expr(1) expr(2) expr(3) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) op expr(3) +#define unroll_csv(expr) expr(0), expr(1), expr(2), expr(3) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + +#define DIM 5 +#define unroll(expr) expr(0) expr(1) expr(2) expr(3) expr(4) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) op expr(3) op expr(4) +#define unroll_csv(expr) expr(0), expr(1), expr(2), expr(3), expr(4) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + +#define DIM 6 +#define unroll(expr) expr(0) expr(1) expr(2) expr(3) expr(4) expr(5) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) op expr(3) op expr(4) op expr(5) +#define unroll_csv(expr) expr(0), expr(1), expr(2), expr(3), expr(4), expr(5) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#undef TEMPLATE_HEADER +#undef CLASSNAME +#undef DERIVED + + + + +//== FULL TEMPLATE SPECIALIZATIONS ============================================ +#else + +/// cross product for Vec3f +template<> +inline VectorT +VectorT::operator%(const VectorT& _rhs) const +{ + return + VectorT(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1], + values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2], + values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]); +} + + +/// cross product for Vec3d +template<> +inline VectorT +VectorT::operator%(const VectorT& _rhs) const +{ + return + VectorT(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1], + values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2], + values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]); +} + +#endif + + + +//== GLOBAL FUNCTIONS ========================================================= + + +/// \relates OpenMesh::VectorT +/// scalar * vector +template +inline VectorT operator*(Scalar2 _s, const VectorT& _v) { + return _v*_s; +} + + +/// \relates OpenMesh::VectorT +/// symmetric version of the dot product +template +inline Scalar +dot(const VectorT& _v1, const VectorT& _v2) { + return (_v1 | _v2); +} + + +/// \relates OpenMesh::VectorT +/// symmetric version of the cross product +template +inline VectorT +cross(const VectorT& _v1, const VectorT& _v2) { + return (_v1 % _v2); +} + + +/// \relates OpenMesh::VectorT +/// non-member norm +template +Scalar norm(const VectorT& _v) { + return _v.norm(); +} + + +/// \relates OpenMesh::VectorT +/// non-member sqrnorm +template +Scalar sqrnorm(const VectorT& _v) { + return _v.sqrnorm(); +} + + +/// \relates OpenMesh::VectorT +/// non-member vectorize +template +VectorT& vectorize(VectorT& _v, OtherScalar const& _val) { + return _v.vectorize(_val); +} + + +/// \relates OpenMesh::VectorT +/// non-member normalize +template +VectorT& normalize(VectorT& _v) { + return _v.normalize(); +} + + +/// \relates OpenMesh::VectorT +/// non-member maximize +template +VectorT& maximize(VectorT& _v1, VectorT& _v2) { + return _v1.maximize(_v2); +} + + +/// \relates OpenMesh::VectorT +/// non-member minimize +template +VectorT& minimize(VectorT& _v1, VectorT& _v2) { + return _v1.minimize(_v2); +} + + +/// \relates OpenMesh::VectorT +/// non-member max +template +VectorT max(const VectorT& _v1, const VectorT& _v2) { + return VectorT(_v1).maximize(_v2); +} + + +/// \relates OpenMesh::VectorT +/// non-member min +template +VectorT min(const VectorT& _v1, const VectorT& _v2) { + return VectorT(_v1).minimize(_v2); +} + + +//== TYPEDEFS ================================================================= + +/** 1-byte signed vector */ +typedef VectorT Vec1c; +/** 1-byte unsigned vector */ +typedef VectorT Vec1uc; +/** 1-short signed vector */ +typedef VectorT Vec1s; +/** 1-short unsigned vector */ +typedef VectorT Vec1us; +/** 1-int signed vector */ +typedef VectorT Vec1i; +/** 1-int unsigned vector */ +typedef VectorT Vec1ui; +/** 1-float vector */ +typedef VectorT Vec1f; +/** 1-double vector */ +typedef VectorT Vec1d; + +/** 2-byte signed vector */ +typedef VectorT Vec2c; +/** 2-byte unsigned vector */ +typedef VectorT Vec2uc; +/** 2-short signed vector */ +typedef VectorT Vec2s; +/** 2-short unsigned vector */ +typedef VectorT Vec2us; +/** 2-int signed vector */ +typedef VectorT Vec2i; +/** 2-int unsigned vector */ +typedef VectorT Vec2ui; +/** 2-float vector */ +typedef VectorT Vec2f; +/** 2-double vector */ +typedef VectorT Vec2d; + +/** 3-byte signed vector */ +typedef VectorT Vec3c; +/** 3-byte unsigned vector */ +typedef VectorT Vec3uc; +/** 3-short signed vector */ +typedef VectorT Vec3s; +/** 3-short unsigned vector */ +typedef VectorT Vec3us; +/** 3-int signed vector */ +typedef VectorT Vec3i; +/** 3-int unsigned vector */ +typedef VectorT Vec3ui; +/** 3-float vector */ +typedef VectorT Vec3f; +/** 3-double vector */ +typedef VectorT Vec3d; +/** 3-bool vector */ +typedef VectorT Vec3b; + +/** 4-byte signed vector */ +typedef VectorT Vec4c; +/** 4-byte unsigned vector */ +typedef VectorT Vec4uc; +/** 4-short signed vector */ +typedef VectorT Vec4s; +/** 4-short unsigned vector */ +typedef VectorT Vec4us; +/** 4-int signed vector */ +typedef VectorT Vec4i; +/** 4-int unsigned vector */ +typedef VectorT Vec4ui; +/** 4-float vector */ +typedef VectorT Vec4f; +/** 4-double vector */ +typedef VectorT Vec4d; + +/** 5-byte signed vector */ +typedef VectorT Vec5c; +/** 5-byte unsigned vector */ +typedef VectorT Vec5uc; +/** 5-short signed vector */ +typedef VectorT Vec5s; +/** 5-short unsigned vector */ +typedef VectorT Vec5us; +/** 5-int signed vector */ +typedef VectorT Vec5i; +/** 5-int unsigned vector */ +typedef VectorT Vec5ui; +/** 5-float vector */ +typedef VectorT Vec5f; +/** 5-double vector */ +typedef VectorT Vec5d; + +/** 6-byte signed vector */ +typedef VectorT Vec6c; +/** 6-byte unsigned vector */ +typedef VectorT Vec6uc; +/** 6-short signed vector */ +typedef VectorT Vec6s; +/** 6-short unsigned vector */ +typedef VectorT Vec6us; +/** 6-int signed vector */ +typedef VectorT Vec6i; +/** 6-int unsigned vector */ +typedef VectorT Vec6ui; +/** 6-float vector */ +typedef VectorT Vec6f; +/** 6-double vector */ +typedef VectorT Vec6d; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + + +#endif // OPENMESH_VECTOR_HH defined +//============================================================================= +#endif // DOXYGEN +#endif // C++11 diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/VectorT_inc.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/VectorT_inc.hh new file mode 100644 index 0000000..de7680b --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Geometry/VectorT_inc.hh @@ -0,0 +1,663 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + + +// Set template keywords and class names properly when +// parsing with doxygen. This only seems to work this way since +// the scope of preprocessor defines is limited to one file in doxy. +#ifdef DOXYGEN + +// Only used for correct doxygen parsing +#define OPENMESH_VECTOR_HH + +#define DIM N +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT +#define unroll(expr) for (int i=0; i vector_type; + + /// returns dimension of the vector (deprecated) + static inline int dim() { return DIM; } + + /// returns dimension of the vector + static inline size_t size() { return DIM; } + + static const size_t size_ = DIM; + + + //-------------------------------------------------------------- constructors + + /// default constructor creates uninitialized values. + inline VectorT() {} + + /// special constructor for 1D vectors + explicit inline VectorT(const Scalar& v) { +// assert(DIM==1); +// values_[0] = v0; + vectorize(v); + } + +#if DIM == 2 + /// special constructor for 2D vectors + inline VectorT(const Scalar v0, const Scalar v1) { + Base::values_[0] = v0; Base::values_[1] = v1; + } +#endif + +#if DIM == 3 + /// special constructor for 3D vectors + inline VectorT(const Scalar v0, const Scalar v1, const Scalar v2) { + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; + } +#endif + +#if DIM == 4 + /// special constructor for 4D vectors + inline VectorT(const Scalar v0, const Scalar v1, + const Scalar v2, const Scalar v3) { + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; Base::values_[3]=v3; + } + + VectorT homogenized() const { return VectorT(Base::values_[0]/Base::values_[3], Base::values_[1]/Base::values_[3], Base::values_[2]/Base::values_[3], 1); } +#endif + +#if DIM == 5 + /// special constructor for 5D vectors + inline VectorT(const Scalar v0, const Scalar v1, const Scalar v2, + const Scalar v3, const Scalar v4) { + Base::values_[0]=v0; Base::values_[1]=v1;Base::values_[2]=v2; Base::values_[3]=v3; Base::values_[4]=v4; + } +#endif + +#if DIM == 6 + /// special constructor for 6D vectors + inline VectorT(const Scalar v0, const Scalar v1, const Scalar v2, + const Scalar v3, const Scalar v4, const Scalar v5) { + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; + Base::values_[3]=v3; Base::values_[4]=v4; Base::values_[5]=v5; + } +#endif + + /// construct from a value array (explicit) + explicit inline VectorT(const Scalar _values[DIM]) { + memcpy(data(), _values, DIM*sizeof(Scalar)); + } + + +#ifdef OM_CC_MIPS + /// assignment from a vector of the same kind + // mipspro need this method + inline vector_type& operator=(const vector_type& _rhs) { + memcpy(Base::values_, _rhs.Base::values_, DIM*sizeof(Scalar)); + return *this; + } +#endif + + + /// copy & cast constructor (explicit) + template + explicit inline VectorT(const VectorT& _rhs) { + operator=(_rhs); + } + + + + + //--------------------------------------------------------------------- casts + + /// cast from vector with a different scalar type + template + inline vector_type& operator=(const VectorT& _rhs) { +#define expr(i) Base::values_[i] = (Scalar)_rhs[i]; + unroll(expr); +#undef expr + return *this; + } + +// /// cast to Scalar array +// inline operator Scalar*() { return Base::values_; } + +// /// cast to const Scalar array +// inline operator const Scalar*() const { return Base::values_; } + + /// access to Scalar array + inline Scalar* data() { return Base::values_; } + + /// access to const Scalar array + inline const Scalar*data() const { return Base::values_; } + + + //----------------------------------------------------------- element access + +// /// get i'th element read-write +// inline Scalar& operator[](int _i) { +// assert(_i>=0 && _i=0 && _i operator%(const VectorT& _rhs) const +#if DIM==3 + { + return + VectorT(Base::values_[1]*_rhs.Base::values_[2]-Base::values_[2]*_rhs.Base::values_[1], + Base::values_[2]*_rhs.Base::values_[0]-Base::values_[0]*_rhs.Base::values_[2], + Base::values_[0]*_rhs.Base::values_[1]-Base::values_[1]*_rhs.Base::values_[0]); + } +#else + ; +#endif + + + /// compute scalar product + /// \see OpenMesh::dot + inline Scalar operator|(const vector_type& _rhs) const { + Scalar p(0); +#define expr(i) p += Base::values_[i] * _rhs.Base::values_[i]; + unroll(expr); +#undef expr + return p; + } + + + + + + //------------------------------------------------------------ euclidean norm + + /// \name Euclidean norm calculations + //@{ + /// compute euclidean norm + inline Scalar norm() const { return (Scalar)sqrt(sqrnorm()); } + inline Scalar length() const { return norm(); } // OpenSG interface + + /// compute squared euclidean norm + inline Scalar sqrnorm() const + { +#if DIM==N + Scalar s(0); +#define expr(i) s += Base::values_[i] * Base::values_[i]; + unroll(expr); +#undef expr + return s; +#else +#define expr(i) Base::values_[i]*Base::values_[i] + return (unroll_comb(expr, +)); +#undef expr +#endif + } + + /** normalize vector, return normalized vector + */ + + inline vector_type& normalize() + { + *this /= norm(); + return *this; + } + + /** return normalized vector + */ + + inline const vector_type normalized() const + { + return *this / norm(); + } + + /** normalize vector, return normalized vector and avoids div by zero + */ + inline vector_type& normalize_cond() + { + Scalar n = norm(); + if (n != (Scalar)0.0) + { + *this /= n; + } + return *this; + } + + //@} + + //------------------------------------------------------------ euclidean norm + + /// \name Non-Euclidean norm calculations + //@{ + + /// compute L1 (Manhattan) norm + inline Scalar l1_norm() const + { +#if DIM==N + Scalar s(0); +#define expr(i) s += std::abs(Base::values_[i]); + unroll(expr); +#undef expr + return s; +#else +#define expr(i) std::abs(Base::values_[i]) + return (unroll_comb(expr, +)); +#undef expr +#endif + } + + /// compute l8_norm + inline Scalar l8_norm() const + { + return max_abs(); + } + + //@} + + //------------------------------------------------------------ max, min, mean + + /// \name Minimum maximum and mean + //@{ + + /// return the maximal component + inline Scalar max() const + { + Scalar m(Base::values_[0]); + for(int i=1; im) m=Base::values_[i]; + return m; + } + + /// return the maximal absolute component + inline Scalar max_abs() const + { + Scalar m(std::abs(Base::values_[0])); + for(int i=1; im) + m=std::abs(Base::values_[i]); + return m; + } + + + /// return the minimal component + inline Scalar min() const + { + Scalar m(Base::values_[0]); + for(int i=1; i Base::values_[i]) Base::values_[i] = _rhs[i]; + unroll(expr); +#undef expr + return *this; + } + + /// maximize values and signalize coordinate maximization + inline bool maximized(const vector_type& _rhs) { + bool result(false); +#define expr(i) if (_rhs[i] > Base::values_[i]) { Base::values_[i] =_rhs[i]; result = true; } + unroll(expr); +#undef expr + return result; + } + + /// component-wise min + inline vector_type min(const vector_type& _rhs) const { + return vector_type(*this).minimize(_rhs); + } + + /// component-wise max + inline vector_type max(const vector_type& _rhs) const { + return vector_type(*this).maximize(_rhs); + } + + //@} + + //------------------------------------------------------------ misc functions + + /// component-wise apply function object with Scalar operator()(Scalar). + template + inline vector_type apply(const Functor& _func) const { + vector_type result; +#define expr(i) result[i] = _func(Base::values_[i]); + unroll(expr); +#undef expr + return result; + } + + /// store the same value in each component (e.g. to clear all entries) + vector_type& vectorize(const Scalar& _s) { +#define expr(i) Base::values_[i] = _s; + unroll(expr); +#undef expr + return *this; + } + + + /// store the same value in each component + static vector_type vectorized(const Scalar& _s) { + return vector_type().vectorize(_s); + } + + + /// lexicographical comparison + bool operator<(const vector_type& _rhs) const { +#define expr(i) if (Base::values_[i] != _rhs.Base::values_[i]) \ + return (Base::values_[i] < _rhs.Base::values_[i]); + unroll(expr); +#undef expr + return false; + } +}; + + + +/// read the space-separated components of a vector from a stream +TEMPLATE_HEADER +inline std::istream& +operator>>(std::istream& is, VectorT& vec) +{ +#define expr(i) is >> vec[i]; + unroll(expr); +#undef expr + return is; +} + + +/// output a vector by printing its space-separated compontens +TEMPLATE_HEADER +inline std::ostream& +operator<<(std::ostream& os, const VectorT& vec) +{ +#if DIM==N + for(int i=0; i +// -------------------- STL +#if defined( OM_CC_MIPS ) +# include +#else +# include +#endif +#include +// -------------------- OpenMesh + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + +//----------------------------------------------------------------------------- + + +/** Binary read a \c short from \c _is and perform byte swapping if + \c _swap is true */ +short int read_short(FILE* _in, bool _swap=false); + +/** Binary read an \c int from \c _is and perform byte swapping if + \c _swap is true */ +int read_int(FILE* _in, bool _swap=false); + +/** Binary read a \c float from \c _is and perform byte swapping if + \c _swap is true */ +float read_float(FILE* _in, bool _swap=false); + +/** Binary read a \c double from \c _is and perform byte swapping if + \c _swap is true */ +double read_double(FILE* _in, bool _swap=false); + +/** Binary read a \c short from \c _is and perform byte swapping if + \c _swap is true */ +short int read_short(std::istream& _in, bool _swap=false); + +/** Binary read an \c int from \c _is and perform byte swapping if + \c _swap is true */ +int read_int(std::istream& _in, bool _swap=false); + +/** Binary read a \c float from \c _is and perform byte swapping if + \c _swap is true */ +float read_float(std::istream& _in, bool _swap=false); + +/** Binary read a \c double from \c _is and perform byte swapping if + \c _swap is true */ +double read_double(std::istream& _in, bool _swap=false); + + +/** Binary write a \c short to \c _os and perform byte swapping if + \c _swap is true */ +void write_short(short int _i, FILE* _out, bool _swap=false); + +/** Binary write an \c int to \c _os and perform byte swapping if + \c _swap is true */ +void write_int(int _i, FILE* _out, bool _swap=false); + +/** Binary write a \c float to \c _os and perform byte swapping if + \c _swap is true */ +void write_float(float _f, FILE* _out, bool _swap=false); + +/** Binary write a \c double to \c _os and perform byte swapping if + \c _swap is true */ +void write_double(double _d, FILE* _out, bool _swap=false); + +/** Binary write a \c short to \c _os and perform byte swapping if + \c _swap is true */ +void write_short(short int _i, std::ostream& _out, bool _swap=false); + +/** Binary write an \c int to \c _os and perform byte swapping if + \c _swap is true */ +void write_int(int _i, std::ostream& _out, bool _swap=false); + +/** Binary write a \c float to \c _os and perform byte swapping if + \c _swap is true */ +void write_float(float _f, std::ostream& _out, bool _swap=false); + +/** Binary write a \c double to \c _os and perform byte swapping if + \c _swap is true */ +void write_double(double _d, std::ostream& _out, bool _swap=false); + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/IOInstances.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/IOInstances.hh new file mode 100644 index 0000000..6e0b085 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/IOInstances.hh @@ -0,0 +1,112 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper file for static builds +// +// In opposite to dynamic builds where the instance of every reader module +// is generated within the OpenMesh library, static builds only instanciate +// objects that are at least referenced once. As all reader modules are +// never used directly, they will not be part of a static build, hence +// this file. +// +//============================================================================= + + +#ifndef __IOINSTANCES_HH__ +#define __IOINSTANCES_HH__ + +#if defined(OM_STATIC_BUILD) || defined(ARCH_DARWIN) + +//============================================================================= + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + +//============================================================================= + + +// Instanciate every Reader module +static BaseReader* OFFReaderInstance = &OFFReader(); +static BaseReader* OBJReaderInstance = &OBJReader(); +static BaseReader* PLYReaderInstance = &PLYReader(); +static BaseReader* STLReaderInstance = &STLReader(); +static BaseReader* OMReaderInstance = &OMReader(); + +// Instanciate every writer module +static BaseWriter* OBJWriterInstance = &OBJWriter(); +static BaseWriter* OFFWriterInstance = &OFFWriter(); +static BaseWriter* STLWriterInstance = &STLWriter(); +static BaseWriter* OMWriterInstance = &OMWriter(); +static BaseWriter* PLYWriterInstance = &PLYWriter(); +static BaseWriter* VTKWriterInstance = &VTKWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // static ? +#endif //__IOINSTANCES_HH__ +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/IOManager.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/IOManager.hh new file mode 100644 index 0000000..6fa823a --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/IOManager.hh @@ -0,0 +1,267 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// Implements the OpenMesh IOManager singleton +// +//============================================================================= + +#ifndef __IOMANAGER_HH__ +#define __IOMANAGER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include +#include +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** This is the real IOManager class that is later encapsulated by + SingletonT to enforce its uniqueness. _IOManager_ is not meant to be used + directly by the programmer - the IOManager alias exists for this task. + + All reader/writer modules register themselves at this class. For + reading or writing data all modules are asked to do the job. If no + suitable module is found, an error is returned. + + For the sake of reading, the target data structure is hidden + behind the BaseImporter interface that takes care of adding + vertices or faces. + + Writing from a source structure is encapsulate similarly behind a + BaseExporter interface, providing iterators over vertices/faces to + the writer modules. + + \see \ref mesh_io +*/ + +class OPENMESHDLLEXPORT _IOManager_ +{ +private: + + /// Constructor has nothing todo for the Manager + _IOManager_() {} + + /// Destructor has nothing todo for the Manager + ~_IOManager_() {}; + + /** Declare the singleton getter function as friend to access the private constructor + and destructor + */ + friend OPENMESHDLLEXPORT _IOManager_& IOManager(); + +public: + + /** + Read a mesh from file _filename. The target data structure is specified + by the given BaseImporter. The \c read method consecutively queries all + of its reader modules. True is returned upon success, false if all + reader modules failed to interprete _filename. + */ + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + +/** + Read a mesh from open std::istream _is. The target data structure is specified + by the given BaseImporter. The \c sread method consecutively queries all + of its reader modules. True is returned upon success, false if all + reader modules failed to use _is. + */ + bool read(std::istream& _filename, + const std::string& _ext, + BaseImporter& _bi, + Options& _opt); + + + /** Write a mesh to file _filename. The source data structure is specified + by the given BaseExporter. The \c save method consecutively queries all + of its writer modules. True is returned upon success, false if all + writer modules failed to write the requested format. + Options is determined by _filename's extension. + */ + bool write(const std::string& _filename, + BaseExporter& _be, + Options _opt=Options::Default, + std::streamsize _precision = 6); + +/** Write a mesh to open std::ostream _os. The source data structure is specified + by the given BaseExporter. The \c save method consecutively queries all + of its writer modules. True is returned upon success, false if all + writer modules failed to write the requested format. + Options is determined by _filename's extension. + */ + bool write(std::ostream& _filename, + const std::string& _ext, + BaseExporter& _be, + Options _opt=Options::Default, + std::streamsize _precision = 6); + + + /// Returns true if the format is supported by one of the reader modules. + bool can_read( const std::string& _format ) const; + + /// Returns true if the format is supported by one of the writer modules. + bool can_write( const std::string& _format ) const; + + + size_t binary_size(const std::string& _format, + BaseExporter& _be, + Options _opt = Options::Default) + { + const BaseWriter *bw = find_writer(_format); + return bw ? bw->binary_size(_be,_opt) : 0; + } + + + +public: //-- QT convenience function ------------------------------------------ + + + /** Returns all readable file extension + descriptions in one string. + File formats are separated by ;;. + Convenience function for Qt file dialogs. + */ + const std::string& qt_read_filters() const { return read_filters_; } + + + /** Returns all writeable file extension + descriptions in one string. + File formats are separated by ;;. + Convenience function for Qt file dialogs. + */ + const std::string& qt_write_filters() const { return write_filters_; } + + + +private: + + // collect all readable file extensions + void update_read_filters(); + + + // collect all writeable file extensions + void update_write_filters(); + + + +public: //-- SYSTEM PART------------------------------------------------------ + + + /** Registers a new reader module. A call to this function should be + implemented in the constructor of all classes derived from BaseReader. + */ + bool register_module(BaseReader* _bl) + { + reader_modules_.insert(_bl); + update_read_filters(); + return true; + } + + + + /** Registers a new writer module. A call to this function should be + implemented in the constructor of all classed derived from BaseWriter. + */ + bool register_module(BaseWriter* _bw) + { + writer_modules_.insert(_bw); + update_write_filters(); + return true; + } + + +private: + + const BaseWriter *find_writer(const std::string& _format); + + // stores registered reader modules + std::set reader_modules_; + + // stores registered writer modules + std::set writer_modules_; + + // input filters (e.g. for Qt file dialog) + std::string read_filters_; + + // output filters (e.g. for Qt file dialog) + std::string write_filters_; +}; + + +//============================================================================= + + +//_IOManager_* __IOManager_instance; Causes memory leak, as destructor is never called + +OPENMESHDLLEXPORT _IOManager_& IOManager(); + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/MeshIO.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/MeshIO.hh new file mode 100644 index 0000000..66c0819 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/MeshIO.hh @@ -0,0 +1,274 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef OM_MESHIO_HH +#define OM_MESHIO_HH + + +//=== INCLUDES ================================================================ + +// -------------------- system settings +#include + +// -------------------- OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Convenience functions the map to IOManager functions. + \see OpenMesh::IO::_IOManager_ +*/ +//@{ + + +//----------------------------------------------------------------------------- + + +/** \brief Read a mesh from file _filename. + + The file format is determined by the file extension. + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The target mesh that will be filled with the read data + @param _filename fill to load + + @return Successful? + */ +template +bool +read_mesh(Mesh& _mesh, + const std::string& _filename) +{ + Options opt; + return read_mesh(_mesh, _filename, opt, true); +} + + +/** \brief Read a mesh from file _filename. + + The file format is determined by the file extension. + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The target mesh that will be filled with the read data + @param _filename fill to load + @param _opt Reader options (e.g. skip loading of normals ... depends + on the reader capabilities). Note that simply passing an + Options::Flag enum is not sufficient. + @param _clear Clear the target data before filling it (allows to + load multiple files into one Mesh). If you only want to read a mesh + without clearing set _clear to false. Providing a default Options + object is sufficient in this case. + + @return Successful? +*/ +template +bool +read_mesh(Mesh& _mesh, + const std::string& _filename, + Options& _opt, + bool _clear = true) +{ + if (_clear) _mesh.clear(); + ImporterT importer(_mesh); + return IOManager().read(_filename, importer, _opt); +} + + +/** \brief Read a mesh from file open std::istream. + + The file format is determined by parameter _ext. _ext has to include + ".[format]" in order to work properly (e.g. ".OFF") + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The target mesh that will be filled with the read data + @param _is stream to load the data from + @param _ext The file format that is written to the stream + @param _opt Reader options (e.g. skip loading of normals ... depends + on the reader capabilities) + @param _clear Clear the target data before filling it (allows to + load multiple files into one Mesh) + + @return Successful? +*/ +template +bool +read_mesh(Mesh& _mesh, + std::istream& _is, + const std::string& _ext, + Options& _opt, + bool _clear = true) +{ + if (_clear) _mesh.clear(); + ImporterT importer(_mesh); + return IOManager().read(_is,_ext, importer, _opt); +} + + + +//----------------------------------------------------------------------------- + + +/** \brief Write a mesh to the file _filename. + + The file format is determined by _filename's extension. + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The mesh that will be written to file + @param _filename output filename + @param _opt Writer options (e.g. writing of normals ... depends + on the writer capabilities) + @param _precision specifies stream precision for ascii files + + @return Successful? +*/ +template +bool write_mesh(const Mesh& _mesh, + const std::string& _filename, + Options _opt = Options::Default, + std::streamsize _precision = 6) +{ + ExporterT exporter(_mesh); + return IOManager().write(_filename, exporter, _opt, _precision); +} + + +//----------------------------------------------------------------------------- + + +/** Write a mesh to an open std::ostream. + + The file format is determined by parameter _ext. _ext has to include + ".[format]" in order to work properly (e.g. ".OFF") + + \note If you link statically against OpenMesh, you have to add + the define OM_STATIC_BUILD to your application. This will + ensure that readers and writers get initialized correctly. + + @param _mesh The mesh that will be written to file + @param _os output stream to write into + @param _ext extension defining the type of output + @param _opt Writer options (e.g. writing of normals ... depends + on the writer capabilities) + @param _precision specifies stream precision for ascii files + + @return Successful? +*/ +template +bool write_mesh(const Mesh& _mesh, + std::ostream& _os, + const std::string& _ext, + Options _opt = Options::Default, + std::streamsize _precision = 6) +{ + ExporterT exporter(_mesh); + return IOManager().write(_os,_ext, exporter, _opt, _precision); +} + + +//----------------------------------------------------------------------------- + +/** \brief Get binary size of data + + This function calls the corresponding writer which calculates the size + of the data that would be written to a binary file + + The file format is determined by parameter _ext. _ext has to include + ".[format]" in order to work properly (e.g. ".OFF") + + @param _mesh Mesh to write + @param _ext extension of the file (used to determine the writing module) + @param _opt Writer options (e.g. writing of normals ... depends + on the writer capabilities) + + @return Binary size in bytes used when writing the data +*/ +template +size_t binary_size(const Mesh& _mesh, + const std::string& _ext, + Options _opt = Options::Default) +{ + ExporterT exporter(_mesh); + return IOManager().binary_size(_ext, exporter, _opt); +} + + +//----------------------------------------------------------------------------- + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#if defined(OM_STATIC_BUILD) || defined(ARCH_DARWIN) +# include +#endif +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/OFFFormat.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/OFFFormat.hh new file mode 100644 index 0000000..79ab28d --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/OFFFormat.hh @@ -0,0 +1,94 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef OPENMESH_IO_OFFFORMAT_HH +#define OPENMESH_IO_OFFFORMAT_HH + + +//=== INCLUDES ================================================================ + + +// OpenMesh +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Option for writer modules. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +#ifndef DOXY_IGNORE_THIS + +struct OPENMESHDLLEXPORT OFFFormat +{ + typedef int integer_type; + typedef float float_type; +}; + +#endif + + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/OMFormat.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/OMFormat.hh new file mode 100644 index 0000000..4ba0dc7 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/OMFormat.hh @@ -0,0 +1,758 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef OPENMESH_IO_OMFORMAT_HH +#define OPENMESH_IO_OMFORMAT_HH + + +//=== INCLUDES ================================================================ + +#include +#include +#include +#include +#include +#include +// -------------------- +#include +#if defined(OM_CC_GCC) && (OM_GCC_VERSION < 30000) +# include +# define OM_MISSING_HEADER_LIMITS 1 +#else +# include +#endif + + +//== NAMESPACES ============================================================== + +#ifndef DOXY_IGNORE_THIS +namespace OpenMesh { +namespace IO { +namespace OMFormat { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing +*/ +//@{ + +//----------------------------------------------------------------------------- + + // <:Header> + // <:Comment> + // Chunk 0 + // <:ChunkHeader> + // <:Comment> + // data + // Chunk 1 + // <:ChunkHeader> + // <:Comment> + // data + // . + // . + // . + // Chunk N + + // + // NOTICE! + // + // The usage of data types who differ in size + // on different pc architectures (32/64 bit) and/or + // operating systems, e.g. (unsigned) long, size_t, + // is not recommended because of inconsistencies + // in case of cross writing and reading. + // + // Basic types that are supported are: + + + typedef unsigned char uchar; + typedef uint8_t uint8; + typedef uint16_t uint16; + typedef uint32_t uint32; + typedef uint64_t uint64; + typedef int8_t int8; + typedef int16_t int16; + typedef int32_t int32; + typedef int64_t int64; + typedef float32_t float32; + typedef float64_t float64; + + struct Header + { + uchar magic_[2]; // OM + uchar mesh_; // [T]riangles, [Q]uads, [P]olygonals + uint8 version_; + uint32 n_vertices_; + uint32 n_faces_; + uint32 n_edges_; + + size_t store( std::ostream& _os, bool _swap ) const + { + _os.write( (char*)this, 4); // magic_, mesh_, version_ + size_t bytes = 4; + bytes += binary::store( _os, n_vertices_, _swap ); + bytes += binary::store( _os, n_faces_, _swap ); + bytes += binary::store( _os, n_edges_, _swap ); + return bytes; + } + + size_t restore( std::istream& _is, bool _swap ) + { + if (_is.read( reinterpret_cast(this) , 4 ).eof()) + return 0; + + size_t bytes = 4; + bytes += binary::restore( _is, n_vertices_, _swap ); + bytes += binary::restore( _is, n_faces_, _swap ); + bytes += binary::restore( _is, n_edges_, _swap ); + return bytes; + } + + }; + + struct Chunk + { + // Hardcoded this size to an uint32 to make the system 32/64 bit compatible. + // Needs further investigation! + typedef uint32 esize_t; // element size, used for custom properties + + enum Type { + Type_Pos = 0x00, + Type_Normal = 0x01, + Type_Texcoord = 0x02, + Type_Status = 0x03, + Type_Color = 0x04, + Type_Custom = 0x06, + Type_Topology = 0x07 + }; + + enum Entity { + Entity_Vertex = 0x00, + Entity_Mesh = 0x01, + Entity_Face = 0x02, + Entity_Edge = 0x04, + Entity_Halfedge = 0x06, + Entity_Sentinel = 0x07 + }; + + enum Dim { + Dim_1D = 0x00, + Dim_2D = 0x01, + Dim_3D = 0x02, + Dim_4D = 0x03, + Dim_5D = 0x04, + Dim_6D = 0x05, + Dim_7D = 0x06, + Dim_8D = 0x07 + }; + + enum Integer_Size { + Integer_8 = 0x00, // 1 byte for (unsigned) char + Integer_16 = 0x01, // 2 bytes for short + Integer_32 = 0x02, // 4 bytes for long + Integer_64 = 0x03 // 8 bytes for long long + }; + + enum Float_Size { + Float_32 = 0x00, // 4 bytes for float + Float_64 = 0x01, // 8 bytes for double + Float_128 = 0x02 // 16 bytes for long double (an assumption!) + }; + + static const int SIZE_RESERVED = 1; // 1 + static const int SIZE_NAME = 1; // 2 + static const int SIZE_ENTITY = 3; // 5 + static const int SIZE_TYPE = 4; // 9 + + static const int SIZE_SIGNED = 1; // 10 + static const int SIZE_FLOAT = 1; // 11 + static const int SIZE_DIM = 3; // 14 + static const int SIZE_BITS = 2; // 16 + + static const int OFF_RESERVED = 0; // 0 + static const int OFF_NAME = SIZE_RESERVED + OFF_RESERVED; // 2 + static const int OFF_ENTITY = SIZE_NAME + OFF_NAME; // 3 + static const int OFF_TYPE = SIZE_ENTITY + OFF_ENTITY; // 5 + static const int OFF_SIGNED = SIZE_TYPE + OFF_TYPE; // 9 + static const int OFF_FLOAT = SIZE_SIGNED + OFF_SIGNED; // 10 + static const int OFF_DIM = SIZE_FLOAT + OFF_FLOAT; // 11 + static const int OFF_BITS = SIZE_DIM + OFF_DIM; // 14 + + // !Attention! When changing the bit size, the operators + // << (uint16, Header) and << (Header, uint16) must be changed as well + // + // Entries signed_, float_, dim_, bits_ are not used when type_ + // equals Type_Custom + // + struct Header // 16 bits long + { + unsigned reserved_: SIZE_RESERVED; + unsigned name_ : SIZE_NAME; // 1 named property, 0 anonymous + unsigned entity_ : SIZE_ENTITY; // 0 vertex, 1 mesh, 2 edge, + // 4 halfedge, 6 face + unsigned type_ : SIZE_TYPE; // 0 pos, 1 normal, 2 texcoord, + // 3 status, 4 color 6 custom 7 topology + unsigned signed_ : SIZE_SIGNED; // bool + unsigned float_ : SIZE_FLOAT; // bool + unsigned dim_ : SIZE_DIM; // 0 1D, 1 2D, 2 3D, .., 7 8D + unsigned bits_ : SIZE_BITS; // {8, 16, 32, 64} | {32, 64, 128} + // (integer) (float) + unsigned unused_ : 16; // fill up to 32 bits + }; // struct Header + + + class PropertyName : public std::string + { + public: + + static const size_t size_max = 256; + + PropertyName( ) { } + + explicit PropertyName( const std::string& _name ) { *this = _name; } + + bool is_valid() const { return is_valid( size() ); } + + static bool is_valid( size_t _s ) { return _s <= size_max; } + + PropertyName& operator = ( const std::string& _rhs ) + { + assert( is_valid( _rhs.size() ) ); + + if ( is_valid( _rhs.size() ) ) + std::string::operator = ( _rhs ); + else + { + omerr() << "Warning! Property name too long. Will be shortened!\n"; + this->std::string::operator = ( _rhs.substr(0, size_max) ); + } + + return *this; + } + + }; + + }; // Chunk + + // ------------------------------------------------------------ Helper + // -------------------- get size information + + /// Return size of header in bytes. + inline size_t header_size(void) { return sizeof(Header); } + + + /// Return size of chunk header in bytes. + inline size_t chunk_header_size( void ) { return sizeof(uint16); } + + + /// Return the size of a scaler in bytes. + inline size_t scalar_size( const Chunk::Header& _hdr ) + { + return _hdr.float_ ? (0x01 << _hdr.bits_) : (0x04 << _hdr.bits_); + } + + + /// Return the dimension of the vector in a chunk + inline size_t dimensions(const Chunk::Header& _chdr) { return _chdr.dim_+1; } + + + /// Return the size of a vector in bytes. + inline size_t vector_size( const Chunk::Header& _chdr ) + { + return dimensions(_chdr)*scalar_size(_chdr); + } + + + /// Return the size of chunk data in bytes + inline size_t chunk_data_size( const Header& _hdr, const Chunk::Header& _chunk_hdr ) + { + size_t C; + switch( _chunk_hdr.entity_ ) + { + case Chunk::Entity_Vertex: C = _hdr.n_vertices_; break; + case Chunk::Entity_Face: C = _hdr.n_faces_; break; + case Chunk::Entity_Halfedge: C = _hdr.n_edges_*2; break; + case Chunk::Entity_Edge: C = _hdr.n_edges_; break; + case Chunk::Entity_Mesh: C = 1; break; + default: + C = 0; + std::cerr << "Invalid value in _chunk_hdr.entity_\n"; + assert( false ); + break; + } + + return C * vector_size( _chunk_hdr ); + } + + inline size_t chunk_size( const Header& _hdr, const Chunk::Header& _chunk_hdr ) + { + return chunk_header_size() + chunk_data_size( _hdr, _chunk_hdr ); + } + + // -------------------- convert from Chunk::Header to storage type + + uint16& operator << (uint16& val, const Chunk::Header& hdr); + Chunk::Header& operator << (Chunk::Header& hdr, const uint16 val); + + + // -------------------- type information + + template bool is_float(const T&) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return !Utils::NumLimitsT::is_integer(); +#else + return !std::numeric_limits::is_integer; +#endif + } + + template bool is_double(const T&) + { + return false; + } + + template <> inline bool is_double(const double&) + { + return true; + } + + template bool is_integer(const T) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return Utils::NumLimitsT::is_integer(); +#else + return std::numeric_limits::is_integer; +#endif + } + + template bool is_signed(const T&) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return Utils::NumLimitsT::is_signed(); +#else + return std::numeric_limits::is_signed; +#endif + } + + // -------------------- conversions (format type <- type/value) + + template + inline + Chunk::Dim dim( VecType ) + { + assert( vector_traits< VecType >::size() < 9 ); + return static_cast(vector_traits< VecType >::size() - 1); + } + + template + inline + Chunk::Dim dim( const Chunk::Header& _hdr ) + { + return static_cast( _hdr.dim_ ); + } + + // calc minimum (power-of-2) number of bits needed + Chunk::Integer_Size needed_bits( size_t s ); + + // Convert size of type to Integer_Size +#ifdef NDEBUG + template Chunk::Integer_Size integer_size(const T&) +#else + template Chunk::Integer_Size integer_size(const T& d) +#endif + { +#ifndef NDEBUG + assert( is_integer(d) ); +#endif + + switch( sizeof(T) ) + { + case 1: return OMFormat::Chunk::Integer_8; + case 2: return OMFormat::Chunk::Integer_16; + case 4: return OMFormat::Chunk::Integer_32; + case 8: return OMFormat::Chunk::Integer_64; + default: + std::cerr << "Invalid value in integer_size\n"; + assert( false ); + break; + } + return Chunk::Integer_Size(0); + } + + + // Convert size of type to FLoat_Size +#ifdef NDEBUG + template Chunk::Float_Size float_size(const T&) +#else + template Chunk::Float_Size float_size(const T& d) +#endif + { +#ifndef NDEBUG + assert( is_float(d) ); +#endif + + switch( sizeof(T) ) + { + case 4: return OMFormat::Chunk::Float_32; + case 8: return OMFormat::Chunk::Float_64; + case 16: return OMFormat::Chunk::Float_128; + default: + std::cerr << "Invalid value in float_size\n"; + assert( false ); + break; + } + return Chunk::Float_Size(0); + } + + // Return the storage type (Chunk::Header::bits_) + template + inline + unsigned int bits(const T& val) + { + return is_integer(val) + ? (static_cast(integer_size(val))) + : (static_cast(float_size(val))); + } + + // -------------------- create/read version + + inline uint8 mk_version(const uint16 major, const uint16 minor) + { return (major & 0x07) << 5 | (minor & 0x1f); } + + + inline uint16 major_version(const uint8 version) + { return (version >> 5) & 0x07; } + + + inline uint16 minor_version(const uint8 version) + { return (version & 0x001f); } + + + // ---------------------------------------- convenience functions + + std::string as_string(uint8 version); + + const char *as_string(Chunk::Type t); + const char *as_string(Chunk::Entity e); + const char *as_string(Chunk::Dim d); + const char *as_string(Chunk::Integer_Size d); + const char *as_string(Chunk::Float_Size d); + + std::ostream& operator << ( std::ostream& _os, const Header& _h ); + std::ostream& operator << ( std::ostream& _os, const Chunk::Header& _c ); + +//@} +} // namespace OMFormat + + // -------------------- (re-)store header + + template <> inline + size_t store( std::ostream& _os, const OMFormat::Header& _hdr, bool _swap) + { return _hdr.store( _os, _swap ); } + + template <> inline + size_t restore( std::istream& _is, OMFormat::Header& _hdr, bool _swap ) + { return _hdr.restore( _is, _swap ); } + + + // -------------------- (re-)store chunk header + + template <> inline + size_t + store( std::ostream& _os, const OMFormat::Chunk::Header& _hdr, bool _swap) + { + OMFormat::uint16 val; + val << _hdr; + return binary::store( _os, val, _swap ); + } + + template <> inline + size_t + restore( std::istream& _is, OMFormat::Chunk::Header& _hdr, bool _swap ) + { + OMFormat::uint16 val; + size_t bytes = binary::restore( _is, val, _swap ); + + _hdr << val; + + return bytes; + } + + // -------------------- (re-)store integer with wanted number of bits (bytes) + + typedef GenProg::TrueType t_signed; + typedef GenProg::FalseType t_unsigned; + + // helper to store a an integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed); + + // helper to store a an unsigned integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned); + + /// Store an integer with a wanted number of bits + template< typename T > + inline + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap) + { + assert( OMFormat::is_integer( _val ) ); + + if ( OMFormat::is_signed( _val ) ) + return store( _os, _val, _b, _swap, t_signed() ); + return store( _os, _val, _b, _swap, t_unsigned() ); + } + + // helper to store a an integer + template< typename T > inline + size_t restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed); + + // helper to store a an unsigned integer + template< typename T > inline + size_t restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned); + + /// Restore an integer with a wanted number of bits + template< typename T > + inline + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap) + { + assert( OMFormat::is_integer( _val ) ); + + if ( OMFormat::is_signed( _val ) ) + return restore( _is, _val, _b, _swap, t_signed() ); + return restore( _is, _val, _b, _swap, t_unsigned() ); + } + + + // + // ---------------------------------------- storing vectors + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<2>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<3>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + bytes += store( _os, _vec[2], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<4>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + bytes += store( _os, _vec[2], _swap ); + bytes += store( _os, _vec[3], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<1>, + bool _swap ) + { + return store( _os, _vec[0], _swap ); + } + + /// storing a vector type + template inline + size_t vector_store( std::ostream& _os, const VecT& _vec, bool _swap ) + { + return store( _os, _vec, + GenProg::Int2Type< vector_traits::size_ >(), + _swap ); + } + + // ---------------------------------------- restoring vectors + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<2>, + bool _swap ) + { + size_t bytes = restore( _is, _vec[0], _swap ); + bytes += restore( _is, _vec[1], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<3>, + bool _swap ) + { + typedef typename vector_traits::value_type scalar_type; + size_t bytes; + + bytes = binary::restore( _is, _vec[0], _swap ); + bytes += binary::restore( _is, _vec[1], _swap ); + bytes += binary::restore( _is, _vec[2], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<4>, + bool _swap ) + { + typedef typename vector_traits::value_type scalar_type; + size_t bytes; + + bytes = binary::restore( _is, _vec[0], _swap ); + bytes += binary::restore( _is, _vec[1], _swap ); + bytes += binary::restore( _is, _vec[2], _swap ); + bytes += binary::restore( _is, _vec[3], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<1>, + bool _swap ) + { + return restore( _is, _vec[0], _swap ); + } + + /// Restoring a vector type + template + inline + size_t + vector_restore( std::istream& _is, VecT& _vec, bool _swap ) + { + return restore( _is, _vec, + GenProg::Int2Type< vector_traits::size_ >(), + _swap ); + } + + + // ---------------------------------------- storing property names + + template <> + inline + size_t store( std::ostream& _os, const OMFormat::Chunk::PropertyName& _pn, + bool _swap ) + { + store( _os, _pn.size(), OMFormat::Chunk::Integer_8, _swap ); // 1 byte + if ( _pn.size() ) + _os.write( _pn.c_str(), _pn.size() ); // size bytes + return _pn.size() + 1; + } + + template <> + inline + size_t restore( std::istream& _is, OMFormat::Chunk::PropertyName& _pn, + bool _swap ) + { + size_t size; + + restore( _is, size, OMFormat::Chunk::Integer_8, _swap); // 1 byte + + assert( OMFormat::Chunk::PropertyName::is_valid( size ) ); + + if ( size > 0 ) + { + char buf[256]; + _is.read( buf, size ); // size bytes + buf[size] = '\0'; + _pn.resize(size); + _pn = buf; + } + return size+1; + } + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +#endif +//============================================================================= +#if defined(OM_MISSING_HEADER_LIMITS) +# undef OM_MISSING_HEADER_LIMITS +#endif +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_IO_OMFORMAT_CC) +# define OPENMESH_IO_OMFORMAT_TEMPLATES +# include "OMFormatT_impl.hh" +#endif +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/OMFormatT_impl.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/OMFormatT_impl.hh new file mode 100644 index 0000000..e512ba9 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/OMFormatT_impl.hh @@ -0,0 +1,240 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#define OPENMESH_IO_OMFORMAT_CC + + +//== INCLUDES ================================================================= + +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + // helper to store a an integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed) + { + assert( OMFormat::is_integer( _val ) ); + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::int8 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::int16 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::int32 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_64: + { + OMFormat::int64 v = static_cast(_val); + return store( _os, v, _swap ); + } + } + return 0; + } + + + // helper to store a an unsigned integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned) + { + assert( OMFormat::is_integer( _val ) ); + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::uint8 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::uint16 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::uint32 v = static_cast(_val); + return store( _os, v, _swap ); + } + + case OMFormat::Chunk::Integer_64: + { + OMFormat::uint64 v = static_cast(_val); + return store( _os, v, _swap ); + } + } + return 0; + } + + + // helper to restore a an integer + template< typename T > + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed) + { + assert( OMFormat::is_integer( _val ) ); + size_t bytes = 0; + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::int8 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::int16 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::int32 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_64: + { + OMFormat::int64 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + } + return bytes; + } + + + // helper to restore a an unsigned integer + template< typename T > + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned) + { + assert( OMFormat::is_integer( _val ) ); + size_t bytes = 0; + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::uint8 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::uint16 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::uint32 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + + case OMFormat::Chunk::Integer_64: + { + OMFormat::uint64 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + } + return bytes; + } + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/Options.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/Options.hh new file mode 100644 index 0000000..74c54d4 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/Options.hh @@ -0,0 +1,239 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef OPENMESH_IO_OPTIONS_HH +#define OPENMESH_IO_OPTIONS_HH + + +//=== INCLUDES ================================================================ + + +// OpenMesh +#include +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Option for reader and writer modules. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +/** \brief Set options for reader/writer modules. + * + * The class is used in a twofold way. + * -# In combination with reader modules the class is used + * - to pass hints to the reading module, whether the input is + * binary and what byte ordering the binary data has + * - to retrieve information about the file contents after + * succesful reading. + * -# In combination with write modules the class gives directions to + * the writer module, whether to + * - use binary mode or not and what byte order to use + * - store one of the standard properties. + * + * The option are defined in \c Options::Flag as bit values and stored in + * an \c int value as a bitset. + */ +class Options +{ +public: + typedef int enum_type; + typedef enum_type value_type; + + /// Definitions of %Options for reading and writing. The options can be + /// or'ed. + enum Flag { + None = 0x0000, ///< No options + Binary = 0x0001, ///< Set binary mode for r/w + MSB = 0x0002, ///< Assume big endian byte ordering + LSB = 0x0004, ///< Assume little endian byte ordering + Swap = 0x0008, ///< Swap byte order in binary mode + VertexNormal = 0x0010, ///< Has (r) / store (w) vertex normals + VertexColor = 0x0020, ///< Has (r) / store (w) vertex colors + VertexTexCoord = 0x0040, ///< Has (r) / store (w) texture coordinates + EdgeColor = 0x0080, ///< Has (r) / store (w) edge colors + FaceNormal = 0x0100, ///< Has (r) / store (w) face normals + FaceColor = 0x0200, ///< Has (r) / store (w) face colors + FaceTexCoord = 0x0400, ///< Has (r) / store (w) face texture coordinates + ColorAlpha = 0x0800, ///< Has (r) / store (w) alpha values for colors + ColorFloat = 0x1000, ///< Has (r) / store (w) float values for colors (currently only implemented for PLY and OFF files) + Custom = 0x2000, ///< Has (r) / store (w) custom properties marked persistent (currently PLY only supports reading and only ASCII version. OM supports reading and writing) + Status = 0x4000, ///< Has (r) / store (w) status properties + TexCoordST = 0x8000, ///< Write texture coordinates as ST instead of UV + Default = Custom, ///< By default write persistent custom properties + }; + + /// Texture filename. This will be written as + /// map_Kd in the OBJ writer into the material file. + std::string texture_file ; + + /// Filename extension for material files when writing OBJs + /// default is currently .mat + std::string material_file_extension; + +public: + + /// Default constructor + Options() : texture_file(""), material_file_extension(".mat"), flags_( Default ) + { } + + /// Initializing constructor setting multiple options + Options(const value_type _flgs) : flags_( _flgs) + { } + + /// Restore state after default constructor. + void cleanup(void) + { flags_ = Default; } + + /// Clear all bits. + void clear(void) + { flags_ = 0; } + + /// Returns true if all bits are zero. + bool is_empty(void) const { return !flags_; } + +public: + + + Options& operator = ( const value_type _rhs ) + { flags_ = _rhs; return *this; } + + + //@{ + /// Unset options defined in _rhs. + + Options& operator -= ( const value_type _rhs ) + { flags_ &= ~_rhs; return *this; } + + Options& unset( const value_type _rhs) + { return (*this -= _rhs); } + + //@} + + + + //@{ + /// Set options defined in _rhs + + Options& operator += ( const value_type _rhs ) + { flags_ |= _rhs; return *this; } + + Options& set( const value_type _rhs) + { return (*this += _rhs); } + + //@} + +public: + + + // Check if an option or several options are set. + bool check(const value_type _rhs) const + { + return (flags_ & _rhs)==_rhs; + } + + bool is_binary() const { return check(Binary); } + bool vertex_has_normal() const { return check(VertexNormal); } + bool vertex_has_color() const { return check(VertexColor); } + bool vertex_has_texcoord() const { return check(VertexTexCoord); } + bool vertex_has_status() const { return check(Status); } + bool edge_has_color() const { return check(EdgeColor); } + bool edge_has_status() const { return check(Status); } + bool halfedge_has_status() const { return check(Status); } + bool face_has_normal() const { return check(FaceNormal); } + bool face_has_color() const { return check(FaceColor); } + bool face_has_texcoord() const { return check(FaceTexCoord); } + bool face_has_status() const { return check(Status); } + bool color_has_alpha() const { return check(ColorAlpha); } + bool color_is_float() const { return check(ColorFloat); } + bool use_st_coordinates() const { return check(TexCoordST); } + + + /// Returns true if _rhs has the same options enabled. + bool operator == (const value_type _rhs) const + { return flags_ == _rhs; } + + + /// Returns true if _rhs does not have the same options enabled. + bool operator != (const value_type _rhs) const + { return flags_ != _rhs; } + + + /// Returns the option set. + operator value_type () const { return flags_; } + +private: + + bool operator && (const value_type _rhs) const; + + value_type flags_; +}; + +//----------------------------------------------------------------------------- + + + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_binary.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_binary.hh new file mode 100644 index 0000000..65f4ac0 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_binary.hh @@ -0,0 +1,145 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_BINARY_HH +#define OPENMESH_SR_BINARY_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#include +#include +#include +#include // accumulate +// -------------------- OpenMesh + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +//----------------------------------------------------------------------------- + + const static size_t UnknownSize(size_t(-1)); + + +//----------------------------------------------------------------------------- +// struct binary, helper for storing/restoring + +/// \struct binary SR_binary.hh +/// +/// The struct defines how to store and restore the type T. +/// It's used by the OM reader/writer modules. +/// +/// The following specialization are provided: +/// - Fundamental types except \c long +/// - %OpenMesh vector types +/// - %OpenMesh::StatusInfo +/// - std::string (max. length 65535) +/// - std::vector (requires a specialization for T) +/// +/// \todo Complete documentation of members +template < typename T, typename = void > struct binary +{ + typedef T value_type; + + /// Can we store T? Set this to true in your specialization. + static const bool is_streamable = false; + + /// What's the size of T? If it depends on the actual value (e.g. for vectors) return UnknownSize + static size_t size_of(void) { return UnknownSize; } + /// What't the size of a specific value of type T. + static size_t size_of(const value_type&) { return UnknownSize; } + + /// A string that identifies the type of T. + static std::string type_identifier (void) { return "UnknownType"; } + + /// Store a value of T and return the number of bytes written + static + size_t store( std::ostream& /* _os */, + const value_type& /* _v */, + bool /* _swap */ = false , + bool /* store_size */ = true ) // for vectors + { + std::ostringstream msg; + msg << "Type not supported: " << typeid(value_type).name(); + throw std::logic_error(msg.str()); + } + + /// Restore a value of T and return the number of bytes read + static + size_t restore( std::istream& /* _is */, + value_type& /* _v */, + bool /* _swap */ = false , + bool /* store_size */ = true ) // for vectors + { + std::ostringstream msg; + msg << "Type not supported: " << typeid(value_type).name(); + throw std::logic_error(msg.str()); + } +}; + +#undef X + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_RBO_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_binary_spec.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_binary_spec.hh new file mode 100644 index 0000000..0343ad9 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_binary_spec.hh @@ -0,0 +1,439 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_BINARY_SPEC_HH +#define OPENMESH_SR_BINARY_SPEC_HH + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#include +#include +#if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000) +# include +#else +# include +#endif +#include +#include // logic_error +#include // accumulate +// -------------------- OpenMesh +#include +#include +#include +#include +#include + + +#include + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + +#ifndef DOXY_IGNORE_THIS + +//----------------------------------------------------------------------------- +// struct binary, helper for storing/restoring + +#define SIMPLE_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(const value_type&) { return sizeof(value_type); } \ + static size_t size_of(void) { return sizeof(value_type); } \ + static std::string type_identifier(void) { return #T; } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + if (_swap) reverse_byte_order(tmp); \ + _os.write( (const char*)&tmp, sizeof(value_type) ); \ + return _os.good() ? sizeof(value_type) : 0; \ + } \ + \ + static size_t restore( std::istream& _is, value_type& _val, \ + bool _swap=false) { \ + _is.read( (char*)&_val, sizeof(value_type) ); \ + if (_swap) reverse_byte_order(_val); \ + return _is.good() ? sizeof(value_type) : 0; \ + } \ + } + +SIMPLE_BINARY(bool); +//SIMPLE_BINARY(int); + +// Why is this needed? Should not be used as not 32 bit compatible +//SIMPLE_BINARY(unsigned long); +SIMPLE_BINARY(float); +SIMPLE_BINARY(double); +SIMPLE_BINARY(long double); +SIMPLE_BINARY(char); + +SIMPLE_BINARY(int8_t); +SIMPLE_BINARY(int16_t); +SIMPLE_BINARY(int32_t); +//SIMPLE_BINARY(int64_t); // TODO: This does not work. Find out why. +SIMPLE_BINARY(uint8_t); +SIMPLE_BINARY(uint16_t); +SIMPLE_BINARY(uint32_t); +SIMPLE_BINARY(uint64_t); + +//handles +SIMPLE_BINARY(FaceHandle); +SIMPLE_BINARY(EdgeHandle); +SIMPLE_BINARY(HalfedgeHandle); +SIMPLE_BINARY(VertexHandle); +SIMPLE_BINARY(MeshHandle); + +#undef SIMPLE_BINARY + +// For unsigned long which is of size 64 bit on 64 bit +// architectures: convert into 32 bit unsigned integer value +// in order to stay compatible between 32/64 bit architectures. +// This allows cross reading BUT forbids storing unsigned longs +// as data type since higher order word (4 bytes) will be truncated. +// Does not work in case the data type that is to be stored +// exceeds the value range of unsigned int in size, which is improbable... + +#define SIMPLE_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(const value_type&) { return sizeof(value_type); } \ + static size_t size_of(void) { return sizeof(value_type); } \ + static std::string type_identifier(void) { return #T; } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + if (_swap) reverse_byte_order(tmp); \ + /* Convert unsigned long to unsigned int for compatibility reasons */ \ + unsigned int t1 = static_cast(tmp); \ + _os.write( (const char*)&t1, sizeof(unsigned int) ); \ + return _os.good() ? sizeof(unsigned int) : 0; \ + } \ + \ + static size_t restore( std::istream& _is, value_type& _val, \ + bool _swap=false) { \ + unsigned int t1; \ + _is.read( (char*)&t1, sizeof(unsigned int) ); \ + _val = t1; \ + if (_swap) reverse_byte_order(_val); \ + return _is.good() ? sizeof(unsigned int) : 0; \ + } \ + } + +SIMPLE_BINARY(unsigned long); + +#undef SIMPLE_BINARY + +#define VECTORT_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(void) { return sizeof(value_type); } \ + static size_t size_of(const value_type&) { return size_of(); } \ + static std::string type_identifier(void) { return #T; } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + size_t b = size_of(_val), N = value_type::size_; \ + if (_swap) \ + for (size_t i=0; i struct binary< std::string > { + typedef std::string value_type; + typedef uint16_t length_t; + + static const bool is_streamable = true; + + static size_t size_of() { return UnknownSize; } + static size_t size_of(const value_type &_v) + { return sizeof(length_t) + _v.size(); } + static std::string type_identifier(void) { return "std::string"; } + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { +#if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000) + if (_v.size() < Utils::NumLimitsT::max() ) +#else + if (_v.size() < std::numeric_limits::max() ) +#endif + { + length_t len = length_t(_v.size()); + + size_t bytes = binary::store( _os, len, _swap ); + _os.write( _v.data(), len ); + return _os.good() ? len+bytes : 0; + } + throw std::runtime_error("Cannot store string longer than 64Kb"); + } + + static + size_t restore(std::istream& _is, value_type& _val, bool _swap=false) + { + length_t len; + size_t bytes = binary::restore( _is, len, _swap ); + _val.resize(len); + _is.read( const_cast(_val.data()), len ); + + return _is.good() ? (len+bytes) : 0; + } +}; + +template <> struct binary +{ + typedef OpenMesh::Attributes::StatusInfo value_type; + typedef value_type::value_type status_t; + + static const bool is_streamable = true; + + static size_t size_of() { return sizeof(status_t); } + static size_t size_of(const value_type&) { return size_of(); } + + static std::string type_identifier(void) { return "StatusInfo";} + static size_t n_bytes(size_t _n_elem) + { return _n_elem*sizeof(status_t); } + + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { + status_t v=_v.bits(); + return binary::store(_os, v, _swap); + } + + static + size_t restore( std::istream& _os, value_type& _v, bool _swap=false) + { + status_t v; + size_t b = binary::restore(_os, v, _swap); + _v.set_bits(v); + return b; + } +}; + + +//----------------------------------------------------------------------------- +// std::vector specializations for struct binary<> + +template +struct FunctorStore { + FunctorStore( std::ostream& _os, bool _swap) : os_(_os), swap_(_swap) { } + size_t operator () ( size_t _v1, const T& _s2 ) + { return _v1+binary::store(os_, _s2, swap_ ); } + + std::ostream& os_; + bool swap_; +}; + + +template +struct FunctorRestore { + FunctorRestore( std::istream& _is, bool _swap) : is_(_is), swap_(_swap) { } + size_t operator () ( size_t _v1, T& _s2 ) + { return _v1+binary::restore(is_, _s2, swap_ ); } + std::istream& is_; + bool swap_; +}; + +template +struct binary< std::vector< T >, typename std::enable_if::value>::type > { + typedef std::vector< T > value_type; + typedef typename value_type::value_type elem_type; + + static const bool is_streamable = binary::is_streamable; + static size_t size_of(bool /*_store_size*/ = true) + { return IO::UnknownSize; } + + static size_t size_of(const value_type& _v, bool _store_size = true) + { + if(binary::size_of() != IO::UnknownSize) + { + unsigned int N = static_cast(_v.size()); + auto res = binary::size_of()*_v.size() + (_store_size? sizeof(decltype(N)) : 0); + return res; + } + else + { + size_t size = 0; + for(auto v : _v) + size += binary::size_of(v); + if(_store_size) + size += binary::size_of(); + + return size; + } + } + + static std::string type_identifier(void) { return "std::vector<" + binary::type_identifier() + ">"; } + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false, bool _store_size = true) { + size_t bytes=0; + if(_store_size) + { + unsigned int N = static_cast(_v.size()); + bytes += binary::store( _os, N, _swap ); + } + if (_swap) + bytes += std::accumulate( _v.begin(), _v.end(), static_cast(0), + FunctorStore(_os,_swap) ); + else + { + auto elem_size = binary::size_of(); + if (elem_size != IO::UnknownSize && elem_size == sizeof(elem_type)) + { + // size of all elements is known, equal, and densely packed in vector. + // Just store vector data + auto bytes_of_vec = size_of(_v, false); + bytes += bytes_of_vec; + if (_v.size() > 0) + _os.write( reinterpret_cast(&_v[0]), bytes_of_vec); + } + else + { + // store individual elements + for (const auto& v : _v) + bytes += binary::store(_os, v, _swap); + } + } + return _os.good() ? bytes : 0; + } + + static size_t restore(std::istream& _is, value_type& _v, bool _swap=false, bool _restore_size = true) { + + size_t bytes=0; + + if(_restore_size) + { + unsigned int size_of_vec; + bytes += binary::restore(_is, size_of_vec, _swap); + _v.resize(size_of_vec); + } + + if ( _swap) + bytes += std::accumulate( _v.begin(), _v.end(), size_t(0), + FunctorRestore(_is, _swap) ); + else + { + auto elem_size = binary::size_of(); + if (elem_size != IO::UnknownSize && elem_size == sizeof(elem_type)) + { + // size of all elements is known, equal, and densely packed in vector. + // Just restore vector data + auto bytes_of_vec = size_of(_v, false); + bytes += bytes_of_vec; + if (_v.size() > 0) + _is.read( reinterpret_cast(&_v[0]), bytes_of_vec ); + } + else + { + // restore individual elements + for (auto& v : _v) + bytes += binary::restore(_is, v, _swap); + } + } + return _is.good() ? bytes : 0; + } +}; + +#include + +// ---------------------------------------------------------------------------- + +#endif // DOXY_IGNORE_THIS + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_BINARY_SPEC_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_binary_vector_of_bool.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_binary_vector_of_bool.hh new file mode 100644 index 0000000..70e06e3 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_binary_vector_of_bool.hh @@ -0,0 +1,106 @@ + +template <> struct binary< std::vector > +{ + typedef std::vector< bool > value_type; + typedef value_type::value_type elem_type; + + static const bool is_streamable = true; + + static size_t size_of(bool /*_store_size*/ = true) { return UnknownSize; } + static size_t size_of(const value_type& _v, bool _store_size = true) + { + size_t size = _v.size() / 8 + ((_v.size() % 8)!=0); + if(_store_size) + size += binary::size_of(); + return size; + } + static std::string type_identifier(void) { return "std::vector"; } + static + size_t store( std::ostream& _ostr, const value_type& _v, bool _swap, bool _store_size = true) + { + size_t bytes = 0; + + size_t N = _v.size() / 8; + size_t R = _v.size() % 8; + + if(_store_size) + { + unsigned int size_N = static_cast(_v.size()); + bytes += binary::store( _ostr, size_N, _swap ); + } + + size_t idx; // element index + size_t bidx; + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + bits = static_cast(_v[bidx]) + | (static_cast(_v[bidx+1]) << 1) + | (static_cast(_v[bidx+2]) << 2) + | (static_cast(_v[bidx+3]) << 3) + | (static_cast(_v[bidx+4]) << 4) + | (static_cast(_v[bidx+5]) << 5) + | (static_cast(_v[bidx+6]) << 6) + | (static_cast(_v[bidx+7]) << 7); + _ostr << bits; + } + bytes += N; + + if (R) + { + bits = 0; + for (idx=0; idx < R; ++idx) + bits |= static_cast(_v[bidx+idx]) << idx; + _ostr << bits; + ++bytes; + } + assert( bytes == size_of(_v, _store_size) ); + + return bytes; + } + + static + size_t restore( std::istream& _istr, value_type& _v, bool _swap, bool _restore_size = true) + { + size_t bytes = 0; + + if(_restore_size) + { + unsigned int size_of_vec; + bytes += binary::restore(_istr, size_of_vec, _swap); + _v.resize(size_of_vec); + } + + size_t N = _v.size() / 8; + size_t R = _v.size() % 8; + + size_t idx; // element index + size_t bidx; // + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + _istr >> bits; + _v[bidx+0] = (bits & 0x01) != 0; + _v[bidx+1] = (bits & 0x02) != 0; + _v[bidx+2] = (bits & 0x04) != 0; + _v[bidx+3] = (bits & 0x08) != 0; + _v[bidx+4] = (bits & 0x10) != 0; + _v[bidx+5] = (bits & 0x20) != 0; + _v[bidx+6] = (bits & 0x40) != 0; + _v[bidx+7] = (bits & 0x80) != 0; + } + bytes += N; + + if (R) + { + _istr >> bits; + for (idx=0; idx < R; ++idx) + _v[bidx+idx] = (bits & (1< +// -------------------- STL +#if defined(OM_CC_MIPS) +# include // size_t +#else +# include // size_t +#endif +#include +#include +// -------------------- OpenMesh +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +/** this does not compile for g++3.4 and higher, hence we comment the +function body which will result in a linker error */ + +template < size_t N > inline +void _reverse_byte_order_N(uint8_t* _val); + +template <> inline +void _reverse_byte_order_N<1>(uint8_t* /*_val*/) { } + + +template <> inline +void _reverse_byte_order_N<2>(uint8_t* _val) +{ + _val[0] ^= _val[1]; _val[1] ^= _val[0]; _val[0] ^= _val[1]; +} + + +template <> inline +void _reverse_byte_order_N<4>(uint8_t* _val) +{ + _val[0] ^= _val[3]; _val[3] ^= _val[0]; _val[0] ^= _val[3]; // 0 <-> 3 + _val[1] ^= _val[2]; _val[2] ^= _val[1]; _val[1] ^= _val[2]; // 1 <-> 2 +} + + +template <> inline +void _reverse_byte_order_N<8>(uint8_t* _val) +{ + _val[0] ^= _val[7]; _val[7] ^= _val[0]; _val[0] ^= _val[7]; // 0 <-> 7 + _val[1] ^= _val[6]; _val[6] ^= _val[1]; _val[1] ^= _val[6]; // 1 <-> 6 + _val[2] ^= _val[5]; _val[5] ^= _val[2]; _val[2] ^= _val[5]; // 2 <-> 5 + _val[3] ^= _val[4]; _val[4] ^= _val[3]; _val[3] ^= _val[4]; // 3 <-> 4 +} + + +template <> inline +void _reverse_byte_order_N<12>(uint8_t* _val) +{ + _val[0] ^= _val[11]; _val[11] ^= _val[0]; _val[0] ^= _val[11]; // 0 <-> 11 + _val[1] ^= _val[10]; _val[10] ^= _val[1]; _val[1] ^= _val[10]; // 1 <-> 10 + _val[2] ^= _val[ 9]; _val[ 9] ^= _val[2]; _val[2] ^= _val[ 9]; // 2 <-> 9 + _val[3] ^= _val[ 8]; _val[ 8] ^= _val[3]; _val[3] ^= _val[ 8]; // 3 <-> 8 + _val[4] ^= _val[ 7]; _val[ 7] ^= _val[4]; _val[4] ^= _val[ 7]; // 4 <-> 7 + _val[5] ^= _val[ 6]; _val[ 6] ^= _val[5]; _val[5] ^= _val[ 6]; // 5 <-> 6 +} + + +template <> inline +void _reverse_byte_order_N<16>(uint8_t* _val) +{ + _reverse_byte_order_N<8>(_val); + _reverse_byte_order_N<8>(_val+8); + std::swap(*(uint64_t*)_val, *(((uint64_t*)_val)+1)); +} + + +//----------------------------------------------------------------------------- +// wrapper for byte reordering + +// reverting pointers makes no sense, hence forbid it. +/** this does not compile for g++3.4 and higher, hence we comment the +function body which will result in a linker error */ +template inline T* reverse_byte_order(T* t); +// Should never reach this point. If so, then some operator were not +// overloaded. Especially check for IO::binary<> specialization on +// custom data types. + + +inline void compile_time_error__no_fundamental_type() +{ + // we should never reach this point + assert(false); +} + +// default action for byte reversal: cause an error to avoid +// surprising behaviour! +template T& reverse_byte_order( T& _t ) +{ + omerr() << "Not defined for type " << typeid(T).name() << std::endl; + compile_time_error__no_fundamental_type(); + return _t; +} + +template <> inline bool& reverse_byte_order(bool & _t) { return _t; } +template <> inline char& reverse_byte_order(char & _t) { return _t; } +#if defined(OM_CC_GCC) +template <> inline signed char& reverse_byte_order(signed char & _t) { return _t; } +#endif +template <> inline uchar& reverse_byte_order(uchar& _t) { return _t; } + +// Instead do specializations for the necessary types +#define REVERSE_FUNDAMENTAL_TYPE( T ) \ + template <> inline T& reverse_byte_order( T& _t ) {\ + _reverse_byte_order_N( reinterpret_cast(&_t) ); \ + return _t; \ + } + +// REVERSE_FUNDAMENTAL_TYPE(bool) +// REVERSE_FUNDAMENTAL_TYPE(char) +// REVERSE_FUNDAMENTAL_TYPE(uchar) +REVERSE_FUNDAMENTAL_TYPE(int16_t) +REVERSE_FUNDAMENTAL_TYPE(uint16_t) +// REVERSE_FUNDAMENTAL_TYPE(int) +// REVERSE_FUNDAMENTAL_TYPE(uint) + +REVERSE_FUNDAMENTAL_TYPE(unsigned long) +REVERSE_FUNDAMENTAL_TYPE(int32_t) +REVERSE_FUNDAMENTAL_TYPE(uint32_t) +REVERSE_FUNDAMENTAL_TYPE(int64_t) +REVERSE_FUNDAMENTAL_TYPE(uint64_t) +REVERSE_FUNDAMENTAL_TYPE(float) +REVERSE_FUNDAMENTAL_TYPE(double) +REVERSE_FUNDAMENTAL_TYPE(long double) + +#undef REVERSE_FUNDAMENTAL_TYPE + +#if 0 + +#define REVERSE_VECTORT_TYPE( T ) \ + template <> inline T& reverse_byte_order(T& _v) {\ + for (size_t i; i< T::size_; ++i) \ + _reverse_byte_order_N< sizeof(T::value_type) >( reinterpret_cast(&_v[i])); \ + return _v; \ + } + +#define REVERSE_VECTORT_TYPES( N ) \ + REVERSE_VECTORT_TYPE( Vec##N##c ) \ + REVERSE_VECTORT_TYPE( Vec##N##uc ) \ + REVERSE_VECTORT_TYPE( Vec##N##s ) \ + REVERSE_VECTORT_TYPE( Vec##N##us ) \ + REVERSE_VECTORT_TYPE( Vec##N##i ) \ + REVERSE_VECTORT_TYPE( Vec##N##ui ) \ + REVERSE_VECTORT_TYPE( Vec##N##f ) \ + REVERSE_VECTORT_TYPE( Vec##N##d ) \ + +REVERSE_VECTORT_TYPES(1) +REVERSE_VECTORT_TYPES(2) +REVERSE_VECTORT_TYPES(3) +REVERSE_VECTORT_TYPES(4) +REVERSE_VECTORT_TYPES(6) + +#undef REVERSE_VECTORT_TYPES +#undef REVERSE_VECTORT_TYPE + +#endif + +template inline +T reverse_byte_order(const T& a) +{ + compile_timer_error__const_means_const(a); + return a; +} + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_RBO_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_store.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_store.hh new file mode 100644 index 0000000..374b415 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_store.hh @@ -0,0 +1,67 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_STORE_HH +#define OPENMESH_SR_STORE_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include + +//============================================================================= +#endif // OPENMESH_STORE_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_types.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_types.hh new file mode 100644 index 0000000..484eb1d --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/SR_types.hh @@ -0,0 +1,107 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_TYPES_HH +#define OPENMESH_SR_TYPES_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + +//----------------------------------------------------------------------------- + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; + +typedef signed char int8_t; typedef unsigned char uint8_t; +typedef short int16_t; typedef unsigned short uint16_t; + +// Int should be 32 bit on all archs. +// long is 32 under windows but 64 under unix 64 bit +typedef int int32_t; typedef unsigned int uint32_t; +#if defined(OM_CC_MSVC) +typedef __int64 int64_t; typedef unsigned __int64 uint64_t; +#else +typedef long long int64_t; typedef unsigned long long uint64_t; +#endif + +typedef float float32_t; +typedef double float64_t; + +typedef uint8_t rgb_t[3]; +typedef uint8_t rgba_t[4]; + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/StoreRestore.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/StoreRestore.hh new file mode 100644 index 0000000..9c9631b --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/StoreRestore.hh @@ -0,0 +1,128 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_STORERESTORE_HH +#define OPENMESH_STORERESTORE_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + + +//----------------------------------------------------------------------------- +// StoreRestore definitions + +template inline +bool is_streamable(void) +{ return binary< T >::is_streamable; } + +template inline +bool is_streamable( const T& ) +{ return binary< T >::is_streamable; } + +template inline +size_t size_of( const T& _v ) +{ return binary< T >::size_of(_v); } + +template inline +size_t size_of( const std::vector & _v, bool _store_size = true) +{ return binary< std::vector >::size_of(_v, _store_size); } + +template inline +size_t size_of(void) +{ return binary< T >::size_of(); } + +template inline +size_t size_of(bool _store_size) +{ return binary< std::vector >::size_of(_store_size); } + +template inline +size_t store( std::ostream& _os, const T& _v, bool _swap =false) +{ return binary< T >::store( _os, _v, _swap ); } + +template inline +size_t store( std::ostream& _os, const std::vector& _v, bool _swap=false, bool _store_size = true) +{ return binary< std::vector >::store( _os, _v, _swap, _store_size); } + +template inline +size_t restore( std::istream& _is, T& _v, bool _swap = false) +{ return binary< T >::restore( _is, _v, _swap ); } + +template inline +size_t restore( std::istream& _is, std::vector& _v, bool _swap=false, bool _restore_size = true) +{ return binary< std::vector >::restore( _is, _v, _swap, _restore_size); } + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/exporter/BaseExporter.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/exporter/BaseExporter.hh new file mode 100644 index 0000000..398d28a --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/exporter/BaseExporter.hh @@ -0,0 +1,181 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the baseclass for MeshWriter exporter modules +// +//============================================================================= + + +#ifndef __BASEEXPORTER_HH__ +#define __BASEEXPORTER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include + +// OpenMesh +#include +#include +#include + + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== EXPORTER ================================================================ + + +/** + Base class for exporter modules. + The exporter modules provide an interface between the writer modules and + the target data structure. +*/ + +class OPENMESHDLLEXPORT BaseExporter +{ +public: + + virtual ~BaseExporter() { } + + + // get vertex data + virtual Vec3f point(VertexHandle _vh) const = 0; + virtual Vec3d pointd(VertexHandle _vh) const = 0; + virtual bool is_point_double() const = 0; + virtual Vec3f normal(VertexHandle _vh) const = 0; + virtual Vec3d normald(VertexHandle _vh) const = 0; + virtual bool is_normal_double() const = 0; + virtual Vec3uc color(VertexHandle _vh) const = 0; + virtual Vec4uc colorA(VertexHandle _vh) const = 0; + virtual Vec3ui colori(VertexHandle _vh) const = 0; + virtual Vec4ui colorAi(VertexHandle _vh) const = 0; + virtual Vec3f colorf(VertexHandle _vh) const = 0; + virtual Vec4f colorAf(VertexHandle _vh) const = 0; + virtual Vec2f texcoord(VertexHandle _vh) const = 0; + virtual Vec2f texcoord(HalfedgeHandle _heh) const = 0; + virtual OpenMesh::Attributes::StatusInfo status(VertexHandle _vh) const = 0; + + + // get face data + virtual unsigned int + get_vhandles(FaceHandle _fh, + std::vector& _vhandles) const=0; + + /// + /// \brief getHeh returns the HalfEdgeHandle that belongs to the face + /// specified by _fh and has a toVertexHandle that corresponds to _vh. + /// \param _fh FaceHandle that is used to search for the half edge handle + /// \param _vh to_vertex_handle of the searched heh + /// \return HalfEdgeHandle or invalid HalfEdgeHandle if none is found. + /// + virtual HalfedgeHandle getHeh(FaceHandle _fh, VertexHandle _vh) const = 0; + virtual unsigned int + get_face_texcoords(std::vector& _hehandles) const = 0; + virtual Vec3f normal(FaceHandle _fh) const = 0; + virtual Vec3d normald(FaceHandle _fh) const = 0; + virtual Vec3uc color (FaceHandle _fh) const = 0; + virtual Vec4uc colorA(FaceHandle _fh) const = 0; + virtual Vec3ui colori(FaceHandle _fh) const = 0; + virtual Vec4ui colorAi(FaceHandle _fh) const = 0; + virtual Vec3f colorf(FaceHandle _fh) const = 0; + virtual Vec4f colorAf(FaceHandle _fh) const = 0; + virtual OpenMesh::Attributes::StatusInfo status(FaceHandle _fh) const = 0; + + // get edge data + virtual Vec3uc color(EdgeHandle _eh) const = 0; + virtual Vec4uc colorA(EdgeHandle _eh) const = 0; + virtual Vec3ui colori(EdgeHandle _eh) const = 0; + virtual Vec4ui colorAi(EdgeHandle _eh) const = 0; + virtual Vec3f colorf(EdgeHandle _eh) const = 0; + virtual Vec4f colorAf(EdgeHandle _eh) const = 0; + virtual OpenMesh::Attributes::StatusInfo status(EdgeHandle _eh) const = 0; + + // get halfedge data + virtual int get_halfedge_id(VertexHandle _vh) = 0; + virtual int get_halfedge_id(FaceHandle _vh) = 0; + virtual int get_next_halfedge_id(HalfedgeHandle _heh) = 0; + virtual int get_to_vertex_id(HalfedgeHandle _heh) = 0; + virtual int get_face_id(HalfedgeHandle _heh) = 0; + virtual OpenMesh::Attributes::StatusInfo status(HalfedgeHandle _heh) const = 0; + + // get reference to base kernel + virtual const BaseKernel* kernel() { return nullptr; } + + + // query number of faces, vertices, normals, texcoords + virtual size_t n_vertices() const = 0; + virtual size_t n_faces() const = 0; + virtual size_t n_edges() const = 0; + + + // property information + virtual bool is_triangle_mesh() const { return false; } + virtual bool has_vertex_normals() const { return false; } + virtual bool has_vertex_colors() const { return false; } + virtual bool has_vertex_status() const { return false; } + virtual bool has_vertex_texcoords() const { return false; } + virtual bool has_edge_colors() const { return false; } + virtual bool has_edge_status() const { return false; } + virtual bool has_halfedge_status() const { return false; } + virtual bool has_face_normals() const { return false; } + virtual bool has_face_colors() const { return false; } + virtual bool has_face_status() const { return false; } +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/exporter/ExporterT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/exporter/ExporterT.hh new file mode 100644 index 0000000..2c1d4be --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/exporter/ExporterT.hh @@ -0,0 +1,422 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements an exporter module for arbitrary OpenMesh meshes +// +//============================================================================= + + +#ifndef __EXPORTERT_HH__ +#define __EXPORTERT_HH__ + + +//=== INCLUDES ================================================================ + +// C++ +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include +#include +#include + + +//=== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + + +//=== EXPORTER CLASS ========================================================== + +/** + * This class template provides an exporter module for OpenMesh meshes. + */ +template +class ExporterT : public BaseExporter +{ +public: + + // Constructor + explicit ExporterT(const Mesh& _mesh) : mesh_(_mesh) {} + + + // get vertex data + + Vec3f point(VertexHandle _vh) const override + { + return vector_cast(mesh_.point(_vh)); + } + + Vec3d pointd(VertexHandle _vh) const override + { + return vector_cast(mesh_.point(_vh)); + } + + bool is_point_double() const override + { + return OMFormat::is_double(typename Mesh::Point()[0]); + } + + bool is_normal_double() const override + { + return OMFormat::is_double(typename Mesh::Normal()[0]); + } + + Vec3f normal(VertexHandle _vh) const override + { + return (mesh_.has_vertex_normals() + ? vector_cast(mesh_.normal(_vh)) + : Vec3f(0.0f, 0.0f, 0.0f)); + } + + Vec3d normald(VertexHandle _vh) const override + { + return (mesh_.has_vertex_normals() + ? vector_cast(mesh_.normal(_vh)) + : Vec3d(0.0f, 0.0f, 0.0f)); + } + + Vec3uc color(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec4uc(0, 0, 0, 0)); + } + + Vec3ui colori(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec3ui(0, 0, 0)); + } + + Vec4ui colorAi(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec4ui(0, 0, 0, 0)); + } + + Vec3f colorf(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec3f(0, 0, 0)); + } + + Vec4f colorAf(VertexHandle _vh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec4f(0, 0, 0, 0)); + } + + Vec2f texcoord(VertexHandle _vh) const override + { +#if defined(OM_CC_GCC) && (OM_CC_VERSION<30000) + // Workaround! + // gcc 2.95.3 exits with internal compiler error at the + // code below!??? **) + if (mesh_.has_vertex_texcoords2D()) + return vector_cast(mesh_.texcoord2D(_vh)); + return Vec2f(0.0f, 0.0f); +#else // **) + return (mesh_.has_vertex_texcoords2D() + ? vector_cast(mesh_.texcoord2D(_vh)) + : Vec2f(0.0f, 0.0f)); +#endif + } + + Vec2f texcoord(HalfedgeHandle _heh) const override + { + return (mesh_.has_halfedge_texcoords2D() + ? vector_cast(mesh_.texcoord2D(_heh)) + : Vec2f(0.0f, 0.0f)); + } + + OpenMesh::Attributes::StatusInfo status(VertexHandle _vh) const override + { + if (mesh_.has_vertex_status()) + return mesh_.status(_vh); + return OpenMesh::Attributes::StatusInfo(); + } + + // get edge data + + Vec3uc color(EdgeHandle _eh) const override + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(EdgeHandle _eh) const override + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec4uc(0, 0, 0, 0)); + } + + Vec3ui colori(EdgeHandle _eh) const override + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec3ui(0, 0, 0)); + } + + Vec4ui colorAi(EdgeHandle _eh) const override + { + return (mesh_.has_edge_colors() + ? color_cast(mesh_.color(_eh)) + : Vec4ui(0, 0, 0, 0)); + } + + Vec3f colorf(EdgeHandle _eh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_eh)) + : Vec3f(0, 0, 0)); + } + + Vec4f colorAf(EdgeHandle _eh) const override + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_eh)) + : Vec4f(0, 0, 0, 0)); + } + + OpenMesh::Attributes::StatusInfo status(EdgeHandle _eh) const override + { + if (mesh_.has_edge_status()) + return mesh_.status(_eh); + return OpenMesh::Attributes::StatusInfo(); + } + + // get halfedge data + + int get_halfedge_id(VertexHandle _vh) override + { + return mesh_.halfedge_handle(_vh).idx(); + } + + int get_halfedge_id(FaceHandle _fh) override + { + return mesh_.halfedge_handle(_fh).idx(); + } + + int get_next_halfedge_id(HalfedgeHandle _heh) override + { + return mesh_.next_halfedge_handle(_heh).idx(); + } + + int get_to_vertex_id(HalfedgeHandle _heh) override + { + return mesh_.to_vertex_handle(_heh).idx(); + } + + int get_face_id(HalfedgeHandle _heh) override + { + return mesh_.face_handle(_heh).idx(); + } + + OpenMesh::Attributes::StatusInfo status(HalfedgeHandle _heh) const override + { + if (mesh_.has_halfedge_status()) + return mesh_.status(_heh); + return OpenMesh::Attributes::StatusInfo(); + } + + // get face data + + unsigned int get_vhandles(FaceHandle _fh, + std::vector& _vhandles) const override + { + unsigned int count(0); + _vhandles.clear(); + for (typename Mesh::CFVIter fv_it=mesh_.cfv_iter(_fh); fv_it.is_valid(); ++fv_it) + { + _vhandles.push_back(*fv_it); + ++count; + } + return count; + } + + unsigned int get_face_texcoords(std::vector& _hehandles) const override + { + unsigned int count(0); + _hehandles.clear(); + for(auto heh: mesh_.halfedges().filtered(!OpenMesh::Predicates::Boundary())) + { + _hehandles.push_back(vector_cast(mesh_.texcoord2D(heh))); + ++count; + } + + return count; + } + + HalfedgeHandle getHeh(FaceHandle _fh, VertexHandle _vh) const override + { + typename Mesh::ConstFaceHalfedgeIter fh_it; + for(fh_it = mesh_.cfh_iter(_fh); fh_it.is_valid();++fh_it) + { + if(mesh_.to_vertex_handle(*fh_it) == _vh) + return *fh_it; + } + return *fh_it; + } + + Vec3f normal(FaceHandle _fh) const override + { + return (mesh_.has_face_normals() + ? vector_cast(mesh_.normal(_fh)) + : Vec3f(0.0f, 0.0f, 0.0f)); + } + + Vec3d normald(FaceHandle _fh) const override + { + return (mesh_.has_face_normals() + ? vector_cast(mesh_.normal(_fh)) + : Vec3d(0.0, 0.0, 0.0)); + } + + Vec3uc color(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec4uc(0, 0, 0, 0)); + } + + Vec3ui colori(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec3ui(0, 0, 0)); + } + + Vec4ui colorAi(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec4ui(0, 0, 0, 0)); + } + + Vec3f colorf(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec3f(0, 0, 0)); + } + + Vec4f colorAf(FaceHandle _fh) const override + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec4f(0, 0, 0, 0)); + } + + OpenMesh::Attributes::StatusInfo status(FaceHandle _fh) const override + { + if (mesh_.has_face_status()) + return mesh_.status(_fh); + return OpenMesh::Attributes::StatusInfo(); + } + + virtual const BaseKernel* kernel() override { return &mesh_; } + + + // query number of faces, vertices, normals, texcoords + size_t n_vertices() const override { return mesh_.n_vertices(); } + size_t n_faces() const override { return mesh_.n_faces(); } + size_t n_edges() const override { return mesh_.n_edges(); } + + + // property information + bool is_triangle_mesh() const override + { return Mesh::is_triangles(); } + + bool has_vertex_normals() const override { return mesh_.has_vertex_normals(); } + bool has_vertex_colors() const override { return mesh_.has_vertex_colors(); } + bool has_vertex_texcoords() const override { return mesh_.has_vertex_texcoords2D(); } + bool has_vertex_status() const override { return mesh_.has_vertex_status(); } + bool has_edge_colors() const override { return mesh_.has_edge_colors(); } + bool has_edge_status() const override { return mesh_.has_edge_status(); } + bool has_halfedge_status() const override { return mesh_.has_halfedge_status(); } + bool has_face_normals() const override { return mesh_.has_face_normals(); } + bool has_face_colors() const override { return mesh_.has_face_colors(); } + bool has_face_status() const override { return mesh_.has_face_status(); } + +private: + + const Mesh& mesh_; +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/importer/BaseImporter.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/importer/BaseImporter.hh new file mode 100644 index 0000000..ff44141 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/importer/BaseImporter.hh @@ -0,0 +1,239 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the baseclass for IOManager importer modules +// +//============================================================================= + + +#ifndef __BASEIMPORTER_HH__ +#define __BASEIMPORTER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include + +// OpenMesh +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** Base class for importer modules. Importer modules provide an + * interface between the loader modules and the target data + * structure. This is basically a wrapper providing virtual versions + * for the required mesh functions. + */ +class OPENMESHDLLEXPORT BaseImporter +{ +public: + + // base class needs virtual destructor + virtual ~BaseImporter() {} + + + // add a vertex with coordinate \c _point + virtual VertexHandle add_vertex(const Vec3f& _point) = 0; + + // add a vertex with coordinate \c _point + virtual VertexHandle add_vertex(const Vec3d& _point) { return add_vertex(Vec3f(_point)); } + + // add a vertex without coordinate. Use set_point to set the position deferred + virtual VertexHandle add_vertex() = 0; + + // add an edge. Use set_next, set_vertex and set_face to set corresponding entities for halfedges + virtual HalfedgeHandle add_edge(VertexHandle _vh0, VertexHandle _vh1) = 0; + + // add a face with indices _indices refering to vertices + typedef std::vector VHandles; + virtual FaceHandle add_face(const VHandles& _indices) = 0; + + // add a face with incident halfedge + virtual FaceHandle add_face(HalfedgeHandle _heh) = 0; + + // add texture coordinates per face, _vh references the first texcoord + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) = 0; + + // add texture 3d coordinates per face, _vh references the first texcoord + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) = 0; + + // Set the texture index for a face + virtual void set_face_texindex( FaceHandle _fh, int _texId ) = 0; + + // Set coordinate of the given vertex. Use this function, if you created a vertex without coordinate + virtual void set_point(VertexHandle _vh, const Vec3f& _point) = 0; + + // Set outgoing halfedge for the given vertex. + virtual void set_halfedge(VertexHandle _vh, HalfedgeHandle _heh) = 0; + + // set vertex normal + virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) = 0; + + // set vertex normal + virtual void set_normal(VertexHandle _vh, const Vec3d& _normal) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec3uc& _color) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec4uc& _color) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec3f& _color) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec4f& _color) = 0; + + // set vertex texture coordinate + virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) = 0; + + // set vertex status + virtual void set_status(VertexHandle _vh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + + // set next halfedge handle + virtual void set_next(HalfedgeHandle _heh, HalfedgeHandle _next) = 0; + + // set incident face handle for given halfedge + virtual void set_face(HalfedgeHandle _heh, FaceHandle _fh) = 0; + + // request texture coordinate property + virtual void request_face_texcoords2D() = 0; + + // set vertex texture coordinate + virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) = 0; + + // set 3d vertex texture coordinate + virtual void set_texcoord(VertexHandle _vh, const Vec3f& _texcoord) = 0; + + // set 3d vertex texture coordinate + virtual void set_texcoord(HalfedgeHandle _heh, const Vec3f& _texcoord) = 0; + + // set halfedge status + virtual void set_status(HalfedgeHandle _heh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec3uc& _color) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec4uc& _color) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec3f& _color) = 0; + + // set edge color + virtual void set_color(EdgeHandle _eh, const Vec4f& _color) = 0; + + // set edge status + virtual void set_status(EdgeHandle _eh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + + // set face normal + virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) = 0; + + // set face normal + virtual void set_normal(FaceHandle _fh, const Vec3d& _normal) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec3uc& _color) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec4uc& _color) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec3f& _color) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec4f& _color) = 0; + + // set face status + virtual void set_status(FaceHandle _fh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + + // Store a property in the mesh mapping from an int to a texture file + // Use set_face_texindex to set the index for each face + virtual void add_texture_information( int _id , std::string _name ) = 0; + + // get reference to base kernel + virtual BaseKernel* kernel() { return nullptr; } + + virtual bool is_triangle_mesh() const { return false; } + + // reserve mem for elements + virtual void reserve( unsigned int /* nV */, + unsigned int /* nE */, + unsigned int /* nF */) {} + + // query number of faces, vertices, normals, texcoords + virtual size_t n_vertices() const = 0; + virtual size_t n_faces() const = 0; + virtual size_t n_edges() const = 0; + + + // pre-processing + virtual void prepare() {} + + // post-processing + virtual void finish() {} +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/importer/ImporterT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/importer/ImporterT.hh new file mode 100644 index 0000000..55a2a2c --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/importer/ImporterT.hh @@ -0,0 +1,486 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements an importer module for arbitrary OpenMesh meshes +// +//============================================================================= + + +#ifndef __IMPORTERT_HH__ +#define __IMPORTERT_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + * This class template provides an importer module for OpenMesh meshes. + */ +template +class ImporterT : public BaseImporter +{ +public: + + typedef typename Mesh::Point Point; + typedef typename Mesh::Normal Normal; + typedef typename Mesh::Color Color; + typedef typename Mesh::TexCoord2D TexCoord2D; + typedef typename Mesh::TexCoord3D TexCoord3D; + typedef std::vector VHandles; + + + explicit ImporterT(Mesh& _mesh) : mesh_(_mesh), halfedgeNormals_() {} + + + virtual VertexHandle add_vertex(const Vec3f& _point) override + { + return mesh_.add_vertex(vector_cast(_point)); + } + + virtual VertexHandle add_vertex(const Vec3d& _point) override + { + return mesh_.add_vertex(vector_cast(_point)); + } + + virtual VertexHandle add_vertex() override + { + return mesh_.new_vertex(); + } + + virtual HalfedgeHandle add_edge(VertexHandle _vh0, VertexHandle _vh1) override + { + return mesh_.new_edge(_vh0, _vh1); + } + + virtual FaceHandle add_face(const VHandles& _indices) override + { + FaceHandle fh; + + if (_indices.size() > 2) + { + VHandles::const_iterator it, it2, end(_indices.end()); + + + // Test if all vertex handles are valid. If not, we throw an error. + if ( std::any_of(_indices.begin(),_indices.end(),[this](const VertexHandle& vh){ return !mesh_.is_valid_handle(vh); } ) ) + { + omerr() << "ImporterT: Face contains invalid vertex index\n"; + return fh; + } + + // don't allow double vertices + for (it=_indices.begin(); it!=end; ++it) + for (it2=it+1; it2!=end; ++it2) + if (*it == *it2) + { + omerr() << "ImporterT: Face has equal vertices\n"; + return fh; + } + + + // try to add face + fh = mesh_.add_face(_indices); + // separate non-manifold faces and mark them + if (!fh.is_valid()) + { + VHandles vhandles(_indices.size()); + + // double vertices + for (unsigned int j=0; j<_indices.size(); ++j) + { + // DO STORE p, reference may not work since vertex array + // may be relocated after adding a new vertex ! + Point p = mesh_.point(_indices[j]); + vhandles[j] = mesh_.add_vertex(p); + + // Mark vertices of failed face as non-manifold + if (mesh_.has_vertex_status()) { + mesh_.status(vhandles[j]).set_fixed_nonmanifold(true); + } + } + + // add face + fh = mesh_.add_face(vhandles); + + // Mark failed face as non-manifold + if (mesh_.has_face_status()) + mesh_.status(fh).set_fixed_nonmanifold(true); + + // Mark edges of failed face as non-two-manifold + if (mesh_.has_edge_status()) { + typename Mesh::FaceEdgeIter fe_it = mesh_.fe_iter(fh); + for(; fe_it.is_valid(); ++fe_it) { + mesh_.status(*fe_it).set_fixed_nonmanifold(true); + } + } + } + + //write the half edge normals + if (mesh_.has_halfedge_normals()) + { + //iterate over all incoming haldedges of the added face + for (typename Mesh::FaceHalfedgeIter fh_iter = mesh_.fh_begin(fh); + fh_iter != mesh_.fh_end(fh); ++fh_iter) + { + //and write the normals to it + typename Mesh::HalfedgeHandle heh = *fh_iter; + typename Mesh::VertexHandle vh = mesh_.to_vertex_handle(heh); + typename std::map::iterator it_heNs = halfedgeNormals_.find(vh); + if (it_heNs != halfedgeNormals_.end()) + mesh_.set_normal(heh,it_heNs->second); + } + halfedgeNormals_.clear(); + } + } + return fh; + } + + virtual FaceHandle add_face(HalfedgeHandle _heh) override + { + auto fh = mesh_.new_face(); + mesh_.set_halfedge_handle(fh, _heh); + return fh; + } + + // vertex attributes + + virtual void set_point(VertexHandle _vh, const Vec3f& _point) override + { + mesh_.set_point(_vh,vector_cast(_point)); + } + + virtual void set_halfedge(VertexHandle _vh, HalfedgeHandle _heh) override + { + mesh_.set_halfedge_handle(_vh, _heh); + } + + virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) override + { + if (mesh_.has_vertex_normals()) + mesh_.set_normal(_vh, vector_cast(_normal)); + + //saves normals for half edges. + //they will be written, when the face is added + if (mesh_.has_halfedge_normals()) + halfedgeNormals_[_vh] = vector_cast(_normal); + } + + virtual void set_normal(VertexHandle _vh, const Vec3d& _normal) override + { + if (mesh_.has_vertex_normals()) + mesh_.set_normal(_vh, vector_cast(_normal)); + + //saves normals for half edges. + //they will be written, when the face is added + if (mesh_.has_halfedge_normals()) + halfedgeNormals_[_vh] = vector_cast(_normal); + } + + virtual void set_color(VertexHandle _vh, const Vec4uc& _color) override + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_color(VertexHandle _vh, const Vec3uc& _color) override + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_color(VertexHandle _vh, const Vec4f& _color) override + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_color(VertexHandle _vh, const Vec3f& _color) override + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) override + { + if (mesh_.has_vertex_texcoords2D()) + mesh_.set_texcoord2D(_vh, vector_cast(_texcoord)); + } + + virtual void set_status(VertexHandle _vh, const OpenMesh::Attributes::StatusInfo& _status) override + { + if (!mesh_.has_vertex_status()) + mesh_.request_vertex_status(); + mesh_.status(_vh) = _status; + } + + virtual void set_next(HalfedgeHandle _heh, HalfedgeHandle _next) override + { + mesh_.set_next_halfedge_handle(_heh, _next); + } + + virtual void set_face(HalfedgeHandle _heh, FaceHandle _fh) override + { + mesh_.set_face_handle(_heh, _fh); + } + + virtual void request_face_texcoords2D() override + { + if(!mesh_.has_halfedge_texcoords2D()) + mesh_.request_halfedge_texcoords2D(); + } + + virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) override + { + if (mesh_.has_halfedge_texcoords2D()) + mesh_.set_texcoord2D(_heh, vector_cast(_texcoord)); + } + + virtual void set_texcoord(VertexHandle _vh, const Vec3f& _texcoord) override + { + if (mesh_.has_vertex_texcoords3D()) + mesh_.set_texcoord3D(_vh, vector_cast(_texcoord)); + } + + virtual void set_texcoord(HalfedgeHandle _heh, const Vec3f& _texcoord) override + { + if (mesh_.has_halfedge_texcoords3D()) + mesh_.set_texcoord3D(_heh, vector_cast(_texcoord)); + } + + virtual void set_status(HalfedgeHandle _heh, const OpenMesh::Attributes::StatusInfo& _status) override + { + if (!mesh_.has_halfedge_status()) + mesh_.request_halfedge_status(); + mesh_.status(_heh) = _status; + } + + // edge attributes + + virtual void set_color(EdgeHandle _eh, const Vec4uc& _color) override + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_color(EdgeHandle _eh, const Vec3uc& _color) override + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_color(EdgeHandle _eh, const Vec4f& _color) override + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_color(EdgeHandle _eh, const Vec3f& _color) override + { + if (mesh_.has_edge_colors()) + mesh_.set_color(_eh, color_cast(_color)); + } + + virtual void set_status(EdgeHandle _eh, const OpenMesh::Attributes::StatusInfo& _status) override + { + if (!mesh_.has_edge_status()) + mesh_.request_edge_status(); + mesh_.status(_eh) = _status; + } + + // face attributes + + virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) override + { + if (mesh_.has_face_normals()) + mesh_.set_normal(_fh, vector_cast(_normal)); + } + + virtual void set_normal(FaceHandle _fh, const Vec3d& _normal) override + { + if (mesh_.has_face_normals()) + mesh_.set_normal(_fh, vector_cast(_normal)); + } + + virtual void set_color(FaceHandle _fh, const Vec3uc& _color) override + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_color(FaceHandle _fh, const Vec4uc& _color) override + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_color(FaceHandle _fh, const Vec3f& _color) override + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_color(FaceHandle _fh, const Vec4f& _color) override + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_status(FaceHandle _fh, const OpenMesh::Attributes::StatusInfo& _status) override + { + if (!mesh_.has_face_status()) + mesh_.request_face_status(); + mesh_.status(_fh) = _status; + } + + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) override + { + // get first halfedge handle + HalfedgeHandle cur_heh = mesh_.halfedge_handle(_fh); + HalfedgeHandle end_heh = mesh_.prev_halfedge_handle(cur_heh); + + // find start heh + while( mesh_.to_vertex_handle(cur_heh) != _vh && cur_heh != end_heh ) + cur_heh = mesh_.next_halfedge_handle( cur_heh); + + for(unsigned int i=0; i<_face_texcoords.size(); ++i) + { + set_texcoord( cur_heh, _face_texcoords[i]); + cur_heh = mesh_.next_halfedge_handle( cur_heh); + } + } + + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) override + { + // get first halfedge handle + HalfedgeHandle cur_heh = mesh_.halfedge_handle(_fh); + HalfedgeHandle end_heh = mesh_.prev_halfedge_handle(cur_heh); + + // find start heh + while( mesh_.to_vertex_handle(cur_heh) != _vh && cur_heh != end_heh ) + cur_heh = mesh_.next_halfedge_handle( cur_heh); + + for(unsigned int i=0; i<_face_texcoords.size(); ++i) + { + set_texcoord( cur_heh, _face_texcoords[i]); + cur_heh = mesh_.next_halfedge_handle( cur_heh); + } + } + + virtual void set_face_texindex( FaceHandle _fh, int _texId ) override + { + if ( mesh_.has_face_texture_index() ) { + mesh_.set_texture_index(_fh , _texId); + } + } + + virtual void add_texture_information( int _id , std::string _name ) override + { + OpenMesh::MPropHandleT< std::map< int, std::string > > property; + + if ( !mesh_.get_property_handle(property,"TextureMapping") ) { + mesh_.add_property(property,"TextureMapping"); + } + + if ( mesh_.property(property).find( _id ) == mesh_.property(property).end() ) { + mesh_.property(property)[_id] = _name; + } + } + + // low-level access to mesh + + virtual BaseKernel* kernel() override { return &mesh_; } + + bool is_triangle_mesh() const override + { return Mesh::is_triangles(); } + + void reserve(unsigned int nV, unsigned int nE, unsigned int nF) override + { + mesh_.reserve(nV, nE, nF); + } + + // query number of faces, vertices, normals, texcoords + size_t n_vertices() const override { return mesh_.n_vertices(); } + size_t n_faces() const override { return mesh_.n_faces(); } + size_t n_edges() const override { return mesh_.n_edges(); } + + + void prepare() override{ } + + + void finish() override { } + + +private: + + Mesh& mesh_; + // stores normals for halfedges of the next face + std::map halfedgeNormals_; +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/BaseReader.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/BaseReader.hh new file mode 100644 index 0000000..8705f7d --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/BaseReader.hh @@ -0,0 +1,203 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the baseclass for IOManager file access modules +// +//============================================================================= + +#pragma once + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include +#include +#include +#include + +// OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Base class for reader modules. + Reader modules access persistent data and pass them to the desired + data structure by the means of a BaseImporter derivative. + All reader modules must be derived from this class. +*/ +class OPENMESHDLLEXPORT BaseReader +{ +public: + + /// Destructor + virtual ~BaseReader() {} + + /// Returns a brief description of the file type that can be parsed. + virtual std::string get_description() const = 0; + + /** Returns a string with the accepted file extensions separated by a + whitespace and in small caps. + */ + virtual std::string get_extensions() const = 0; + + /// Return magic bits used to determine file format + virtual std::string get_magic() const { return std::string(""); } + + + /** Reads a mesh given by a filename. Usually this method opens a stream + and passes it to stream read method. Acceptance checks by filename + extension can be placed here. + + Options can be passed via _opt. After execution _opt contains the Options + that were available + */ + virtual bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) = 0; + + /** Reads a mesh given by a std::stream. This method usually uses the same stream reading method + that read uses. Options can be passed via _opt. After execution _opt contains the Options + that were available. + + Please make sure that if _is is std::ifstream, the correct std::ios_base::openmode flags are set. + */ + virtual bool read(std::istream& _is, + BaseImporter& _bi, + Options& _opt) = 0; + + + /** \brief Returns true if writer can parse _filename (checks extension). + * _filename can also provide an extension without a name for a file e.g. _filename == "om" checks, if the reader can read the "om" extension + * @param _filename complete name of a file or just the extension + * @result true, if reader can read data with the given extension + */ + virtual bool can_u_read(const std::string& _filename) const; + + +protected: + + // case insensitive search for _ext in _fname. + bool check_extension(const std::string& _fname, + const std::string& _ext) const; +}; + + +/** \brief Trim left whitespace + * + * Removes whitespace at the beginning of the string + * + * @param _string input string + * @return trimmed string + */ +static inline std::string &left_trim(std::string &_string) { + + // Find out if the compiler supports CXX11 + #if ( __cplusplus >= 201103L || _MSVC_LANG >= 201103L ) + // as with CXX11 we can use lambda expressions + _string.erase(_string.begin(), std::find_if(_string.begin(), _string.end(), [](int i)->int { return ! std::isspace(i); })); + #else + // we do what we did before + _string.erase(_string.begin(), std::find_if(_string.begin(), _string.end(), std::not1(std::ptr_fun(std::isspace)))); + #endif + + return _string; +} + +/** \brief Trim right whitespace + * + * Removes whitespace at the end of the string + * + * @param _string input string + * @return trimmed string + */ +static inline std::string &right_trim(std::string &_string) { + + // Find out if the compiler supports CXX11 + #if ( __cplusplus >= 201103L || _MSVC_LANG >= 201103L ) + // as with CXX11 we can use lambda expressions + _string.erase(std::find_if(_string.rbegin(), _string.rend(), [](int i)->int { return ! std::isspace(i); } ).base(), _string.end()); + #else + // we do what we did before + _string.erase(std::find_if(_string.rbegin(), _string.rend(), std::not1(std::ptr_fun(std::isspace))).base(), _string.end()); + #endif + + + + return _string; +} + +/** \brief Trim whitespace + * + * Removes whitespace at the beginning and end of the string + * + * @param _string input string + * @return trimmed string + */ +static inline std::string &trim(std::string &_string) { + return left_trim(right_trim(_string)); +} + + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/OBJReader.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/OBJReader.hh new file mode 100644 index 0000000..e90765d --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/OBJReader.hh @@ -0,0 +1,196 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements an reader module for OBJ files +// +//============================================================================= + + +#ifndef __OBJREADER_HH__ +#define __OBJREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OBJ format reader. +*/ +class OPENMESHDLLEXPORT _OBJReader_ : public BaseReader +{ +public: + + _OBJReader_(); + + virtual ~_OBJReader_() { } + + std::string get_description() const override { return "Alias/Wavefront"; } + std::string get_extensions() const override { return "obj"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) override; + + bool read(std::istream& _in, + BaseImporter& _bi, + Options& _opt) override; + +private: + +#ifndef DOXY_IGNORE_THIS + class Material + { + public: + + Material():Tr_(0),index_Kd_(0) { cleanup(); } + + void cleanup() + { + Kd_is_set_ = false; + Ka_is_set_ = false; + Ks_is_set_ = false; + Tr_is_set_ = false; + map_Kd_is_set_ = false; + } + + bool is_valid(void) const + { return Kd_is_set_ || Ka_is_set_ || Ks_is_set_ || Tr_is_set_ || map_Kd_is_set_; } + + bool has_Kd(void) { return Kd_is_set_; } + bool has_Ka(void) { return Ka_is_set_; } + bool has_Ks(void) { return Ks_is_set_; } + bool has_Tr(void) { return Tr_is_set_; } + bool has_map_Kd(void) { return map_Kd_is_set_; } + + void set_Kd( float r, float g, float b ) + { Kd_=Vec3f(r,g,b); Kd_is_set_=true; } + + void set_Ka( float r, float g, float b ) + { Ka_=Vec3f(r,g,b); Ka_is_set_=true; } + + void set_Ks( float r, float g, float b ) + { Ks_=Vec3f(r,g,b); Ks_is_set_=true; } + + void set_Tr( float t ) + { Tr_=t; Tr_is_set_=true; } + + void set_map_Kd( const std::string& _name, int _index_Kd ) + { map_Kd_ = _name, index_Kd_ = _index_Kd; map_Kd_is_set_ = true; }; + + const Vec3f& Kd( void ) const { return Kd_; } + const Vec3f& Ka( void ) const { return Ka_; } + const Vec3f& Ks( void ) const { return Ks_; } + float Tr( void ) const { return Tr_; } + const std::string& map_Kd( void ) { return map_Kd_ ; } + const int& map_Kd_index( void ) { return index_Kd_ ; } + + private: + + Vec3f Kd_; bool Kd_is_set_; // diffuse + Vec3f Ka_; bool Ka_is_set_; // ambient + Vec3f Ks_; bool Ks_is_set_; // specular + float Tr_; bool Tr_is_set_; // transperency + + std::string map_Kd_; int index_Kd_; bool map_Kd_is_set_; // Texture + + }; +#endif + + typedef std::map MaterialList; + + MaterialList materials_; + + bool read_material( std::fstream& _in ); + + +private: + + bool read_vertices(std::istream& _in, BaseImporter& _bi, Options& _opt, + std::vector & normals, + std::vector & colors, + std::vector & texcoords3d, + std::vector & texcoords, + std::vector & vertexHandles, + Options & fileOptions); + + std::string path_; + +}; + + +//== TYPE DEFINITION ========================================================== + + +extern _OBJReader_ __OBJReaderInstance; +OPENMESHDLLEXPORT _OBJReader_& OBJReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/OFFReader.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/OFFReader.hh new file mode 100644 index 0000000..57cda96 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/OFFReader.hh @@ -0,0 +1,161 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + +#pragma once + +//=== INCLUDES ================================================================ + + +#include +#include +#include + +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== FORWARDS ================================================================= + + +class BaseImporter; + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OFF format reader. This class is singleton'ed by + SingletonT to OFFReader. + + By passing Options to the read function you can manipulate the reading behavoir. + The following options can be set: + + VertexNormal + VertexColor + VertexTexCoord + FaceColor + ColorAlpha [only when reading binary] + + These options define if the corresponding data should be read (if available) + or if it should be omitted. + + After execution of the read function. The options object contains information about + what was actually read. + + e.g. if VertexNormal was true when the read function was called, but the file + did not contain vertex normals then it is false afterwards. + + When reading a binary off with Color Flag in the header it is assumed that all vertices + and faces have colors in the format "int int int". + If ColorAlpha is set the format "int int int int" is assumed. + +*/ + +class OPENMESHDLLEXPORT _OFFReader_ : public BaseReader +{ +public: + + _OFFReader_(); + + /// Destructor + virtual ~_OFFReader_() {}; + + std::string get_description() const override { return "Object File Format"; } + std::string get_extensions() const override { return "off"; } + std::string get_magic() const override { return "OFF"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) override; + + bool can_u_read(const std::string& _filename) const override; + + bool read(std::istream& _in, BaseImporter& _bi, Options& _opt ) override; + +private: + + bool can_u_read(std::istream& _is) const; + + bool read_ascii(std::istream& _in, BaseImporter& _bi, Options& _opt) const; + bool read_binary(std::istream& _in, BaseImporter& _bi, Options& _opt, bool swap) const; + + void readValue(std::istream& _in, float& _value) const; + void readValue(std::istream& _in, int& _value) const; + void readValue(std::istream& _in, unsigned int& _value) const; + + int getColorType(std::string & _line, bool _texCoordsAvailable) const; + + //available options for reading + mutable Options options_; + //options that the user wants to read + mutable Options userOptions_; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OFF reader +extern _OFFReader_ __OFFReaderInstance; +OPENMESHDLLEXPORT _OFFReader_& OFFReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/OMReader.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/OMReader.hh new file mode 100644 index 0000000..7382066 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/OMReader.hh @@ -0,0 +1,176 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + + +#ifndef __OMREADER_HH__ +#define __OMREADER_HH__ + + +//=== INCLUDES ================================================================ + +// OpenMesh +#include +#include +#include +#include +#include +#include + +// STD C++ +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OM format reader. This class is singleton'ed by + SingletonT to OMReader. +*/ +class OPENMESHDLLEXPORT _OMReader_ : public BaseReader +{ +public: + + _OMReader_(); + virtual ~_OMReader_() { } + + std::string get_description() const override { return "OpenMesh File Format"; } + std::string get_extensions() const override { return "om"; } + std::string get_magic() const override { return "OM"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt ) override; + +//! Stream Reader for std::istream input in binary format + bool read(std::istream& _is, + BaseImporter& _bi, + Options& _opt ) override; + + virtual bool can_u_read(const std::string& _filename) const override; + virtual bool can_u_read(std::istream& _is) const; + + +private: + + bool supports( const OMFormat::uint8 version ) const; + + bool read_ascii(std::istream& _is, BaseImporter& _bi, const Options& _opt) const; + bool read_binary(std::istream& _is, BaseImporter& _bi, const Options& _opt) const; + + typedef OMFormat::Header Header; + typedef OMFormat::Chunk::Header ChunkHeader; + typedef OMFormat::Chunk::PropertyName PropertyName; + + // initialized/updated by read_binary*/read_ascii* + mutable size_t bytes_; + mutable Options fileOptions_; + mutable Header header_; + mutable ChunkHeader chunk_header_; + mutable PropertyName property_name_; + + bool read_binary_vertex_chunk( std::istream &_is, + BaseImporter &_bi, + const Options &_opt, + bool _swap) const; + + bool read_binary_face_chunk( std::istream &_is, + BaseImporter &_bi, + const Options &_opt, + bool _swap) const; + + bool read_binary_edge_chunk( std::istream &_is, + BaseImporter &_bi, + const Options &_opt, + bool _swap) const; + + bool read_binary_halfedge_chunk( std::istream &_is, + BaseImporter &_bi, + const Options &_opt, + bool _swap) const; + + bool read_binary_mesh_chunk( std::istream &_is, + BaseImporter &_bi, + const Options &_opt, + bool _swap) const; + + size_t restore_binary_custom_data(std::istream& _is, + BaseProperty* _bp, + size_t _n_elem, + bool _swap) const; + + //------------------helper +private: + void add_generic_property(OMFormat::Chunk::PropertyName& _property_type, BaseImporter& _bi) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OM reader. +extern _OMReader_ __OMReaderInstance; +OPENMESHDLLEXPORT _OMReader_& OMReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/PLYReader.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/PLYReader.hh new file mode 100644 index 0000000..58cb2ea --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/PLYReader.hh @@ -0,0 +1,262 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + + +#ifndef __PLYREADER_HH__ +#define __PLYREADER_HH__ + + +//=== INCLUDES ================================================================ + + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== FORWARDS ================================================================= + + +class BaseImporter; + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the PLY format reader. This class is singleton'ed by + SingletonT to OFFReader. It can read custom properties, accessible via the name + of the custom properties. List properties has the type std::vector. + +*/ + +class OPENMESHDLLEXPORT _PLYReader_ : public BaseReader +{ +public: + + _PLYReader_(); + + std::string get_description() const override { return "PLY polygon file format"; } + std::string get_extensions() const override { return "ply"; } + std::string get_magic() const override { return "PLY"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) override; + + bool read(std::istream& _is, + BaseImporter& _bi, + Options& _opt) override; + + bool can_u_read(const std::string& _filename) const override; + + enum ValueType { + Unsupported, + ValueTypeINT8, ValueTypeCHAR, + ValueTypeUINT8, ValueTypeUCHAR, + ValueTypeINT16, ValueTypeSHORT, + ValueTypeUINT16, ValueTypeUSHORT, + ValueTypeINT32, ValueTypeINT, + ValueTypeUINT32, ValueTypeUINT, + ValueTypeFLOAT32, ValueTypeFLOAT, + ValueTypeFLOAT64, ValueTypeDOUBLE + }; + +private: + + bool can_u_read(std::istream& _is) const; + + bool read_ascii(std::istream& _in, BaseImporter& _bi, const Options& _opt) const; + bool read_binary(std::istream& _in, BaseImporter& _bi, bool swap, const Options& _opt) const; + + void readValue(ValueType _type , std::istream& _in, float& _value) const; + void readValue(ValueType _type , std::istream& _in, double& _value) const; + void readValue(ValueType _type , std::istream& _in, unsigned int& _value) const; + void readValue(ValueType _type , std::istream& _in, unsigned short& _value) const; + void readValue(ValueType _type , std::istream& _in, unsigned char& _value) const; + void readValue(ValueType _type , std::istream& _in, int& _value) const; + void readValue(ValueType _type , std::istream& _in, short& _value) const; + void readValue(ValueType _type , std::istream& _in, signed char& _value) const; + + template + void readInteger(ValueType _type, std::istream& _in, T& _value) const; + + /// Read unsupported properties in PLY file + void consume_input(std::istream& _in, int _count) const { + + // Make sure, we do not run over our buffer size + int loops = _count / 8 ; + + // Read only our buffer size batches + for ( auto i = 0 ; i < loops; ++i) { + _in.read(reinterpret_cast(&buff[0]), 8); + } + + // Read reminder which is smaller than our buffer size + _in.read(reinterpret_cast(&buff[0]), _count - 8 * loops ); + } + + mutable unsigned char buff[8]; + + /// Available per file options for reading + mutable Options options_; + + /// Options that the user wants to read + mutable Options userOptions_; + + mutable unsigned int vertexCount_; + mutable unsigned int faceCount_; + + mutable uint vertexDimension_; + + enum Property { + XCOORD,YCOORD,ZCOORD, + TEXX,TEXY, + COLORRED,COLORGREEN,COLORBLUE,COLORALPHA, + XNORM,YNORM,ZNORM, CUSTOM_PROP, VERTEX_INDICES, + TEXCOORD, TEXNUMBER, UNSUPPORTED + }; + + /// Stores sizes of property types + mutable std::map scalar_size_; + + // Number of vertex properties + struct PropertyInfo + { + Property property; + ValueType value; + std::string name;//for custom properties + ValueType listIndexType;//if type is unsupported, the poerty is not a list. otherwise, it the index type + PropertyInfo():property(UNSUPPORTED),value(Unsupported),name(""),listIndexType(Unsupported){} + PropertyInfo(Property _p, ValueType _v):property(_p),value(_v),name(""),listIndexType(Unsupported){} + PropertyInfo(Property _p, ValueType _v, const std::string& _n):property(_p),value(_v),name(_n),listIndexType(Unsupported){} + }; + + enum Element { + VERTEX, + FACE, + UNKNOWN + }; + + // Information on the elements + struct ElementInfo + { + Element element_; + std::string name_; + unsigned int count_; + std::vector< PropertyInfo > properties_; + }; + + mutable std::vector< ElementInfo > elements_; + + mutable std::vector< std::string > texture_files_; + + template + inline void read(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::TrueType /*_binary*/) const + { + readValue(_type, _in, _value); + } + + template + inline void read(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::FalseType /*_binary*/) const + { + _in >> _value; + } + + template + inline void readInteger(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::TrueType /*_binary*/) const + { + readInteger(_type, _in, _value); + } + + template + inline void readInteger(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::FalseType /*_binary*/) const + { + _in >> _value; + } + + //read and assign custom properties with the given type. Also creates property, if not exist + template + void readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const ValueType _valueType, const ValueType _listType) const; + + template + void readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listIndexType) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the PLY reader +extern _PLYReader_ __PLYReaderInstance; +OPENMESHDLLEXPORT _PLYReader_& PLYReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/STLReader.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/STLReader.hh new file mode 100644 index 0000000..78af039 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/reader/STLReader.hh @@ -0,0 +1,146 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements an reader module for STL files +// +//============================================================================= + + +#ifndef __STLREADER_HH__ +#define __STLREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include + +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +//== FORWARDS ================================================================= + +class BaseImporter; + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the STL format reader. This class is singleton'ed by + SingletonT to STLReader. +*/ +class OPENMESHDLLEXPORT _STLReader_ : public BaseReader +{ +public: + + // constructor + _STLReader_(); + + /// Destructor + virtual ~_STLReader_() {}; + + + std::string get_description() const override + { return "Stereolithography Interface Format"; } + std::string get_extensions() const override { return "stl stla stlb"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) override; + + bool read(std::istream& _in, + BaseImporter& _bi, + Options& _opt) override; + + /** Set the threshold to be used for considering two point to be equal. + Can be used to merge small gaps */ + void set_epsilon(float _eps) { eps_=_eps; } + + /// Returns the threshold to be used for considering two point to be equal. + float epsilon() const { return eps_; } + + + +private: + + enum STL_Type { STLA, STLB, NONE }; + STL_Type check_stl_type(const std::string& _filename) const; + + bool read_stla(const std::string& _filename, BaseImporter& _bi, Options& _opt) const; + bool read_stla(std::istream& _in, BaseImporter& _bi, Options& _opt) const; + bool read_stlb(const std::string& _filename, BaseImporter& _bi, Options& _opt) const; + bool read_stlb(std::istream& _in, BaseImporter& _bi, Options& _opt) const; + + +private: + + float eps_; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the STL reader +extern _STLReader_ __STLReaderInstance; +OPENMESHDLLEXPORT _STLReader_& STLReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/BaseWriter.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/BaseWriter.hh new file mode 100644 index 0000000..20babbb --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/BaseWriter.hh @@ -0,0 +1,152 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the baseclass for IOManager writer modules +// +//============================================================================= + + +#ifndef __BASEWRITER_HH__ +#define __BASEWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include + +// OpenMesh +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Base class for all writer modules. The module should register itself at + the IOManager by calling the register_module function. +*/ +class OPENMESHDLLEXPORT BaseWriter +{ +public: + + typedef unsigned int Option; + + /// Destructor + virtual ~BaseWriter() {}; + + /// Return short description of the supported file format. + virtual std::string get_description() const = 0; + + /// Return file format's extension. + virtual std::string get_extensions() const = 0; + + /** \brief Returns true if writer can write _filename (checks extension). + * _filename can also provide an extension without a name for a file e.g. _filename == "om" checks, if the writer can write the "om" extension + * @param _filename complete name of a file or just the extension + * @result true, if writer can write data with the given extension + */ + virtual bool can_u_write(const std::string& _filename) const; + + /** Write to a file + * @param _filename write to file with the given filename + * @param _be BaseExporter, which specifies the data source + * @param _writeOptions writing options + * @param _precision can be used to specify the precision of the floating point notation. + */ + virtual bool write(const std::string& _filename, + BaseExporter& _be, + const Options& _writeOptions, + std::streamsize _precision = 6) const = 0; + + /** Write to a std::ostream + * @param _os write to std::ostream + * @param _be BaseExporter, which specifies the data source + * @param _writeOptions writing options + * @param _precision can be used to specify the precision of the floating point notation. + */ + virtual bool write(std::ostream& _os, + BaseExporter& _be, + const Options& _writeOptions, + std::streamsize _precision = 6) const = 0; + + /// Returns expected size of file if binary format is supported else 0. + virtual size_t binary_size(BaseExporter&, const Options&) const { return 0; } + + + +protected: + + bool check(BaseExporter& _be, const Options& _writeOptions) const + { + // Check for all Options. When we want to write them (_opt.check() ) , they have to be available ( has_ ) + // Converts to not A (write them) or B (available) + return ( !_writeOptions.check(Options::VertexNormal ) || _be.has_vertex_normals()) + && ( !_writeOptions.check(Options::VertexTexCoord)|| _be.has_vertex_texcoords()) + && ( !_writeOptions.check(Options::VertexColor) || _be.has_vertex_colors()) + && ( !_writeOptions.check(Options::FaceNormal) || _be.has_face_normals()) + && ( !_writeOptions.check(Options::FaceColor) || _be.has_face_colors()); + } +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/OBJWriter.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/OBJWriter.hh new file mode 100644 index 0000000..e48b3ca --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/OBJWriter.hh @@ -0,0 +1,133 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements an IOManager writer module for OBJ files +// +//============================================================================= + + +#ifndef __OBJWRITER_HH__ +#define __OBJWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + This class defines the OBJ writer. This class is further singleton'ed + by SingletonT to OBJWriter. +*/ +class OPENMESHDLLEXPORT _OBJWriter_ : public BaseWriter +{ +public: + + _OBJWriter_(); + + /// Destructor + virtual ~_OBJWriter_() {}; + + std::string get_description() const override { return "Alias/Wavefront"; } + std::string get_extensions() const override { return "obj"; } + + bool write(const std::string&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter&, const Options&) const override { return 0; } + +private: + + mutable std::string path_; + mutable std::string objName_; + + mutable std::vector< OpenMesh::Vec3f > material_; + mutable std::map< OpenMesh::Vec3f, size_t> material_idx_; + mutable std::vector< OpenMesh::Vec4f > materialA_; + mutable std::map< OpenMesh::Vec4f, size_t> materialA_idx_; + + size_t getMaterial(OpenMesh::Vec3f _color) const; + + size_t getMaterial(OpenMesh::Vec4f _color) const; + + bool writeMaterial(std::ostream& _out, BaseExporter&, Options) const; + + +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OBJ writer +extern _OBJWriter_ __OBJWriterinstance; +OPENMESHDLLEXPORT _OBJWriter_& OBJWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/OFFWriter.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/OFFWriter.hh new file mode 100644 index 0000000..dca5bb9 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/OFFWriter.hh @@ -0,0 +1,133 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a writer module for OFF files +// +//============================================================================= + + +#ifndef __OFFWRITER_HH__ +#define __OFFWRITER_HH__ + + +//=== INCLUDES ================================================================ + +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the OFF format writer. This class is singleton'ed by + SingletonT to OFFWriter. + + By passing Options to the write function you can manipulate the writing behavoir. + The following options can be set: + + Binary + VertexNormal + VertexColor + VertexTexCoord + FaceColor + ColorAlpha + +*/ +class OPENMESHDLLEXPORT _OFFWriter_ : public BaseWriter +{ +public: + + _OFFWriter_(); + + virtual ~_OFFWriter_() {}; + + std::string get_description() const override { return "no description"; } + std::string get_extensions() const override { return "off"; } + + bool write(const std::string&, BaseExporter&, const Options&, std::streamsize _precision = 6) const override; + + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter& _be, const Options& _opt) const override; + + +protected: + void writeValue(std::ostream& _out, int value) const; + void writeValue(std::ostream& _out, unsigned int value) const; + void writeValue(std::ostream& _out, float value) const; + + bool write_ascii(std::ostream& _in, BaseExporter&, const Options& _writeOptions) const; + bool write_binary(std::ostream& _in, BaseExporter&, const Options& _writeOptions) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OFF writer. +extern _OFFWriter_ __OFFWriterInstance; +OPENMESHDLLEXPORT _OFFWriter_& OFFWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/OMWriter.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/OMWriter.hh new file mode 100644 index 0000000..083a69a --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/OMWriter.hh @@ -0,0 +1,142 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a writer module for OM files +// +//============================================================================= + + +#ifndef __OMWRITER_HH__ +#define __OMWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +//=== FORWARDS ================================================================ + + +class BaseExporter; + + +//=== IMPLEMENTATION ========================================================== + + +/** + * Implementation of the OM format writer. This class is singleton'ed by + * SingletonT to OMWriter. + */ +class OPENMESHDLLEXPORT _OMWriter_ : public BaseWriter +{ +public: + + /// Constructor + _OMWriter_(); + + /// Destructor + virtual ~_OMWriter_() {}; + + std::string get_description() const override + { return "OpenMesh Format"; } + + std::string get_extensions() const override + { return "om"; } + + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter& _be, const Options& _opt) const override; + + static OMFormat::uint8 get_version() { return version_; } + + +protected: + + static const OMFormat::uchar magic_[3]; + static const OMFormat::uint8 version_; + + bool write(const std::string&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + bool write_binary(std::ostream&, BaseExporter&, const Options& _writeOptions) const; + + + size_t store_binary_custom_chunk(std::ostream&, BaseProperty&, + OMFormat::Chunk::Entity, bool) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OM writer. +extern _OMWriter_ __OMWriterInstance; +OPENMESHDLLEXPORT _OMWriter_& OMWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/PLYWriter.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/PLYWriter.hh new file mode 100644 index 0000000..760e689 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/PLYWriter.hh @@ -0,0 +1,173 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a writer module for PLY files +// +//============================================================================= + + +#ifndef __PLYWRITER_HH__ +#define __PLYWRITER_HH__ + + +//=== INCLUDES ================================================================ + +#include +#include +#include + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the PLY format writer. This class is singleton'ed by + SingletonT to PLYWriter. + + currently supported options: + - VertexColors + - FaceColors + - Binary + - Binary -> MSB +*/ +class OPENMESHDLLEXPORT _PLYWriter_ : public BaseWriter +{ +public: + + _PLYWriter_(); + + /// Destructor + virtual ~_PLYWriter_() {}; + + std::string get_description() const override { return "PLY polygon file format"; } + std::string get_extensions() const override { return "ply"; } + + bool write(const std::string&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter& _be, const Options& _opt) const override; + + enum ValueType { + Unsupported = 0, + ValueTypeFLOAT32, ValueTypeFLOAT, + ValueTypeINT32, ValueTypeINT , ValueTypeUINT, + ValueTypeUCHAR, ValueTypeCHAR, ValueTypeUINT8, + ValueTypeUSHORT, ValueTypeSHORT, + ValueTypeDOUBLE + }; + +private: + mutable Options options_; + + struct CustomProperty + { + ValueType type; + const BaseProperty* property; + explicit CustomProperty(const BaseProperty* const _p):type(Unsupported),property(_p){} + }; + + const char* nameOfType_[12]; + + /// write custom persistant properties into the header for the current element, returns all properties, which were written sorted + std::vector writeCustomTypeHeader(std::ostream& _out, BaseKernel::const_prop_iterator _begin, BaseKernel::const_prop_iterator _end) const; + template + void write_customProp(std::ostream& _our, const CustomProperty& _prop, size_t _index) const; + template + void writeProxy(ValueType _type, std::ostream& _out, T _value, OpenMesh::GenProg::TrueType /*_binary*/) const + { + writeValue(_type, _out, _value); + } + template + void writeProxy(ValueType /*_type*/, std::ostream& _out, T _value, OpenMesh::GenProg::FalseType /*_binary*/) const + { + _out << " " << _value; + } + +protected: + void writeValue(ValueType _type, std::ostream& _out, signed char value) const; + void writeValue(ValueType _type, std::ostream& _out, unsigned char value) const; + void writeValue(ValueType _type, std::ostream& _out, short value) const; + void writeValue(ValueType _type, std::ostream& _out, unsigned short value) const; + void writeValue(ValueType _type, std::ostream& _out, int value) const; + void writeValue(ValueType _type, std::ostream& _out, unsigned int value) const; + void writeValue(ValueType _type, std::ostream& _out, float value) const; + void writeValue(ValueType _type, std::ostream& _out, double value) const; + + bool write_ascii(std::ostream& _out, BaseExporter&, Options) const; + bool write_binary(std::ostream& _out, BaseExporter&, Options) const; + /// write header into the stream _out. Returns custom properties (vertex and face) which are written into the header + void write_header(std::ostream& _out, BaseExporter& _be, Options& _opt, std::vector& _ovProps, std::vector& _ofProps) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the PLY writer. +extern _PLYWriter_ __PLYWriterInstance; +OPENMESHDLLEXPORT _PLYWriter_& PLYWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/STLWriter.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/STLWriter.hh new file mode 100644 index 0000000..b0cdb12 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/STLWriter.hh @@ -0,0 +1,121 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a writer module for STL ascii files +// +//============================================================================= + + +#ifndef __STLWRITER_HH__ +#define __STLWRITER_HH__ + + +//=== INCLUDES ================================================================ + +// -------------------- STL +#include +#include +// -------------------- OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the STL format writer. This class is singleton'ed by + SingletonT to STLWriter. +*/ +class OPENMESHDLLEXPORT _STLWriter_ : public BaseWriter +{ +public: + + _STLWriter_(); + + /// Destructor + virtual ~_STLWriter_() {}; + + std::string get_description() const override { return "Stereolithography Format"; } + std::string get_extensions() const override { return "stl stla stlb"; } + + bool write(const std::string&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter&, const Options&) const override; + +private: + bool write_stla(const std::string&, const BaseExporter&, Options) const; + bool write_stla(std::ostream&, const BaseExporter&, Options, std::streamsize _precision = 6) const; + bool write_stlb(const std::string&, const BaseExporter&, Options) const; + bool write_stlb(std::ostream&, const BaseExporter&, Options, std::streamsize _precision = 6) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +// Declare the single entity of STL writer. +extern _STLWriter_ __STLWriterInstance; +OPENMESHDLLEXPORT _STLWriter_& STLWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/VTKWriter.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/VTKWriter.hh new file mode 100644 index 0000000..8887a40 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/IO/writer/VTKWriter.hh @@ -0,0 +1,52 @@ +//============================================================================= +// +// Implements an IOManager writer module for VTK files +// +//============================================================================= + +#ifndef __VTKWRITER_HH__ +#define __VTKWRITER_HH__ + +//=== INCLUDES ================================================================ + +#include +#include + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + +//=== IMPLEMENTATION ========================================================== + +class OPENMESHDLLEXPORT _VTKWriter_ : public BaseWriter +{ +public: + _VTKWriter_(); + + std::string get_description() const override { return "VTK"; } + std::string get_extensions() const override { return "vtk"; } + + bool write(const std::string&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + bool write(std::ostream&, BaseExporter&, const Options& _writeOptions, std::streamsize _precision = 6) const override; + + size_t binary_size(BaseExporter&, const Options&) const override { return 0; } +}; + +//== TYPE DEFINITION ========================================================== + +/// Declare the single entity of the OBJ writer +extern _VTKWriter_ __VTKWriterinstance; +OPENMESHDLLEXPORT _VTKWriter_& VTKWriter(); + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/ArrayItems.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/ArrayItems.hh new file mode 100644 index 0000000..9031ba2 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/ArrayItems.hh @@ -0,0 +1,126 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_ARRAY_ITEMS_HH +#define OPENMESH_ARRAY_ITEMS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/// Definition of mesh items for use in the ArrayKernel +struct ArrayItems +{ + + //------------------------------------------------------ internal vertex type + + /// The vertex item + class Vertex + { + friend class ArrayKernel; + HalfedgeHandle halfedge_handle_; + }; + + + //---------------------------------------------------- internal halfedge type + +#ifndef DOXY_IGNORE_THIS + class Halfedge_without_prev + { + friend class ArrayKernel; + FaceHandle face_handle_; + VertexHandle vertex_handle_; + HalfedgeHandle next_halfedge_handle_; + }; +#endif + +#ifndef DOXY_IGNORE_THIS + class Halfedge_with_prev : public Halfedge_without_prev + { + friend class ArrayKernel; + HalfedgeHandle prev_halfedge_handle_; + }; +#endif + + //TODO: should be selected with config.h define + typedef Halfedge_with_prev Halfedge; + typedef Halfedge_without_prev HalfedgeNoPrev; + typedef GenProg::Bool2Type HasPrevHalfedge; + + //-------------------------------------------------------- internal edge type +#ifndef DOXY_IGNORE_THIS + class Edge + { + friend class ArrayKernel; + Halfedge halfedges_[2]; + }; +#endif + + //-------------------------------------------------------- internal face type +#ifndef DOXY_IGNORE_THIS + class Face + { + friend class ArrayKernel; + HalfedgeHandle halfedge_handle_; + }; +}; +#endif + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ITEMS_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/ArrayKernel.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/ArrayKernel.hh new file mode 100644 index 0000000..833519e --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/ArrayKernel.hh @@ -0,0 +1,913 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS ArrayKernel +// +//============================================================================= + + +#ifndef OPENMESH_ARRAY_KERNEL_HH +#define OPENMESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= +#include + +#include +#include + +#include +#include +#include + +//== NAMESPACES =============================================================== +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= +/** \ingroup mesh_kernels_group + + Mesh kernel using arrays for mesh item storage. + + This mesh kernel uses the std::vector as container to store the + mesh items. Therefore all handle types are internally represented + by integers. To get the index from a handle use the handle's \c + idx() method. + + \note For a description of the minimal kernel interface see + OpenMesh::Mesh::BaseKernel. + \note You do not have to use this class directly, use the predefined + mesh-kernel combinations in \ref mesh_types_group. + \see OpenMesh::Concepts::KernelT, \ref mesh_type +*/ + +class OPENMESHDLLEXPORT ArrayKernel : public BaseKernel, public ArrayItems +{ +public: + + // handles + typedef OpenMesh::VertexHandle VertexHandle; + typedef OpenMesh::HalfedgeHandle HalfedgeHandle; + typedef OpenMesh::EdgeHandle EdgeHandle; + typedef OpenMesh::FaceHandle FaceHandle; + typedef Attributes::StatusInfo StatusInfo; + typedef VPropHandleT VertexStatusPropertyHandle; + typedef HPropHandleT HalfedgeStatusPropertyHandle; + typedef EPropHandleT EdgeStatusPropertyHandle; + typedef FPropHandleT FaceStatusPropertyHandle; + +public: + + // --- constructor/destructor --- + ArrayKernel(); + virtual ~ArrayKernel(); + + /** ArrayKernel uses the default copy constructor and assignment operator, which means + that the connectivity and all properties are copied, including reference + counters, allocated bit status masks, etc.. In contrast assign_connectivity + copies only the connectivity, i.e. vertices, edges, faces and their status fields. + NOTE: The geometry (the points property) is NOT copied. Poly/TriConnectivity + override(and hide) that function to provide connectivity consistence.*/ + void assign_connectivity(const ArrayKernel& _other); + + // --- handle -> item --- + VertexHandle handle(const Vertex& _v) const; + + HalfedgeHandle handle(const Halfedge& _he) const; + + EdgeHandle handle(const Edge& _e) const; + + FaceHandle handle(const Face& _f) const; + + + ///checks handle validity - useful for debugging + bool is_valid_handle(VertexHandle _vh) const; + + ///checks handle validity - useful for debugging + bool is_valid_handle(HalfedgeHandle _heh) const; + + ///checks handle validity - useful for debugging + bool is_valid_handle(EdgeHandle _eh) const; + + ///checks handle validity - useful for debugging + bool is_valid_handle(FaceHandle _fh) const; + + + // --- item -> handle --- + const Vertex& vertex(VertexHandle _vh) const + { + assert(is_valid_handle(_vh)); + return vertices_[_vh.idx()]; + } + + Vertex& vertex(VertexHandle _vh) + { + assert(is_valid_handle(_vh)); + return vertices_[_vh.idx()]; + } + + const Halfedge& halfedge(HalfedgeHandle _heh) const + { + assert(is_valid_handle(_heh)); + return edges_[_heh.idx() >> 1].halfedges_[_heh.idx() & 1]; + } + + Halfedge& halfedge(HalfedgeHandle _heh) + { + assert(is_valid_handle(_heh)); + return edges_[_heh.idx() >> 1].halfedges_[_heh.idx() & 1]; + } + + const Edge& edge(EdgeHandle _eh) const + { + assert(is_valid_handle(_eh)); + return edges_[_eh.idx()]; + } + + Edge& edge(EdgeHandle _eh) + { + assert(is_valid_handle(_eh)); + return edges_[_eh.idx()]; + } + + const Face& face(FaceHandle _fh) const + { + assert(is_valid_handle(_fh)); + return faces_[_fh.idx()]; + } + + Face& face(FaceHandle _fh) + { + assert(is_valid_handle(_fh)); + return faces_[_fh.idx()]; + } + + // --- get i'th items --- + + VertexHandle vertex_handle(unsigned int _i) const + { return (_i < n_vertices()) ? handle( vertices_[_i] ) : VertexHandle(); } + + HalfedgeHandle halfedge_handle(unsigned int _i) const + { + return (_i < n_halfedges()) ? + halfedge_handle(edge_handle(_i/2), _i%2) : HalfedgeHandle(); + } + + EdgeHandle edge_handle(unsigned int _i) const + { return (_i < n_edges()) ? handle(edges_[_i]) : EdgeHandle(); } + + FaceHandle face_handle(unsigned int _i) const + { return (_i < n_faces()) ? handle(faces_[_i]) : FaceHandle(); } + +public: + + /** + * \brief Add a new vertex. + * + * If you are rebuilding a mesh that you previously erased using clean() or + * clean_keep_reservation() you probably want to use new_vertex_dirty() + * instead. + * + * \sa new_vertex_dirty() + */ + inline VertexHandle new_vertex() + { + vertices_.push_back(Vertex()); + vprops_resize(n_vertices());//TODO:should it be push_back()? + + return handle(vertices_.back()); + } + + /** + * Same as new_vertex() but uses PropertyContainer::resize_if_smaller() to + * resize the vertex property container. + * + * If you are rebuilding a mesh that you erased with clean() or + * clean_keep_reservation() using this method instead of new_vertex() saves + * reallocation and reinitialization of property memory. + * + * \sa new_vertex() + */ + inline VertexHandle new_vertex_dirty() + { + vertices_.push_back(Vertex()); + vprops_resize_if_smaller(n_vertices());//TODO:should it be push_back()? + + return handle(vertices_.back()); + } + + inline HalfedgeHandle new_edge(VertexHandle _start_vh, VertexHandle _end_vh) + { +// assert(_start_vh != _end_vh); + edges_.push_back(Edge()); + eprops_resize(n_edges());//TODO:should it be push_back()? + hprops_resize(n_halfedges());//TODO:should it be push_back()? + + EdgeHandle eh(handle(edges_.back())); + HalfedgeHandle heh0(halfedge_handle(eh, 0)); + HalfedgeHandle heh1(halfedge_handle(eh, 1)); + set_vertex_handle(heh0, _end_vh); + set_vertex_handle(heh1, _start_vh); + return heh0; + } + + inline FaceHandle new_face() + { + faces_.push_back(Face()); + fprops_resize(n_faces()); + return handle(faces_.back()); + } + + inline FaceHandle new_face(const Face& _f) + { + faces_.push_back(_f); + fprops_resize(n_faces()); + return handle(faces_.back()); + } + +public: + // --- resize/reserve --- + void resize( size_t _n_vertices, size_t _n_edges, size_t _n_faces ); + void reserve(size_t _n_vertices, size_t _n_edges, size_t _n_faces ); + + // --- deletion --- + /** \brief garbage collection + * + * Usually if you delete primitives in OpenMesh, they are only flagged as deleted. + * Only when you call garbage collection, they will be actually removed. + * + * \note Garbage collection invalidates all handles. If you need to keep track of + * a set of handles, you can pass them to the second garbage collection + * function, which will update a vector of handles. + * See also \ref deletedElements. + * + * @param _v Remove deleted vertices? + * @param _e Remove deleted edges? + * @param _f Remove deleted faces? + * + */ + void garbage_collection(bool _v=true, bool _e=true, bool _f=true); + + /** \brief garbage collection with handle tracking + * + * Usually if you delete primitives in OpenMesh, they are only flagged as deleted. + * Only when you call garbage collection, they will be actually removed. + * + * \note Garbage collection invalidates all handles. If you need to keep track of + * a set of handles, you can pass them to this function. The handles that the + * given pointers point to are updated in place. Warning: You cannot update + * handles stored in a mesh property, as the memory might be moved + * during garbage collection! + * See also \ref deletedElements. + * + * @param vh_to_update Pointers to vertex handles that should get updated + * @param hh_to_update Pointers to halfedge handles that should get updated + * @param fh_to_update Pointers to face handles that should get updated + * @param _v Remove deleted vertices? + * @param _e Remove deleted edges? + * @param _f Remove deleted faces? + */ + template + void garbage_collection(std_API_Container_VHandlePointer& vh_to_update, + std_API_Container_HHandlePointer& hh_to_update, + std_API_Container_FHandlePointer& fh_to_update, + bool _v=true, bool _e=true, bool _f=true); + + /// \brief Does the same as clean() and in addition erases all properties. + void clear(); + + /** \brief Remove all vertices, edges and faces and deallocates their memory. + * + * In contrast to clear() this method does neither erases the properties + * nor clears the property vectors. Depending on how you add any new entities + * to the mesh after calling this method, your properties will be initialized + * with old values. + * + * \sa clean_keep_reservation() + */ + void clean(); + + /** \brief Remove all vertices, edges and faces but keep memory allocated. + * + * This method behaves like clean() (also regarding the properties) but + * leaves the memory used for vertex, edge and face storage allocated. This + * leads to no reduction in memory consumption but allows for faster + * performance when rebuilding the mesh. + */ + void clean_keep_reservation(); + + // --- number of items --- + size_t n_vertices() const override { return vertices_.size(); } + size_t n_halfedges() const override { return 2*edges_.size(); } + size_t n_edges() const override { return edges_.size(); } + size_t n_faces() const override { return faces_.size(); } + + bool vertices_empty() const { return vertices_.empty(); } + bool halfedges_empty() const { return edges_.empty(); } + bool edges_empty() const { return edges_.empty(); } + bool faces_empty() const { return faces_.empty(); } + + // --- vertex connectivity --- + + HalfedgeHandle halfedge_handle(VertexHandle _vh) const + { return vertex(_vh).halfedge_handle_; } + + void set_halfedge_handle(VertexHandle _vh, HalfedgeHandle _heh) + { +// assert(is_valid_handle(_heh)); + vertex(_vh).halfedge_handle_ = _heh; + } + + bool is_isolated(VertexHandle _vh) const + { return !halfedge_handle(_vh).is_valid(); } + + void set_isolated(VertexHandle _vh) + { vertex(_vh).halfedge_handle_.invalidate(); } + + unsigned int delete_isolated_vertices(); + + // --- halfedge connectivity --- + VertexHandle to_vertex_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).vertex_handle_; } + + VertexHandle from_vertex_handle(HalfedgeHandle _heh) const + { return to_vertex_handle(opposite_halfedge_handle(_heh)); } + + void set_vertex_handle(HalfedgeHandle _heh, VertexHandle _vh) + { +// assert(is_valid_handle(_vh)); + halfedge(_heh).vertex_handle_ = _vh; + } + + FaceHandle face_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).face_handle_; } + + void set_face_handle(HalfedgeHandle _heh, FaceHandle _fh) + { +// assert(is_valid_handle(_fh)); + halfedge(_heh).face_handle_ = _fh; + } + + void set_boundary(HalfedgeHandle _heh) + { halfedge(_heh).face_handle_.invalidate(); } + + /// Is halfedge _heh a boundary halfedge (is its face handle invalid) ? + bool is_boundary(HalfedgeHandle _heh) const + { return !face_handle(_heh).is_valid(); } + + HalfedgeHandle next_halfedge_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).next_halfedge_handle_; } + + void set_next_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _nheh) + { + assert(is_valid_handle(_nheh)); +// assert(to_vertex_handle(_heh) == from_vertex_handle(_nheh)); + halfedge(_heh).next_halfedge_handle_ = _nheh; + set_prev_halfedge_handle(_nheh, _heh); + } + + + void set_prev_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _pheh) + { + assert(is_valid_handle(_pheh)); + set_prev_halfedge_handle(_heh, _pheh, HasPrevHalfedge()); + } + + void set_prev_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _pheh, + GenProg::TrueType) + { halfedge(_heh).prev_halfedge_handle_ = _pheh; } + + void set_prev_halfedge_handle(HalfedgeHandle /* _heh */, HalfedgeHandle /* _pheh */, + GenProg::FalseType) + {} + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh) const + { return prev_halfedge_handle(_heh, HasPrevHalfedge() ); } + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh, GenProg::TrueType) const + { return halfedge(_heh).prev_halfedge_handle_; } + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh, GenProg::FalseType) const + { + if (is_boundary(_heh)) + {//iterating around the vertex should be faster than iterating the boundary + HalfedgeHandle curr_heh(opposite_halfedge_handle(_heh)); + HalfedgeHandle next_heh(next_halfedge_handle(curr_heh)); + do + { + curr_heh = opposite_halfedge_handle(next_heh); + next_heh = next_halfedge_handle(curr_heh); + } + while (next_heh != _heh); + return curr_heh; + } + else + { + HalfedgeHandle heh(_heh); + HalfedgeHandle next_heh(next_halfedge_handle(heh)); + while (next_heh != _heh) { + heh = next_heh; + next_heh = next_halfedge_handle(next_heh); + } + return heh; + } + } + + + HalfedgeHandle opposite_halfedge_handle(HalfedgeHandle _heh) const + { return HalfedgeHandle(_heh.idx() ^ 1); } + + + HalfedgeHandle ccw_rotated_halfedge_handle(HalfedgeHandle _heh) const + { return opposite_halfedge_handle(prev_halfedge_handle(_heh)); } + + + HalfedgeHandle cw_rotated_halfedge_handle(HalfedgeHandle _heh) const + { return next_halfedge_handle(opposite_halfedge_handle(_heh)); } + + // --- edge connectivity --- + static HalfedgeHandle s_halfedge_handle(EdgeHandle _eh, unsigned int _i = 0) + { + assert(_i<=1); + return HalfedgeHandle((_eh.idx() << 1) + _i); + } + + static EdgeHandle s_edge_handle(HalfedgeHandle _heh) + { return EdgeHandle(_heh.idx() >> 1); } + + HalfedgeHandle halfedge_handle(EdgeHandle _eh, unsigned int _i = 0) const + { + return s_halfedge_handle(_eh, _i); + } + + EdgeHandle edge_handle(HalfedgeHandle _heh) const + { return s_edge_handle(_heh); } + + // --- face connectivity --- + HalfedgeHandle halfedge_handle(FaceHandle _fh) const + { return face(_fh).halfedge_handle_; } + + void set_halfedge_handle(FaceHandle _fh, HalfedgeHandle _heh) + { +// assert(is_valid_handle(_heh)); + face(_fh).halfedge_handle_ = _heh; + } + + /// Status Query API + //------------------------------------------------------------ vertex status + const StatusInfo& status(VertexHandle _vh) const + { return property(vertex_status_, _vh); } + + StatusInfo& status(VertexHandle _vh) + { return property(vertex_status_, _vh); } + + /** + * Reinitializes the status of all vertices using the StatusInfo default + * constructor, i.e. all flags will be set to false. + */ + void reset_status() { + PropertyT &status_prop = property(vertex_status_); + PropertyT::vector_type &sprop_v = status_prop.data_vector(); + std::fill(sprop_v.begin(), sprop_v.begin() + n_vertices(), StatusInfo()); + } + + //----------------------------------------------------------- halfedge status + const StatusInfo& status(HalfedgeHandle _hh) const + { return property(halfedge_status_, _hh); } + + StatusInfo& status(HalfedgeHandle _hh) + { return property(halfedge_status_, _hh); } + + //--------------------------------------------------------------- edge status + const StatusInfo& status(EdgeHandle _eh) const + { return property(edge_status_, _eh); } + + StatusInfo& status(EdgeHandle _eh) + { return property(edge_status_, _eh); } + + //--------------------------------------------------------------- face status + const StatusInfo& status(FaceHandle _fh) const + { return property(face_status_, _fh); } + + StatusInfo& status(FaceHandle _fh) + { return property(face_status_, _fh); } + + inline bool has_vertex_status() const + { return vertex_status_.is_valid(); } + + inline bool has_halfedge_status() const + { return halfedge_status_.is_valid(); } + + inline bool has_edge_status() const + { return edge_status_.is_valid(); } + + inline bool has_face_status() const + { return face_status_.is_valid(); } + + inline VertexStatusPropertyHandle vertex_status_pph() const + { return vertex_status_; } + + inline HalfedgeStatusPropertyHandle halfedge_status_pph() const + { return halfedge_status_; } + + inline EdgeStatusPropertyHandle edge_status_pph() const + { return edge_status_; } + + inline FaceStatusPropertyHandle face_status_pph() const + { return face_status_; } + + /// status property by handle + inline VertexStatusPropertyHandle status_pph(VertexHandle /*_hnd*/) const + { return vertex_status_pph(); } + + inline HalfedgeStatusPropertyHandle status_pph(HalfedgeHandle /*_hnd*/) const + { return halfedge_status_pph(); } + + inline EdgeStatusPropertyHandle status_pph(EdgeHandle /*_hnd*/) const + { return edge_status_pph(); } + + inline FaceStatusPropertyHandle status_pph(FaceHandle /*_hnd*/) const + { return face_status_pph(); } + + /// Status Request API + void request_vertex_status() + { + if (!refcount_vstatus_++) + add_property( vertex_status_, "v:status" ); + } + + void request_halfedge_status() + { + if (!refcount_hstatus_++) + add_property( halfedge_status_, "h:status" ); + } + + void request_edge_status() + { + if (!refcount_estatus_++) + add_property( edge_status_, "e:status" ); + } + + void request_face_status() + { + if (!refcount_fstatus_++) + add_property( face_status_, "f:status" ); + } + + /// Status Release API + void release_vertex_status() + { + if ((refcount_vstatus_ > 0) && (! --refcount_vstatus_)) + remove_property(vertex_status_); + } + + void release_halfedge_status() + { + if ((refcount_hstatus_ > 0) && (! --refcount_hstatus_)) + remove_property(halfedge_status_); + } + + void release_edge_status() + { + if ((refcount_estatus_ > 0) && (! --refcount_estatus_)) + remove_property(edge_status_); + } + + void release_face_status() + { + if ((refcount_fstatus_ > 0) && (! --refcount_fstatus_)) + remove_property(face_status_); + } + + /// --- StatusSet API --- + + /*! + Implements a set of connectivity entities (vertex, edge, face, halfedge) + using the available bits in the corresponding mesh status field. + + Status-based sets are much faster than std::set<> and equivalent + in performance to std::vector, but much more convenient. + */ + template + class StatusSetT + { + public: + typedef HandleT Handle; + + protected: + ArrayKernel& kernel_; + + public: + const unsigned int bit_mask_; + + public: + StatusSetT(ArrayKernel& _kernel, const unsigned int _bit_mask) + : kernel_(_kernel), bit_mask_(_bit_mask) + {} + + ~StatusSetT() + {} + + inline bool is_in(Handle _hnd) const + { return kernel_.status(_hnd).is_bit_set(bit_mask_); } + + inline void insert(Handle _hnd) + { kernel_.status(_hnd).set_bit(bit_mask_); } + + inline void erase(Handle _hnd) + { kernel_.status(_hnd).unset_bit(bit_mask_); } + + //! Note: 0(n) complexity + size_t size() const + { + const int n = kernel_.status_pph(Handle()).is_valid() ? + (int)kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; + + size_t sz = 0; + for (int i = 0; i < n; ++i) + sz += (size_t)is_in(Handle(i)); + return sz; + } + + //! Note: O(n) complexity + void clear() + { + const int n = kernel_.status_pph(Handle()).is_valid() ? + (int)kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; + + for (int i = 0; i < n; ++i) + erase(Handle(i)); + } + }; + + friend class StatusSetT; + friend class StatusSetT; + friend class StatusSetT; + friend class StatusSetT; + + //! AutoStatusSetT: A status set that automatically picks a status bit + template + class AutoStatusSetT : public StatusSetT + { + private: + typedef HandleT Handle; + typedef StatusSetT Base; + + public: + explicit AutoStatusSetT(ArrayKernel& _kernel) + : StatusSetT(_kernel, _kernel.pop_bit_mask(Handle())) + { /*assert(size() == 0);*/ } //the set should be empty on creation + + ~AutoStatusSetT() + { + //assert(size() == 0);//the set should be empty on leave? + Base::kernel_.push_bit_mask(Handle(), Base::bit_mask_); + } + }; + + friend class AutoStatusSetT; + friend class AutoStatusSetT; + friend class AutoStatusSetT; + friend class AutoStatusSetT; + + typedef AutoStatusSetT VertexStatusSet; + typedef AutoStatusSetT EdgeStatusSet; + typedef AutoStatusSetT FaceStatusSet; + typedef AutoStatusSetT HalfedgeStatusSet; + + //! ExtStatusSet: A status set augmented with an array + template + class ExtStatusSetT : public AutoStatusSetT + { + public: + typedef HandleT Handle; + typedef AutoStatusSetT Base; + + protected: + typedef std::vector HandleContainer; + HandleContainer handles_; + + public: + typedef typename HandleContainer::iterator + iterator; + typedef typename HandleContainer::const_iterator + const_iterator; + public: + explicit ExtStatusSetT(ArrayKernel& _kernel, size_t _capacity_hint = 0) + : Base(_kernel) + { handles_.reserve(_capacity_hint); } + + ~ExtStatusSetT() + { Base::clear(); } + + // Complexity: O(1) + inline void insert(Handle _hnd) + { + if (!Base::is_in(_hnd)) + { + Base::insert(_hnd); + handles_.push_back(_hnd); + } + } + + //! Complexity: O(k), (k - number of the elements in the set) + inline void erase(Handle _hnd) + { + if (is_in(_hnd)) + { + iterator it = std::find(begin(), end(), _hnd); + erase(it); + } + } + + //! Complexity: O(1) + inline void erase(iterator _it) + { + assert(_it != const_cast(this)->end() && + Base::is_in(*_it)); + Base::erase(*_it); + *_it = handles_.back(); + _it.pop_back(); + } + + inline void clear() + { + for (iterator it = begin(); it != end(); ++it) + { + assert(Base::is_in(*it)); + Base::erase(*it); + } + handles_.clear(); + } + + /// Complexity: 0(1) + inline unsigned int size() const + { return handles_.size(); } + inline bool empty() const + { return handles_.empty(); } + + //Vector API + inline iterator begin() + { return handles_.begin(); } + inline const_iterator begin() const + { return handles_.begin(); } + + inline iterator end() + { return handles_.end(); } + inline const_iterator end() const + { return handles_.end(); } + + inline Handle& front() + { return handles_.front(); } + inline const Handle& front() const + { return handles_.front(); } + + inline Handle& back() + { return handles_.back(); } + inline const Handle& back() const + { return handles_.back(); } + }; + + typedef ExtStatusSetT ExtFaceStatusSet; + typedef ExtStatusSetT ExtVertexStatusSet; + typedef ExtStatusSetT ExtEdgeStatusSet; + typedef ExtStatusSetT ExtHalfedgeStatusSet; + +private: + // iterators + typedef std::vector VertexContainer; + typedef std::vector EdgeContainer; + typedef std::vector FaceContainer; + typedef VertexContainer::iterator KernelVertexIter; + typedef VertexContainer::const_iterator KernelConstVertexIter; + typedef EdgeContainer::iterator KernelEdgeIter; + typedef EdgeContainer::const_iterator KernelConstEdgeIter; + typedef FaceContainer::iterator KernelFaceIter; + typedef FaceContainer::const_iterator KernelConstFaceIter; + typedef std::vector BitMaskContainer; + + + KernelVertexIter vertices_begin() { return vertices_.begin(); } + KernelConstVertexIter vertices_begin() const { return vertices_.begin(); } + KernelVertexIter vertices_end() { return vertices_.end(); } + KernelConstVertexIter vertices_end() const { return vertices_.end(); } + + KernelEdgeIter edges_begin() { return edges_.begin(); } + KernelConstEdgeIter edges_begin() const { return edges_.begin(); } + KernelEdgeIter edges_end() { return edges_.end(); } + KernelConstEdgeIter edges_end() const { return edges_.end(); } + + KernelFaceIter faces_begin() { return faces_.begin(); } + KernelConstFaceIter faces_begin() const { return faces_.begin(); } + KernelFaceIter faces_end() { return faces_.end(); } + KernelConstFaceIter faces_end() const { return faces_.end(); } + + /// bit mask container by handle + inline BitMaskContainer& bit_masks(VertexHandle /*_dummy_hnd*/) + { return vertex_bit_masks_; } + inline BitMaskContainer& bit_masks(EdgeHandle /*_dummy_hnd*/) + { return edge_bit_masks_; } + inline BitMaskContainer& bit_masks(FaceHandle /*_dummy_hnd*/) + { return face_bit_masks_; } + inline BitMaskContainer& bit_masks(HalfedgeHandle /*_dummy_hnd*/) + { return halfedge_bit_masks_; } + + template + unsigned int pop_bit_mask(Handle _hnd) + { + assert(!bit_masks(_hnd).empty());//check if the client request too many status sets + unsigned int bit_mask = bit_masks(_hnd).back(); + bit_masks(_hnd).pop_back(); + return bit_mask; + } + + template + void push_bit_mask(Handle _hnd, unsigned int _bit_mask) + { + assert(std::find(bit_masks(_hnd).begin(), bit_masks(_hnd).end(), _bit_mask) == + bit_masks(_hnd).end());//this mask should be not already used + bit_masks(_hnd).push_back(_bit_mask); + } + + void init_bit_masks(BitMaskContainer& _bmc); + void init_bit_masks(); + +protected: + + VertexStatusPropertyHandle vertex_status_; + HalfedgeStatusPropertyHandle halfedge_status_; + EdgeStatusPropertyHandle edge_status_; + FaceStatusPropertyHandle face_status_; + + unsigned int refcount_vstatus_; + unsigned int refcount_hstatus_; + unsigned int refcount_estatus_; + unsigned int refcount_fstatus_; + +private: + VertexContainer vertices_; + EdgeContainer edges_; + FaceContainer faces_; + + BitMaskContainer halfedge_bit_masks_; + BitMaskContainer edge_bit_masks_; + BitMaskContainer vertex_bit_masks_; + BitMaskContainer face_bit_masks_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_ARRAY_KERNEL_C) +# define OPENMESH_ARRAY_KERNEL_TEMPLATES +# include "ArrayKernelT_impl.hh" +#endif +//============================================================================= +#endif // OPENMESH_ARRAY_KERNEL_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/ArrayKernelT_impl.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/ArrayKernelT_impl.hh new file mode 100644 index 0000000..2a8a156 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/ArrayKernelT_impl.hh @@ -0,0 +1,308 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#define OPENMESH_ARRAY_KERNEL_C + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh +{ + +//== IMPLEMENTATION ========================================================== + +template +void ArrayKernel::garbage_collection(std_API_Container_VHandlePointer& vh_to_update, + std_API_Container_HHandlePointer& hh_to_update, + std_API_Container_FHandlePointer& fh_to_update, + bool _v, bool _e, bool _f) +{ + +#ifdef DEBUG + #ifndef OM_GARBAGE_NO_STATUS_WARNING + if ( !this->has_vertex_status() ) + omerr() << "garbage_collection: No vertex status available. You can request it: mesh.request_vertex_status() or define OM_GARBAGE_NO_STATUS_WARNING to silence this warning." << std::endl; + if ( !this->has_edge_status() ) + omerr() << "garbage_collection: No edge status available. You can request it: mesh.request_edge_status() or define OM_GARBAGE_NO_STATUS_WARNING to silence this warning." << std::endl; + if ( !this->has_face_status() ) + omerr() << "garbage_collection: No face status available. You can request it: mesh.request_face_status() or define OM_GARBAGE_NO_STATUS_WARNING to silence this warning." << std::endl; + #endif +#endif + + const bool track_vhandles = ( !vh_to_update.empty() ); + const bool track_hhandles = ( !hh_to_update.empty() ); + const bool track_fhandles = ( !fh_to_update.empty() ); + + int i, i0, i1; + + int nV = int(n_vertices()); + int nE = int(n_edges()); + int nH = int(2*n_edges()); + int nF = (int(n_faces())); + + std::vector vh_map; + std::vector hh_map; + std::vector fh_map; + + std::map vertex_inverse_map; + std::map halfedge_inverse_map; + std::map face_inverse_map; + + // setup handle mapping: + vh_map.reserve(nV); + for (i=0; i 0 && this->has_vertex_status() ) + { + i0=0; i1=nV-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(VertexHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(VertexHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // If we keep track of the vertex handles for updates, + // we need to have the opposite direction + if ( track_vhandles ) { + vertex_inverse_map[i1] = i0; + vertex_inverse_map[i0] = -1; + } + + // swap + std::swap(vertices_[i0], vertices_[i1]); + std::swap(vh_map[i0], vh_map[i1]); + vprops_swap(i0, i1); + }; + + vertices_.resize(status(VertexHandle(i0)).deleted() ? i0 : i0+1); + vprops_resize(n_vertices()); + } + + + // remove deleted edges + if (_e && n_edges() > 0 && this->has_edge_status() ) + { + i0=0; i1=nE-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(EdgeHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(EdgeHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // If we keep track of the vertex handles for updates, + // we need to have the opposite direction + if ( track_hhandles ) { + halfedge_inverse_map[2*i1] = 2 * i0; + halfedge_inverse_map[2*i0] = -1; + + halfedge_inverse_map[2*i1 + 1] = 2 * i0 + 1; + halfedge_inverse_map[2*i0 + 1] = -1; + } + + // swap + std::swap(edges_[i0], edges_[i1]); + std::swap(hh_map[2*i0], hh_map[2*i1]); + std::swap(hh_map[2*i0+1], hh_map[2*i1+1]); + eprops_swap(i0, i1); + hprops_swap(2*i0, 2*i1); + hprops_swap(2*i0+1, 2*i1+1); + }; + + edges_.resize(status(EdgeHandle(i0)).deleted() ? i0 : i0+1); + eprops_resize(n_edges()); + hprops_resize(n_halfedges()); + } + + + // remove deleted faces + if (_f && n_faces() > 0 && this->has_face_status() ) + { + i0=0; i1=nF-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(FaceHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(FaceHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // If we keep track of the face handles for updates, + // we need to have the opposite direction + if ( track_fhandles ) { + face_inverse_map[i1] = i0; + face_inverse_map[i0] = -1; + } + + // swap + std::swap(faces_[i0], faces_[i1]); + std::swap(fh_map[i0], fh_map[i1]); + fprops_swap(i0, i1); + }; + + faces_.resize(status(FaceHandle(i0)).deleted() ? i0 : i0+1); + fprops_resize(n_faces()); + } + + + // update handles of vertices + if (_e) + { + KernelVertexIter v_it(vertices_begin()), v_end(vertices_end()); + VertexHandle vh; + + for (; v_it!=v_end; ++v_it) + { + vh = handle(*v_it); + if (!is_isolated(vh)) + { + set_halfedge_handle(vh, hh_map[halfedge_handle(vh).idx()]); + } + } + } + + HalfedgeHandle hh; + // update handles of halfedges + for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) + {//in the first pass update the (half)edges vertices + hh = halfedge_handle(handle(*e_it), 0); + set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); + hh = halfedge_handle(handle(*e_it), 1); + set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); + } + for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) + {//in the second pass update the connectivity of the (half)edges + hh = halfedge_handle(handle(*e_it), 0); + set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); + if (!is_boundary(hh)) + { + set_face_handle(hh, fh_map[face_handle(hh).idx()]); + } + hh = halfedge_handle(handle(*e_it), 1); + set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); + if (!is_boundary(hh)) + { + set_face_handle(hh, fh_map[face_handle(hh).idx()]); + } + } + + // update handles of faces + if (_e) + { + KernelFaceIter f_it(faces_begin()), f_end(faces_end()); + FaceHandle fh; + + for (; f_it!=f_end; ++f_it) + { + fh = handle(*f_it); + set_halfedge_handle(fh, hh_map[halfedge_handle(fh).idx()]); + } + } + + const int vertexCount = int(vertices_.size()); + const int halfedgeCount = int(edges_.size() * 2); + const int faceCount = int(faces_.size()); + + // Update the vertex handles in the vertex handle vector + typename std_API_Container_VHandlePointer::iterator v_it(vh_to_update.begin()), v_it_end(vh_to_update.end()); + for(; v_it != v_it_end; ++v_it) + { + + // Only changed vertices need to be considered + if ( (*v_it)->idx() != vh_map[(*v_it)->idx()].idx() ) { + *(*v_it) = VertexHandle(vertex_inverse_map[(*v_it)->idx()]); + + // Vertices above the vertex count have to be already mapped, or they are invalid now! + } else if ( ((*v_it)->idx() >= vertexCount) && (vertex_inverse_map.find((*v_it)->idx()) == vertex_inverse_map.end()) ) { + (*v_it)->invalidate(); + } + + } + + // Update the halfedge handles in the halfedge handle vector + typename std_API_Container_HHandlePointer::iterator hh_it(hh_to_update.begin()), hh_it_end(hh_to_update.end()); + for(; hh_it != hh_it_end; ++hh_it) + { + // Only changed faces need to be considered + if ( (*hh_it)->idx() != hh_map[(*hh_it)->idx()].idx() ) { + *(*hh_it) = HalfedgeHandle(halfedge_inverse_map[(*hh_it)->idx()]); + + // Vertices above the face count have to be already mapped, or they are invalid now! + } else if ( ((*hh_it)->idx() >= halfedgeCount) && (halfedge_inverse_map.find((*hh_it)->idx()) == halfedge_inverse_map.end()) ) { + (*hh_it)->invalidate(); + } + + } + + // Update the face handles in the face handle vector + typename std_API_Container_FHandlePointer::iterator fh_it(fh_to_update.begin()), fh_it_end(fh_to_update.end()); + for(; fh_it != fh_it_end; ++fh_it) + { + + // Only changed faces need to be considered + if ( (*fh_it)->idx() != fh_map[(*fh_it)->idx()].idx() ) { + *(*fh_it) = FaceHandle(face_inverse_map[(*fh_it)->idx()]); + + // Vertices above the face count have to be already mapped, or they are invalid now! + } else if ( ((*fh_it)->idx() >= faceCount) && (face_inverse_map.find((*fh_it)->idx()) == face_inverse_map.end()) ) { + (*fh_it)->invalidate(); + } + + } +} + +} + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/AttribKernelT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/AttribKernelT.hh new file mode 100644 index 0000000..125be37 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/AttribKernelT.hh @@ -0,0 +1,792 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_ATTRIBKERNEL_HH +#define OPENMESH_ATTRIBKERNEL_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/** \class AttribKernelT AttribKernelT.hh + + The attribute kernel adds all standard properties to the kernel. Therefore + the functions/types defined here provide a subset of the kernel + interface as described in Concepts::KernelT. + + \see Concepts::KernelT +*/ +template +class AttribKernelT : public Connectivity +{ +public: + + //---------------------------------------------------------------- item types + + enum Attribs { + VAttribs = MeshItems::VAttribs, + HAttribs = MeshItems::HAttribs, + EAttribs = MeshItems::EAttribs, + FAttribs = MeshItems::FAttribs + }; + + typedef MeshItems MeshItemsT; + typedef Connectivity ConnectivityT; + typedef typename Connectivity::Vertex Vertex; + + //Define Halfedge based on PrevHalfedge. + typedef typename GenProg::IF< + (bool)(HAttribs & Attributes::PrevHalfedge), + typename Connectivity::Halfedge, + typename Connectivity::HalfedgeNoPrev + >::Result Halfedge; + typedef typename GenProg::IF< + (bool)(HAttribs & Attributes::PrevHalfedge), + GenProg::Bool2Type, + GenProg::Bool2Type + >::Result HasPrevHalfedge; + + //typedef typename Connectivity::Halfedge Halfedge; + typedef typename Connectivity::Edge Edge; + typedef typename Connectivity::Face Face; + + typedef typename MeshItems::Point Point; + typedef typename MeshItems::Normal Normal; + typedef typename MeshItems::Color Color; + typedef typename MeshItems::TexCoord1D TexCoord1D; + typedef typename MeshItems::TexCoord2D TexCoord2D; + typedef typename MeshItems::TexCoord3D TexCoord3D; + typedef typename MeshItems::Scalar Scalar; + typedef typename MeshItems::TextureIndex TextureIndex; + + typedef typename MeshItems::VertexData VertexData; + typedef typename MeshItems::HalfedgeData HalfedgeData; + typedef typename MeshItems::EdgeData EdgeData; + typedef typename MeshItems::FaceData FaceData; + + typedef AttribKernelT AttribKernel; + + + typedef VPropHandleT DataVPropHandle; + typedef HPropHandleT DataHPropHandle; + typedef EPropHandleT DataEPropHandle; + typedef FPropHandleT DataFPropHandle; + + typedef VPropHandleT PointsPropertyHandle; + typedef VPropHandleT VertexNormalsPropertyHandle; + typedef VPropHandleT VertexColorsPropertyHandle; + typedef VPropHandleT VertexTexCoords1DPropertyHandle; + typedef VPropHandleT VertexTexCoords2DPropertyHandle; + typedef VPropHandleT VertexTexCoords3DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords1DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords2DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords3DPropertyHandle; + typedef EPropHandleT EdgeColorsPropertyHandle; + typedef HPropHandleT HalfedgeNormalsPropertyHandle; + typedef HPropHandleT HalfedgeColorsPropertyHandle; + typedef FPropHandleT FaceNormalsPropertyHandle; + typedef FPropHandleT FaceColorsPropertyHandle; + typedef FPropHandleT FaceTextureIndexPropertyHandle; + +public: + + //-------------------------------------------------- constructor / destructor + + AttribKernelT() + : refcount_vnormals_(0), + refcount_vcolors_(0), + refcount_vtexcoords1D_(0), + refcount_vtexcoords2D_(0), + refcount_vtexcoords3D_(0), + refcount_htexcoords1D_(0), + refcount_htexcoords2D_(0), + refcount_htexcoords3D_(0), + refcount_henormals_(0), + refcount_hecolors_(0), + refcount_ecolors_(0), + refcount_fnormals_(0), + refcount_fcolors_(0), + refcount_ftextureIndex_(0) + { + this->add_property( points_, "v:points" ); + + if (VAttribs & Attributes::Normal) + request_vertex_normals(); + + if (VAttribs & Attributes::Color) + request_vertex_colors(); + + if (VAttribs & Attributes::TexCoord1D) + request_vertex_texcoords1D(); + + if (VAttribs & Attributes::TexCoord2D) + request_vertex_texcoords2D(); + + if (VAttribs & Attributes::TexCoord3D) + request_vertex_texcoords3D(); + + if (HAttribs & Attributes::TexCoord1D) + request_halfedge_texcoords1D(); + + if (HAttribs & Attributes::TexCoord2D) + request_halfedge_texcoords2D(); + + if (HAttribs & Attributes::TexCoord3D) + request_halfedge_texcoords3D(); + + if (HAttribs & Attributes::Color) + request_halfedge_colors(); + + if (VAttribs & Attributes::Status) + Connectivity::request_vertex_status(); + + if (HAttribs & Attributes::Status) + Connectivity::request_halfedge_status(); + + if (HAttribs & Attributes::Normal) + request_halfedge_normals(); + + if (EAttribs & Attributes::Status) + Connectivity::request_edge_status(); + + if (EAttribs & Attributes::Color) + request_edge_colors(); + + if (FAttribs & Attributes::Normal) + request_face_normals(); + + if (FAttribs & Attributes::Color) + request_face_colors(); + + if (FAttribs & Attributes::Status) + Connectivity::request_face_status(); + + if (FAttribs & Attributes::TextureIndex) + request_face_texture_index(); + + //FIXME: data properties might actually cost storage even + //if there are no data traits?? + this->add_property(data_vpph_); + this->add_property(data_fpph_); + this->add_property(data_hpph_); + this->add_property(data_epph_); + } + + virtual ~AttribKernelT() + { + // should remove properties, but this will be done in + // BaseKernel's destructor anyway... + } + + /** Assignment from another mesh of \em another type. + \note All that's copied is connectivity and vertex positions. + All other information (like e.g. attributes or additional + elements from traits classes) is not copied. + \note If you want to copy all information, including *custom* properties, + use PolyMeshT::operator=() instead. + */ + template + void assign(const _AttribKernel& _other, bool copyStandardProperties = false) + { + //copy standard properties if necessary + if(copyStandardProperties) + this->copy_all_kernel_properties(_other); + + this->assign_connectivity(_other); + for (typename Connectivity::VertexIter v_it = Connectivity::vertices_begin(); + v_it != Connectivity::vertices_end(); ++v_it) + {//assumes Point constructor supports cast from _AttribKernel::Point + set_point(*v_it, (Point)_other.point(*v_it)); + } + + //initialize standard properties if necessary + if(copyStandardProperties) + initializeStandardProperties(); + } + + //-------------------------------------------------------------------- points + + const Point* points() const + { return this->property(points_).data(); } + + const Point& point(VertexHandle _vh) const + { return this->property(points_, _vh); } + + Point& point(VertexHandle _vh) + { return this->property(points_, _vh); } + + void set_point(VertexHandle _vh, const Point& _p) + { this->property(points_, _vh) = _p; } + + const PointsPropertyHandle& points_property_handle() const + { return points_; } + + + //------------------------------------------------------------ vertex normals + + const Normal* vertex_normals() const + { return this->property(vertex_normals_).data(); } + + const Normal& normal(VertexHandle _vh) const + { return this->property(vertex_normals_, _vh); } + + void set_normal(VertexHandle _vh, const Normal& _n) + { this->property(vertex_normals_, _vh) = _n; } + + + //------------------------------------------------------------- vertex colors + + const Color* vertex_colors() const + { return this->property(vertex_colors_).data(); } + + const Color& color(VertexHandle _vh) const + { return this->property(vertex_colors_, _vh); } + + void set_color(VertexHandle _vh, const Color& _c) + { this->property(vertex_colors_, _vh) = _c; } + + + //------------------------------------------------------- vertex 1D texcoords + + const TexCoord1D* texcoords1D() const { + return this->property(vertex_texcoords1D_).data(); + } + + const TexCoord1D& texcoord1D(VertexHandle _vh) const { + return this->property(vertex_texcoords1D_, _vh); + } + + void set_texcoord1D(VertexHandle _vh, const TexCoord1D& _t) { + this->property(vertex_texcoords1D_, _vh) = _t; + } + + + //------------------------------------------------------- vertex 2D texcoords + + const TexCoord2D* texcoords2D() const { + return this->property(vertex_texcoords2D_).data(); + } + + const TexCoord2D& texcoord2D(VertexHandle _vh) const { + return this->property(vertex_texcoords2D_, _vh); + } + + void set_texcoord2D(VertexHandle _vh, const TexCoord2D& _t) { + this->property(vertex_texcoords2D_, _vh) = _t; + } + + + //------------------------------------------------------- vertex 3D texcoords + + const TexCoord3D* texcoords3D() const { + return this->property(vertex_texcoords3D_).data(); + } + + const TexCoord3D& texcoord3D(VertexHandle _vh) const { + return this->property(vertex_texcoords3D_, _vh); + } + + void set_texcoord3D(VertexHandle _vh, const TexCoord3D& _t) { + this->property(vertex_texcoords3D_, _vh) = _t; + } + + //.------------------------------------------------------ halfedge 1D texcoords + + const TexCoord1D* htexcoords1D() const { + return this->property(halfedge_texcoords1D_).data(); + } + + const TexCoord1D& texcoord1D(HalfedgeHandle _heh) const { + return this->property(halfedge_texcoords1D_, _heh); + } + + void set_texcoord1D(HalfedgeHandle _heh, const TexCoord1D& _t) { + this->property(halfedge_texcoords1D_, _heh) = _t; + } + + + //------------------------------------------------------- halfedge 2D texcoords + + const TexCoord2D* htexcoords2D() const { + return this->property(halfedge_texcoords2D_).data(); + } + + const TexCoord2D& texcoord2D(HalfedgeHandle _heh) const { + return this->property(halfedge_texcoords2D_, _heh); + } + + void set_texcoord2D(HalfedgeHandle _heh, const TexCoord2D& _t) { + this->property(halfedge_texcoords2D_, _heh) = _t; + } + + + //------------------------------------------------------- halfedge 3D texcoords + + const TexCoord3D* htexcoords3D() const { + return this->property(halfedge_texcoords3D_).data(); + } + + const TexCoord3D& texcoord3D(HalfedgeHandle _heh) const { + return this->property(halfedge_texcoords3D_, _heh); + } + + void set_texcoord3D(HalfedgeHandle _heh, const TexCoord3D& _t) { + this->property(halfedge_texcoords3D_, _heh) = _t; + } + + //------------------------------------------------------------- edge colors + + const Color* edge_colors() const + { return this->property(edge_colors_).data(); } + + const Color& color(EdgeHandle _eh) const + { return this->property(edge_colors_, _eh); } + + void set_color(EdgeHandle _eh, const Color& _c) + { this->property(edge_colors_, _eh) = _c; } + + + //------------------------------------------------------------- halfedge normals + + const Normal& normal(HalfedgeHandle _heh) const + { return this->property(halfedge_normals_, _heh); } + + void set_normal(HalfedgeHandle _heh, const Normal& _n) + { this->property(halfedge_normals_, _heh) = _n; } + + + //------------------------------------------------------------- halfedge colors + + const Color* halfedge_colors() const + { return this->property(halfedge_colors_).data(); } + + const Color& color(HalfedgeHandle _heh) const + { return this->property(halfedge_colors_, _heh); } + + void set_color(HalfedgeHandle _heh, const Color& _c) + { this->property(halfedge_colors_, _heh) = _c; } + + //-------------------------------------------------------------- face normals + + const Normal& normal(FaceHandle _fh) const + { return this->property(face_normals_, _fh); } + + void set_normal(FaceHandle _fh, const Normal& _n) + { this->property(face_normals_, _fh) = _n; } + + //-------------------------------------------------------------- per Face Texture index + + const TextureIndex& texture_index(FaceHandle _fh) const + { return this->property(face_texture_index_, _fh); } + + void set_texture_index(FaceHandle _fh, const TextureIndex& _t) + { this->property(face_texture_index_, _fh) = _t; } + + //--------------------------------------------------------------- face colors + + const Color& color(FaceHandle _fh) const + { return this->property(face_colors_, _fh); } + + void set_color(FaceHandle _fh, const Color& _c) + { this->property(face_colors_, _fh) = _c; } + + //------------------------------------------------ request / alloc properties + + void request_vertex_normals() + { + if (!refcount_vnormals_++) + this->add_property( vertex_normals_, "v:normals" ); + } + + void request_vertex_colors() + { + if (!refcount_vcolors_++) + this->add_property( vertex_colors_, "v:colors" ); + } + + void request_vertex_texcoords1D() + { + if (!refcount_vtexcoords1D_++) + this->add_property( vertex_texcoords1D_, "v:texcoords1D" ); + } + + void request_vertex_texcoords2D() + { + if (!refcount_vtexcoords2D_++) + this->add_property( vertex_texcoords2D_, "v:texcoords2D" ); + } + + void request_vertex_texcoords3D() + { + if (!refcount_vtexcoords3D_++) + this->add_property( vertex_texcoords3D_, "v:texcoords3D" ); + } + + void request_halfedge_texcoords1D() + { + if (!refcount_htexcoords1D_++) + this->add_property( halfedge_texcoords1D_, "h:texcoords1D" ); + } + + void request_halfedge_texcoords2D() + { + if (!refcount_htexcoords2D_++) + this->add_property( halfedge_texcoords2D_, "h:texcoords2D" ); + } + + void request_halfedge_texcoords3D() + { + if (!refcount_htexcoords3D_++) + this->add_property( halfedge_texcoords3D_, "h:texcoords3D" ); + } + + void request_edge_colors() + { + if (!refcount_ecolors_++) + this->add_property( edge_colors_, "e:colors" ); + } + + void request_halfedge_normals() + { + if (!refcount_henormals_++) + this->add_property( halfedge_normals_, "h:normals" ); + } + + void request_halfedge_colors() + { + if (!refcount_hecolors_++) + this->add_property( halfedge_colors_, "h:colors" ); + } + + void request_face_normals() + { + if (!refcount_fnormals_++) + this->add_property( face_normals_, "f:normals" ); + } + + void request_face_colors() + { + if (!refcount_fcolors_++) + this->add_property( face_colors_, "f:colors" ); + } + + void request_face_texture_index() + { + if (!refcount_ftextureIndex_++) + this->add_property( face_texture_index_, "f:textureindex" ); + } + + //------------------------------------------------- release / free properties + + void release_vertex_normals() + { + if ((refcount_vnormals_ > 0) && (! --refcount_vnormals_)) + this->remove_property(vertex_normals_); + } + + void release_vertex_colors() + { + if ((refcount_vcolors_ > 0) && (! --refcount_vcolors_)) + this->remove_property(vertex_colors_); + } + + void release_vertex_texcoords1D() { + if ((refcount_vtexcoords1D_ > 0) && (! --refcount_vtexcoords1D_)) + this->remove_property(vertex_texcoords1D_); + } + + void release_vertex_texcoords2D() { + if ((refcount_vtexcoords2D_ > 0) && (! --refcount_vtexcoords2D_)) + this->remove_property(vertex_texcoords2D_); + } + + void release_vertex_texcoords3D() { + if ((refcount_vtexcoords3D_ > 0) && (! --refcount_vtexcoords3D_)) + this->remove_property(vertex_texcoords3D_); + } + + void release_halfedge_texcoords1D() { + if ((refcount_htexcoords1D_ > 0) && (! --refcount_htexcoords1D_)) + this->remove_property(halfedge_texcoords1D_); + } + + void release_halfedge_texcoords2D() { + if ((refcount_htexcoords2D_ > 0) && (! --refcount_htexcoords2D_)) + this->remove_property(halfedge_texcoords2D_); + } + + void release_halfedge_texcoords3D() { + if ((refcount_htexcoords3D_ > 0) && (! --refcount_htexcoords3D_)) + this->remove_property(halfedge_texcoords3D_); + } + + void release_edge_colors() + { + if ((refcount_ecolors_ > 0) && (! --refcount_ecolors_)) + this->remove_property(edge_colors_); + } + + void release_halfedge_normals() + { + if ((refcount_henormals_ > 0) && (! --refcount_henormals_)) + this->remove_property(halfedge_normals_); + } + + void release_halfedge_colors() + { + if ((refcount_hecolors_ > 0) && (! --refcount_hecolors_)) + this->remove_property(halfedge_colors_); + } + + void release_face_normals() + { + if ((refcount_fnormals_ > 0) && (! --refcount_fnormals_)) + this->remove_property(face_normals_); + } + + void release_face_colors() + { + if ((refcount_fcolors_ > 0) && (! --refcount_fcolors_)) + this->remove_property(face_colors_); + } + + void release_face_texture_index() + { + if ((refcount_ftextureIndex_ > 0) && (! --refcount_ftextureIndex_)) + this->remove_property(face_texture_index_); + } + + //---------------------------------------------- dynamic check for properties + + bool has_vertex_normals() const { return vertex_normals_.is_valid(); } + bool has_vertex_colors() const { return vertex_colors_.is_valid(); } + bool has_vertex_texcoords1D() const { return vertex_texcoords1D_.is_valid(); } + bool has_vertex_texcoords2D() const { return vertex_texcoords2D_.is_valid(); } + bool has_vertex_texcoords3D() const { return vertex_texcoords3D_.is_valid(); } + bool has_halfedge_texcoords1D() const { return halfedge_texcoords1D_.is_valid();} + bool has_halfedge_texcoords2D() const { return halfedge_texcoords2D_.is_valid();} + bool has_halfedge_texcoords3D() const { return halfedge_texcoords3D_.is_valid();} + bool has_edge_colors() const { return edge_colors_.is_valid(); } + bool has_halfedge_normals() const { return halfedge_normals_.is_valid(); } + bool has_halfedge_colors() const { return halfedge_colors_.is_valid(); } + bool has_face_normals() const { return face_normals_.is_valid(); } + bool has_face_colors() const { return face_colors_.is_valid(); } + bool has_face_texture_index() const { return face_texture_index_.is_valid(); } + +public: + //standard vertex properties + PointsPropertyHandle points_pph() const + { return points_; } + + VertexNormalsPropertyHandle vertex_normals_pph() const + { return vertex_normals_; } + + VertexColorsPropertyHandle vertex_colors_pph() const + { return vertex_colors_; } + + VertexTexCoords1DPropertyHandle vertex_texcoords1D_pph() const + { return vertex_texcoords1D_; } + + VertexTexCoords2DPropertyHandle vertex_texcoords2D_pph() const + { return vertex_texcoords2D_; } + + VertexTexCoords3DPropertyHandle vertex_texcoords3D_pph() const + { return vertex_texcoords3D_; } + + //standard halfedge properties + HalfedgeTexCoords1DPropertyHandle halfedge_texcoords1D_pph() const + { return halfedge_texcoords1D_; } + + HalfedgeTexCoords2DPropertyHandle halfedge_texcoords2D_pph() const + { return halfedge_texcoords2D_; } + + HalfedgeTexCoords3DPropertyHandle halfedge_texcoords3D_pph() const + { return halfedge_texcoords3D_; } + + // standard edge properties + HalfedgeNormalsPropertyHandle halfedge_normals_pph() const + { return halfedge_normals_; } + + + // standard edge properties + HalfedgeColorsPropertyHandle halfedge_colors_pph() const + { return halfedge_colors_; } + + // standard edge properties + EdgeColorsPropertyHandle edge_colors_pph() const + { return edge_colors_; } + + //standard face properties + FaceNormalsPropertyHandle face_normals_pph() const + { return face_normals_; } + + FaceColorsPropertyHandle face_colors_pph() const + { return face_colors_; } + + FaceTextureIndexPropertyHandle face_texture_index_pph() const + { return face_texture_index_; } + + VertexData& data(VertexHandle _vh) + { return this->property(data_vpph_, _vh); } + + const VertexData& data(VertexHandle _vh) const + { return this->property(data_vpph_, _vh); } + + FaceData& data(FaceHandle _fh) + { return this->property(data_fpph_, _fh); } + + const FaceData& data(FaceHandle _fh) const + { return this->property(data_fpph_, _fh); } + + EdgeData& data(EdgeHandle _eh) + { return this->property(data_epph_, _eh); } + + const EdgeData& data(EdgeHandle _eh) const + { return this->property(data_epph_, _eh); } + + HalfedgeData& data(HalfedgeHandle _heh) + { return this->property(data_hpph_, _heh); } + + const HalfedgeData& data(HalfedgeHandle _heh) const + { return this->property(data_hpph_, _heh); } + +private: + //standard vertex properties + PointsPropertyHandle points_; + VertexNormalsPropertyHandle vertex_normals_; + VertexColorsPropertyHandle vertex_colors_; + VertexTexCoords1DPropertyHandle vertex_texcoords1D_; + VertexTexCoords2DPropertyHandle vertex_texcoords2D_; + VertexTexCoords3DPropertyHandle vertex_texcoords3D_; + //standard halfedge properties + HalfedgeTexCoords1DPropertyHandle halfedge_texcoords1D_; + HalfedgeTexCoords2DPropertyHandle halfedge_texcoords2D_; + HalfedgeTexCoords3DPropertyHandle halfedge_texcoords3D_; + HalfedgeNormalsPropertyHandle halfedge_normals_; + HalfedgeColorsPropertyHandle halfedge_colors_; + // standard edge properties + EdgeColorsPropertyHandle edge_colors_; + //standard face properties + FaceNormalsPropertyHandle face_normals_; + FaceColorsPropertyHandle face_colors_; + FaceTextureIndexPropertyHandle face_texture_index_; + //data properties handles + DataVPropHandle data_vpph_; + DataHPropHandle data_hpph_; + DataEPropHandle data_epph_; + DataFPropHandle data_fpph_; + + unsigned int refcount_vnormals_; + unsigned int refcount_vcolors_; + unsigned int refcount_vtexcoords1D_; + unsigned int refcount_vtexcoords2D_; + unsigned int refcount_vtexcoords3D_; + unsigned int refcount_htexcoords1D_; + unsigned int refcount_htexcoords2D_; + unsigned int refcount_htexcoords3D_; + unsigned int refcount_henormals_; + unsigned int refcount_hecolors_; + unsigned int refcount_ecolors_; + unsigned int refcount_fnormals_; + unsigned int refcount_fcolors_; + unsigned int refcount_ftextureIndex_; + + /** + * @brief initializeStandardProperties Initializes the standard properties + * and sets refcount to 1 if found. (e.g. when the copy constructor was used) + */ + void initializeStandardProperties() + { + if(!this->get_property_handle(points_, + "v:points")) + { + //mesh has no points? + } + refcount_vnormals_ = this->get_property_handle(vertex_normals_, + "v:normals") ? 1 : 0 ; + refcount_vcolors_ = this->get_property_handle(vertex_colors_, + "v:colors") ? 1 : 0 ; + refcount_vtexcoords1D_ = this->get_property_handle(vertex_texcoords1D_, + "v:texcoords1D") ? 1 : 0 ; + refcount_vtexcoords2D_ = this->get_property_handle(vertex_texcoords2D_, + "v:texcoords2D") ? 1 : 0 ; + refcount_vtexcoords3D_ = this->get_property_handle(vertex_texcoords3D_, + "v:texcoords3D") ? 1 : 0 ; + refcount_htexcoords1D_ = this->get_property_handle(halfedge_texcoords1D_, + "h:texcoords1D") ? 1 : 0 ; + refcount_htexcoords2D_ = this->get_property_handle(halfedge_texcoords2D_, + "h:texcoords2D") ? 1 : 0 ; + refcount_htexcoords3D_ = this->get_property_handle(halfedge_texcoords3D_, + "h:texcoords3D") ? 1 : 0 ; + refcount_henormals_ = this->get_property_handle(halfedge_normals_, + "h:normals") ? 1 : 0 ; + refcount_hecolors_ = this->get_property_handle(halfedge_colors_, + "h:colors") ? 1 : 0 ; + refcount_ecolors_ = this->get_property_handle(edge_colors_, + "e:colors") ? 1 : 0 ; + refcount_fnormals_ = this->get_property_handle(face_normals_, + "f:normals") ? 1 : 0 ; + refcount_fcolors_ = this->get_property_handle(face_colors_, + "f:colors") ? 1 : 0 ; + refcount_ftextureIndex_ = this->get_property_handle(face_texture_index_, + "f:textureindex") ? 1 : 0 ; + } +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBKERNEL_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Attributes.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Attributes.hh new file mode 100644 index 0000000..b7bccc5 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Attributes.hh @@ -0,0 +1,98 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +/** + \file Attributes.hh + This file provides some macros containing attribute usage. +*/ + + +#ifndef OPENMESH_ATTRIBUTES_HH +#define OPENMESH_ATTRIBUTES_HH + + +//== INCLUDES ================================================================= + + +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Attributes { + + +//== CLASS DEFINITION ======================================================== + +/** Attribute bits + * + * Use the bits to define a standard property at compile time using traits. + * + * \include traits5.cc + * + * \see \ref mesh_type + */ +enum AttributeBits +{ + None = 0, ///< Clear all attribute bits + Normal = 1, ///< Add normals to mesh item (vertices/faces) + Color = 2, ///< Add colors to mesh item (vertices/faces/edges) + PrevHalfedge = 4, ///< Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits. + Status = 8, ///< Add status to mesh item (all items) + TexCoord1D = 16, ///< Add 1D texture coordinates (vertices, halfedges) + TexCoord2D = 32, ///< Add 2D texture coordinates (vertices, halfedges) + TexCoord3D = 64, ///< Add 3D texture coordinates (vertices, halfedges) + TextureIndex = 128 ///< Add texture index (faces) +}; + + +//============================================================================= +} // namespace Attributes +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBUTES_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/BaseKernel.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/BaseKernel.hh new file mode 100644 index 0000000..ca2873f --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/BaseKernel.hh @@ -0,0 +1,834 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS BaseKernel +// +//============================================================================= + + +#ifndef OPENMESH_BASE_KERNEL_HH +#define OPENMESH_BASE_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +// -------------------- +#include +#include +#include +#include +// -------------------- +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/// This class provides low-level property management like adding/removing +/// properties and access to properties. Under most circumstances, it is +/// advisable to use the high-level property management provided by +/// PropertyManager, instead. +/// +/// All operations provided by %BaseKernel need at least a property handle +/// (VPropHandleT, EPropHandleT, HPropHandleT, FPropHandleT, MPropHandleT). +/// which keeps the data type of the property, too. +/// +/// There are two types of properties: +/// -# Standard properties - mesh data (e.g. vertex normal or face color) +/// -# Custom properties - user defined data +/// +/// The differentiation is only semantically, technically both are +/// equally handled. Therefore the methods provided by the %BaseKernel +/// are applicable to both property types. +/// +/// \attention Since the class PolyMeshT derives from a kernel, hence all public +/// elements of %BaseKernel are usable. + +class OPENMESHDLLEXPORT BaseKernel +{ +public: //-------------------------------------------- constructor / destructor + + BaseKernel() {} + virtual ~BaseKernel() { + vprops_.clear(); + eprops_.clear(); + hprops_.clear(); + fprops_.clear(); + } + + +public: //-------------------------------------------------- add new properties + + /// \name Add a property to a mesh item + + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper and/or one of its helper functions such as + * makePropertyManagerFromNew, makePropertyManagerFromExisting, or + * makePropertyManagerFromExistingOrNew. + * + * Adds a property + * + * Depending on the property handle type a vertex, (half-)edge, face or + * mesh property is added to the mesh. If the action fails the handle + * is invalid. + * On success the handle must be used to access the property data with + * property(). + * + * \param _ph A property handle defining the data type to bind to mesh. + * On success the handle is valid else invalid. + * \param _name Optional name of property. Following restrictions apply + * to the name: + * -# Maximum length of name is 256 characters + * -# The prefixes matching "^[vhefm]:" are reserved for + * internal usage. + * -# The expression "^<.*>$" is reserved for internal usage. + * + */ + + template + void add_property( VPropHandleT& _ph, const std::string& _name="") + { + _ph = VPropHandleT( vprops_.add(T(), _name) ); + vprops_.resize(n_vertices()); + } + + template + void add_property( HPropHandleT& _ph, const std::string& _name="") + { + _ph = HPropHandleT( hprops_.add(T(), _name) ); + hprops_.resize(n_halfedges()); + } + + template + void add_property( EPropHandleT& _ph, const std::string& _name="") + { + _ph = EPropHandleT( eprops_.add(T(), _name) ); + eprops_.resize(n_edges()); + } + + template + void add_property( FPropHandleT& _ph, const std::string& _name="") + { + _ph = FPropHandleT( fprops_.add(T(), _name) ); + fprops_.resize(n_faces()); + } + + template + void add_property( MPropHandleT& _ph, const std::string& _name="") + { + _ph = MPropHandleT( mprops_.add(T(), _name) ); + mprops_.resize(1); + } + + //@} + + +public: //--------------------------------------------------- remove properties + + /// \name Removing a property from a mesh tiem + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper to manage (and remove) properties. + * + * Remove a property. + * + * Removes the property represented by the handle from the apropriate + * mesh item. + * \param _ph Property to be removed. The handle is invalid afterwords. + */ + + template + void remove_property(VPropHandleT& _ph) + { + if (_ph.is_valid()) + vprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(HPropHandleT& _ph) + { + if (_ph.is_valid()) + hprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(EPropHandleT& _ph) + { + if (_ph.is_valid()) + eprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(FPropHandleT& _ph) + { + if (_ph.is_valid()) + fprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(MPropHandleT& _ph) + { + if (_ph.is_valid()) + mprops_.remove(_ph); + _ph.reset(); + } + + //@} + +public: //------------------------------------------------ get handle from name + + /// \name Get property handle by name + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::propertyExists) or one of + * its higher level helper functions such as + * makePropertyManagerFromExisting, or makePropertyManagerFromExistingOrNew. + * + * Retrieves the handle to a named property by it's name. + * + * \param _ph A property handle. On success the handle is valid else + * invalid. + * \param _name Name of wanted property. + * \return \c true if such a named property is available, else \c false. + */ + + template + bool get_property_handle(VPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = VPropHandleT(vprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(HPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = HPropHandleT(hprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(EPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = EPropHandleT(eprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(FPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = FPropHandleT(fprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(MPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = MPropHandleT(mprops_.handle(T(), _name))).is_valid(); + } + + //@} + +public: //--------------------------------------------------- access properties + + /// \name Access a property + //@{ + + /** In most cases you should use the convenient PropertyManager wrapper + * and use of this function should not be necessary. Under some + * circumstances, however (i.e. making a property persistent), it might be + * necessary to use this function. + * + * Access a property + * + * This method returns a reference to property. The property handle + * must be valid! The result is unpredictable if the handle is invalid! + * + * \param _ph A \em valid (!) property handle. + * \return The wanted property if the handle is valid. + */ + + template + PropertyT& property(VPropHandleT _ph) { + return vprops_.property(_ph); + } + template + const PropertyT& property(VPropHandleT _ph) const { + return vprops_.property(_ph); + } + + template + PropertyT& property(HPropHandleT _ph) { + return hprops_.property(_ph); + } + template + const PropertyT& property(HPropHandleT _ph) const { + return hprops_.property(_ph); + } + + template + PropertyT& property(EPropHandleT _ph) { + return eprops_.property(_ph); + } + template + const PropertyT& property(EPropHandleT _ph) const { + return eprops_.property(_ph); + } + + template + PropertyT& property(FPropHandleT _ph) { + return fprops_.property(_ph); + } + template + const PropertyT& property(FPropHandleT _ph) const { + return fprops_.property(_ph); + } + + template + PropertyT& mproperty(MPropHandleT _ph) { + return mprops_.property(_ph); + } + template + const PropertyT& mproperty(MPropHandleT _ph) const { + return mprops_.property(_ph); + } + + //@} + +public: //-------------------------------------------- access property elements + + /// \name Access a property element using a handle to a mesh item + //@{ + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper. + * + * Return value of property for an item + */ + + template + typename VPropHandleT::reference + property(VPropHandleT _ph, VertexHandle _vh) { + return vprops_.property(_ph)[_vh.idx()]; + } + + template + typename VPropHandleT::const_reference + property(VPropHandleT _ph, VertexHandle _vh) const { + return vprops_.property(_ph)[_vh.idx()]; + } + + + template + typename HPropHandleT::reference + property(HPropHandleT _ph, HalfedgeHandle _hh) { + return hprops_.property(_ph)[_hh.idx()]; + } + + template + typename HPropHandleT::const_reference + property(HPropHandleT _ph, HalfedgeHandle _hh) const { + return hprops_.property(_ph)[_hh.idx()]; + } + + + template + typename EPropHandleT::reference + property(EPropHandleT _ph, EdgeHandle _eh) { + return eprops_.property(_ph)[_eh.idx()]; + } + + template + typename EPropHandleT::const_reference + property(EPropHandleT _ph, EdgeHandle _eh) const { + return eprops_.property(_ph)[_eh.idx()]; + } + + + template + typename FPropHandleT::reference + property(FPropHandleT _ph, FaceHandle _fh) { + return fprops_.property(_ph)[_fh.idx()]; + } + + template + typename FPropHandleT::const_reference + property(FPropHandleT _ph, FaceHandle _fh) const { + return fprops_.property(_ph)[_fh.idx()]; + } + + + template + typename MPropHandleT::reference + property(MPropHandleT _ph) { + return mprops_.property(_ph)[0]; + } + + template + typename MPropHandleT::const_reference + property(MPropHandleT _ph) const { + return mprops_.property(_ph)[0]; + } + + //@} + + +public: //------------------------------------------------ copy property + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph A vertex property handle + * @param _vh_from From vertex handle + * @param _vh_to To vertex handle + */ + template + void copy_property(VPropHandleT& _ph, VertexHandle _vh_from, VertexHandle _vh_to) { + if(_vh_from.is_valid() && _vh_to.is_valid()) + vprops_.property(_ph)[_vh_to.idx()] = vprops_.property(_ph)[_vh_from.idx()]; + } + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph A halfedge property handle + * @param _hh_from From halfedge handle + * @param _hh_to To halfedge handle + */ + template + void copy_property(HPropHandleT _ph, HalfedgeHandle _hh_from, HalfedgeHandle _hh_to) { + if(_hh_from.is_valid() && _hh_to.is_valid()) + hprops_.property(_ph)[_hh_to.idx()] = hprops_.property(_ph)[_hh_from.idx()]; + } + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph An edge property handle + * @param _eh_from From edge handle + * @param _eh_to To edge handle + */ + template + void copy_property(EPropHandleT _ph, EdgeHandle _eh_from, EdgeHandle _eh_to) { + if(_eh_from.is_valid() && _eh_to.is_valid()) + eprops_.property(_ph)[_eh_to.idx()] = eprops_.property(_ph)[_eh_from.idx()]; + } + + /** You should not use this function directly. Instead, use the convenient + * PropertyManager wrapper (e.g. PropertyManager::copy_to or + * PropertyManager::copy). + * + * Copies a single property from one mesh element to another (of the same type) + * + * @param _ph A face property handle + * @param _fh_from From face handle + * @param _fh_to To face handle + */ + template + void copy_property(FPropHandleT _ph, FaceHandle _fh_from, FaceHandle _fh_to) { + if(_fh_from.is_valid() && _fh_to.is_valid()) + fprops_.property(_ph)[_fh_to.idx()] = fprops_.property(_ph)[_fh_from.idx()]; + } + + +public: + //------------------------------------------------ copy all properties + + /** Copies all properties from one mesh element to another (of the same type) + * + * + * @param _vh_from A vertex handle - source + * @param _vh_to A vertex handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + */ + void copy_all_properties(VertexHandle _vh_from, VertexHandle _vh_to, bool _copyBuildIn = false) { + + for( PropertyContainer::iterator p_it = vprops_.begin(); + p_it != vprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "v:" ) ) + (*p_it)->copy(static_cast(_vh_from.idx()), static_cast(_vh_to.idx())); + + } + } + + /** Copies all properties from one mesh element to another (of the same type) + * + * @param _hh_from A halfedge handle - source + * @param _hh_to A halfedge handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + */ + void copy_all_properties(HalfedgeHandle _hh_from, HalfedgeHandle _hh_to, bool _copyBuildIn = false) { + + for( PropertyContainer::iterator p_it = hprops_.begin(); + p_it != hprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "h:") ) + (*p_it)->copy(_hh_from.idx(), _hh_to.idx()); + + } + } + + /** Copies all properties from one mesh element to another (of the same type) + * + * @param _eh_from An edge handle - source + * @param _eh_to An edge handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + */ + void copy_all_properties(EdgeHandle _eh_from, EdgeHandle _eh_to, bool _copyBuildIn = false) { + for( PropertyContainer::iterator p_it = eprops_.begin(); + p_it != eprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "e:") ) + (*p_it)->copy(_eh_from.idx(), _eh_to.idx()); + + } + } + + /** Copies all properties from one mesh element to another (of the same type) + * + * @param _fh_from A face handle - source + * @param _fh_to A face handle - target + * @param _copyBuildIn Should the internal properties (position, normal, texture coordinate,..) be copied? + * + */ + void copy_all_properties(FaceHandle _fh_from, FaceHandle _fh_to, bool _copyBuildIn = false) { + + for( PropertyContainer::iterator p_it = fprops_.begin(); + p_it != fprops_.end(); ++p_it) { + + // Copy all properties, if build in is true + // Otherwise, copy only properties without build in specifier + if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "f:") ) + (*p_it)->copy(_fh_from.idx(), _fh_to.idx()); + } + + } + + /** + * @brief copy_all_kernel_properties uses the = operator to copy all properties from a given other BaseKernel. + * @param _other Another BaseKernel, to copy the properties from. + */ + void copy_all_kernel_properties(const BaseKernel & _other) + { + this->vprops_ = _other.vprops_; + this->eprops_ = _other.eprops_; + this->hprops_ = _other.hprops_; + this->fprops_ = _other.fprops_; + } + +protected: //------------------------------------------------- low-level access + +public: // used by non-native kernel and MeshIO, should be protected + + size_t n_vprops(void) const { return vprops_.size(); } + + size_t n_eprops(void) const { return eprops_.size(); } + + size_t n_hprops(void) const { return hprops_.size(); } + + size_t n_fprops(void) const { return fprops_.size(); } + + size_t n_mprops(void) const { return mprops_.size(); } + + BaseProperty* _get_vprop( const std::string& _name) + { return vprops_.property(_name); } + + BaseProperty* _get_eprop( const std::string& _name) + { return eprops_.property(_name); } + + BaseProperty* _get_hprop( const std::string& _name) + { return hprops_.property(_name); } + + BaseProperty* _get_fprop( const std::string& _name) + { return fprops_.property(_name); } + + BaseProperty* _get_mprop( const std::string& _name) + { return mprops_.property(_name); } + + const BaseProperty* _get_vprop( const std::string& _name) const + { return vprops_.property(_name); } + + const BaseProperty* _get_eprop( const std::string& _name) const + { return eprops_.property(_name); } + + const BaseProperty* _get_hprop( const std::string& _name) const + { return hprops_.property(_name); } + + const BaseProperty* _get_fprop( const std::string& _name) const + { return fprops_.property(_name); } + + const BaseProperty* _get_mprop( const std::string& _name) const + { return mprops_.property(_name); } + + BaseProperty& _vprop( size_t _idx ) { return vprops_._property( _idx ); } + BaseProperty& _eprop( size_t _idx ) { return eprops_._property( _idx ); } + BaseProperty& _hprop( size_t _idx ) { return hprops_._property( _idx ); } + BaseProperty& _fprop( size_t _idx ) { return fprops_._property( _idx ); } + BaseProperty& _mprop( size_t _idx ) { return mprops_._property( _idx ); } + + const BaseProperty& _vprop( size_t _idx ) const + { return vprops_._property( _idx ); } + const BaseProperty& _eprop( size_t _idx ) const + { return eprops_._property( _idx ); } + const BaseProperty& _hprop( size_t _idx ) const + { return hprops_._property( _idx ); } + const BaseProperty& _fprop( size_t _idx ) const + { return fprops_._property( _idx ); } + const BaseProperty& _mprop( size_t _idx ) const + { return mprops_._property( _idx ); } + + size_t _add_vprop( BaseProperty* _bp ) { return vprops_._add( _bp ); } + size_t _add_eprop( BaseProperty* _bp ) { return eprops_._add( _bp ); } + size_t _add_hprop( BaseProperty* _bp ) { return hprops_._add( _bp ); } + size_t _add_fprop( BaseProperty* _bp ) { return fprops_._add( _bp ); } + size_t _add_mprop( BaseProperty* _bp ) { return mprops_._add( _bp ); } + +protected: // low-level access non-public + + BaseProperty& _vprop( BaseHandle _h ) + { return vprops_._property( _h.idx() ); } + BaseProperty& _eprop( BaseHandle _h ) + { return eprops_._property( _h.idx() ); } + BaseProperty& _hprop( BaseHandle _h ) + { return hprops_._property( _h.idx() ); } + BaseProperty& _fprop( BaseHandle _h ) + { return fprops_._property( _h.idx() ); } + BaseProperty& _mprop( BaseHandle _h ) + { return mprops_._property( _h.idx() ); } + + const BaseProperty& _vprop( BaseHandle _h ) const + { return vprops_._property( _h.idx() ); } + const BaseProperty& _eprop( BaseHandle _h ) const + { return eprops_._property( _h.idx() ); } + const BaseProperty& _hprop( BaseHandle _h ) const + { return hprops_._property( _h.idx() ); } + const BaseProperty& _fprop( BaseHandle _h ) const + { return fprops_._property( _h.idx() ); } + const BaseProperty& _mprop( BaseHandle _h ) const + { return mprops_._property( _h.idx() ); } + + +public: //----------------------------------------------------- element numbers + + + virtual size_t n_vertices() const { return 0; } + virtual size_t n_halfedges() const { return 0; } + virtual size_t n_edges() const { return 0; } + virtual size_t n_faces() const { return 0; } + + template + size_t n_elements() const; + + +protected: //------------------------------------------- synchronize properties + + /// Reserves space for \p _n elements in all vertex property vectors. + void vprops_reserve(size_t _n) const { vprops_.reserve(_n); } + + /// Resizes all vertex property vectors to the specified size. + void vprops_resize(size_t _n) const { vprops_.resize(_n); } + + /** + * Same as vprops_resize() but ignores vertex property vectors that have + * a size larger than \p _n. + * + * Use this method instead of vprops_resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ + void vprops_resize_if_smaller(size_t _n) const { vprops_.resize_if_smaller(_n); } + + void vprops_clear() { + vprops_.clear(); + } + + void vprops_swap(unsigned int _i0, unsigned int _i1) const { + vprops_.swap(_i0, _i1); + } + + void hprops_reserve(size_t _n) const { hprops_.reserve(_n); } + void hprops_resize(size_t _n) const { hprops_.resize(_n); } + void hprops_clear() { + hprops_.clear(); + } + void hprops_swap(unsigned int _i0, unsigned int _i1) const { + hprops_.swap(_i0, _i1); + } + + void eprops_reserve(size_t _n) const { eprops_.reserve(_n); } + void eprops_resize(size_t _n) const { eprops_.resize(_n); } + void eprops_clear() { + eprops_.clear(); + } + void eprops_swap(unsigned int _i0, unsigned int _i1) const { + eprops_.swap(_i0, _i1); + } + + void fprops_reserve(size_t _n) const { fprops_.reserve(_n); } + void fprops_resize(size_t _n) const { fprops_.resize(_n); } + void fprops_clear() { + fprops_.clear(); + } + void fprops_swap(unsigned int _i0, unsigned int _i1) const { + fprops_.swap(_i0, _i1); + } + + void mprops_resize(size_t _n) const { mprops_.resize(_n); } + void mprops_clear() { + mprops_.clear(); + } + +public: + + // uses std::clog as output stream + void property_stats() const; + void property_stats(std::ostream& _ostr) const; + + void vprop_stats( std::string& _string ) const; + void hprop_stats( std::string& _string ) const; + void eprop_stats( std::string& _string ) const; + void fprop_stats( std::string& _string ) const; + void mprop_stats( std::string& _string ) const; + + // uses std::clog as output stream + void vprop_stats() const; + void hprop_stats() const; + void eprop_stats() const; + void fprop_stats() const; + void mprop_stats() const; + + void vprop_stats(std::ostream& _ostr) const; + void hprop_stats(std::ostream& _ostr) const; + void eprop_stats(std::ostream& _ostr) const; + void fprop_stats(std::ostream& _ostr) const; + void mprop_stats(std::ostream& _ostr) const; + +public: + + typedef PropertyContainer::iterator prop_iterator; + typedef PropertyContainer::const_iterator const_prop_iterator; + + prop_iterator vprops_begin() { return vprops_.begin(); } + prop_iterator vprops_end() { return vprops_.end(); } + const_prop_iterator vprops_begin() const { return vprops_.begin(); } + const_prop_iterator vprops_end() const { return vprops_.end(); } + + prop_iterator eprops_begin() { return eprops_.begin(); } + prop_iterator eprops_end() { return eprops_.end(); } + const_prop_iterator eprops_begin() const { return eprops_.begin(); } + const_prop_iterator eprops_end() const { return eprops_.end(); } + + prop_iterator hprops_begin() { return hprops_.begin(); } + prop_iterator hprops_end() { return hprops_.end(); } + const_prop_iterator hprops_begin() const { return hprops_.begin(); } + const_prop_iterator hprops_end() const { return hprops_.end(); } + + prop_iterator fprops_begin() { return fprops_.begin(); } + prop_iterator fprops_end() { return fprops_.end(); } + const_prop_iterator fprops_begin() const { return fprops_.begin(); } + const_prop_iterator fprops_end() const { return fprops_.end(); } + + prop_iterator mprops_begin() { return mprops_.begin(); } + prop_iterator mprops_end() { return mprops_.end(); } + const_prop_iterator mprops_begin() const { return mprops_.begin(); } + const_prop_iterator mprops_end() const { return mprops_.end(); } + +private: + + PropertyContainer vprops_; + PropertyContainer hprops_; + PropertyContainer eprops_; + PropertyContainer fprops_; + PropertyContainer mprops_; +}; + + +template <> +inline size_t BaseKernel::n_elements() const { return n_vertices(); } +template <> +inline size_t BaseKernel::n_elements() const { return n_halfedges(); } +template <> +inline size_t BaseKernel::n_elements() const { return n_edges(); } +template <> +inline size_t BaseKernel::n_elements() const { return n_faces(); } + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_BASE_KERNEL_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/BaseMesh.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/BaseMesh.hh new file mode 100644 index 0000000..17af0fb --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/BaseMesh.hh @@ -0,0 +1,92 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS BaseMesh +// +//============================================================================= + + +#ifndef OPENMESH_BASEMESH_HH +#define OPENMESH_BASEMESH_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class BaseMesh BaseMesh.hh + + Base class for all meshes. +*/ + +class BaseMesh { +public: + virtual ~BaseMesh(void) {;} +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_BASEMESH_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Casts.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Casts.hh new file mode 100644 index 0000000..cb7388f --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Casts.hh @@ -0,0 +1,72 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_CASTS_HH +#define OPENMESH_CASTS_HH +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== +namespace OpenMesh +{ + +template +inline TriMesh_ArrayKernelT& TRIMESH_CAST(PolyMesh_ArrayKernelT& _poly_mesh) +{ return reinterpret_cast< TriMesh_ArrayKernelT& >(_poly_mesh); } + +template +inline const TriMesh_ArrayKernelT& TRIMESH_CAST(const PolyMesh_ArrayKernelT& _poly_mesh) +{ return reinterpret_cast< const TriMesh_ArrayKernelT& >(_poly_mesh); } + +template +inline PolyMesh_ArrayKernelT& POLYMESH_CAST(TriMesh_ArrayKernelT& _tri_mesh) +{ return reinterpret_cast< PolyMesh_ArrayKernelT& >(_tri_mesh); } + +template +inline const PolyMesh_ArrayKernelT& POLYMESH_CAST(const TriMesh_ArrayKernelT& _tri_mesh) +{ return reinterpret_cast< const PolyMesh_ArrayKernelT& >(_tri_mesh); } + +}; +#endif//OPENMESH_CASTS_HH diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/CirculatorsT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/CirculatorsT.hh new file mode 100644 index 0000000..90412a1 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/CirculatorsT.hh @@ -0,0 +1,654 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#pragma once + +//============================================================================= +// +// Vertex, Face, and Edge circulators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +template class CirculatorRange; + +namespace Iterators { + +template +class GenericCirculator_CenterEntityFnsT { + public: + static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter); + static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter); +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->cw_rotated_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->ccw_rotated_halfedge_handle(heh); + } +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->next_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->prev_halfedge_handle(heh); + } +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->opposite_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->opposite_halfedge_handle(heh); + } +}; + +///////////////////////////////////////////////////////////// +// CCW + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->ccw_rotated_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->cw_rotated_halfedge_handle(heh); + } +}; + +template +class GenericCirculator_CenterEntityFnsT { + public: + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + heh = mesh->prev_halfedge_handle(heh); + if (heh == start) ++lap_counter; + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh == start) --lap_counter; + heh = mesh->next_halfedge_handle(heh); + } +}; +///////////////////////////////////////////////////////////// + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + //inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, const int &lap_counter); +}; + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) { + return mesh->face_handle(mesh->opposite_halfedge_handle(heh)).is_valid(); + } +}; + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) { + return mesh->face_handle(heh).is_valid(); + } +}; + +template +class GenericCirculator_DereferenciabilityCheckT { + public: + inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) { + return mesh->face_handle(heh).is_valid(); + } +}; + +template +class GenericCirculator_ValueHandleFnsT { + public: + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) { + return ( heh.is_valid() && (lap_counter == 0 ) ); + } + inline static void init(const Mesh* mesh, typename Mesh::HalfedgeHandle& heh, typename Mesh::HalfedgeHandle& start, int& lap_counter, bool adjust_for_ccw) + { + if (!CW) // TODO: constexpr if + { + if (adjust_for_ccw) + { + // increment current heh and start so that cw and ccw version dont start with the same element but ranges are actually reversed + int lc = lap_counter; + increment(mesh, heh, start, lap_counter); + start = heh; + lap_counter = lc; + } + } + } + + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } +}; + +template +class GenericCirculator_ValueHandleFnsT { + public: + typedef GenericCirculator_DereferenciabilityCheckT GenericCirculator_DereferenciabilityCheck; + + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) { + return ( heh.is_valid() && (lap_counter == 0)); + } + inline static void init(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter, bool adjust_for_ccw) + { + if (!CW) // TODO: constexpr if + { + if (adjust_for_ccw) + { + // increment current heh and start so that cw and ccw version dont start with the same element but ranges are actually reversed + int lc = lap_counter; + increment(mesh, heh, start, lap_counter); + start = heh; + lap_counter = lc; + } + } + if (heh.is_valid() && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh) && lap_counter == 0 ) + increment(mesh, heh, start, lap_counter); + }; + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } +}; + +template +class GenericCirculatorBaseT { + public: + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; + + template friend class OpenMesh::CirculatorRange; + + public: + GenericCirculatorBaseT() : mesh_(0), lap_counter_(0) {} + + GenericCirculatorBaseT(mesh_ref mesh, typename Mesh::HalfedgeHandle heh, bool end = false) : + mesh_(&mesh), start_(heh), heh_(heh), lap_counter_(static_cast(end && heh.is_valid())) {} + + GenericCirculatorBaseT(const GenericCirculatorBaseT &rhs) : + mesh_(rhs.mesh_), start_(rhs.start_), heh_(rhs.heh_), lap_counter_(rhs.lap_counter_) {} + + inline typename Mesh::FaceHandle toFaceHandle() const { + return mesh_->face_handle(heh_); + } + + inline typename Mesh::FaceHandle toOppositeFaceHandle() const { + return mesh_->face_handle(toOppositeHalfedgeHandle()); + } + + inline typename Mesh::EdgeHandle toEdgeHandle() const { + return mesh_->edge_handle(heh_); + } + + inline typename Mesh::HalfedgeHandle toHalfedgeHandle() const { + return heh_; + } + + inline typename Mesh::HalfedgeHandle toOppositeHalfedgeHandle() const { + return mesh_->opposite_halfedge_handle(heh_); + } + + inline typename Mesh::VertexHandle toVertexHandle() const { + return mesh_->to_vertex_handle(heh_); + } + + inline GenericCirculatorBaseT &operator=(const GenericCirculatorBaseT &rhs) { + mesh_ = rhs.mesh_; + start_ = rhs.start_; + heh_ = rhs.heh_; + lap_counter_ = rhs.lap_counter_; + return *this; + } + + inline bool operator==(const GenericCirculatorBaseT &rhs) const { + return mesh_ == rhs.mesh_ && start_ == rhs.start_ && heh_ == rhs.heh_ && lap_counter_ == rhs.lap_counter_; + } + + inline bool operator!=(const GenericCirculatorBaseT &rhs) const { + return !operator==(rhs); + } + + protected: + mesh_ptr mesh_; + typename Mesh::HalfedgeHandle start_, heh_; + int lap_counter_; +}; + +//template::*Handle2Value)() const, bool CW = true > +template +class GenericCirculatorT : protected GenericCirculatorBaseT { + public: + using Mesh = typename GenericCirculatorT_TraitsT::Mesh; + using value_type = typename GenericCirculatorT_TraitsT::ValueHandle; + using CenterEntityHandle = typename GenericCirculatorT_TraitsT::CenterEntityHandle; + + using smart_value_type = decltype(make_smart(std::declval(), std::declval())); + + typedef std::ptrdiff_t difference_type; + typedef const value_type& reference; + typedef const smart_value_type* pointer; + typedef std::bidirectional_iterator_tag iterator_category; + + typedef typename GenericCirculatorBaseT::mesh_ptr mesh_ptr; + typedef typename GenericCirculatorBaseT::mesh_ref mesh_ref; + typedef GenericCirculator_ValueHandleFnsT GenericCirculator_ValueHandleFns; + + template friend class OpenMesh::CirculatorRange; + + public: + GenericCirculatorT() {} + GenericCirculatorT(mesh_ref mesh, CenterEntityHandle start, bool end = false) : + GenericCirculatorBaseT(mesh, mesh.halfedge_handle(start), end) + { + bool adjust_for_ccw = true; + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_, adjust_for_ccw); + } + GenericCirculatorT(mesh_ref mesh, typename Mesh::HalfedgeHandle heh, bool end = false) : + GenericCirculatorBaseT(mesh, heh, end) + { + bool adjust_for_ccw = false; // if iterator is initialized with specific heh, we want to start there + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_, adjust_for_ccw); + } + GenericCirculatorT(const GenericCirculatorT &rhs) : GenericCirculatorBaseT(rhs) {} + + friend class GenericCirculatorT; + explicit GenericCirculatorT( const GenericCirculatorT& rhs ) + :GenericCirculatorBaseT(rhs){} + + GenericCirculatorT& operator++() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } + GenericCirculatorT& operator--() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::decrement(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } + + /// Post-increment + GenericCirculatorT operator++(int) { + assert(this->mesh_); + GenericCirculatorT cpy(*this); + ++(*this); + return cpy; + } + + /// Post-decrement + GenericCirculatorT operator--(int) { + assert(this->mesh_); + GenericCirculatorT cpy(*this); + --(*this); + return cpy; + } + + /// Standard dereferencing operator. + smart_value_type operator*() const { +#ifndef NDEBUG + assert(this->heh_.is_valid()); + value_type res = GenericCirculatorT_TraitsT::toHandle(this->mesh_, this->heh_); + assert(res.is_valid()); + return make_smart(res, this->mesh_); +#else + return make_smart(GenericCirculatorT_TraitsT::toHandle(this->mesh_, this->heh_), this->mesh_); +#endif + } + + /** + * @brief Pointer dereferentiation. + * + * This returns a pointer which points to a handle + * that loses its validity once this dereferentiation is + * invoked again. Thus, do not store the result of + * this operation. + */ + pointer operator->() const { + pointer_deref_value = **this; + return &pointer_deref_value; + } + + GenericCirculatorT &operator=(const GenericCirculatorT &rhs) { + GenericCirculatorBaseT::operator=(rhs); + return *this; + }; + + bool operator==(const GenericCirculatorT &rhs) const { + return GenericCirculatorBaseT::operator==(rhs); + } + + bool operator!=(const GenericCirculatorT &rhs) const { + return GenericCirculatorBaseT::operator!=(rhs); + } + + bool is_valid() const { + return GenericCirculator_ValueHandleFns::is_valid(this->heh_, this->lap_counter_); + } + + template + friend STREAM &operator<< (STREAM &s, const GenericCirculatorT &self) { + return s << self.mesh_ << ", " << self.start_.idx() << ", " << self.heh_.idx() << ", " << self.lap_counter_; + } + + private: + mutable smart_value_type pointer_deref_value; +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////// OLD /////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// OLD CIRCULATORS +// deprecated circulators, will be removed soon +// if you remove these circulators and go to the old ones, PLEASE ENABLE FOLLOWING UNITTESTS: +// +// OpenMeshTrimeshCirculatorVertexIHalfEdge.VertexIHalfEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexEdge.VertexEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexVertex.VertexVertexIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexOHalfEdge.VertexOHalfEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexFace.VertexFaceIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorVertexFace.VertexFaceIterWithoutHolesDecrement +// OpenMeshTrimeshCirculatorFaceEdge.FaceEdgeIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorFaceFace.FaceFaceIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorFaceHalfEdge.FaceHalfedgeIterWithoutHolesIncrement +// OpenMeshTrimeshCirculatorFaceVertex.FaceVertexIterCheckInvalidationAtEnds +// OpenMeshTrimeshCirculatorFaceHalfEdge.FaceHalfedgeIterCheckInvalidationAtEnds +// + +template +class GenericCirculator_ValueHandleFnsT_DEPRECATED { + public: + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh,const typename Mesh::HalfedgeHandle &start, const int lap_counter) { + return ( heh.is_valid() && ((start != heh) || (lap_counter == 0 )) ); + } + inline static void init(const Mesh*, typename Mesh::HalfedgeHandle&, typename Mesh::HalfedgeHandle&, int&) {}; + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } +}; + +template +class GenericCirculator_ValueHandleFnsT_DEPRECATED { + public: + typedef GenericCirculator_DereferenciabilityCheckT GenericCirculator_DereferenciabilityCheck; + + inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, const int lap_counter) { + return ( heh.is_valid() && ((start != heh) || (lap_counter == 0 ))); + } + inline static void init(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + if (heh.is_valid() && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh) && lap_counter == 0 ) + increment(mesh, heh, start, lap_counter); + }; + inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::increment(mesh, heh, start, lap_counter); + } while (is_valid(heh, start, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } + inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) { + do { + GenericCirculator_CenterEntityFnsT::decrement(mesh, heh, start, lap_counter); + } while (is_valid(heh, start, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh)); + } +}; + +template +class GenericCirculatorT_DEPRECATED : protected GenericCirculatorBaseT { + public: + using Mesh = typename GenericCirculatorT_DEPRECATED_TraitsT::Mesh; + using CenterEntityHandle = typename GenericCirculatorT_DEPRECATED_TraitsT::CenterEntityHandle; + using value_type = typename GenericCirculatorT_DEPRECATED_TraitsT::ValueHandle; + using smart_value_type = decltype (make_smart(std::declval(), std::declval())); + + typedef std::ptrdiff_t difference_type; + typedef const value_type& reference; + typedef const smart_value_type* pointer; + typedef std::bidirectional_iterator_tag iterator_category; + + typedef typename GenericCirculatorBaseT::mesh_ptr mesh_ptr; + typedef typename GenericCirculatorBaseT::mesh_ref mesh_ref; + typedef GenericCirculator_ValueHandleFnsT_DEPRECATED GenericCirculator_ValueHandleFns; + + template friend class OpenMesh::CirculatorRange; + + public: + GenericCirculatorT_DEPRECATED() {} + GenericCirculatorT_DEPRECATED(mesh_ref mesh, CenterEntityHandle start, bool end = false) : + GenericCirculatorBaseT(mesh, mesh.halfedge_handle(start), end) { + + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_); + } + GenericCirculatorT_DEPRECATED(mesh_ref mesh, typename Mesh::HalfedgeHandle heh, bool end = false) : + GenericCirculatorBaseT(mesh, heh, end) { + + GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_); + } + GenericCirculatorT_DEPRECATED(const GenericCirculatorT_DEPRECATED &rhs) : GenericCirculatorBaseT(rhs) {} + + GenericCirculatorT_DEPRECATED& operator++() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } +#ifndef NO_DECREMENT_DEPRECATED_WARNINGS +#define DECREMENT_DEPRECATED_WARNINGS_TEXT "The current decrement operator has the unintended behavior that it stays\ + valid when iterating below the start and will visit the first entity\ + twice before getting invalid. Furthermore it gets valid again, if you\ + increment at the end.\ + When you are sure that you don't iterate below the start anywhere in\ + your code or rely on this behaviour, you can disable this warning by\ + setting the define NO_DECREMENT_DEPRECATED_WARNINGS at the command line (or enable it via the\ + cmake flags).\ + To be save, you can use the CW/CCW circulator definitions, which behave\ + the same as the original ones, without the previously mentioned issues." + + OM_DEPRECATED( DECREMENT_DEPRECATED_WARNINGS_TEXT ) +#endif // NO_DECREMENT_DEPRECATED_WARNINGS + GenericCirculatorT_DEPRECATED& operator--() { + assert(this->mesh_); + GenericCirculator_ValueHandleFns::decrement(this->mesh_, this->heh_, this->start_, this->lap_counter_); + return *this; + } + + /// Post-increment + GenericCirculatorT_DEPRECATED operator++(int) { + assert(this->mesh_); + GenericCirculatorT_DEPRECATED cpy(*this); + ++(*this); + return cpy; + } + + /// Post-decrement +#ifndef NO_DECREMENT_DEPRECATED_WARNINGS + OM_DEPRECATED( DECREMENT_DEPRECATED_WARNINGS_TEXT ) +#undef DECREMENT_DEPRECATED_WARNINGS_TEXT +#endif //NO_DECREMENT_DEPRECATED_WARNINGS + GenericCirculatorT_DEPRECATED operator--(int) { + assert(this->mesh_); + GenericCirculatorT_DEPRECATED cpy(*this); + --(*this); + return cpy; + } + + /// Standard dereferencing operator. + smart_value_type operator*() const { +#ifndef NDEBUG + assert(this->heh_.is_valid()); + value_type res = (GenericCirculatorT_DEPRECATED_TraitsT::toHandle(this->mesh_, this->heh_)); + assert(res.is_valid()); + return make_smart(res, this->mesh_); +#else + return make_smart(GenericCirculatorT_DEPRECATED_TraitsT::toHandle(this->mesh_, this->heh_), this->mesh_); +#endif + } + + /** + * @brief Pointer dereferentiation. + * + * This returns a pointer which points to a handle + * that loses its validity once this dereferentiation is + * invoked again. Thus, do not store the result of + * this operation. + */ + pointer operator->() const { + pointer_deref_value = **this; + return &pointer_deref_value; + } + + GenericCirculatorT_DEPRECATED &operator=(const GenericCirculatorT_DEPRECATED &rhs) { + GenericCirculatorBaseT::operator=(rhs); + return *this; + }; + + bool operator==(const GenericCirculatorT_DEPRECATED &rhs) const { + return GenericCirculatorBaseT::operator==(rhs); + } + + bool operator!=(const GenericCirculatorT_DEPRECATED &rhs) const { + return GenericCirculatorBaseT::operator!=(rhs); + } + + bool is_valid() const { + return GenericCirculator_ValueHandleFns::is_valid(this->heh_,this->start_, this->lap_counter_); + } + + OM_DEPRECATED("current_halfedge_handle() is an implementation detail and should not be accessed from outside the iterator class.") + /** + * \deprecated + * current_halfedge_handle() is an implementation detail and should not + * be accessed from outside the iterator class. + */ + const typename Mesh::HalfedgeHandle ¤t_halfedge_handle() const { + return this->heh_; + } + + OM_DEPRECATED("Do not use this error prone implicit cast. Compare to end-iterator or use is_valid(), instead.") + /** + * \deprecated + * Do not use this error prone implicit cast. Compare to the + * end-iterator or use is_valid() instead. + */ + operator bool() const { + return is_valid(); + } + + /** + * \brief Return the handle of the current target. + * \deprecated + * This function clutters your code. Use dereferencing operators -> and * instead. + */ + OM_DEPRECATED("This function clutters your code. Use dereferencing operators -> and * instead.") + smart_value_type handle() const { + return **this; + } + + /** + * \brief Cast to the handle of the current target. + * \deprecated + * Implicit casts of iterators are unsafe. Use dereferencing operators + * -> and * instead. + */ + OM_DEPRECATED("Implicit casts of iterators are unsafe. Use dereferencing operators -> and * instead.") + operator value_type() const { + return **this; + } + + template + friend STREAM &operator<< (STREAM &s, const GenericCirculatorT_DEPRECATED &self) { + return s << self.mesh_ << ", " << self.start_.idx() << ", " << self.heh_.idx() << ", " << self.lap_counter_; + } + + private: + mutable smart_value_type pointer_deref_value; +}; + +} // namespace Iterators +} // namespace OpenMesh + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/DefaultPolyMesh.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/DefaultPolyMesh.hh new file mode 100644 index 0000000..76c9ede --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/DefaultPolyMesh.hh @@ -0,0 +1,66 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#ifndef OPENMESH_DEFAULTPOLYMESH_HH +#define OPENMESH_DEFAULTPOLYMESH_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== TYPEDEFS ================================================================= + +typedef PolyMesh_ArrayKernelT PolyMesh; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_DEFAULTPOLYMESH_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/DefaultTriMesh.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/DefaultTriMesh.hh new file mode 100644 index 0000000..5d0b434 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/DefaultTriMesh.hh @@ -0,0 +1,66 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#ifndef OPENMESH_DEFAULTTRIMESH_HH +#define OPENMESH_DEFAULTTRIMESH_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== TYPEDEFS ================================================================= + +typedef TriMesh_ArrayKernelT TriMesh; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_DEFAULTTRIMESH_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/FinalMeshItemsT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/FinalMeshItemsT.hh new file mode 100644 index 0000000..872e783 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/FinalMeshItemsT.hh @@ -0,0 +1,222 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_MESH_ITEMS_HH +#define OPENMESH_MESH_ITEMS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/// Definition of the mesh entities (items). +template +struct FinalMeshItemsT +{ + //--- build Refs structure --- +#ifndef DOXY_IGNORE_THIS + struct Refs + { + typedef typename Traits::Point Point; + typedef typename vector_traits::value_type Scalar; + + typedef typename Traits::Normal Normal; + typedef typename Traits::Color Color; + typedef typename Traits::TexCoord1D TexCoord1D; + typedef typename Traits::TexCoord2D TexCoord2D; + typedef typename Traits::TexCoord3D TexCoord3D; + typedef typename Traits::TextureIndex TextureIndex; + typedef OpenMesh::VertexHandle VertexHandle; + typedef OpenMesh::FaceHandle FaceHandle; + typedef OpenMesh::EdgeHandle EdgeHandle; + typedef OpenMesh::HalfedgeHandle HalfedgeHandle; + }; +#endif + //--- export Refs types --- + typedef typename Refs::Point Point; + typedef typename Refs::Scalar Scalar; + typedef typename Refs::Normal Normal; + typedef typename Refs::Color Color; + typedef typename Refs::TexCoord1D TexCoord1D; + typedef typename Refs::TexCoord2D TexCoord2D; + typedef typename Refs::TexCoord3D TexCoord3D; + typedef typename Refs::TextureIndex TextureIndex; + + //--- get attribute bits from Traits --- + enum Attribs + { + VAttribs = Traits::VertexAttributes, + HAttribs = Traits::HalfedgeAttributes, + EAttribs = Traits::EdgeAttributes, + FAttribs = Traits::FaceAttributes + }; + //--- merge internal items with traits items --- + + +/* + typedef typename GenProg::IF< + (bool)(HAttribs & Attributes::PrevHalfedge), + typename InternalItems::Halfedge_with_prev, + typename InternalItems::Halfedge_without_prev + >::Result InternalHalfedge; +*/ + //typedef typename InternalItems::Vertex InternalVertex; + //typedef typename InternalItems::template Edge InternalEdge; + //typedef typename InternalItems::template Face InternalFace; + class ITraits + {}; + + typedef typename Traits::template VertexT VertexData; + typedef typename Traits::template HalfedgeT HalfedgeData; + typedef typename Traits::template EdgeT EdgeData; + typedef typename Traits::template FaceT FaceData; +}; + + +#ifndef DOXY_IGNORE_THIS +namespace { +namespace TM { +template struct TypeEquality; +template struct TypeEquality {}; + +template struct ItemsEquality { + TypeEquality te1; + TypeEquality te2; + TypeEquality te3; + TypeEquality te4; + TypeEquality te5; + TypeEquality te6; + TypeEquality te7; + TypeEquality te8; +}; + +} /* namespace TM */ +} /* anonymous namespace */ +#endif + +/** + * @brief Cast a mesh with different but identical traits into each other. + * + * Note that there exists a syntactically more convenient global method + * mesh_cast(). + * + * Example: + * @code{.cpp} + * struct TriTraits1 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits2 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits3 : public OpenMesh::DefaultTraits { + * typedef Vec3f Point; + * }; + * + * TriMesh_ArrayKernelT a; + * TriMesh_ArrayKernelT &b = MeshCast&, TriMesh_ArrayKernelT&>::cast(a); // OK + * TriMesh_ArrayKernelT &c = MeshCast&, TriMesh_ArrayKernelT&>::cast(a); // ERROR + * @endcode + * + * @see mesh_cast() + * + * @param rhs + * @return + */ +template struct MeshCast; + +template +struct MeshCast { + static LhsMeshT &cast(RhsMeshT &rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + +template +struct MeshCast { + static const LhsMeshT &cast(const RhsMeshT &rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + +template +struct MeshCast { + static LhsMeshT *cast(RhsMeshT *rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + +template +struct MeshCast { + static const LhsMeshT *cast(const RhsMeshT *rhs) { + (void)sizeof(TM::ItemsEquality); + (void)sizeof(TM::TypeEquality); + return reinterpret_cast(rhs); + } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESH_ITEMS_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Handles.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Handles.hh new file mode 100644 index 0000000..9023f3f --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Handles.hh @@ -0,0 +1,242 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_HANDLES_HH +#define OPENMESH_HANDLES_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + + +/// Base class for all handle types +class OPENMESHDLLEXPORT BaseHandle +{ +public: + + explicit BaseHandle(int _idx=-1) : idx_(_idx) {} + + /// Get the underlying index of this handle + int idx() const { return idx_; } + + /// The handle is valid iff the index is not negative. + bool is_valid() const { return idx_ >= 0; } + + /// reset handle to be invalid + void reset() { idx_=-1; } + /// reset handle to be invalid + void invalidate() { idx_ = -1; } + + bool operator==(const BaseHandle& _rhs) const { + return (this->idx_ == _rhs.idx_); + } + + bool operator!=(const BaseHandle& _rhs) const { + return (this->idx_ != _rhs.idx_); + } + + bool operator<(const BaseHandle& _rhs) const { + return (this->idx_ < _rhs.idx_); + } + + + // this is to be used only by the iterators + void __increment() { ++idx_; } + void __decrement() { --idx_; } + + void __increment(int amount) { idx_ += amount; } + void __decrement(int amount) { idx_ -= amount; } + +private: + + int idx_; +}; + +// this is used by boost::unordered_set/map +inline size_t hash_value(const BaseHandle& h) { return h.idx(); } + +//----------------------------------------------------------------------------- + +/// Write handle \c _hnd to stream \c _os +inline std::ostream& operator<<(std::ostream& _os, const BaseHandle& _hnd) +{ + return (_os << _hnd.idx()); +} + + +//----------------------------------------------------------------------------- + + +/// Handle for a vertex entity +struct OPENMESHDLLEXPORT VertexHandle : public BaseHandle +{ + explicit VertexHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a halfedge entity +struct OPENMESHDLLEXPORT HalfedgeHandle : public BaseHandle +{ + explicit HalfedgeHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a edge entity +struct OPENMESHDLLEXPORT EdgeHandle : public BaseHandle +{ + explicit EdgeHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a face entity +struct OPENMESHDLLEXPORT FaceHandle : public BaseHandle +{ + explicit FaceHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle type for meshes to simplify some template programming +struct OPENMESHDLLEXPORT MeshHandle : public BaseHandle +{ + explicit MeshHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +#ifdef OM_HAS_HASH +#include +namespace std { + +#if defined(_MSVC_VER) +# pragma warning(push) +# pragma warning(disable:4099) // For VC++ it is class hash +#endif + + +template <> +struct hash +{ + typedef OpenMesh::BaseHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::BaseHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + typedef OpenMesh::VertexHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::VertexHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + + typedef OpenMesh::HalfedgeHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::HalfedgeHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + + typedef OpenMesh::EdgeHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::EdgeHandle& h) const + { + return h.idx(); + } +}; + +template <> +struct hash +{ + + typedef OpenMesh::FaceHandle argument_type; + typedef std::size_t result_type; + + std::size_t operator()(const OpenMesh::FaceHandle& h) const + { + return h.idx(); + } +}; + +#if defined(_MSVC_VER) +# pragma warning(pop) +#endif + +} +#endif // OM_HAS_HASH + + +#endif // OPENMESH_HANDLES_HH +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/IteratorsT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/IteratorsT.hh new file mode 100644 index 0000000..1ca32c9 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/IteratorsT.hh @@ -0,0 +1,250 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#pragma once + +//============================================================================= +// +// Iterators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class ConstVertexIterT; +template class VertexIterT; +template class ConstHalfedgeIterT; +template class HalfedgeIterT; +template class ConstEdgeIterT; +template class EdgeIterT; +template class ConstFaceIterT; +template class FaceIterT; + + +template +class GenericIteratorT { + public: + //--- Typedefs --- + + typedef ValueHandle value_handle; + typedef value_handle value_type; + typedef std::bidirectional_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; + typedef decltype(make_smart(std::declval(), std::declval())) SmartHandle; + typedef const SmartHandle& reference; + typedef const SmartHandle* pointer; + + /// Default constructor. + GenericIteratorT() + : hnd_(make_smart(ValueHandle(),nullptr)), skip_bits_(0) + {} + + /// Construct with mesh and a target handle. + GenericIteratorT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : hnd_(make_smart(_hnd, _mesh)), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + /// Standard dereferencing operator. + reference operator*() const { + return hnd_; + } + + /// Standard pointer operator. + pointer operator->() const { + return &hnd_; + } + + /** + * \brief Get the handle of the item the iterator refers to. + * \deprecated + * This function clutters your code. Use dereferencing operators -> and * instead. + */ + OM_DEPRECATED("This function clutters your code. Use dereferencing operators -> and * instead.") + value_handle handle() const { + return hnd_; + } + + /** + * \brief Cast to the handle of the item the iterator refers to. + * \deprecated + * Implicit casts of iterators are unsafe. Use dereferencing operators + * -> and * instead. + */ + OM_DEPRECATED("Implicit casts of iterators are unsafe. Use dereferencing operators -> and * instead.") + operator value_handle() const { + return hnd_; + } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const GenericIteratorT& _rhs) const { + return ((hnd_.mesh() == _rhs.hnd_.mesh()) && (hnd_ == _rhs.hnd_)); + } + + /// Not equal? + bool operator!=(const GenericIteratorT& _rhs) const { + return !operator==(_rhs); + } + + /// Standard pre-increment operator + GenericIteratorT& operator++() { + hnd_.__increment(); + if (skip_bits_) + skip_fwd(); + return *this; + } + + /// Standard post-increment operator + GenericIteratorT operator++(int) { + GenericIteratorT cpy(*this); + ++(*this); + return cpy; + } + +#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) + template + auto operator+=(int amount) -> + typename std::enable_if< + sizeof(decltype(std::declval().__increment(amount))) >= 0, + GenericIteratorT&>::type { + static_assert(std::is_same::value, + "Template parameter must not deviate from default."); + if (skip_bits_) + throw std::logic_error("Skipping iterators do not support " + "random access."); + hnd_.__increment(amount); + return *this; + } + + template + auto operator+(int rhs) -> + typename std::enable_if< + sizeof(decltype(std::declval().__increment(rhs), void (), int {})) >= 0, + GenericIteratorT>::type { + static_assert(std::is_same::value, + "Template parameter must not deviate from default."); + if (skip_bits_) + throw std::logic_error("Skipping iterators do not support " + "random access."); + GenericIteratorT result = *this; + result.hnd_.__increment(rhs); + return result; + } +#endif + + /// Standard pre-decrement operator + GenericIteratorT& operator--() { + hnd_.__decrement(); + if (skip_bits_) + skip_bwd(); + return *this; + } + + /// Standard post-decrement operator + GenericIteratorT operator--(int) { + GenericIteratorT cpy(*this); + --(*this); + return cpy; + } + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() { + if (hnd_.mesh() && (hnd_.mesh()->*PrimitiveStatusMember)()) { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } else + skip_bits_ = 0; + } + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { + skip_bits_ = 0; + } + + private: + + void skip_fwd() { + assert(hnd_.mesh() && skip_bits_); + while ((hnd_.idx() < (signed) (hnd_.mesh()->*PrimitiveCountMember)()) + && (hnd_.mesh()->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + void skip_bwd() { + assert(hnd_.mesh() && skip_bits_); + while ((hnd_.idx() >= 0) && (hnd_.mesh()->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + protected: + SmartHandle hnd_; + unsigned int skip_bits_; +}; + +//============================================================================= +} // namespace Iterators +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyConnectivity.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyConnectivity.hh new file mode 100644 index 0000000..aa427ca --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyConnectivity.hh @@ -0,0 +1,1841 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_POLYCONNECTIVITY_HH +#define OPENMESH_POLYCONNECTIVITY_HH + +#include +#include + +namespace OpenMesh +{ + +namespace Iterators +{ + template + class GenericIteratorT; + + template + class GenericCirculatorBaseT; + + template + class GenericCirculatorT_DEPRECATED; + + template + class GenericCirculatorT; +} + +template +class EntityRange; + +template< + typename CONTAINER_T, + typename ITER_T, + ITER_T (CONTAINER_T::*begin_fn)() const, + ITER_T (CONTAINER_T::*end_fn)() const> +struct RangeTraitT +{ + using CONTAINER_TYPE = CONTAINER_T; + using ITER_TYPE = ITER_T; + static ITER_TYPE begin(const CONTAINER_TYPE& _container) { return (_container.*begin_fn)(); } + static ITER_TYPE end(const CONTAINER_TYPE& _container) { return (_container.*end_fn)(); } +}; + + +template +class CirculatorRange; + +template< + typename CONTAINER_T, + typename ITER_T, + typename CENTER_ENTITY_T, + typename TO_ENTITY_T, + ITER_T (CONTAINER_T::*begin_fn)(CENTER_ENTITY_T) const, + ITER_T (CONTAINER_T::*end_fn)(CENTER_ENTITY_T) const> +struct CirculatorRangeTraitT +{ + using CONTAINER_TYPE = CONTAINER_T; + using ITER_TYPE = ITER_T; + using CENTER_ENTITY_TYPE = CENTER_ENTITY_T; + using TO_ENTITYE_TYPE = TO_ENTITY_T; + static ITER_TYPE begin(const CONTAINER_TYPE& _container, CENTER_ENTITY_TYPE _ce) { return (_container.*begin_fn)(_ce); } + static ITER_TYPE begin(const CONTAINER_TYPE& _container, HalfedgeHandle _heh, int) { return ITER_TYPE(_container, _heh); } + static ITER_TYPE end(const CONTAINER_TYPE& _container, CENTER_ENTITY_TYPE _ce) { return (_container.*end_fn)(_ce); } + static ITER_TYPE end(const CONTAINER_TYPE& _container, HalfedgeHandle _heh, int) { return ITER_TYPE(_container, _heh, true); } +}; + +struct SmartVertexHandle; +struct SmartHalfedgeHandle; +struct SmartEdgeHandle; +struct SmartFaceHandle; + +/** \brief Connectivity Class for polygonal meshes +*/ +class OPENMESHDLLEXPORT PolyConnectivity : public ArrayKernel +{ +public: + /// \name Mesh Handles + //@{ + /// Invalid handle + static const VertexHandle InvalidVertexHandle; + /// Invalid handle + static const HalfedgeHandle InvalidHalfedgeHandle; + /// Invalid handle + static const EdgeHandle InvalidEdgeHandle; + /// Invalid handle + static const FaceHandle InvalidFaceHandle; + //@} + + typedef PolyConnectivity This; + + //--- iterators --- + + /** \name Mesh Iterators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators for + documentation. + */ + //@{ + /// Linear iterator + typedef Iterators::GenericIteratorT VertexIter; + typedef Iterators::GenericIteratorT HalfedgeIter; + typedef Iterators::GenericIteratorT EdgeIter; + typedef Iterators::GenericIteratorT FaceIter; + + typedef VertexIter ConstVertexIter; + typedef HalfedgeIter ConstHalfedgeIter; + typedef EdgeIter ConstEdgeIter; + typedef FaceIter ConstFaceIter; + //@} + + //--- circulators --- + + /** \name Mesh Circulators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators + for documentation. + */ + //@{ + + /* + * Vertex-centered circulators + */ + + struct VertexVertexTraits + { + using Mesh = This; + using CenterEntityHandle = This::VertexHandle; + using ValueHandle = This::VertexHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return _mesh->to_vertex_handle(_heh);} + }; + + + /** + * Enumerates 1-ring vertices in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED VertexVertexIter; + typedef Iterators::GenericCirculatorT VertexVertexCWIter; + + /** + * Enumerates 1-ring vertices in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT VertexVertexCCWIter; + + + struct VertexHalfedgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::VertexHandle; + using ValueHandle = This::HalfedgeHandle; + static ValueHandle toHandle(const Mesh* const /*_mesh*/, This::HalfedgeHandle _heh) { return _heh;} + }; + + /** + * Enumerates outgoing half edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED VertexOHalfedgeIter; + typedef Iterators::GenericCirculatorT VertexOHalfedgeCWIter; + + /** + * Enumerates outgoing half edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT VertexOHalfedgeCCWIter; + + struct VertexOppositeHalfedgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::VertexHandle; + using ValueHandle = This::HalfedgeHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return _mesh->opposite_halfedge_handle(_heh); } + }; + + /** + * Enumerates incoming half edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED VertexIHalfedgeIter; + typedef Iterators::GenericCirculatorT VertexIHalfedgeCWIter; + + /** + * Enumerates incoming half edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT VertexIHalfedgeCCWIter; + + + struct VertexFaceTraits + { + using Mesh = This; + using CenterEntityHandle = This::VertexHandle; + using ValueHandle = This::FaceHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->face_handle(_heh); } + }; + + /** + * Enumerates incident faces in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED VertexFaceIter; + typedef Iterators::GenericCirculatorT VertexFaceCWIter; + + /** + * Enumerates incident faces in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT VertexFaceCCWIter; + + + struct VertexEdgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::VertexHandle; + using ValueHandle = This::EdgeHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->edge_handle(_heh); } + }; + + /** + * Enumerates incident edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED VertexEdgeIter; + typedef Iterators::GenericCirculatorT VertexEdgeCWIter; + /** + * Enumerates incident edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT VertexEdgeCCWIter; + + + struct FaceHalfedgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::FaceHandle; + using ValueHandle = This::HalfedgeHandle; + static ValueHandle toHandle(const Mesh* const /*_mesh*/, This::HalfedgeHandle _heh) { return _heh; } + }; + + /** + * Identical to #FaceHalfedgeIter. God knows why this typedef exists. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED HalfedgeLoopIter; + typedef Iterators::GenericCirculatorT HalfedgeLoopCWIter; + /** + * Identical to #FaceHalfedgeIter. God knows why this typedef exists. + */ + typedef Iterators::GenericCirculatorT HalfedgeLoopCCWIter; + + typedef VertexVertexIter ConstVertexVertexIter; + typedef VertexVertexCWIter ConstVertexVertexCWIter; + typedef VertexVertexCCWIter ConstVertexVertexCCWIter; + typedef VertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef VertexOHalfedgeCWIter ConstVertexOHalfedgeCWIter; + typedef VertexOHalfedgeCCWIter ConstVertexOHalfedgeCCWIter; + typedef VertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef VertexIHalfedgeCWIter ConstVertexIHalfedgeCWIter; + typedef VertexIHalfedgeCCWIter ConstVertexIHalfedgeCCWIter; + typedef VertexFaceIter ConstVertexFaceIter; + typedef VertexFaceCWIter ConstVertexFaceCWIter; + typedef VertexFaceCCWIter ConstVertexFaceCCWIter; + typedef VertexEdgeIter ConstVertexEdgeIter; + typedef VertexEdgeCWIter ConstVertexEdgeCWIter; + typedef VertexEdgeCCWIter ConstVertexEdgeCCWIter; + + /* + * Face-centered circulators + */ + + struct FaceVertexTraits + { + using Mesh = This; + using CenterEntityHandle = This::FaceHandle; + using ValueHandle = This::VertexHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->to_vertex_handle(_heh); } + }; + + /** + * Enumerate incident vertices in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED FaceVertexIter; + typedef Iterators::GenericCirculatorT FaceVertexCCWIter; + + /** + * Enumerate incident vertices in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT FaceVertexCWIter; + + /** + * Enumerate incident half edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED FaceHalfedgeIter; + typedef Iterators::GenericCirculatorT FaceHalfedgeCCWIter; + + /** + * Enumerate incident half edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT FaceHalfedgeCWIter; + + + struct FaceEdgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::FaceHandle; + using ValueHandle = This::EdgeHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->edge_handle(_heh); } + }; + + /** + * Enumerate incident edges in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED FaceEdgeIter; + typedef Iterators::GenericCirculatorT FaceEdgeCCWIter; + + /** + * Enumerate incident edges in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT FaceEdgeCWIter; + + + struct FaceFaceTraits + { + using Mesh = This; + using CenterEntityHandle = This::FaceHandle; + using ValueHandle = This::FaceHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->face_handle(_mesh->opposite_halfedge_handle(_heh)); } + }; + + /** + * Enumerate adjacent faces in a counter clockwise fashion. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED FaceFaceIter; + typedef Iterators::GenericCirculatorT FaceFaceCCWIter; + + /** + * Enumerate adjacent faces in a clockwise fashion. + */ + typedef Iterators::GenericCirculatorT FaceFaceCWIter; + + typedef FaceVertexIter ConstFaceVertexIter; + typedef FaceVertexCWIter ConstFaceVertexCWIter; + typedef FaceVertexCCWIter ConstFaceVertexCCWIter; + typedef FaceHalfedgeIter ConstFaceHalfedgeIter; + typedef FaceHalfedgeCWIter ConstFaceHalfedgeCWIter; + typedef FaceHalfedgeCCWIter ConstFaceHalfedgeCCWIter; + typedef FaceEdgeIter ConstFaceEdgeIter; + typedef FaceEdgeCWIter ConstFaceEdgeCWIter; + typedef FaceEdgeCCWIter ConstFaceEdgeCCWIter; + typedef FaceFaceIter ConstFaceFaceIter; + typedef FaceFaceCWIter ConstFaceFaceCWIter; + typedef FaceFaceCCWIter ConstFaceFaceCCWIter; + + /* + * Edge-centered circulators + */ + + struct EdgeVertexTraits + { + using Mesh = This; + using CenterEntityHandle = This::EdgeHandle; + using ValueHandle = This::VertexHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->from_vertex_handle(_heh); } + }; + + /** + * Enumerate vertices incident to an edge. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED EdgeVertexIter; + + struct EdgeHalfedgeTraits + { + using Mesh = This; + using CenterEntityHandle = This::EdgeHandle; + using ValueHandle = This::HalfedgeHandle; + static ValueHandle toHandle(const Mesh* const /* _mesh */, This::HalfedgeHandle _heh) { return _heh; } + }; + + /** + * Enumerate the halfedges of an edge. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED EdgeHalfedgeIter; + + struct EdgeFaceTraits + { + using Mesh = This; + using CenterEntityHandle = This::EdgeHandle; + using ValueHandle = This::FaceHandle; + static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->face_handle(_heh); } + }; + + /** + * Enumerate faces incident to an edge. + */ + typedef Iterators::GenericCirculatorT_DEPRECATED EdgeFaceIter; + + typedef EdgeVertexIter ConstEdgeVertexIter; + typedef EdgeHalfedgeIter ConstEdgeHalfedgeIter; + typedef EdgeFaceIter ConstEdgeFaceIter; + + /* + * Halfedge circulator + */ + typedef HalfedgeLoopIter ConstHalfedgeLoopIter; + typedef HalfedgeLoopCWIter ConstHalfedgeLoopCWIter; + typedef HalfedgeLoopCCWIter ConstHalfedgeLoopCCWIter; + + //@} + + // --- shortcuts + + /** \name Typedef Shortcuts + Provided for convenience only + */ + //@{ + /// Alias typedef + typedef VertexHandle VHandle; + typedef HalfedgeHandle HHandle; + typedef EdgeHandle EHandle; + typedef FaceHandle FHandle; + + typedef VertexIter VIter; + typedef HalfedgeIter HIter; + typedef EdgeIter EIter; + typedef FaceIter FIter; + + typedef ConstVertexIter CVIter; + typedef ConstHalfedgeIter CHIter; + typedef ConstEdgeIter CEIter; + typedef ConstFaceIter CFIter; + + typedef VertexVertexIter VVIter; + typedef VertexVertexCWIter VVCWIter; + typedef VertexVertexCCWIter VVCCWIter; + typedef VertexOHalfedgeIter VOHIter; + typedef VertexOHalfedgeCWIter VOHCWIter; + typedef VertexOHalfedgeCCWIter VOHCCWIter; + typedef VertexIHalfedgeIter VIHIter; + typedef VertexIHalfedgeCWIter VIHICWter; + typedef VertexIHalfedgeCCWIter VIHICCWter; + typedef VertexEdgeIter VEIter; + typedef VertexEdgeCWIter VECWIter; + typedef VertexEdgeCCWIter VECCWIter; + typedef VertexFaceIter VFIter; + typedef VertexFaceCWIter VFCWIter; + typedef VertexFaceCCWIter VFCCWIter; + typedef FaceVertexIter FVIter; + typedef FaceVertexCWIter FVCWIter; + typedef FaceVertexCCWIter FVCCWIter; + typedef FaceHalfedgeIter FHIter; + typedef FaceHalfedgeCWIter FHCWIter; + typedef FaceHalfedgeCCWIter FHCWWIter; + typedef FaceEdgeIter FEIter; + typedef FaceEdgeCWIter FECWIter; + typedef FaceEdgeCCWIter FECWWIter; + typedef FaceFaceIter FFIter; + typedef EdgeVertexIter EVIter; + typedef EdgeHalfedgeIter EHIter; + typedef EdgeFaceIter EFIter; + + typedef ConstVertexVertexIter CVVIter; + typedef ConstVertexVertexCWIter CVVCWIter; + typedef ConstVertexVertexCCWIter CVVCCWIter; + typedef ConstVertexOHalfedgeIter CVOHIter; + typedef ConstVertexOHalfedgeCWIter CVOHCWIter; + typedef ConstVertexOHalfedgeCCWIter CVOHCCWIter; + typedef ConstVertexIHalfedgeIter CVIHIter; + typedef ConstVertexIHalfedgeCWIter CVIHCWIter; + typedef ConstVertexIHalfedgeCCWIter CVIHCCWIter; + typedef ConstVertexEdgeIter CVEIter; + typedef ConstVertexEdgeCWIter CVECWIter; + typedef ConstVertexEdgeCCWIter CVECCWIter; + typedef ConstVertexFaceIter CVFIter; + typedef ConstVertexFaceCWIter CVFCWIter; + typedef ConstVertexFaceCCWIter CVFCCWIter; + typedef ConstFaceVertexIter CFVIter; + typedef ConstFaceVertexCWIter CFVCWIter; + typedef ConstFaceVertexCCWIter CFVCCWIter; + typedef ConstFaceHalfedgeIter CFHIter; + typedef ConstFaceHalfedgeCWIter CFHCWIter; + typedef ConstFaceHalfedgeCCWIter CFHCCWIter; + typedef ConstFaceEdgeIter CFEIter; + typedef ConstFaceEdgeCWIter CFECWIter; + typedef ConstFaceEdgeCCWIter CFECCWIter; + typedef ConstFaceFaceIter CFFIter; + typedef ConstFaceFaceCWIter CFFCWIter; + typedef ConstFaceFaceCCWIter CFFCCWIter; + typedef ConstEdgeVertexIter CEVIter; + typedef ConstEdgeHalfedgeIter CEHIter; + typedef ConstEdgeFaceIter CEFIter; + //@} + +public: + + PolyConnectivity() {} + virtual ~PolyConnectivity() {} + + inline static bool is_triangles() + { return false; } + + /** assign_connectivity() method. See ArrayKernel::assign_connectivity() + for more details. */ + inline void assign_connectivity(const PolyConnectivity& _other) + { ArrayKernel::assign_connectivity(_other); } + + /** \name Adding items to a mesh + */ + //@{ + + /// Add a new vertex + inline SmartVertexHandle add_vertex(); + + /** \brief Add and connect a new face + * + * Create a new face consisting of the vertices provided by the vertex handle vector. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vhandles sorted list of vertex handles (also defines order in which the vertices are added to the face) + */ + SmartFaceHandle add_face(const std::vector& _vhandles); + + /** \brief Add and connect a new face + * + * Create a new face consisting of the vertices provided by the vertex handle vector. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vhandles sorted list of vertex handles (also defines order in which the vertices are added to the face) + */ + SmartFaceHandle add_face(const std::vector& _vhandles); + + + /** \brief Add and connect a new face + * + * Create a new face consisting of three vertices provided by the handles. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vh0 First vertex handle + * @param _vh1 Second vertex handle + * @param _vh2 Third vertex handle + */ + SmartFaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2); + + /** \brief Add and connect a new face + * + * Create a new face consisting of four vertices provided by the handles. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vh0 First vertex handle + * @param _vh1 Second vertex handle + * @param _vh2 Third vertex handle + * @param _vh3 Fourth vertex handle + */ + SmartFaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2, VertexHandle _vh3); + + /** \brief Add and connect a new face + * + * Create a new face consisting of vertices provided by a handle array. + * (The vertices have to be already added to the mesh by add_vertex) + * + * @param _vhandles pointer to a sorted list of vertex handles (also defines order in which the vertices are added to the face) + * @param _vhs_size number of vertex handles in the array + */ + SmartFaceHandle add_face(const VertexHandle* _vhandles, size_t _vhs_size); + + //@} + + /// \name Deleting mesh items and other connectivity/topology modifications + //@{ + + /** Returns whether collapsing halfedge _heh is ok or would lead to + topological inconsistencies. + \attention This method need the Attributes::Status attribute and + changes the \em tagged bit. */ + bool is_collapse_ok(HalfedgeHandle _he); + + + /** Mark vertex and all incident edges and faces deleted. + Items marked deleted will be removed by garbageCollection(). + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices = true); + + /** Mark edge (two opposite halfedges) and incident faces deleted. + Resulting isolated vertices are marked deleted if + _delete_isolated_vertices is true. Items marked deleted will be + removed by garbageCollection(). + + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices=true); + + /** Delete face _fh and resulting degenerated empty halfedges as + well. Resulting isolated vertices will be deleted if + _delete_isolated_vertices is true. + + \attention All item will only be marked to be deleted. They will + actually be removed by calling garbage_collection(). + + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_face(FaceHandle _fh, bool _delete_isolated_vertices=true); + + + //@} + + /** \name Navigation with smart handles to allow usage of old-style navigation with smart handles + */ + //@{ + + using ArrayKernel::next_halfedge_handle; + using ArrayKernel::prev_halfedge_handle; + using ArrayKernel::opposite_halfedge_handle; + using ArrayKernel::ccw_rotated_halfedge_handle; + using ArrayKernel::cw_rotated_halfedge_handle; + + inline SmartHalfedgeHandle next_halfedge_handle (SmartHalfedgeHandle _heh) const; + inline SmartHalfedgeHandle prev_halfedge_handle (SmartHalfedgeHandle _heh) const; + inline SmartHalfedgeHandle opposite_halfedge_handle (SmartHalfedgeHandle _heh) const; + inline SmartHalfedgeHandle ccw_rotated_halfedge_handle(SmartHalfedgeHandle _heh) const; + inline SmartHalfedgeHandle cw_rotated_halfedge_handle (SmartHalfedgeHandle _heh) const; + + using ArrayKernel::s_halfedge_handle; + using ArrayKernel::s_edge_handle; + + static SmartHalfedgeHandle s_halfedge_handle(SmartEdgeHandle _eh, unsigned int _i = 0); + static SmartEdgeHandle s_edge_handle(SmartHalfedgeHandle _heh); + + using ArrayKernel::halfedge_handle; + using ArrayKernel::edge_handle; + using ArrayKernel::face_handle; + + inline SmartHalfedgeHandle halfedge_handle(SmartEdgeHandle _eh, unsigned int _i = 0) const; + inline SmartHalfedgeHandle halfedge_handle(SmartFaceHandle _fh) const; + inline SmartHalfedgeHandle halfedge_handle(SmartVertexHandle _vh) const; + inline SmartEdgeHandle edge_handle(SmartHalfedgeHandle _heh) const; + inline SmartFaceHandle face_handle(SmartHalfedgeHandle _heh) const; + + /// returns the face handle of the opposite halfedge + inline SmartFaceHandle opposite_face_handle(HalfedgeHandle _heh) const; + + //@} + + /** \name Begin and end iterators + */ + //@{ + + /// Begin iterator for vertices + VertexIter vertices_begin(); + /// Const begin iterator for vertices + ConstVertexIter vertices_begin() const; + /// End iterator for vertices + VertexIter vertices_end(); + /// Const end iterator for vertices + ConstVertexIter vertices_end() const; + + /// Begin iterator for halfedges + HalfedgeIter halfedges_begin(); + /// Const begin iterator for halfedges + ConstHalfedgeIter halfedges_begin() const; + /// End iterator for halfedges + HalfedgeIter halfedges_end(); + /// Const end iterator for halfedges + ConstHalfedgeIter halfedges_end() const; + + /// Begin iterator for edges + EdgeIter edges_begin(); + /// Const begin iterator for edges + ConstEdgeIter edges_begin() const; + /// End iterator for edges + EdgeIter edges_end(); + /// Const end iterator for edges + ConstEdgeIter edges_end() const; + + /// Begin iterator for faces + FaceIter faces_begin(); + /// Const begin iterator for faces + ConstFaceIter faces_begin() const; + /// End iterator for faces + FaceIter faces_end(); + /// Const end iterator for faces + ConstFaceIter faces_end() const; + //@} + + + /** \name Begin for skipping iterators + */ + //@{ + + /// Begin iterator for vertices + VertexIter vertices_sbegin(); + /// Const begin iterator for vertices + ConstVertexIter vertices_sbegin() const; + + /// Begin iterator for halfedges + HalfedgeIter halfedges_sbegin(); + /// Const begin iterator for halfedges + ConstHalfedgeIter halfedges_sbegin() const; + + /// Begin iterator for edges + EdgeIter edges_sbegin(); + /// Const begin iterator for edges + ConstEdgeIter edges_sbegin() const; + + /// Begin iterator for faces + FaceIter faces_sbegin(); + /// Const begin iterator for faces + ConstFaceIter faces_sbegin() const; + + //@} + + //--- circulators --- + + /** \name Vertex, Face, and Edge circulators + */ + //@{ + + /// vertex - vertex circulator + VertexVertexIter vv_iter(VertexHandle _vh); + /// vertex - vertex circulator cw + VertexVertexCWIter vv_cwiter(VertexHandle _vh); + /// vertex - vertex circulator ccw + VertexVertexCCWIter vv_ccwiter(VertexHandle _vh); + /// vertex - incoming halfedge circulator + VertexIHalfedgeIter vih_iter(VertexHandle _vh); + /// vertex - incoming halfedge circulator cw + VertexIHalfedgeCWIter vih_cwiter(VertexHandle _vh); + /// vertex - incoming halfedge circulator ccw + VertexIHalfedgeCCWIter vih_ccwiter(VertexHandle _vh); + /// vertex - outgoing halfedge circulator + VertexOHalfedgeIter voh_iter(VertexHandle _vh); + /// vertex - outgoing halfedge circulator cw + VertexOHalfedgeCWIter voh_cwiter(VertexHandle _vh); + /// vertex - outgoing halfedge circulator ccw + VertexOHalfedgeCCWIter voh_ccwiter(VertexHandle _vh); + /// vertex - edge circulator + VertexEdgeIter ve_iter(VertexHandle _vh); + /// vertex - edge circulator cw + VertexEdgeCWIter ve_cwiter(VertexHandle _vh); + /// vertex - edge circulator ccw + VertexEdgeCCWIter ve_ccwiter(VertexHandle _vh); + /// vertex - face circulator + VertexFaceIter vf_iter(VertexHandle _vh); + /// vertex - face circulator cw + VertexFaceCWIter vf_cwiter(VertexHandle _vh); + /// vertex - face circulator ccw + VertexFaceCCWIter vf_ccwiter(VertexHandle _vh); + + /// const vertex circulator + ConstVertexVertexIter cvv_iter(VertexHandle _vh) const; + /// const vertex circulator cw + ConstVertexVertexCWIter cvv_cwiter(VertexHandle _vh) const; + /// const vertex circulator ccw + ConstVertexVertexCCWIter cvv_ccwiter(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator + ConstVertexIHalfedgeIter cvih_iter(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator cw + ConstVertexIHalfedgeCWIter cvih_cwiter(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator ccw + ConstVertexIHalfedgeCCWIter cvih_ccwiter(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator + ConstVertexOHalfedgeIter cvoh_iter(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator cw + ConstVertexOHalfedgeCWIter cvoh_cwiter(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator ccw + ConstVertexOHalfedgeCCWIter cvoh_ccwiter(VertexHandle _vh) const; + /// const vertex - edge circulator + ConstVertexEdgeIter cve_iter(VertexHandle _vh) const; + /// const vertex - edge circulator cw + ConstVertexEdgeCWIter cve_cwiter(VertexHandle _vh) const; + /// const vertex - edge circulator ccw + ConstVertexEdgeCCWIter cve_ccwiter(VertexHandle _vh) const; + /// const vertex - face circulator + ConstVertexFaceIter cvf_iter(VertexHandle _vh) const; + /// const vertex - face circulator cw + ConstVertexFaceCWIter cvf_cwiter(VertexHandle _vh) const; + /// const vertex - face circulator ccw + ConstVertexFaceCCWIter cvf_ccwiter(VertexHandle _vh) const; + + /// face - vertex circulator + FaceVertexIter fv_iter(FaceHandle _fh); + /// face - vertex circulator cw + FaceVertexCWIter fv_cwiter(FaceHandle _fh); + /// face - vertex circulator ccw + FaceVertexCCWIter fv_ccwiter(FaceHandle _fh); + /// face - halfedge circulator + FaceHalfedgeIter fh_iter(FaceHandle _fh); + /// face - halfedge circulator cw + FaceHalfedgeCWIter fh_cwiter(FaceHandle _fh); + /// face - halfedge circulator ccw + FaceHalfedgeCCWIter fh_ccwiter(FaceHandle _fh); + /// face - edge circulator + FaceEdgeIter fe_iter(FaceHandle _fh); + /// face - edge circulator cw + FaceEdgeCWIter fe_cwiter(FaceHandle _fh); + /// face - edge circulator ccw + FaceEdgeCCWIter fe_ccwiter(FaceHandle _fh); + /// face - face circulator + FaceFaceIter ff_iter(FaceHandle _fh); + /// face - face circulator cw + FaceFaceCWIter ff_cwiter(FaceHandle _fh); + /// face - face circulator ccw + FaceFaceCCWIter ff_ccwiter(FaceHandle _fh); + + /// const face - vertex circulator + ConstFaceVertexIter cfv_iter(FaceHandle _fh) const; + /// const face - vertex circulator cw + ConstFaceVertexCWIter cfv_cwiter(FaceHandle _fh) const; + /// const face - vertex circulator ccw + ConstFaceVertexCCWIter cfv_ccwiter(FaceHandle _fh) const; + /// const face - halfedge circulator + ConstFaceHalfedgeIter cfh_iter(FaceHandle _fh) const; + /// const face - halfedge circulator cw + ConstFaceHalfedgeCWIter cfh_cwiter(FaceHandle _fh) const; + /// const face - halfedge circulator ccw + ConstFaceHalfedgeCCWIter cfh_ccwiter(FaceHandle _fh) const; + /// const face - edge circulator + ConstFaceEdgeIter cfe_iter(FaceHandle _fh) const; + /// const face - edge circulator cw + ConstFaceEdgeCWIter cfe_cwiter(FaceHandle _fh) const; + /// const face - edge circulator ccw + ConstFaceEdgeCCWIter cfe_ccwiter(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceIter cff_iter(FaceHandle _fh) const; + /// const face - face circulator cw + ConstFaceFaceCWIter cff_cwiter(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceCCWIter cff_ccwiter(FaceHandle _fh) const; + + /// edge - vertex circulator + EdgeVertexIter ev_iter(EdgeHandle _eh); + /// edge - halfedge circulator + EdgeHalfedgeIter eh_iter(EdgeHandle _eh); + /// edge - face circulator + EdgeFaceIter ef_iter(EdgeHandle _eh); + + /// const edge - vertex circulator + ConstEdgeVertexIter cev_iter(EdgeHandle _eh) const; + /// const edge - halfedge circulator + ConstEdgeHalfedgeIter ceh_iter(EdgeHandle _eh) const; + /// const edge - face circulator + ConstEdgeFaceIter cef_iter(EdgeHandle _eh) const; + + // 'begin' circulators + + /// vertex - vertex circulator + VertexVertexIter vv_begin(VertexHandle _vh); + /// vertex - vertex circulator cw + VertexVertexCWIter vv_cwbegin(VertexHandle _vh); + /// vertex - vertex circulator ccw + VertexVertexCCWIter vv_ccwbegin(VertexHandle _vh); + /// vertex - incoming halfedge circulator + VertexIHalfedgeIter vih_begin(VertexHandle _vh); + /// vertex - incoming halfedge circulator cw + VertexIHalfedgeCWIter vih_cwbegin(VertexHandle _vh); + /// vertex - incoming halfedge circulator ccw + VertexIHalfedgeCCWIter vih_ccwbegin(VertexHandle _vh); + /// vertex - outgoing halfedge circulator + VertexOHalfedgeIter voh_begin(VertexHandle _vh); + /// vertex - outgoing halfedge circulator cw + VertexOHalfedgeCWIter voh_cwbegin(VertexHandle _vh); + /// vertex - outgoing halfedge circulator ccw + VertexOHalfedgeCCWIter voh_ccwbegin(VertexHandle _vh); + /// vertex - edge circulator + VertexEdgeIter ve_begin(VertexHandle _vh); + /// vertex - edge circulator cw + VertexEdgeCWIter ve_cwbegin(VertexHandle _vh); + /// vertex - edge circulator ccw + VertexEdgeCCWIter ve_ccwbegin(VertexHandle _vh); + /// vertex - face circulator + VertexFaceIter vf_begin(VertexHandle _vh); + /// vertex - face circulator cw + VertexFaceCWIter vf_cwbegin(VertexHandle _vh); + /// vertex - face circulator ccw + VertexFaceCCWIter vf_ccwbegin(VertexHandle _vh); + + + /// const vertex circulator + ConstVertexVertexIter cvv_begin(VertexHandle _vh) const; + /// const vertex circulator cw + ConstVertexVertexCWIter cvv_cwbegin(VertexHandle _vh) const; + /// const vertex circulator ccw + ConstVertexVertexCCWIter cvv_ccwbegin(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator + ConstVertexIHalfedgeIter cvih_begin(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator cw + ConstVertexIHalfedgeCWIter cvih_cwbegin(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator ccw + ConstVertexIHalfedgeCCWIter cvih_ccwbegin(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator + ConstVertexOHalfedgeIter cvoh_begin(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator cw + ConstVertexOHalfedgeCWIter cvoh_cwbegin(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator ccw + ConstVertexOHalfedgeCCWIter cvoh_ccwbegin(VertexHandle _vh) const; + /// const vertex - edge circulator + ConstVertexEdgeIter cve_begin(VertexHandle _vh) const; + /// const vertex - edge circulator cw + ConstVertexEdgeCWIter cve_cwbegin(VertexHandle _vh) const; + /// const vertex - edge circulator ccw + ConstVertexEdgeCCWIter cve_ccwbegin(VertexHandle _vh) const; + /// const vertex - face circulator + ConstVertexFaceIter cvf_begin(VertexHandle _vh) const; + /// const vertex - face circulator cw + ConstVertexFaceCWIter cvf_cwbegin(VertexHandle _vh) const; + /// const vertex - face circulator ccw + ConstVertexFaceCCWIter cvf_ccwbegin(VertexHandle _vh) const; + + /// face - vertex circulator + FaceVertexIter fv_begin(FaceHandle _fh); + /// face - vertex circulator cw + FaceVertexCWIter fv_cwbegin(FaceHandle _fh); + /// face - vertex circulator ccw + FaceVertexCCWIter fv_ccwbegin(FaceHandle _fh); + /// face - halfedge circulator + FaceHalfedgeIter fh_begin(FaceHandle _fh); + /// face - halfedge circulator cw + FaceHalfedgeCWIter fh_cwbegin(FaceHandle _fh); + /// face - halfedge circulator ccw + FaceHalfedgeCCWIter fh_ccwbegin(FaceHandle _fh); + /// face - edge circulator + FaceEdgeIter fe_begin(FaceHandle _fh); + /// face - edge circulator cw + FaceEdgeCWIter fe_cwbegin(FaceHandle _fh); + /// face - edge circulator ccw + FaceEdgeCCWIter fe_ccwbegin(FaceHandle _fh); + /// face - face circulator + FaceFaceIter ff_begin(FaceHandle _fh); + /// face - face circulator cw + FaceFaceCWIter ff_cwbegin(FaceHandle _fh); + /// face - face circulator ccw + FaceFaceCCWIter ff_ccwbegin(FaceHandle _fh); + /// halfedge circulator + HalfedgeLoopIter hl_begin(HalfedgeHandle _heh); + /// halfedge circulator + HalfedgeLoopCWIter hl_cwbegin(HalfedgeHandle _heh); + /// halfedge circulator ccw + HalfedgeLoopCCWIter hl_ccwbegin(HalfedgeHandle _heh); + + /// const face - vertex circulator + ConstFaceVertexIter cfv_begin(FaceHandle _fh) const; + /// const face - vertex circulator cw + ConstFaceVertexCWIter cfv_cwbegin(FaceHandle _fh) const; + /// const face - vertex circulator ccw + ConstFaceVertexCCWIter cfv_ccwbegin(FaceHandle _fh) const; + /// const face - halfedge circulator + ConstFaceHalfedgeIter cfh_begin(FaceHandle _fh) const; + /// const face - halfedge circulator cw + ConstFaceHalfedgeCWIter cfh_cwbegin(FaceHandle _fh) const; + /// const face - halfedge circulator ccw + ConstFaceHalfedgeCCWIter cfh_ccwbegin(FaceHandle _fh) const; + /// const face - edge circulator + ConstFaceEdgeIter cfe_begin(FaceHandle _fh) const; + /// const face - edge circulator cw + ConstFaceEdgeCWIter cfe_cwbegin(FaceHandle _fh) const; + /// const face - edge circulator ccw + ConstFaceEdgeCCWIter cfe_ccwbegin(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceIter cff_begin(FaceHandle _fh) const; + /// const face - face circulator cw + ConstFaceFaceCWIter cff_cwbegin(FaceHandle _fh) const; + /// const face - face circulator ccw + ConstFaceFaceCCWIter cff_ccwbegin(FaceHandle _fh) const; + /// const halfedge circulator + ConstHalfedgeLoopIter chl_begin(HalfedgeHandle _heh) const; + /// const halfedge circulator cw + ConstHalfedgeLoopCWIter chl_cwbegin(HalfedgeHandle _heh) const; + /// const halfedge circulator ccw + ConstHalfedgeLoopCCWIter chl_ccwbegin(HalfedgeHandle _heh) const; + + /// edge - vertex circulator + EdgeVertexIter ev_begin(EdgeHandle _eh); + /// edge - halfedge circulator + EdgeHalfedgeIter eh_begin(EdgeHandle _eh); + /// edge - face circulator + EdgeFaceIter ef_begin(EdgeHandle _eh); + + /// const edge - vertex circulator + ConstEdgeVertexIter cev_begin(EdgeHandle _eh) const; + /// const edge - halfedge circulator + ConstEdgeHalfedgeIter ceh_begin(EdgeHandle _eh) const; + /// const edge - face circulator + ConstEdgeFaceIter cef_begin(EdgeHandle _eh) const; + + // 'end' circulators + + /// vertex - vertex circulator + VertexVertexIter vv_end(VertexHandle _vh); + /// vertex - vertex circulator cw + VertexVertexCWIter vv_cwend(VertexHandle _vh); + /// vertex - vertex circulator ccw + VertexVertexCCWIter vv_ccwend(VertexHandle _vh); + /// vertex - incoming halfedge circulator + VertexIHalfedgeIter vih_end(VertexHandle _vh); + /// vertex - incoming halfedge circulator cw + VertexIHalfedgeCWIter vih_cwend(VertexHandle _vh); + /// vertex - incoming halfedge circulator ccw + VertexIHalfedgeCCWIter vih_ccwend(VertexHandle _vh); + /// vertex - outgoing halfedge circulator + VertexOHalfedgeIter voh_end(VertexHandle _vh); + /// vertex - outgoing halfedge circulator cw + VertexOHalfedgeCWIter voh_cwend(VertexHandle _vh); + /// vertex - outgoing halfedge circulator ccw + VertexOHalfedgeCCWIter voh_ccwend(VertexHandle _vh); + /// vertex - edge circulator + VertexEdgeIter ve_end(VertexHandle _vh); + /// vertex - edge circulator cw + VertexEdgeCWIter ve_cwend(VertexHandle _vh); + /// vertex - edge circulator ccw + VertexEdgeCCWIter ve_ccwend(VertexHandle _vh); + /// vertex - face circulator + VertexFaceIter vf_end(VertexHandle _vh); + /// vertex - face circulator cw + VertexFaceCWIter vf_cwend(VertexHandle _vh); + /// vertex - face circulator ccw + VertexFaceCCWIter vf_ccwend(VertexHandle _vh); + + /// const vertex circulator + ConstVertexVertexIter cvv_end(VertexHandle _vh) const; + /// const vertex circulator cw + ConstVertexVertexCWIter cvv_cwend(VertexHandle _vh) const; + /// const vertex circulator ccw + ConstVertexVertexCCWIter cvv_ccwend(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator + ConstVertexIHalfedgeIter cvih_end(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator cw + ConstVertexIHalfedgeCWIter cvih_cwend(VertexHandle _vh) const; + /// const vertex - incoming halfedge circulator ccw + ConstVertexIHalfedgeCCWIter cvih_ccwend(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator + ConstVertexOHalfedgeIter cvoh_end(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator cw + ConstVertexOHalfedgeCWIter cvoh_cwend(VertexHandle _vh) const; + /// const vertex - outgoing halfedge circulator ccw + ConstVertexOHalfedgeCCWIter cvoh_ccwend(VertexHandle _vh) const; + /// const vertex - edge circulator + ConstVertexEdgeIter cve_end(VertexHandle _vh) const; + /// const vertex - edge circulator cw + ConstVertexEdgeCWIter cve_cwend(VertexHandle _vh) const; + /// const vertex - edge circulator ccw + ConstVertexEdgeCCWIter cve_ccwend(VertexHandle _vh) const; + /// const vertex - face circulator + ConstVertexFaceIter cvf_end(VertexHandle _vh) const; + /// const vertex - face circulator cw + ConstVertexFaceCWIter cvf_cwend(VertexHandle _vh) const; + /// const vertex - face circulator ccw + ConstVertexFaceCCWIter cvf_ccwend(VertexHandle _vh) const; + + /// face - vertex circulator + FaceVertexIter fv_end(FaceHandle _fh); + /// face - vertex circulator cw + FaceVertexCWIter fv_cwend(FaceHandle _fh); + /// face - vertex circulator ccw + FaceVertexCCWIter fv_ccwend(FaceHandle _fh); + /// face - halfedge circulator + FaceHalfedgeIter fh_end(FaceHandle _fh); + /// face - halfedge circulator cw + FaceHalfedgeCWIter fh_cwend(FaceHandle _fh); + /// face - halfedge circulator ccw + FaceHalfedgeCCWIter fh_ccwend(FaceHandle _fh); + /// face - edge circulator + FaceEdgeIter fe_end(FaceHandle _fh); + /// face - edge circulator cw + FaceEdgeCWIter fe_cwend(FaceHandle _fh); + /// face - edge circulator ccw + FaceEdgeCCWIter fe_ccwend(FaceHandle _fh); + /// face - face circulator + FaceFaceIter ff_end(FaceHandle _fh); + /// face - face circulator cw + FaceFaceCWIter ff_cwend(FaceHandle _fh); + /// face - face circulator ccw + FaceFaceCCWIter ff_ccwend(FaceHandle _fh); + /// face - face circulator + HalfedgeLoopIter hl_end(HalfedgeHandle _heh); + /// face - face circulator cw + HalfedgeLoopCWIter hl_cwend(HalfedgeHandle _heh); + /// face - face circulator ccw + HalfedgeLoopCCWIter hl_ccwend(HalfedgeHandle _heh); + + /// const face - vertex circulator + ConstFaceVertexIter cfv_end(FaceHandle _fh) const; + /// const face - vertex circulator cw + ConstFaceVertexCWIter cfv_cwend(FaceHandle _fh) const; + /// const face - vertex circulator ccw + ConstFaceVertexCCWIter cfv_ccwend(FaceHandle _fh) const; + /// const face - halfedge circulator + ConstFaceHalfedgeIter cfh_end(FaceHandle _fh) const; + /// const face - halfedge circulator cw + ConstFaceHalfedgeCWIter cfh_cwend(FaceHandle _fh) const; + /// const face - halfedge circulator ccw + ConstFaceHalfedgeCCWIter cfh_ccwend(FaceHandle _fh) const; + /// const face - edge circulator + ConstFaceEdgeIter cfe_end(FaceHandle _fh) const; + /// const face - edge circulator cw + ConstFaceEdgeCWIter cfe_cwend(FaceHandle _fh) const; + /// const face - edge circulator ccw + ConstFaceEdgeCCWIter cfe_ccwend(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceIter cff_end(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceCWIter cff_cwend(FaceHandle _fh) const; + /// const face - face circulator + ConstFaceFaceCCWIter cff_ccwend(FaceHandle _fh) const; + /// const face - face circulator + ConstHalfedgeLoopIter chl_end(HalfedgeHandle _heh) const; + /// const face - face circulator cw + ConstHalfedgeLoopCWIter chl_cwend(HalfedgeHandle _heh) const; + /// const face - face circulator ccw + ConstHalfedgeLoopCCWIter chl_ccwend(HalfedgeHandle _heh) const; + + /// edge - vertex circulator + EdgeVertexIter ev_end(EdgeHandle _eh); + /// edge - halfedge circulator + EdgeHalfedgeIter eh_end(EdgeHandle _eh); + /// edge - face circulator + EdgeFaceIter ef_end(EdgeHandle _eh); + + /// const edge - vertex circulator + ConstEdgeVertexIter cev_end(EdgeHandle _eh) const; + /// const edge - halfedge circulator + ConstEdgeHalfedgeIter ceh_end(EdgeHandle _eh) const; + /// const edge - face circulator + ConstEdgeFaceIter cef_end(EdgeHandle _eh) const; + + //@} + + /** @name Range based iterators and circulators */ + //@{ + + typedef EntityRange> ConstVertexRange; + typedef EntityRange> ConstVertexRangeSkipping; + typedef EntityRange> ConstHalfedgeRange; + typedef EntityRange> ConstHalfedgeRangeSkipping; + typedef EntityRange> ConstEdgeRange; + typedef EntityRange> ConstEdgeRangeSkipping; + typedef EntityRange> ConstFaceRange; + typedef EntityRange> ConstFaceRangeSkipping; + + + template + struct ElementRange; + + /** + * @return The vertices as a range object suitable + * for C++11 range based for loops. Will skip deleted vertices. + */ + ConstVertexRangeSkipping vertices() const; + + /** + * @return The vertices as a range object suitable + * for C++11 range based for loops. Will include deleted vertices. + */ + ConstVertexRange all_vertices() const; + + /** + * @return The halfedges as a range object suitable + * for C++11 range based for loops. Will skip deleted halfedges. + */ + ConstHalfedgeRangeSkipping halfedges() const; + + /** + * @return The halfedges as a range object suitable + * for C++11 range based for loops. Will include deleted halfedges. + */ + ConstHalfedgeRange all_halfedges() const; + + /** + * @return The edges as a range object suitable + * for C++11 range based for loops. Will skip deleted edges. + */ + ConstEdgeRangeSkipping edges() const; + + /** + * @return The edges as a range object suitable + * for C++11 range based for loops. Will include deleted edges. + */ + ConstEdgeRange all_edges() const; + + /** + * @return The faces as a range object suitable + * for C++11 range based for loops. Will skip deleted faces. + */ + ConstFaceRangeSkipping faces() const; + + /** + * @return The faces as a range object suitable + * for C++11 range based for loops. Will include deleted faces. + */ + ConstFaceRange all_faces() const; + + /** + * @return The elements corresponding to the template type as a range object suitable + * for C++11 range based for loops. Will skip deleted faces. + */ + template + typename ElementRange::RangeSkipping elements() const; + + /** + * @return The elements corresponding to the template type as a range object suitable + * for C++11 range based for loops. Will include deleted faces. + */ + template + typename ElementRange::Range all_elements() const; + + + typedef CirculatorRange> ConstVertexVertexRange; + typedef CirculatorRange> ConstVertexIHalfedgeRange; + typedef CirculatorRange> ConstVertexOHalfedgeRange; + typedef CirculatorRange> ConstVertexEdgeRange; + typedef CirculatorRange> ConstVertexFaceRange; + typedef CirculatorRange> ConstFaceVertexRange; + typedef CirculatorRange> ConstFaceHalfedgeRange; + typedef CirculatorRange> ConstFaceEdgeRange; + typedef CirculatorRange> ConstFaceFaceRange; + typedef CirculatorRange> ConstEdgeVertexRange; + typedef CirculatorRange> ConstEdgeHalfedgeRange; + typedef CirculatorRange> ConstEdgeFaceRange; + typedef CirculatorRange> ConstHalfedgeLoopRange; + + typedef CirculatorRange> ConstVertexVertexCWRange; + typedef CirculatorRange> ConstVertexIHalfedgeCWRange; + typedef CirculatorRange> ConstVertexOHalfedgeCWRange; + typedef CirculatorRange> ConstVertexEdgeCWRange; + typedef CirculatorRange> ConstVertexFaceCWRange; + typedef CirculatorRange> ConstFaceVertexCWRange; + typedef CirculatorRange> ConstFaceHalfedgeCWRange; + typedef CirculatorRange> ConstFaceEdgeCWRange; + typedef CirculatorRange> ConstFaceFaceCWRange; + typedef CirculatorRange> ConstHalfedgeLoopCWRange; + + typedef CirculatorRange> ConstVertexVertexCCWRange; + typedef CirculatorRange> ConstVertexIHalfedgeCCWRange; + typedef CirculatorRange> ConstVertexOHalfedgeCCWRange; + typedef CirculatorRange> ConstVertexEdgeCCWRange; + typedef CirculatorRange> ConstVertexFaceCCWRange; + typedef CirculatorRange> ConstFaceVertexCCWRange; + typedef CirculatorRange> ConstFaceHalfedgeCCWRange; + typedef CirculatorRange> ConstFaceEdgeCCWRange; + typedef CirculatorRange> ConstFaceFaceCCWRange; + typedef CirculatorRange> ConstHalfedgeLoopCCWRange; + + /** + * @return The vertices adjacent to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexVertexRange vv_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexIHalfedgeRange vih_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like vih_range(VertexHandle _heh.to()) but starts iteration at _heh + */ + ConstVertexIHalfedgeRange vih_range(HalfedgeHandle _heh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexOHalfedgeRange voh_range(VertexHandle _vh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like voh_range(VertexHandle _heh.from()) but starts iteration at _heh + */ + ConstVertexOHalfedgeRange voh_range(HalfedgeHandle _heh) const; + + /** + * @return The edges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexEdgeRange ve_range(VertexHandle _vh) const ; + + /** + * @return The faces incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexFaceRange vf_range(VertexHandle _vh) const; + + /** + * @return The vertices incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceVertexRange fv_range(FaceHandle _fh) const; + + /** + * @return The halfedges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceHalfedgeRange fh_range(FaceHandle _fh) const; + + /** + * @return The edges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceEdgeRange fe_range(FaceHandle _fh) const; + + /** + * @return The faces adjacent to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceFaceRange ff_range(FaceHandle _fh) const; + + /** + * @return The vertices incident to the specified edge + * as a range object suitable for C++11 range based for loops. + */ + ConstEdgeVertexRange ev_range(EdgeHandle _eh) const; + + /** + * @return The halfedges of the specified edge + * as a range object suitable for C++11 range based for loops. + */ + ConstEdgeHalfedgeRange eh_range(EdgeHandle _eh) const; + + /** + * @return The halfedges of the specified edge + * as a range object suitable for C++11 range based for loops. + * Like eh_range(_heh.edge()) but starts iteration at _heh + */ + ConstEdgeHalfedgeRange eh_range(HalfedgeHandle _heh) const; + + /** + * @return The faces incident to the specified edge + * as a range object suitable for C++11 range based for loops. + */ + ConstEdgeFaceRange ef_range(EdgeHandle _eh) const; + + /** + * @return The halfedges in the face + * as a range object suitable for C++11 range based for loops. + */ + ConstHalfedgeLoopRange hl_range(HalfedgeHandle _heh) const; + + + /** + * @return The vertices adjacent to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexVertexCWRange vv_cw_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexIHalfedgeCWRange vih_cw_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like vih_cw_range(VertexHandle _heh.to()) but starts iteration at _heh + */ + ConstVertexIHalfedgeCWRange vih_cw_range(HalfedgeHandle _heh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexOHalfedgeCWRange voh_cw_range(VertexHandle _vh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like voh_cw_range(VertexHandle _heh.from()) but starts iteration at _heh + */ + ConstVertexOHalfedgeCWRange voh_cw_range(HalfedgeHandle _heh) const; + + /** + * @return The edges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexEdgeCWRange ve_cw_range(VertexHandle _vh) const; + + /** + * @return The faces incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexFaceCWRange vf_cw_range(VertexHandle _vh) const; + + /** + * @return The vertices incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceVertexCWRange fv_cw_range(FaceHandle _fh) const; + + /** + * @return The halfedges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceHalfedgeCWRange fh_cw_range(FaceHandle _fh) const; + + /** + * @return The edges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceEdgeCWRange fe_cw_range(FaceHandle _fh) const; + + /** + * @return The faces adjacent to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceFaceCWRange ff_cw_range(FaceHandle _fh) const; + + /** + * @return The halfedges in the face + * as a range object suitable for C++11 range based for loops. + */ + ConstHalfedgeLoopCWRange hl_cw_range(HalfedgeHandle _heh) const; + + + /** + * @return The vertices adjacent to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexVertexCCWRange vv_ccw_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexIHalfedgeCCWRange vih_ccw_range(VertexHandle _vh) const; + + /** + * @return The incoming halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like vih_ccw_range(VertexHandle _heh.to()) but starts iteration at _heh + */ + ConstVertexIHalfedgeCCWRange vih_ccw_range(HalfedgeHandle _heh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexOHalfedgeCCWRange voh_ccw_range(VertexHandle _vh) const; + + /** + * @return The outgoing halfedges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + * Like voh_ccw_range(VertexHandle _heh.from()) but starts iteration at _heh + */ + ConstVertexOHalfedgeCCWRange voh_ccw_range(HalfedgeHandle _heh) const; + + /** + * @return The edges incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexEdgeCCWRange ve_ccw_range(VertexHandle _vh) const ; + + /** + * @return The faces incident to the specified vertex + * as a range object suitable for C++11 range based for loops. + */ + ConstVertexFaceCCWRange vf_ccw_range(VertexHandle _vh) const; + + /** + * @return The vertices incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceVertexCCWRange fv_ccw_range(FaceHandle _fh) const; + + /** + * @return The halfedges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceHalfedgeCCWRange fh_ccw_range(FaceHandle _fh) const; + + /** + * @return The edges incident to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceEdgeCCWRange fe_ccw_range(FaceHandle _fh) const; + + /** + * @return The faces adjacent to the specified face + * as a range object suitable for C++11 range based for loops. + */ + ConstFaceFaceCCWRange ff_ccw_range(FaceHandle _fh) const; + + + /** + * @return The halfedges in the face + * as a range object suitable for C++11 range based for loops. + */ + ConstHalfedgeLoopCCWRange hl_ccw_range(HalfedgeHandle _heh) const; + + //@} + + //=========================================================================== + /** @name Boundary and manifold tests + * @{ */ + //=========================================================================== + + /** \brief Check if the halfedge is at the boundary + * + * The halfedge is at the boundary, if no face is incident to it. + * + * @param _heh HalfedgeHandle to test + * @return boundary? + */ + bool is_boundary(HalfedgeHandle _heh) const + { return ArrayKernel::is_boundary(_heh); } + + /** \brief Is the edge a boundary edge? + * + * Checks it the edge _eh is a boundary edge, i.e. is one of its halfedges + * a boundary halfedge. + * + * @param _eh Edge handle to test + * @return boundary? + */ + bool is_boundary(EdgeHandle _eh) const + { + return (is_boundary(halfedge_handle(_eh, 0)) || + is_boundary(halfedge_handle(_eh, 1))); + } + + /** \brief Is vertex _vh a boundary vertex ? + * + * Checks if the associated halfedge (which would on a boundary be the outside + * halfedge), is connected to a face. Which is equivalent, if the vertex is + * at the boundary of the mesh, as OpenMesh will make sure, that if there is a + * boundary halfedge at the vertex, the halfedge will be the one which is associated + * to the vertex. + * + * @param _vh VertexHandle to test + * @return boundary? + */ + bool is_boundary(VertexHandle _vh) const + { + HalfedgeHandle heh(halfedge_handle(_vh)); + return (!(heh.is_valid() && face_handle(heh).is_valid())); + } + + /** \brief Check if face is at the boundary + * + * Is face _fh at boundary, i.e. is one of its edges (or vertices) + * a boundary edge? + * + * @param _fh Check this face + * @param _check_vertex If \c true, check the corner vertices of the face, too. + * @return boundary? + */ + bool is_boundary(FaceHandle _fh, bool _check_vertex=false) const; + + /** \brief Is (the mesh at) vertex _vh two-manifold ? + * + * The vertex is non-manifold if more than one gap exists, i.e. + * more than one outgoing boundary halfedge. If (at least) one + * boundary halfedge exists, the vertex' halfedge must be a + * boundary halfedge. + * + * @param _vh VertexHandle to test + * @return manifold? + */ + bool is_manifold(VertexHandle _vh) const; + + /** @} */ + + // --- misc --- + + /** Adjust outgoing halfedge handle for vertices, so that it is a + boundary halfedge whenever possible. + */ + void adjust_outgoing_halfedge(VertexHandle _vh); + + /// Find halfedge from _vh0 to _vh1. Returns invalid handle if not found. + SmartHalfedgeHandle find_halfedge(VertexHandle _start_vh, VertexHandle _end_vh) const; + /// Vertex valence + uint valence(VertexHandle _vh) const; + /// Face valence + uint valence(FaceHandle _fh) const; + + // --- connectivity operattions + + /** Halfedge collapse: collapse the from-vertex of halfedge _heh + into its to-vertex. + + \attention Needs vertex/edge/face status attribute in order to + delete the items that degenerate. + + \note The from vertex is marked as deleted while the to vertex will still exist. + + \note This function does not perform a garbage collection. It + only marks degenerate items as deleted. + + \attention A halfedge collapse may lead to topological inconsistencies. + Therefore you should check this using is_collapse_ok(). + */ + void collapse(HalfedgeHandle _heh); + /** return true if the this the only link between the faces adjacent to _eh. + _eh is allowed to be boundary, in which case true is returned iff _eh is + the only boundary edge of its ajdacent face. + */ + bool is_simple_link(EdgeHandle _eh) const; + /** return true if _fh shares only one edge with all of its adjacent faces. + Boundary is treated as one face, i.e., the function false if _fh has more + than one boundary edge. + */ + bool is_simply_connected(FaceHandle _fh) const; + /** Removes the edge _eh. Its adjacent faces are merged. _eh and one of the + adjacent faces are set deleted. The handle of the remaining face is + returned (InvalidFaceHandle is returned if _eh is a boundary edge). + + \pre is_simple_link(_eh). This ensures that there are no hole faces + or isolated vertices appearing in result of the operation. + + \attention Needs the Attributes::Status attribute for edges and faces. + + \note This function does not perform a garbage collection. It + only marks items as deleted. + */ + FaceHandle remove_edge(EdgeHandle _eh); + /** Inverse of remove_edge. _eh should be the handle of the edge and the + vertex and halfedge handles pointed by edge(_eh) should be valid. + */ + void reinsert_edge(EdgeHandle _eh); + /** Inserts an edge between to_vh(_prev_heh) and from_vh(_next_heh). + A new face is created started at heh0 of the inserted edge and + its halfedges loop includes both _prev_heh and _next_heh. If an + old face existed which includes the argument halfedges, it is + split at the new edge. heh0 is returned. + + \note assumes _prev_heh and _next_heh are either boundary or pointed + to the same face + */ + HalfedgeHandle insert_edge(HalfedgeHandle _prev_heh, HalfedgeHandle _next_heh); + + /** \brief Face split (= 1-to-n split). + * + * Split an arbitrary face into triangles by connecting each vertex of fh to vh. + * + * \note fh will remain valid (it will become one of the triangles) + * \note the halfedge handles of the new triangles will point to the old halfeges + * + * \note The properties of the new faces and all other new primitives will be undefined! + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle of the new vertex that will be inserted in the face + */ + void split(FaceHandle _fh, VertexHandle _vh); + + /** \brief Face split (= 1-to-n split). + * + * Split an arbitrary face into triangles by connecting each vertex of fh to vh. + * + * \note fh will remain valid (it will become one of the triangles) + * \note the halfedge handles of the new triangles will point to the old halfeges + * + * \note The properties of the new faces will be adjusted to the properties of the original faces + * \note Properties of the new edges and halfedges will be undefined + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle of the new vertex that will be inserted in the face + */ + void split_copy(FaceHandle _fh, VertexHandle _vh); + + /** \brief Triangulate the face _fh + + Split an arbitrary face into triangles by connecting + each vertex of fh after its second to vh. + + \note _fh will remain valid (it will become one of the + triangles) + + \note The halfedge handles of the new triangles will + point to the old halfedges + + @param _fh Handle of the face that should be triangulated + */ + void triangulate(FaceHandle _fh); + + /** \brief triangulate the entire mesh + */ + void triangulate(); + + /** Edge split (inserts a vertex on the edge only) + * + * This edge split only splits the edge without introducing new faces! + * As this is for polygonal meshes, we can have valence 2 vertices here. + * + * \note The properties of the new edges and halfedges will be undefined! + * + * @param _eh Handle of the edge, that will be splitted + * @param _vh Handle of the vertex that will be inserted at the edge + */ + void split_edge(EdgeHandle _eh, VertexHandle _vh); + + /** Edge split (inserts a vertex on the edge only) + * + * This edge split only splits the edge without introducing new faces! + * As this is for polygonal meshes, we can have valence 2 vertices here. + * + * \note The properties of the new edge will be copied from the splitted edge + * \note Properties of the new halfedges will be undefined + * + * @param _eh Handle of the edge, that will be splitted + * @param _vh Handle of the vertex that will be inserted at the edge + */ + void split_edge_copy(EdgeHandle _eh, VertexHandle _vh); + + + /** \name Generic handle derefertiation. + Calls the respective vertex(), halfedge(), edge(), face() + method of the mesh kernel. + */ + //@{ + /// Get item from handle + const Vertex& deref(VertexHandle _h) const { return vertex(_h); } + Vertex& deref(VertexHandle _h) { return vertex(_h); } + const Halfedge& deref(HalfedgeHandle _h) const { return halfedge(_h); } + Halfedge& deref(HalfedgeHandle _h) { return halfedge(_h); } + const Edge& deref(EdgeHandle _h) const { return edge(_h); } + Edge& deref(EdgeHandle _h) { return edge(_h); } + const Face& deref(FaceHandle _h) const { return face(_h); } + Face& deref(FaceHandle _h) { return face(_h); } + //@} + +protected: + /// Helper for halfedge collapse + void collapse_edge(HalfedgeHandle _hh); + /// Helper for halfedge collapse + void collapse_loop(HalfedgeHandle _hh); + + + +private: // Working storage for add_face() + struct AddFaceEdgeInfo + { + HalfedgeHandle halfedge_handle; + bool is_new; + bool needs_adjust; + }; + std::vector edgeData_; // + std::vector > next_cache_; // cache for set_next_halfedge and vertex' set_halfedge + +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstVertexRange; + using RangeSkipping = ConstVertexRangeSkipping; +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstHalfedgeRange; + using RangeSkipping = ConstHalfedgeRangeSkipping; +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstEdgeRange; + using RangeSkipping = ConstEdgeRangeSkipping; +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstFaceRange; + using RangeSkipping = ConstFaceRangeSkipping; +}; + +}//namespace OpenMesh + +#define OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE +#include +#include +#undef OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE + +#endif//OPENMESH_POLYCONNECTIVITY_HH diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyConnectivity_inline_impl.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyConnectivity_inline_impl.hh new file mode 100644 index 0000000..c876b2c --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyConnectivity_inline_impl.hh @@ -0,0 +1,1031 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#ifndef OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE +#error Do not include this directly, include instead PolyConnectivity.hh +#endif // OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE + +#include // To help some IDEs +#include +#include + +namespace OpenMesh { + + +inline SmartVertexHandle PolyConnectivity::add_vertex() { return make_smart(new_vertex(), *this); } + +inline SmartHalfedgeHandle PolyConnectivity::next_halfedge_handle(SmartHalfedgeHandle _heh) const { return make_smart(next_halfedge_handle(HalfedgeHandle(_heh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::prev_halfedge_handle(SmartHalfedgeHandle _heh) const { return make_smart(prev_halfedge_handle(HalfedgeHandle(_heh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::opposite_halfedge_handle(SmartHalfedgeHandle _heh) const { return make_smart(opposite_halfedge_handle(HalfedgeHandle(_heh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::ccw_rotated_halfedge_handle(SmartHalfedgeHandle _heh) const { return make_smart(ccw_rotated_halfedge_handle(HalfedgeHandle(_heh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::cw_rotated_halfedge_handle(SmartHalfedgeHandle _heh) const { return make_smart(cw_rotated_halfedge_handle(HalfedgeHandle(_heh)), *this); } + +inline SmartHalfedgeHandle PolyConnectivity::s_halfedge_handle(SmartEdgeHandle _eh, unsigned int _i) { return make_smart(ArrayKernel::s_halfedge_handle(EdgeHandle(_eh), _i), _eh.mesh()); } +inline SmartEdgeHandle PolyConnectivity::s_edge_handle(SmartHalfedgeHandle _heh) { return make_smart(ArrayKernel::s_edge_handle(HalfedgeHandle(_heh)), _heh.mesh()); } + +inline SmartHalfedgeHandle PolyConnectivity::halfedge_handle(SmartEdgeHandle _eh, unsigned int _i) const { return make_smart(halfedge_handle(EdgeHandle(_eh), _i), *this); } +inline SmartEdgeHandle PolyConnectivity::edge_handle(SmartHalfedgeHandle _heh) const { return make_smart(edge_handle(HalfedgeHandle(_heh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::halfedge_handle(SmartFaceHandle _fh) const { return make_smart(halfedge_handle(FaceHandle(_fh)), *this); } +inline SmartHalfedgeHandle PolyConnectivity::halfedge_handle(SmartVertexHandle _vh) const { return make_smart(halfedge_handle(VertexHandle(_vh)), *this); } + +inline SmartFaceHandle PolyConnectivity::face_handle(SmartHalfedgeHandle _heh) const { return make_smart(face_handle(HalfedgeHandle(_heh)), *this); } + +inline SmartFaceHandle PolyConnectivity::opposite_face_handle(HalfedgeHandle _heh) const { return make_smart(face_handle(opposite_halfedge_handle(_heh)), *this); } + + +/// Generic class for vertex/halfedge/edge/face ranges. +template +class EntityRange : public SmartRangeT, typename RangeTraitT::ITER_TYPE::SmartHandle> { + public: + typedef typename RangeTraitT::ITER_TYPE iterator; + typedef typename RangeTraitT::ITER_TYPE const_iterator; + + explicit EntityRange(typename RangeTraitT::CONTAINER_TYPE &container) : container_(container) {} + typename RangeTraitT::ITER_TYPE begin() const { return RangeTraitT::begin(container_); } + typename RangeTraitT::ITER_TYPE end() const { return RangeTraitT::end(container_); } + + private: + typename RangeTraitT::CONTAINER_TYPE &container_; +}; + +/// Generic class for iterator ranges. +template +//class CirculatorRange : public SmartRangeT, decltype (make_smart(std::declval(), std::declval()))>{ +class CirculatorRange : public SmartRangeT, typename SmartHandle::type>{ + public: + typedef typename CirculatorRangeTraitT::ITER_TYPE ITER_TYPE; + typedef typename CirculatorRangeTraitT::CENTER_ENTITY_TYPE CENTER_ENTITY_TYPE; + typedef typename CirculatorRangeTraitT::CONTAINER_TYPE CONTAINER_TYPE; + typedef ITER_TYPE iterator; + typedef ITER_TYPE const_iterator; + + CirculatorRange( + const CONTAINER_TYPE &container, + CENTER_ENTITY_TYPE center) : + container_(container), heh_() + { + auto it = CirculatorRangeTraitT::begin(container_, center); + heh_ = it.heh_; + } + + CirculatorRange( + const CONTAINER_TYPE &container, + HalfedgeHandle heh, int) : + container_(container), heh_(heh) {} + + ITER_TYPE begin() const { return CirculatorRangeTraitT::begin(container_, heh_, 1); } + ITER_TYPE end() const { return CirculatorRangeTraitT::end(container_, heh_, 1); } + + private: + const CONTAINER_TYPE &container_; + HalfedgeHandle heh_; +}; + + +inline PolyConnectivity::ConstVertexRangeSkipping PolyConnectivity::vertices() const { return ConstVertexRangeSkipping(*this); } +inline PolyConnectivity::ConstVertexRange PolyConnectivity::all_vertices() const { return ConstVertexRange(*this); } +inline PolyConnectivity::ConstHalfedgeRangeSkipping PolyConnectivity::halfedges() const { return ConstHalfedgeRangeSkipping(*this); } +inline PolyConnectivity::ConstHalfedgeRange PolyConnectivity::all_halfedges() const { return ConstHalfedgeRange(*this); } +inline PolyConnectivity::ConstEdgeRangeSkipping PolyConnectivity::edges() const { return ConstEdgeRangeSkipping(*this); } +inline PolyConnectivity::ConstEdgeRange PolyConnectivity::all_edges() const { return ConstEdgeRange(*this); } +inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::faces() const { return ConstFaceRangeSkipping(*this); } +inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_faces() const { return ConstFaceRange(*this); } + +template <> inline PolyConnectivity::ConstVertexRangeSkipping PolyConnectivity::elements() const { return vertices(); } +template <> inline PolyConnectivity::ConstVertexRange PolyConnectivity::all_elements() const { return all_vertices(); } +template <> inline PolyConnectivity::ConstHalfedgeRangeSkipping PolyConnectivity::elements() const { return halfedges(); } +template <> inline PolyConnectivity::ConstHalfedgeRange PolyConnectivity::all_elements() const { return all_halfedges(); } +template <> inline PolyConnectivity::ConstEdgeRangeSkipping PolyConnectivity::elements() const { return edges(); } +template <> inline PolyConnectivity::ConstEdgeRange PolyConnectivity::all_elements() const { return all_edges(); } +template <> inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::elements() const { return faces(); } +template <> inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_elements() const { return all_faces(); } + + +inline PolyConnectivity::ConstVertexVertexRange PolyConnectivity::vv_range(VertexHandle _vh) const { + return ConstVertexVertexRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeRange PolyConnectivity::vih_range(VertexHandle _vh) const { + return ConstVertexIHalfedgeRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeRange PolyConnectivity::vih_range(HalfedgeHandle _heh) const { + return ConstVertexIHalfedgeRange(*this, opposite_halfedge_handle(_heh), 1); +} + +inline PolyConnectivity::ConstVertexOHalfedgeRange PolyConnectivity::voh_range(VertexHandle _vh) const { + return ConstVertexOHalfedgeRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexOHalfedgeRange PolyConnectivity::voh_range(HalfedgeHandle _heh) const { + return ConstVertexOHalfedgeRange(*this, _heh, 1); +} + +inline PolyConnectivity::ConstVertexEdgeRange PolyConnectivity::ve_range(VertexHandle _vh) const { + return ConstVertexEdgeRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexFaceRange PolyConnectivity::vf_range(VertexHandle _vh) const { + return ConstVertexFaceRange(*this, _vh); +} + +inline PolyConnectivity::ConstFaceVertexRange PolyConnectivity::fv_range(FaceHandle _fh) const { + return ConstFaceVertexRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceHalfedgeRange PolyConnectivity::fh_range(FaceHandle _fh) const { + return ConstFaceHalfedgeRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceEdgeRange PolyConnectivity::fe_range(FaceHandle _fh) const { + return ConstFaceEdgeRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceFaceRange PolyConnectivity::ff_range(FaceHandle _fh) const { + return ConstFaceFaceRange(*this, _fh); +} + +inline PolyConnectivity::ConstEdgeVertexRange PolyConnectivity::ev_range(EdgeHandle _eh) const { + return ConstEdgeVertexRange(*this, _eh); +} + +inline PolyConnectivity::ConstEdgeHalfedgeRange PolyConnectivity::eh_range(EdgeHandle _eh) const { + return ConstEdgeHalfedgeRange(*this, _eh); +} + +inline PolyConnectivity::ConstEdgeHalfedgeRange PolyConnectivity::eh_range(HalfedgeHandle _heh) const { + return ConstEdgeHalfedgeRange(*this, _heh, 1); +} + +inline PolyConnectivity::ConstEdgeFaceRange PolyConnectivity::ef_range(EdgeHandle _eh) const { + return ConstEdgeFaceRange(*this, _eh); +} + +inline PolyConnectivity::ConstHalfedgeLoopRange PolyConnectivity::hl_range(HalfedgeHandle _heh) const { + return ConstHalfedgeLoopRange(*this, _heh); +} + + +inline PolyConnectivity::ConstVertexVertexCWRange PolyConnectivity::vv_cw_range(VertexHandle _vh) const { + return ConstVertexVertexCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeCWRange PolyConnectivity::vih_cw_range(VertexHandle _vh) const { + return ConstVertexIHalfedgeCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeCWRange PolyConnectivity::vih_cw_range(HalfedgeHandle _heh) const { + return ConstVertexIHalfedgeCWRange(*this, opposite_halfedge_handle(_heh), 1); +} + +inline PolyConnectivity::ConstVertexOHalfedgeCWRange PolyConnectivity::voh_cw_range(VertexHandle _vh) const { + return ConstVertexOHalfedgeCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexOHalfedgeCWRange PolyConnectivity::voh_cw_range(HalfedgeHandle _heh) const { + return ConstVertexOHalfedgeCWRange(*this, _heh, 1); +} + +inline PolyConnectivity::ConstVertexEdgeCWRange PolyConnectivity::ve_cw_range(VertexHandle _vh) const { + return ConstVertexEdgeCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexFaceCWRange PolyConnectivity::vf_cw_range(VertexHandle _vh) const { + return ConstVertexFaceCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstFaceVertexCWRange PolyConnectivity::fv_cw_range(FaceHandle _fh) const { + return ConstFaceVertexCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceHalfedgeCWRange PolyConnectivity::fh_cw_range(FaceHandle _fh) const { + return ConstFaceHalfedgeCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceEdgeCWRange PolyConnectivity::fe_cw_range(FaceHandle _fh) const { + return ConstFaceEdgeCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceFaceCWRange PolyConnectivity::ff_cw_range(FaceHandle _fh) const { + return ConstFaceFaceCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstHalfedgeLoopCWRange PolyConnectivity::hl_cw_range(HalfedgeHandle _heh) const { + return ConstHalfedgeLoopCWRange(*this, _heh); +} + + + +inline PolyConnectivity::ConstVertexVertexCCWRange PolyConnectivity::vv_ccw_range(VertexHandle _vh) const { + return ConstVertexVertexCCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeCCWRange PolyConnectivity::vih_ccw_range(VertexHandle _vh) const { + return ConstVertexIHalfedgeCCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexIHalfedgeCCWRange PolyConnectivity::vih_ccw_range(HalfedgeHandle _heh) const { + return ConstVertexIHalfedgeCCWRange(*this, opposite_halfedge_handle(_heh), 1); +} + +inline PolyConnectivity::ConstVertexOHalfedgeCCWRange PolyConnectivity::voh_ccw_range(VertexHandle _vh) const { + return ConstVertexOHalfedgeCCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexOHalfedgeCCWRange PolyConnectivity::voh_ccw_range(HalfedgeHandle _heh) const { + return ConstVertexOHalfedgeCCWRange(*this, _heh, 1); +} + +inline PolyConnectivity::ConstVertexEdgeCCWRange PolyConnectivity::ve_ccw_range(VertexHandle _vh) const { + return ConstVertexEdgeCCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstVertexFaceCCWRange PolyConnectivity::vf_ccw_range(VertexHandle _vh) const { + return ConstVertexFaceCCWRange(*this, _vh); +} + +inline PolyConnectivity::ConstFaceVertexCCWRange PolyConnectivity::fv_ccw_range(FaceHandle _fh) const { + return ConstFaceVertexCCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceHalfedgeCCWRange PolyConnectivity::fh_ccw_range(FaceHandle _fh) const { + return ConstFaceHalfedgeCCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceEdgeCCWRange PolyConnectivity::fe_ccw_range(FaceHandle _fh) const { + return ConstFaceEdgeCCWRange(*this, _fh); +} + +inline PolyConnectivity::ConstFaceFaceCCWRange PolyConnectivity::ff_ccw_range(FaceHandle _fh) const { + return ConstFaceFaceCCWRange(*this, _fh); +} + + +inline PolyConnectivity::ConstHalfedgeLoopCCWRange PolyConnectivity::hl_ccw_range(HalfedgeHandle _heh) const { + return ConstHalfedgeLoopCCWRange(*this, _heh); +} + + + +inline PolyConnectivity::VertexIter PolyConnectivity::vertices_begin() +{ return VertexIter(*this, VertexHandle(0)); } + +inline PolyConnectivity::ConstVertexIter PolyConnectivity::vertices_begin() const +{ return ConstVertexIter(*this, VertexHandle(0)); } + +inline PolyConnectivity::VertexIter PolyConnectivity::vertices_end() +{ return VertexIter(*this, VertexHandle( int(n_vertices() ) )); } + +inline PolyConnectivity::ConstVertexIter PolyConnectivity::vertices_end() const +{ return ConstVertexIter(*this, VertexHandle( int(n_vertices()) )); } + +inline PolyConnectivity::HalfedgeIter PolyConnectivity::halfedges_begin() +{ return HalfedgeIter(*this, HalfedgeHandle(0)); } + +inline PolyConnectivity::ConstHalfedgeIter PolyConnectivity::halfedges_begin() const +{ return ConstHalfedgeIter(*this, HalfedgeHandle(0)); } + +inline PolyConnectivity::HalfedgeIter PolyConnectivity::halfedges_end() +{ return HalfedgeIter(*this, HalfedgeHandle(int(n_halfedges()))); } + +inline PolyConnectivity::ConstHalfedgeIter PolyConnectivity::halfedges_end() const +{ return ConstHalfedgeIter(*this, HalfedgeHandle(int(n_halfedges()))); } + +inline PolyConnectivity::EdgeIter PolyConnectivity::edges_begin() +{ return EdgeIter(*this, EdgeHandle(0)); } + +inline PolyConnectivity::ConstEdgeIter PolyConnectivity::edges_begin() const +{ return ConstEdgeIter(*this, EdgeHandle(0)); } + +inline PolyConnectivity::EdgeIter PolyConnectivity::edges_end() +{ return EdgeIter(*this, EdgeHandle(int(n_edges()))); } + +inline PolyConnectivity::ConstEdgeIter PolyConnectivity::edges_end() const +{ return ConstEdgeIter(*this, EdgeHandle(int(n_edges()))); } + +inline PolyConnectivity::FaceIter PolyConnectivity::faces_begin() +{ return FaceIter(*this, FaceHandle(0)); } + +inline PolyConnectivity::ConstFaceIter PolyConnectivity::faces_begin() const +{ return ConstFaceIter(*this, FaceHandle(0)); } + +inline PolyConnectivity::FaceIter PolyConnectivity::faces_end() +{ return FaceIter(*this, FaceHandle(int(n_faces()))); } + + +inline PolyConnectivity::ConstFaceIter PolyConnectivity::faces_end() const +{ return ConstFaceIter(*this, FaceHandle(int(n_faces()))); } + +inline PolyConnectivity::VertexIter PolyConnectivity::vertices_sbegin() +{ return VertexIter(*this, VertexHandle(0), true); } + +inline PolyConnectivity::ConstVertexIter PolyConnectivity::vertices_sbegin() const +{ return ConstVertexIter(*this, VertexHandle(0), true); } + +inline PolyConnectivity::HalfedgeIter PolyConnectivity::halfedges_sbegin() +{ return HalfedgeIter(*this, HalfedgeHandle(0), true); } + +inline PolyConnectivity::ConstHalfedgeIter PolyConnectivity::halfedges_sbegin() const +{ return ConstHalfedgeIter(*this, HalfedgeHandle(0), true); } + +inline PolyConnectivity::EdgeIter PolyConnectivity::edges_sbegin() +{ return EdgeIter(*this, EdgeHandle(0), true); } + +inline PolyConnectivity::ConstEdgeIter PolyConnectivity::edges_sbegin() const +{ return ConstEdgeIter(*this, EdgeHandle(0), true); } + +inline PolyConnectivity::FaceIter PolyConnectivity::faces_sbegin() +{ return FaceIter(*this, FaceHandle(0), true); } + +inline PolyConnectivity::ConstFaceIter PolyConnectivity::faces_sbegin() const +{ return ConstFaceIter(*this, FaceHandle(0), true); } + +inline PolyConnectivity::VertexVertexIter PolyConnectivity::vv_iter(ArrayKernel::VertexHandle _vh) +{ return VertexVertexIter(*this, _vh); } + +inline PolyConnectivity::VertexVertexCWIter PolyConnectivity::vv_cwiter(ArrayKernel::VertexHandle _vh) +{ return VertexVertexCWIter(*this, _vh); } + +inline PolyConnectivity::VertexVertexCCWIter PolyConnectivity::vv_ccwiter(ArrayKernel::VertexHandle _vh) +{ return VertexVertexCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeIter PolyConnectivity::vih_iter(ArrayKernel::VertexHandle _vh) +{ return VertexIHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeCWIter PolyConnectivity::vih_cwiter(ArrayKernel::VertexHandle _vh) +{ return VertexIHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeCCWIter PolyConnectivity::vih_ccwiter(ArrayKernel::VertexHandle _vh) +{ return VertexIHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeIter PolyConnectivity::voh_iter(ArrayKernel::VertexHandle _vh) +{ return VertexOHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeCWIter PolyConnectivity::voh_cwiter(ArrayKernel::VertexHandle _vh) +{ return VertexOHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeCCWIter PolyConnectivity::voh_ccwiter(ArrayKernel::VertexHandle _vh) +{ return VertexOHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeIter PolyConnectivity::ve_iter(ArrayKernel::VertexHandle _vh) +{ return VertexEdgeIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeCWIter PolyConnectivity::ve_cwiter(ArrayKernel::VertexHandle _vh) +{ return VertexEdgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeCCWIter PolyConnectivity::ve_ccwiter(ArrayKernel::VertexHandle _vh) +{ return VertexEdgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceIter PolyConnectivity::vf_iter(ArrayKernel::VertexHandle _vh) +{ return VertexFaceIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceCWIter PolyConnectivity::vf_cwiter(ArrayKernel::VertexHandle _vh) +{ return VertexFaceCWIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceCCWIter PolyConnectivity::vf_ccwiter(ArrayKernel::VertexHandle _vh) +{ return VertexFaceCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexVertexIter PolyConnectivity::cvv_iter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexVertexIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexVertexCWIter PolyConnectivity::cvv_cwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexVertexCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexVertexCCWIter PolyConnectivity::cvv_ccwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexVertexCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeIter PolyConnectivity::cvih_iter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexIHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeCWIter PolyConnectivity::cvih_cwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexIHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeCCWIter PolyConnectivity::cvih_ccwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexIHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeIter PolyConnectivity::cvoh_iter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexOHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeCWIter PolyConnectivity::cvoh_cwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexOHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeCCWIter PolyConnectivity::cvoh_ccwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexOHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeIter PolyConnectivity::cve_iter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexEdgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeCWIter PolyConnectivity::cve_cwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexEdgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeCCWIter PolyConnectivity::cve_ccwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexEdgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceIter PolyConnectivity::cvf_iter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexFaceIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceCWIter PolyConnectivity::cvf_cwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexFaceCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceCCWIter PolyConnectivity::cvf_ccwiter(ArrayKernel::VertexHandle _vh) const +{ return ConstVertexFaceCCWIter(*this, _vh); } + +inline PolyConnectivity::FaceVertexIter PolyConnectivity::fv_iter(ArrayKernel::FaceHandle _fh) +{ return FaceVertexIter(*this, _fh); } + +inline PolyConnectivity::FaceVertexCWIter PolyConnectivity::fv_cwiter(ArrayKernel::FaceHandle _fh) +{ return FaceVertexCWIter(*this, _fh); } + +inline PolyConnectivity::FaceVertexCCWIter PolyConnectivity::fv_ccwiter(ArrayKernel::FaceHandle _fh) +{ return FaceVertexCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeIter PolyConnectivity::fh_iter(ArrayKernel::FaceHandle _fh) +{ return FaceHalfedgeIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeCWIter PolyConnectivity::fh_cwiter(ArrayKernel::FaceHandle _fh) +{ return FaceHalfedgeCWIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeCCWIter PolyConnectivity::fh_ccwiter(ArrayKernel::FaceHandle _fh) +{ return FaceHalfedgeCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeIter PolyConnectivity::fe_iter(ArrayKernel::FaceHandle _fh) +{ return FaceEdgeIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeCWIter PolyConnectivity::fe_cwiter(ArrayKernel::FaceHandle _fh) +{ return FaceEdgeCWIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeCCWIter PolyConnectivity::fe_ccwiter(ArrayKernel::FaceHandle _fh) +{ return FaceEdgeCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceIter PolyConnectivity::ff_iter(ArrayKernel::FaceHandle _fh) +{ return FaceFaceIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceCWIter PolyConnectivity::ff_cwiter(ArrayKernel::FaceHandle _fh) +{ return FaceFaceCWIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceCCWIter PolyConnectivity::ff_ccwiter(ArrayKernel::FaceHandle _fh) +{ return FaceFaceCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceVertexIter PolyConnectivity::cfv_iter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceVertexIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceVertexCWIter PolyConnectivity::cfv_cwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceVertexCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceVertexCCWIter PolyConnectivity::cfv_ccwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceVertexCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeIter PolyConnectivity::cfh_iter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceHalfedgeIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeCWIter PolyConnectivity::cfh_cwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceHalfedgeCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeCCWIter PolyConnectivity::cfh_ccwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceHalfedgeCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeIter PolyConnectivity::cfe_iter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceEdgeIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeCWIter PolyConnectivity::cfe_cwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceEdgeCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeCCWIter PolyConnectivity::cfe_ccwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceEdgeCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceIter PolyConnectivity::cff_iter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceFaceIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceCWIter PolyConnectivity::cff_cwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceFaceCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceCCWIter PolyConnectivity::cff_ccwiter(ArrayKernel::FaceHandle _fh) const +{ return ConstFaceFaceCCWIter(*this, _fh); } + +inline PolyConnectivity::EdgeVertexIter PolyConnectivity::ev_iter(ArrayKernel::EdgeHandle _eh) +{ return EdgeVertexIter(*this, _eh); } + +inline PolyConnectivity::EdgeHalfedgeIter PolyConnectivity::eh_iter(ArrayKernel::EdgeHandle _eh) +{ return EdgeHalfedgeIter(*this, _eh); } + +inline PolyConnectivity::EdgeFaceIter PolyConnectivity::ef_iter(ArrayKernel::EdgeHandle _eh) +{ return EdgeFaceIter(*this, _eh); } + +inline PolyConnectivity::ConstEdgeVertexIter PolyConnectivity::cev_iter(ArrayKernel::EdgeHandle _eh) const +{ return ConstEdgeVertexIter(*this, _eh); } + +inline PolyConnectivity::ConstEdgeHalfedgeIter PolyConnectivity::ceh_iter(ArrayKernel::EdgeHandle _eh) const +{ return ConstEdgeHalfedgeIter(*this, _eh); } + +inline PolyConnectivity::ConstEdgeFaceIter PolyConnectivity::cef_iter(ArrayKernel::EdgeHandle _eh) const +{ return ConstEdgeFaceIter(*this, _eh); } + + +inline PolyConnectivity::VertexVertexIter PolyConnectivity::vv_begin(VertexHandle _vh) +{ return VertexVertexIter(*this, _vh); } + +inline PolyConnectivity::VertexVertexCWIter PolyConnectivity::vv_cwbegin(VertexHandle _vh) +{ return VertexVertexCWIter(*this, _vh); } + +inline PolyConnectivity::VertexVertexCCWIter PolyConnectivity::vv_ccwbegin(VertexHandle _vh) +{ return VertexVertexCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeIter PolyConnectivity::vih_begin(VertexHandle _vh) +{ return VertexIHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeCWIter PolyConnectivity::vih_cwbegin(VertexHandle _vh) +{ return VertexIHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexIHalfedgeCCWIter PolyConnectivity::vih_ccwbegin(VertexHandle _vh) +{ return VertexIHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeIter PolyConnectivity::voh_begin(VertexHandle _vh) +{ return VertexOHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeCWIter PolyConnectivity::voh_cwbegin(VertexHandle _vh) +{ return VertexOHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexOHalfedgeCCWIter PolyConnectivity::voh_ccwbegin(VertexHandle _vh) +{ return VertexOHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeIter PolyConnectivity::ve_begin(VertexHandle _vh) +{ return VertexEdgeIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeCWIter PolyConnectivity::ve_cwbegin(VertexHandle _vh) +{ return VertexEdgeCWIter(*this, _vh); } + +inline PolyConnectivity::VertexEdgeCCWIter PolyConnectivity::ve_ccwbegin(VertexHandle _vh) +{ return VertexEdgeCCWIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceIter PolyConnectivity::vf_begin(VertexHandle _vh) +{ return VertexFaceIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceCWIter PolyConnectivity::vf_cwbegin(VertexHandle _vh) +{ return VertexFaceCWIter(*this, _vh); } + +inline PolyConnectivity::VertexFaceCCWIter PolyConnectivity::vf_ccwbegin(VertexHandle _vh) +{ return VertexFaceCCWIter(*this, _vh); } + + +inline PolyConnectivity::ConstVertexVertexIter PolyConnectivity::cvv_begin(VertexHandle _vh) const +{ return ConstVertexVertexIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexVertexCWIter PolyConnectivity::cvv_cwbegin(VertexHandle _vh) const +{ return ConstVertexVertexCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexVertexCCWIter PolyConnectivity::cvv_ccwbegin(VertexHandle _vh) const +{ return ConstVertexVertexCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeIter PolyConnectivity::cvih_begin(VertexHandle _vh) const +{ return ConstVertexIHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeCWIter PolyConnectivity::cvih_cwbegin(VertexHandle _vh) const +{ return ConstVertexIHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexIHalfedgeCCWIter PolyConnectivity::cvih_ccwbegin(VertexHandle _vh) const +{ return ConstVertexIHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeIter PolyConnectivity::cvoh_begin(VertexHandle _vh) const +{ return ConstVertexOHalfedgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeCWIter PolyConnectivity::cvoh_cwbegin(VertexHandle _vh) const +{ return ConstVertexOHalfedgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexOHalfedgeCCWIter PolyConnectivity::cvoh_ccwbegin(VertexHandle _vh) const +{ return ConstVertexOHalfedgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeIter PolyConnectivity::cve_begin(VertexHandle _vh) const +{ return ConstVertexEdgeIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeCWIter PolyConnectivity::cve_cwbegin(VertexHandle _vh) const +{ return ConstVertexEdgeCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexEdgeCCWIter PolyConnectivity::cve_ccwbegin(VertexHandle _vh) const +{ return ConstVertexEdgeCCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceIter PolyConnectivity::cvf_begin(VertexHandle _vh) const +{ return ConstVertexFaceIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceCWIter PolyConnectivity::cvf_cwbegin(VertexHandle _vh) const +{ return ConstVertexFaceCWIter(*this, _vh); } + +inline PolyConnectivity::ConstVertexFaceCCWIter PolyConnectivity::cvf_ccwbegin(VertexHandle _vh) const +{ return ConstVertexFaceCCWIter(*this, _vh); } + + +inline PolyConnectivity::FaceVertexIter PolyConnectivity::fv_begin(FaceHandle _fh) +{ return FaceVertexIter(*this, _fh); } + +inline PolyConnectivity::FaceVertexCWIter PolyConnectivity::fv_cwbegin(FaceHandle _fh) +{ return FaceVertexCWIter(*this, _fh); } + +inline PolyConnectivity::FaceVertexCCWIter PolyConnectivity::fv_ccwbegin(FaceHandle _fh) +{ return FaceVertexCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeIter PolyConnectivity::fh_begin(FaceHandle _fh) +{ return FaceHalfedgeIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeCWIter PolyConnectivity::fh_cwbegin(FaceHandle _fh) +{ return FaceHalfedgeCWIter(*this, _fh); } + +inline PolyConnectivity::FaceHalfedgeCCWIter PolyConnectivity::fh_ccwbegin(FaceHandle _fh) +{ return FaceHalfedgeCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeIter PolyConnectivity::fe_begin(FaceHandle _fh) +{ return FaceEdgeIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeCWIter PolyConnectivity::fe_cwbegin(FaceHandle _fh) +{ return FaceEdgeCWIter(*this, _fh); } + +inline PolyConnectivity::FaceEdgeCCWIter PolyConnectivity::fe_ccwbegin(FaceHandle _fh) +{ return FaceEdgeCCWIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceIter PolyConnectivity::ff_begin(FaceHandle _fh) +{ return FaceFaceIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceCWIter PolyConnectivity::ff_cwbegin(FaceHandle _fh) +{ return FaceFaceCWIter(*this, _fh); } + +inline PolyConnectivity::FaceFaceCCWIter PolyConnectivity::ff_ccwbegin(FaceHandle _fh) +{ return FaceFaceCCWIter(*this, _fh); } + +inline PolyConnectivity::HalfedgeLoopIter PolyConnectivity::hl_begin(HalfedgeHandle _heh) +{ return HalfedgeLoopIter(*this, _heh); } + +inline PolyConnectivity::HalfedgeLoopCWIter PolyConnectivity::hl_cwbegin(HalfedgeHandle _heh) +{ return HalfedgeLoopCWIter(*this, _heh); } + +inline PolyConnectivity::HalfedgeLoopCCWIter PolyConnectivity::hl_ccwbegin(HalfedgeHandle _heh) +{ return HalfedgeLoopCCWIter(*this, _heh); } + + +inline PolyConnectivity::ConstFaceVertexIter PolyConnectivity::cfv_begin(FaceHandle _fh) const +{ return ConstFaceVertexIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceVertexCWIter PolyConnectivity::cfv_cwbegin(FaceHandle _fh) const +{ return ConstFaceVertexCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceVertexCCWIter PolyConnectivity::cfv_ccwbegin(FaceHandle _fh) const +{ return ConstFaceVertexCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeIter PolyConnectivity::cfh_begin(FaceHandle _fh) const +{ return ConstFaceHalfedgeIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeCWIter PolyConnectivity::cfh_cwbegin(FaceHandle _fh) const +{ return ConstFaceHalfedgeCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceHalfedgeCCWIter PolyConnectivity::cfh_ccwbegin(FaceHandle _fh) const +{ return ConstFaceHalfedgeCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeIter PolyConnectivity::cfe_begin(FaceHandle _fh) const +{ return ConstFaceEdgeIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeCWIter PolyConnectivity::cfe_cwbegin(FaceHandle _fh) const +{ return ConstFaceEdgeCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceEdgeCCWIter PolyConnectivity::cfe_ccwbegin(FaceHandle _fh) const +{ return ConstFaceEdgeCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceIter PolyConnectivity::cff_begin(FaceHandle _fh) const +{ return ConstFaceFaceIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceCWIter PolyConnectivity::cff_cwbegin(FaceHandle _fh) const +{ return ConstFaceFaceCWIter(*this, _fh); } + +inline PolyConnectivity::ConstFaceFaceCCWIter PolyConnectivity::cff_ccwbegin(FaceHandle _fh) const +{ return ConstFaceFaceCCWIter(*this, _fh); } + +inline PolyConnectivity::ConstHalfedgeLoopIter PolyConnectivity::chl_begin(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopIter(*this, _heh); } + +inline PolyConnectivity::ConstHalfedgeLoopCWIter PolyConnectivity::chl_cwbegin(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopCWIter(*this, _heh); } + +inline PolyConnectivity::ConstHalfedgeLoopCCWIter PolyConnectivity::chl_ccwbegin(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopCCWIter(*this, _heh); } + + +inline PolyConnectivity::EdgeVertexIter PolyConnectivity::ev_begin(EdgeHandle _eh) +{ return EdgeVertexIter(*this, _eh); } + +inline PolyConnectivity::EdgeHalfedgeIter PolyConnectivity::eh_begin(EdgeHandle _eh) +{ return EdgeHalfedgeIter(*this, _eh); } + +inline PolyConnectivity::EdgeFaceIter PolyConnectivity::ef_begin(EdgeHandle _eh) +{ return EdgeFaceIter(*this, _eh); } + + +inline PolyConnectivity::ConstEdgeVertexIter PolyConnectivity::cev_begin(EdgeHandle _eh) const +{ return ConstEdgeVertexIter(*this, _eh); } + +inline PolyConnectivity::ConstEdgeHalfedgeIter PolyConnectivity::ceh_begin(EdgeHandle _eh) const +{ return ConstEdgeHalfedgeIter(*this, _eh); } + +inline PolyConnectivity::ConstEdgeFaceIter PolyConnectivity::cef_begin(EdgeHandle _eh) const +{ return ConstEdgeFaceIter(*this, _eh); } + + +// 'end' circulators + +inline PolyConnectivity::VertexVertexIter PolyConnectivity::vv_end(VertexHandle _vh) +{ return VertexVertexIter(*this, _vh, true); } + +inline PolyConnectivity::VertexVertexCWIter PolyConnectivity::vv_cwend(VertexHandle _vh) +{ return VertexVertexCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexVertexCCWIter PolyConnectivity::vv_ccwend(VertexHandle _vh) +{ return VertexVertexCCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexIHalfedgeIter PolyConnectivity::vih_end(VertexHandle _vh) +{ return VertexIHalfedgeIter(*this, _vh, true); } + +inline PolyConnectivity::VertexIHalfedgeCWIter PolyConnectivity::vih_cwend(VertexHandle _vh) +{ return VertexIHalfedgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexIHalfedgeCCWIter PolyConnectivity::vih_ccwend(VertexHandle _vh) +{ return VertexIHalfedgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexOHalfedgeIter PolyConnectivity::voh_end(VertexHandle _vh) +{ return VertexOHalfedgeIter(*this, _vh, true); } + +inline PolyConnectivity::VertexOHalfedgeCWIter PolyConnectivity::voh_cwend(VertexHandle _vh) +{ return VertexOHalfedgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexOHalfedgeCCWIter PolyConnectivity::voh_ccwend(VertexHandle _vh) +{ return VertexOHalfedgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexEdgeIter PolyConnectivity::ve_end(VertexHandle _vh) +{ return VertexEdgeIter(*this, _vh, true); } + +inline PolyConnectivity::VertexEdgeCWIter PolyConnectivity::ve_cwend(VertexHandle _vh) +{ return VertexEdgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexEdgeCCWIter PolyConnectivity::ve_ccwend(VertexHandle _vh) +{ return VertexEdgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexFaceIter PolyConnectivity::vf_end(VertexHandle _vh) +{ return VertexFaceIter(*this, _vh, true); } + +inline PolyConnectivity::VertexFaceCWIter PolyConnectivity::vf_cwend(VertexHandle _vh) +{ return VertexFaceCWIter(*this, _vh, true); } + +inline PolyConnectivity::VertexFaceCCWIter PolyConnectivity::vf_ccwend(VertexHandle _vh) +{ return VertexFaceCCWIter(*this, _vh, true); } + + +inline PolyConnectivity::ConstVertexVertexIter PolyConnectivity::cvv_end(VertexHandle _vh) const +{ return ConstVertexVertexIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexVertexCWIter PolyConnectivity::cvv_cwend(VertexHandle _vh) const +{ return ConstVertexVertexCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexVertexCCWIter PolyConnectivity::cvv_ccwend(VertexHandle _vh) const +{ return ConstVertexVertexCCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexIHalfedgeIter PolyConnectivity::cvih_end(VertexHandle _vh) const +{ return ConstVertexIHalfedgeIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexIHalfedgeCWIter PolyConnectivity::cvih_cwend(VertexHandle _vh) const +{ return ConstVertexIHalfedgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexIHalfedgeCCWIter PolyConnectivity::cvih_ccwend(VertexHandle _vh) const +{ return ConstVertexIHalfedgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexOHalfedgeIter PolyConnectivity::cvoh_end(VertexHandle _vh) const +{ return ConstVertexOHalfedgeIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexOHalfedgeCWIter PolyConnectivity::cvoh_cwend(VertexHandle _vh) const +{ return ConstVertexOHalfedgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexOHalfedgeCCWIter PolyConnectivity::cvoh_ccwend(VertexHandle _vh) const +{ return ConstVertexOHalfedgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexEdgeIter PolyConnectivity::cve_end(VertexHandle _vh) const +{ return ConstVertexEdgeIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexEdgeCWIter PolyConnectivity::cve_cwend(VertexHandle _vh) const +{ return ConstVertexEdgeCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexEdgeCCWIter PolyConnectivity::cve_ccwend(VertexHandle _vh) const +{ return ConstVertexEdgeCCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexFaceIter PolyConnectivity::cvf_end(VertexHandle _vh) const +{ return ConstVertexFaceIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexFaceCWIter PolyConnectivity::cvf_cwend(VertexHandle _vh) const +{ return ConstVertexFaceCWIter(*this, _vh, true); } + +inline PolyConnectivity::ConstVertexFaceCCWIter PolyConnectivity::cvf_ccwend(VertexHandle _vh) const +{ return ConstVertexFaceCCWIter(*this, _vh, true); } + + +inline PolyConnectivity::FaceVertexIter PolyConnectivity::fv_end(FaceHandle _fh) +{ return FaceVertexIter(*this, _fh, true); } + +inline PolyConnectivity::FaceVertexCWIter PolyConnectivity::fv_cwend(FaceHandle _fh) +{ return FaceVertexCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceVertexCCWIter PolyConnectivity::fv_ccwend(FaceHandle _fh) +{ return FaceVertexCCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceHalfedgeIter PolyConnectivity::fh_end(FaceHandle _fh) +{ return FaceHalfedgeIter(*this, _fh, true); } + +inline PolyConnectivity::FaceHalfedgeCWIter PolyConnectivity::fh_cwend(FaceHandle _fh) +{ return FaceHalfedgeCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceHalfedgeCCWIter PolyConnectivity::fh_ccwend(FaceHandle _fh) +{ return FaceHalfedgeCCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceEdgeIter PolyConnectivity::fe_end(FaceHandle _fh) +{ return FaceEdgeIter(*this, _fh, true); } + +inline PolyConnectivity::FaceEdgeCWIter PolyConnectivity::fe_cwend(FaceHandle _fh) +{ return FaceEdgeCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceEdgeCCWIter PolyConnectivity::fe_ccwend(FaceHandle _fh) +{ return FaceEdgeCCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceFaceIter PolyConnectivity::ff_end(FaceHandle _fh) +{ return FaceFaceIter(*this, _fh, true); } + +inline PolyConnectivity::FaceFaceCWIter PolyConnectivity::ff_cwend(FaceHandle _fh) +{ return FaceFaceCWIter(*this, _fh, true); } + +inline PolyConnectivity::FaceFaceCCWIter PolyConnectivity::ff_ccwend(FaceHandle _fh) +{ return FaceFaceCCWIter(*this, _fh, true); } + +inline PolyConnectivity::HalfedgeLoopIter PolyConnectivity::hl_end(HalfedgeHandle _heh) +{ return HalfedgeLoopIter(*this, _heh, true); } + +inline PolyConnectivity::HalfedgeLoopCWIter PolyConnectivity::hl_cwend(HalfedgeHandle _heh) +{ return HalfedgeLoopCWIter(*this, _heh, true); } + +inline PolyConnectivity::HalfedgeLoopCCWIter PolyConnectivity::hl_ccwend(HalfedgeHandle _heh) +{ return HalfedgeLoopCCWIter(*this, _heh, true); } + + +inline PolyConnectivity::ConstFaceVertexIter PolyConnectivity::cfv_end(FaceHandle _fh) const +{ return ConstFaceVertexIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceVertexCWIter PolyConnectivity::cfv_cwend(FaceHandle _fh) const +{ return ConstFaceVertexCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceVertexCCWIter PolyConnectivity::cfv_ccwend(FaceHandle _fh) const +{ return ConstFaceVertexCCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceHalfedgeIter PolyConnectivity::cfh_end(FaceHandle _fh) const +{ return ConstFaceHalfedgeIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceHalfedgeCWIter PolyConnectivity::cfh_cwend(FaceHandle _fh) const +{ return ConstFaceHalfedgeCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceHalfedgeCCWIter PolyConnectivity::cfh_ccwend(FaceHandle _fh) const +{ return ConstFaceHalfedgeCCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceEdgeIter PolyConnectivity::cfe_end(FaceHandle _fh) const +{ return ConstFaceEdgeIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceEdgeCWIter PolyConnectivity::cfe_cwend(FaceHandle _fh) const +{ return ConstFaceEdgeCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceEdgeCCWIter PolyConnectivity::cfe_ccwend(FaceHandle _fh) const +{ return ConstFaceEdgeCCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceFaceIter PolyConnectivity::cff_end(FaceHandle _fh) const +{ return ConstFaceFaceIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceFaceCWIter PolyConnectivity::cff_cwend(FaceHandle _fh) const +{ return ConstFaceFaceCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstFaceFaceCCWIter PolyConnectivity::cff_ccwend(FaceHandle _fh) const +{ return ConstFaceFaceCCWIter(*this, _fh, true); } + +inline PolyConnectivity::ConstHalfedgeLoopIter PolyConnectivity::chl_end(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopIter(*this, _heh, true); } + +inline PolyConnectivity::ConstHalfedgeLoopCWIter PolyConnectivity::chl_cwend(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopCWIter(*this, _heh, true); } + +inline PolyConnectivity::ConstHalfedgeLoopCCWIter PolyConnectivity::chl_ccwend(HalfedgeHandle _heh) const +{ return ConstHalfedgeLoopCCWIter(*this, _heh, true); } + + +inline PolyConnectivity::EdgeVertexIter PolyConnectivity::ev_end(EdgeHandle _eh) +{ return EdgeVertexIter(*this, _eh, true); } + +inline PolyConnectivity::EdgeHalfedgeIter PolyConnectivity::eh_end(EdgeHandle _eh) +{ return EdgeHalfedgeIter(*this, _eh, true); } + +inline PolyConnectivity::EdgeFaceIter PolyConnectivity::ef_end(EdgeHandle _eh) +{ return EdgeFaceIter(*this, _eh, true); } + + +inline PolyConnectivity::ConstEdgeVertexIter PolyConnectivity::cev_end(EdgeHandle _eh) const +{ return ConstEdgeVertexIter(*this, _eh, true); } + +inline PolyConnectivity::ConstEdgeHalfedgeIter PolyConnectivity::ceh_end(EdgeHandle _eh) const +{ return ConstEdgeHalfedgeIter(*this, _eh, true); } + +inline PolyConnectivity::ConstEdgeFaceIter PolyConnectivity::cef_end(EdgeHandle _eh) const +{ return ConstEdgeFaceIter(*this, _eh, true); } + + +inline PolyConnectivity::ConstVertexFaceRange SmartVertexHandle::faces() const { assert(mesh() != nullptr); return mesh()->vf_range (*this); } +inline PolyConnectivity::ConstVertexFaceCWRange SmartVertexHandle::faces_cw() const { assert(mesh() != nullptr); return mesh()->vf_cw_range (*this); } +inline PolyConnectivity::ConstVertexFaceCCWRange SmartVertexHandle::faces_ccw() const { assert(mesh() != nullptr); return mesh()->vf_ccw_range(*this); } + +inline PolyConnectivity::ConstVertexEdgeRange SmartVertexHandle::edges() const { assert(mesh() != nullptr); return mesh()->ve_range (*this); } +inline PolyConnectivity::ConstVertexEdgeCWRange SmartVertexHandle::edges_cw() const { assert(mesh() != nullptr); return mesh()->ve_cw_range (*this); } +inline PolyConnectivity::ConstVertexEdgeCCWRange SmartVertexHandle::edges_ccw() const { assert(mesh() != nullptr); return mesh()->ve_ccw_range(*this); } + +inline PolyConnectivity::ConstVertexVertexRange SmartVertexHandle::vertices() const { assert(mesh() != nullptr); return mesh()->vv_range (*this); } +inline PolyConnectivity::ConstVertexVertexCWRange SmartVertexHandle::vertices_cw() const { assert(mesh() != nullptr); return mesh()->vv_cw_range (*this); } +inline PolyConnectivity::ConstVertexVertexCCWRange SmartVertexHandle::vertices_ccw() const { assert(mesh() != nullptr); return mesh()->vv_ccw_range (*this); } + +inline PolyConnectivity::ConstVertexIHalfedgeRange SmartVertexHandle::incoming_halfedges() const { assert(mesh() != nullptr); return mesh()->vih_range (*this); } +inline PolyConnectivity::ConstVertexIHalfedgeCWRange SmartVertexHandle::incoming_halfedges_cw() const { assert(mesh() != nullptr); return mesh()->vih_cw_range (*this); } +inline PolyConnectivity::ConstVertexIHalfedgeCCWRange SmartVertexHandle::incoming_halfedges_ccw() const { assert(mesh() != nullptr); return mesh()->vih_ccw_range(*this); } + +inline PolyConnectivity::ConstVertexIHalfedgeRange SmartVertexHandle::incoming_halfedges (HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->vih_range (_heh); } +inline PolyConnectivity::ConstVertexIHalfedgeCWRange SmartVertexHandle::incoming_halfedges_cw (HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->vih_cw_range (_heh); } +inline PolyConnectivity::ConstVertexIHalfedgeCCWRange SmartVertexHandle::incoming_halfedges_ccw(HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->vih_ccw_range(_heh); } + +inline PolyConnectivity::ConstVertexOHalfedgeRange SmartVertexHandle::outgoing_halfedges() const { assert(mesh() != nullptr); return mesh()->voh_range (*this); } +inline PolyConnectivity::ConstVertexOHalfedgeCWRange SmartVertexHandle::outgoing_halfedges_cw() const { assert(mesh() != nullptr); return mesh()->voh_cw_range (*this); } +inline PolyConnectivity::ConstVertexOHalfedgeCCWRange SmartVertexHandle::outgoing_halfedges_ccw() const { assert(mesh() != nullptr); return mesh()->voh_ccw_range(*this); } + +inline PolyConnectivity::ConstVertexOHalfedgeRange SmartVertexHandle::outgoing_halfedges (HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->voh_range (_heh); } +inline PolyConnectivity::ConstVertexOHalfedgeCWRange SmartVertexHandle::outgoing_halfedges_cw (HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->voh_cw_range (_heh); } +inline PolyConnectivity::ConstVertexOHalfedgeCCWRange SmartVertexHandle::outgoing_halfedges_ccw(HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->voh_ccw_range(_heh); } + + +inline PolyConnectivity::ConstHalfedgeLoopRange SmartHalfedgeHandle::loop() const { assert(mesh() != nullptr); return mesh()->hl_range (*this); } +inline PolyConnectivity::ConstHalfedgeLoopCWRange SmartHalfedgeHandle::loop_cw() const { assert(mesh() != nullptr); return mesh()->hl_cw_range (*this); } +inline PolyConnectivity::ConstHalfedgeLoopCCWRange SmartHalfedgeHandle::loop_ccw() const { assert(mesh() != nullptr); return mesh()->hl_ccw_range (*this); } + + +inline PolyConnectivity::ConstFaceVertexRange SmartFaceHandle::vertices() const { assert(mesh() != nullptr); return mesh()->fv_range (*this); } +inline PolyConnectivity::ConstFaceVertexCWRange SmartFaceHandle::vertices_cw() const { assert(mesh() != nullptr); return mesh()->fv_cw_range (*this); } +inline PolyConnectivity::ConstFaceVertexCCWRange SmartFaceHandle::vertices_ccw() const { assert(mesh() != nullptr); return mesh()->fv_ccw_range(*this); } + +inline PolyConnectivity::ConstFaceHalfedgeRange SmartFaceHandle::halfedges() const { assert(mesh() != nullptr); return mesh()->fh_range (*this); } +inline PolyConnectivity::ConstFaceHalfedgeCWRange SmartFaceHandle::halfedges_cw() const { assert(mesh() != nullptr); return mesh()->fh_cw_range (*this); } +inline PolyConnectivity::ConstFaceHalfedgeCCWRange SmartFaceHandle::halfedges_ccw() const { assert(mesh() != nullptr); return mesh()->fh_ccw_range(*this); } + +inline PolyConnectivity::ConstFaceEdgeRange SmartFaceHandle::edges() const { assert(mesh() != nullptr); return mesh()->fe_range (*this); } +inline PolyConnectivity::ConstFaceEdgeCWRange SmartFaceHandle::edges_cw() const { assert(mesh() != nullptr); return mesh()->fe_cw_range (*this); } +inline PolyConnectivity::ConstFaceEdgeCCWRange SmartFaceHandle::edges_ccw() const { assert(mesh() != nullptr); return mesh()->fe_ccw_range(*this); } + +inline PolyConnectivity::ConstFaceFaceRange SmartFaceHandle::faces() const { assert(mesh() != nullptr); return mesh()->ff_range (*this); } +inline PolyConnectivity::ConstFaceFaceCWRange SmartFaceHandle::faces_cw() const { assert(mesh() != nullptr); return mesh()->ff_cw_range (*this); } +inline PolyConnectivity::ConstFaceFaceCCWRange SmartFaceHandle::faces_ccw() const { assert(mesh() != nullptr); return mesh()->ff_ccw_range(*this); } + + +inline PolyConnectivity::ConstEdgeVertexRange SmartEdgeHandle::vertices() const { assert(mesh() != nullptr); return mesh()->ev_range (*this); } + +inline PolyConnectivity::ConstEdgeHalfedgeRange SmartEdgeHandle::halfedges() const { assert(mesh() != nullptr); return mesh()->eh_range (*this); } + +inline PolyConnectivity::ConstEdgeHalfedgeRange SmartEdgeHandle::halfedges(HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->eh_range (_heh); } + +inline PolyConnectivity::ConstEdgeFaceRange SmartEdgeHandle::faces() const { assert(mesh() != nullptr); return mesh()->ef_range (*this); } + +}//namespace OpenMesh diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyMeshT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyMeshT.hh new file mode 100644 index 0000000..757c58e --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyMeshT.hh @@ -0,0 +1,664 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS PolyMeshT +// +//============================================================================= + + +#ifndef OPENMESH_POLYMESHT_HH +#define OPENMESH_POLYMESHT_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + + +/** \class PolyMeshT PolyMeshT.hh + + Base type for a polygonal mesh. + + This is the base class for a polygonal mesh. It is parameterized + by a mesh kernel that is given as a template argument. This class + inherits all methods from its mesh kernel. + + \param Kernel: template argument for the mesh kernel + \note You should use the predefined mesh-kernel combinations in + \ref mesh_types_group + \see \ref mesh_type +*/ + +template +class PolyMeshT : public Kernel +{ +public: + + /// Self type. Used to specify iterators/circulators. + typedef PolyMeshT This; + //--- item types --- + + //@{ + /// Determine whether this is a PolyMeshT or TriMeshT (This function does not check the per face vertex count! It only checks if the datatype is PolyMeshT or TriMeshT) + static constexpr bool is_polymesh() { return true; } + static constexpr bool is_trimesh() { return false; } + using ConnectivityTag = PolyConnectivityTag; + enum { IsPolyMesh = 1 }; + enum { IsTriMesh = 0 }; + //@} + + /// \name Mesh Items + //@{ + /// Scalar type + typedef typename Kernel::Scalar Scalar; + /// Coordinate type + typedef typename Kernel::Point Point; + /// Normal type + typedef typename Kernel::Normal Normal; + /// Color type + typedef typename Kernel::Color Color; + /// TexCoord1D type + typedef typename Kernel::TexCoord1D TexCoord1D; + /// TexCoord2D type + typedef typename Kernel::TexCoord2D TexCoord2D; + /// TexCoord3D type + typedef typename Kernel::TexCoord3D TexCoord3D; + /// Vertex type + typedef typename Kernel::Vertex Vertex; + /// Halfedge type + typedef typename Kernel::Halfedge Halfedge; + /// Edge type + typedef typename Kernel::Edge Edge; + /// Face type + typedef typename Kernel::Face Face; + //@} + + //--- handle types --- + + /// Handle for referencing the corresponding item + typedef typename Kernel::VertexHandle VertexHandle; + typedef typename Kernel::HalfedgeHandle HalfedgeHandle; + typedef typename Kernel::EdgeHandle EdgeHandle; + typedef typename Kernel::FaceHandle FaceHandle; + + + + typedef typename Kernel::VertexIter VertexIter; + typedef typename Kernel::HalfedgeIter HalfedgeIter; + typedef typename Kernel::EdgeIter EdgeIter; + typedef typename Kernel::FaceIter FaceIter; + + typedef typename Kernel::ConstVertexIter ConstVertexIter; + typedef typename Kernel::ConstHalfedgeIter ConstHalfedgeIter; + typedef typename Kernel::ConstEdgeIter ConstEdgeIter; + typedef typename Kernel::ConstFaceIter ConstFaceIter; + //@} + + //--- circulators --- + + /** \name Mesh Circulators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators + for documentation. + */ + //@{ + /// Circulator + typedef typename Kernel::VertexVertexIter VertexVertexIter; + typedef typename Kernel::VertexOHalfedgeIter VertexOHalfedgeIter; + typedef typename Kernel::VertexIHalfedgeIter VertexIHalfedgeIter; + typedef typename Kernel::VertexEdgeIter VertexEdgeIter; + typedef typename Kernel::VertexFaceIter VertexFaceIter; + typedef typename Kernel::FaceVertexIter FaceVertexIter; + typedef typename Kernel::FaceHalfedgeIter FaceHalfedgeIter; + typedef typename Kernel::FaceEdgeIter FaceEdgeIter; + typedef typename Kernel::FaceFaceIter FaceFaceIter; + + typedef typename Kernel::ConstVertexVertexIter ConstVertexVertexIter; + typedef typename Kernel::ConstVertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef typename Kernel::ConstVertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef typename Kernel::ConstVertexEdgeIter ConstVertexEdgeIter; + typedef typename Kernel::ConstVertexFaceIter ConstVertexFaceIter; + typedef typename Kernel::ConstFaceVertexIter ConstFaceVertexIter; + typedef typename Kernel::ConstFaceHalfedgeIter ConstFaceHalfedgeIter; + typedef typename Kernel::ConstFaceEdgeIter ConstFaceEdgeIter; + typedef typename Kernel::ConstFaceFaceIter ConstFaceFaceIter; + //@} + + + // --- constructor/destructor + PolyMeshT() {} + template + explicit PolyMeshT(const T& t) : Kernel(t) {} + virtual ~PolyMeshT() {} + + /** Uses default copy and assignment operator. + Use them to assign two meshes of \b equal type. + If the mesh types vary, use PolyMeshT::assign() instead. */ + + // --- creation --- + + /** + * \brief Adds a new default-initialized vertex. + * + * \sa new_vertex(const Point&), new_vertex_dirty() + */ + inline SmartVertexHandle new_vertex() + { return make_smart(Kernel::new_vertex(), this); } + + /** + * \brief Adds a new vertex initialized to a custom position. + * + * \sa new_vertex(), new_vertex_dirty() + * + */ + inline SmartVertexHandle new_vertex(const Point _p) + { + VertexHandle vh(Kernel::new_vertex()); + this->set_point(vh, _p); + return make_smart(vh, this); + } + + /** + * Same as new_vertex(const Point&) but never shrinks, only enlarges the + * vertex property vectors. + * + * If you are rebuilding a mesh that you erased with ArrayKernel::clean() or + * ArrayKernel::clean_keep_reservation() using this method instead of + * new_vertex(const Point &) saves reallocation and reinitialization of + * property memory. + * + * \sa new_vertex(const Point ) + */ + inline SmartVertexHandle new_vertex_dirty(const Point _p) + { + VertexHandle vh(Kernel::new_vertex_dirty()); + this->set_point(vh, _p); + return make_smart(vh, this); + } + + /** Alias for new_vertex(const Point&). + * + */ + inline SmartVertexHandle add_vertex(const Point _p) + { return new_vertex(_p); } + + /// Alias for new_vertex_dirty(). + inline SmartVertexHandle add_vertex_dirty(const Point _p) + { return make_smart(new_vertex_dirty(_p), this); } + + // --- normal vectors --- + + /** \name Normal vector computation + */ + //@{ + + /** \brief Compute normals for all primitives + * + * Calls update_face_normals() , update_halfedge_normals() and update_vertex_normals() if + * the normals (i.e. the properties) exist. + * + * \note Face normals are required to compute vertex and halfedge normals! + */ + void update_normals(); + + /// Update normal for face _fh + void update_normal(FaceHandle _fh) + { this->set_normal(_fh, calc_face_normal(_fh)); } + + /** \brief Update normal vectors for all faces. + * + * \attention Needs the Attributes::Normal attribute for faces. + * Call request_face_normals() before using it! + */ + void update_face_normals(); + + /** Calculate normal vector for face _fh. */ + virtual Normal calc_face_normal(FaceHandle _fh) const; + + /** Calculate normal vector for face (_p0, _p1, _p2). */ + Normal calc_face_normal(const Point& _p0, const Point& _p1, + const Point& _p2) const; + + /// same as calc_face_normal + Normal calc_normal(FaceHandle _fh) const; + + /// calculates the average of the vertices defining _fh + void calc_face_centroid(FaceHandle _fh, Point& _pt) const { + _pt = calc_face_centroid(_fh); + } + + /// Computes and returns the average of the vertices defining _fh + Point calc_face_centroid(FaceHandle _fh) const; + + /// Computes and returns the average of the vertices defining _fh (same as calc_face_centroid) + Point calc_centroid(FaceHandle _fh) const; + + /// Computes and returns the average of the vertices defining _eh (same as calc_edge_midpoint) + Point calc_centroid(EdgeHandle _eh) const; + + /// Computes and returns the average of the vertices defining _heh (same as calc_edge_midpoint for edge of halfedge) + Point calc_centroid(HalfedgeHandle _heh) const; + + /// Returns the point of _vh + Point calc_centroid(VertexHandle _vh) const; + + /// Computes and returns the average of the vertices defining the mesh + Point calc_centroid(MeshHandle _mh) const; + + /// Update normal for halfedge _heh + void update_normal(HalfedgeHandle _heh, const double _feature_angle = 0.8) + { this->set_normal(_heh, calc_halfedge_normal(_heh,_feature_angle)); } + + /** \brief Update normal vectors for all halfedges. + * + * Uses the existing face normals to compute halfedge normals + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and halfedges. + * Call request_face_normals() and request_halfedge_normals() before using it! + */ + void update_halfedge_normals(const double _feature_angle = 0.8); + + /** \brief Calculate halfedge normal for one specific halfedge + * + * Calculate normal vector for halfedge _heh. + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and vertices. + * Call request_face_normals() and request_halfedge_normals() before using it! + * + * @param _heh Handle of the halfedge + * @param _feature_angle If the dihedral angle across this edge is greater than this value, the edge is considered as a feature edge (angle in radians) + */ + virtual Normal calc_halfedge_normal(HalfedgeHandle _heh, const double _feature_angle = 0.8) const; + + /// same as calc_halfedge_normal + Normal calc_normal(HalfedgeHandle, const double _feature_angle = 0.8) const; + + /** identifies feature edges w.r.t. the minimal dihedral angle for feature edges (in radians) */ + /** and the status feature tag */ + bool is_estimated_feature_edge(HalfedgeHandle _heh, const double _feature_angle) const; + + /// Update normal for vertex _vh + void update_normal(VertexHandle _vh) + { this->set_normal(_vh, calc_vertex_normal(_vh)); } + + /** \brief Update normal vectors for all vertices. + * + * Uses existing face normals to calculate new vertex normals. + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and vertices. + * Call request_face_normals() and request_vertex_normals() before using it! + */ + void update_vertex_normals(); + + /** \brief Calculate vertex normal for one specific vertex + * + * Calculate normal vector for vertex _vh by averaging normals + * of adjacent faces. + * + * \note Face normals have to be computed first! + * + * \attention Needs the Attributes::Normal attribute for faces and vertices. + * Call request_face_normals() and request_vertex_normals() before using it! + * + * @param _vh Handle of the vertex + */ + Normal calc_vertex_normal(VertexHandle _vh) const; + + /** Different methods for calculation of the normal at _vh: + - ..._fast - the default one - the same as calc vertex_normal() + - needs the Attributes::Normal attribute for faces + - ..._correct - works properly for non-triangular meshes + - does not need any attributes + - ..._loop - calculates loop surface normals + - does not need any attributes */ + void calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const; + void calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const; + void calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const; + + /// same as calc_vertex_normal_correct + Normal calc_normal(VertexHandle _vh) const; + + //@} + + // --- Geometry API - still in development --- + + /** Calculates the edge vector as the vector defined by + the halfedge with id #0 (see below) */ + void calc_edge_vector(EdgeHandle _eh, Normal& _edge_vec) const + { + _edge_vec = calc_edge_vector(_eh); + } + + /** Calculates the edge vector as the vector defined by + the halfedge with id #0 (see below) */ + Normal calc_edge_vector(EdgeHandle _eh) const + { + return calc_edge_vector(this->halfedge_handle(_eh,0)); + } + + /** Calculates the edge vector as the difference of the + the points defined by to_vertex_handle() and from_vertex_handle() */ + void calc_edge_vector(HalfedgeHandle _heh, Normal& _edge_vec) const + { + _edge_vec = calc_edge_vector(_heh); + } + + /** Calculates the edge vector as the difference of the + the points defined by to_vertex_handle() and from_vertex_handle() */ + Normal calc_edge_vector(HalfedgeHandle _heh) const + { + return this->point(this->to_vertex_handle(_heh)) - + this->point(this->from_vertex_handle(_heh)); + } + + // Calculates the length of the edge _eh + Scalar calc_edge_length(EdgeHandle _eh) const + { return calc_edge_length(this->halfedge_handle(_eh,0)); } + + /** Calculates the length of the edge _heh + */ + Scalar calc_edge_length(HalfedgeHandle _heh) const + { return (Scalar)sqrt(calc_edge_sqr_length(_heh)); } + + Scalar calc_edge_sqr_length(EdgeHandle _eh) const + { return calc_edge_sqr_length(this->halfedge_handle(_eh,0)); } + + Scalar calc_edge_sqr_length(HalfedgeHandle _heh) const + { + Normal edge_vec; + calc_edge_vector(_heh, edge_vec); + return sqrnorm(edge_vec); + } + + /** Calculates the midpoint of the halfedge _heh, defined by the positions of + the two incident vertices */ + Point calc_edge_midpoint(HalfedgeHandle _heh) const + { + VertexHandle vh0 = this->from_vertex_handle(_heh); + VertexHandle vh1 = this->to_vertex_handle(_heh); + return 0.5 * (this->point(vh0) + this->point(vh1)); + } + + /** Calculates the midpoint of the edge _eh, defined by the positions of the + two incident vertices */ + Point calc_edge_midpoint(EdgeHandle _eh) const + { + return calc_edge_midpoint(this->halfedge_handle(_eh, 0)); + } + + /// calculated and returns the average of the two vertex normals + Normal calc_normal(EdgeHandle _eh) const; + + /** defines a consistent representation of a sector geometry: + the halfedge _in_heh defines the sector orientation + the vertex pointed by _in_heh defines the sector center + _vec0 and _vec1 are resp. the first and the second vectors defining the sector */ + void calc_sector_vectors(HalfedgeHandle _in_heh, Normal& _vec0, Normal& _vec1) const + { + calc_edge_vector(this->next_halfedge_handle(_in_heh), _vec0);//p2 - p1 + calc_edge_vector(this->opposite_halfedge_handle(_in_heh), _vec1);//p0 - p1 + } + + /** calculates the sector angle.\n + * The vertex pointed by _in_heh defines the sector center + * The angle will be calculated between the given halfedge and the next halfedge.\n + * Seen from the center vertex this will be the next halfedge in clockwise direction.\n + NOTE: only boundary concave sectors are treated correctly */ + Scalar calc_sector_angle(HalfedgeHandle _in_heh) const + { + Normal v0, v1; + calc_sector_vectors(_in_heh, v0, v1); + Scalar denom = norm(v0)*norm(v1); + if ( denom == Scalar(0)) + { + return 0; + } + Scalar cos_a = dot(v0 , v1) / denom; + if (this->is_boundary(_in_heh)) + {//determine if the boundary sector is concave or convex + FaceHandle fh(this->face_handle(this->opposite_halfedge_handle(_in_heh))); + Normal f_n(calc_face_normal(fh));//this normal is (for convex fh) OK + Scalar sign_a = dot(cross(v0, v1), f_n); + return angle(cos_a, sign_a); + } + else + { + return acos(sane_aarg(cos_a)); + } + } + + // calculate the cos and the sin of angle <(_in_heh,next_halfedge(_in_heh)) + /* + void calc_sector_angle_cos_sin(HalfedgeHandle _in_heh, Scalar& _cos_a, Scalar& _sin_a) const + { + Normal in_vec, out_vec; + calc_edge_vector(_in_heh, in_vec); + calc_edge_vector(next_halfedge_handle(_in_heh), out_vec); + Scalar denom = norm(in_vec)*norm(out_vec); + if (is_zero(denom)) + { + _cos_a = 1; + _sin_a = 0; + } + else + { + _cos_a = dot(in_vec, out_vec)/denom; + _sin_a = norm(cross(in_vec, out_vec))/denom; + } + } + */ + /** calculates the normal (non-normalized) of the face sector defined by + the angle <(_in_heh,next_halfedge(_in_heh)) */ + void calc_sector_normal(HalfedgeHandle _in_heh, Normal& _sector_normal) const + { + Normal vec0, vec1; + calc_sector_vectors(_in_heh, vec0, vec1); + _sector_normal = cross(vec0, vec1);//(p2-p1)^(p0-p1) + } + + /** calculates the area of the face sector defined by + the angle <(_in_heh,next_halfedge(_in_heh)) + NOTE: special cases (e.g. concave sectors) are not handled correctly */ + Scalar calc_sector_area(HalfedgeHandle _in_heh) const + { + Normal sector_normal; + calc_sector_normal(_in_heh, sector_normal); + return norm(sector_normal)/2; + } + + /** calculates the dihedral angle on the halfedge _heh + \attention Needs the Attributes::Normal attribute for faces */ + Scalar calc_dihedral_angle_fast(HalfedgeHandle _heh) const + { + // Make sure that we have face normals on the mesh + assert(Kernel::has_face_normals()); + + if (this->is_boundary(this->edge_handle(_heh))) + {//the dihedral angle at a boundary edge is 0 + return 0; + } + const Normal& n0 = this->normal(this->face_handle(_heh)); + const Normal& n1 = this->normal(this->face_handle(this->opposite_halfedge_handle(_heh))); + Normal he; + calc_edge_vector(_heh, he); + Scalar da_cos = dot(n0, n1); + //should be normalized, but we need only the sign + Scalar da_sin_sign = dot(cross(n0, n1), he); + return angle(da_cos, da_sin_sign); + } + + /** calculates the dihedral angle on the edge _eh + \attention Needs the Attributes::Normal attribute for faces */ + Scalar calc_dihedral_angle_fast(EdgeHandle _eh) const + { return calc_dihedral_angle_fast(this->halfedge_handle(_eh,0)); } + + // calculates the dihedral angle on the halfedge _heh + Scalar calc_dihedral_angle(HalfedgeHandle _heh) const + { + if (this->is_boundary(this->edge_handle(_heh))) + {//the dihedral angle at a boundary edge is 0 + return 0; + } + Normal n0, n1, he; + calc_sector_normal(_heh, n0); + calc_sector_normal(this->opposite_halfedge_handle(_heh), n1); + calc_edge_vector(_heh, he); + Scalar denom = norm(n0)*norm(n1); + if (denom == Scalar(0)) + { + return 0; + } + Scalar da_cos = dot(n0, n1)/denom; + //should be normalized, but we need only the sign + Scalar da_sin_sign = dot(cross(n0, n1), he); + return angle(da_cos, da_sin_sign); + } + + // calculates the dihedral angle on the edge _eh + Scalar calc_dihedral_angle(EdgeHandle _eh) const + { return calc_dihedral_angle(this->halfedge_handle(_eh,0)); } + + /** tags an edge as a feature if its dihedral angle is larger than _angle_tresh + returns the number of the found feature edges, requires edge_status property*/ + unsigned int find_feature_edges(Scalar _angle_tresh = OpenMesh::deg_to_rad(44.0)); + // --- misc --- + + /// Face split (= 1-to-n split) + inline void split(FaceHandle _fh, const Point& _p) + { Kernel::split(_fh, add_vertex(_p)); } + + inline void split(FaceHandle _fh, VertexHandle _vh) + { Kernel::split(_fh, _vh); } + + inline void split(EdgeHandle _eh, const Point& _p) + { Kernel::split_edge(_eh, add_vertex(_p)); } + + inline void split(EdgeHandle _eh, VertexHandle _vh) + { Kernel::split_edge(_eh, _vh); } + +private: + struct PointIs3DTag {}; + struct PointIsNot3DTag {}; + Normal calc_face_normal_impl(FaceHandle, PointIs3DTag) const; + Normal calc_face_normal_impl(FaceHandle, PointIsNot3DTag) const; + Normal calc_face_normal_impl(const Point&, const Point&, const Point&, PointIs3DTag) const; + Normal calc_face_normal_impl(const Point&, const Point&, const Point&, PointIsNot3DTag) const; +}; + +/** + * @brief Cast a mesh with different but identical traits into each other. + * + * Example: + * @code{.cpp} + * struct TriTraits1 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits2 : public OpenMesh::DefaultTraits { + * typedef Vec3d Point; + * }; + * struct TriTraits3 : public OpenMesh::DefaultTraits { + * typedef Vec3f Point; + * }; + * + * TriMesh_ArrayKernelT a; + * TriMesh_ArrayKernelT &b = mesh_cast&>(a); // OK + * TriMesh_ArrayKernelT &c = mesh_cast&>(a); // ERROR + * @endcode + * + * @see MeshCast + * + * @param rhs + * @return + */ +template +LHS mesh_cast(PolyMeshT &rhs) { + return MeshCast&>::cast(rhs); +} + +template +LHS mesh_cast(PolyMeshT *rhs) { + return MeshCast*>::cast(rhs); +} + +template +const LHS mesh_cast(const PolyMeshT &rhs) { + return MeshCast&>::cast(rhs); +} + +template +const LHS mesh_cast(const PolyMeshT *rhs) { + return MeshCast*>::cast(rhs); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_POLYMESH_C) +# define OPENMESH_POLYMESH_TEMPLATES +# include "PolyMeshT_impl.hh" +#endif +//============================================================================= +#endif // OPENMESH_POLYMESHT_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyMeshT_impl.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyMeshT_impl.hh new file mode 100644 index 0000000..5026a36 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyMeshT_impl.hh @@ -0,0 +1,582 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS PolyMeshT - IMPLEMENTATION +// +//============================================================================= + + +#define OPENMESH_POLYMESH_C + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +//== IMPLEMENTATION ========================================================== + +template +uint PolyMeshT::find_feature_edges(Scalar _angle_tresh) +{ + assert(Kernel::has_edge_status());//this function needs edge status property + uint n_feature_edges = 0; + for (EdgeIter e_it = Kernel::edges_begin(); e_it != Kernel::edges_end(); ++e_it) + { + if (fabs(calc_dihedral_angle(*e_it)) > _angle_tresh) + {//note: could be optimized by comparing cos(dih_angle) vs. cos(_angle_tresh) + this->status(*e_it).set_feature(true); + n_feature_edges++; + } + else + { + this->status(*e_it).set_feature(false); + } + } + return n_feature_edges; +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal(FaceHandle _fh) const +{ + return calc_face_normal_impl(_fh, typename GenProg::IF< + vector_traits::Point>::size_ == 3, + PointIs3DTag, + PointIsNot3DTag + >::Result()); +} + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal_impl(FaceHandle _fh, PointIs3DTag) const +{ + assert(this->halfedge_handle(_fh).is_valid()); + ConstFaceVertexIter fv_it(this->cfv_iter(_fh)); + + // Safeguard for 1-gons + if (!(++fv_it).is_valid()) return Normal(0, 0, 0); + + // Safeguard for 2-gons + if (!(++fv_it).is_valid()) return Normal(0, 0, 0); + + // use Newell's Method to compute the surface normal + Normal n(0,0,0); + for(fv_it = this->cfv_iter(_fh); fv_it.is_valid(); ++fv_it) + { + // next vertex + ConstFaceVertexIter fv_itn = fv_it; + ++fv_itn; + + if (!fv_itn.is_valid()) + fv_itn = this->cfv_iter(_fh); + + // http://www.opengl.org/wiki/Calculating_a_Surface_Normal + const Point a = this->point(*fv_it) - this->point(*fv_itn); + const Point b = this->point(*fv_it) + this->point(*fv_itn); + + + // Due to traits, the value types of normals and points can be different. + // Therefore we cast them here. + n[0] += static_cast::value_type>(a[1] * b[2]); + n[1] += static_cast::value_type>(a[2] * b[0]); + n[2] += static_cast::value_type>(a[0] * b[1]); + } + + const typename vector_traits::value_type length = norm(n); + + // The expression ((n *= (1.0/norm)),n) is used because the OpenSG + // vector class does not return self after component-wise + // self-multiplication with a scalar!!! + return (length != typename vector_traits::value_type(0)) + ? ((n *= (typename vector_traits::value_type(1)/length)), n) + : Normal(0, 0, 0); +} + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal_impl(FaceHandle, PointIsNot3DTag) const +{ + // Dummy fallback implementation + // Returns just an initialized all 0 normal + // This function is only used if we don't have a matching implementation + // for normal computation with the current vector type defined in the mesh traits + + assert(false); + + Normal normal; + vectorize(normal,Scalar(0)); + return normal; +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_face_normal(const Point& _p0, + const Point& _p1, + const Point& _p2) const +{ + return calc_face_normal_impl(_p0, _p1, _p2, typename GenProg::IF< + vector_traits::Point>::size_ == 3, + PointIs3DTag, + PointIsNot3DTag + >::Result()); +} + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_normal(FaceHandle _fh) const +{ + return calc_face_normal(_fh); +} + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_face_normal_impl(const Point& _p0, + const Point& _p1, + const Point& _p2, + PointIs3DTag) const +{ +#if 1 + // The OpenSG ::operator -= () does not support the type Point + // as rhs. Therefore use vector_cast at this point!!! + // Note! OpenSG distinguishes between Normal and Point!!! + Normal p1p0(vector_cast(_p0)); p1p0 -= vector_cast(_p1); + Normal p1p2(vector_cast(_p2)); p1p2 -= vector_cast(_p1); + + Normal n = cross(p1p2, p1p0); + typename vector_traits::value_type length = norm(n); + + // The expression ((n *= (1.0/norm)),n) is used because the OpenSG + // vector class does not return self after component-wise + // self-multiplication with a scalar!!! + return (length != typename vector_traits::value_type(0)) + ? ((n *= (typename vector_traits::value_type(1)/length)),n) + : Normal(0,0,0); +#else + Point p1p0 = _p0; p1p0 -= _p1; + Point p1p2 = _p2; p1p2 -= _p1; + + Normal n = vector_cast(cross(p1p2, p1p0)); + typename vector_traits::value_type length = norm(n); + + return (length != 0.0) ? n *= (1.0/length) : Normal(0,0,0); +#endif +} + +template +typename PolyMeshT::Normal +PolyMeshT::calc_face_normal_impl(const Point&, const Point&, const Point&, PointIsNot3DTag) const +{ + + // Dummy fallback implementation + // Returns just an initialized all 0 normal + // This function is only used if we don't have a matching implementation + // for normal computation with the current vector type defined in the mesh traits + + assert(false); + + Normal normal; + vectorize(normal,Scalar(0)); + return normal; +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_face_centroid(FaceHandle _fh) const +{ + Point _pt; + vectorize(_pt, Scalar(0)); + Scalar valence = 0.0; + for (ConstFaceVertexIter cfv_it = this->cfv_iter(_fh); cfv_it.is_valid(); ++cfv_it, valence += 1.0) + { + _pt += this->point(*cfv_it); + } + _pt /= valence; + return _pt; +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_centroid(FaceHandle _fh) const +{ + return calc_face_centroid(_fh); +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_centroid(EdgeHandle _eh) const +{ + return this->calc_edge_midpoint(_eh); +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_centroid(HalfedgeHandle _heh) const +{ + return this->calc_edge_midpoint(this->edge_handle(_heh)); +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_centroid(VertexHandle _vh) const +{ + return this->point(_vh); +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Point +PolyMeshT:: +calc_centroid(MeshHandle /*_mh*/) const +{ + return this->vertices().avg([this](VertexHandle vh) { return this->point(vh); }); +} + +//----------------------------------------------------------------------------- + +template +void +PolyMeshT:: +update_normals() +{ + // Face normals are required to compute the vertex and the halfedge normals + if (Kernel::has_face_normals() ) { + update_face_normals(); + + if (Kernel::has_vertex_normals() ) update_vertex_normals(); + if (Kernel::has_halfedge_normals()) update_halfedge_normals(); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_face_normals() +{ + FaceIter f_it(Kernel::faces_sbegin()), f_end(Kernel::faces_end()); + + for (; f_it != f_end; ++f_it) + this->set_normal(*f_it, calc_face_normal(*f_it)); +} + + +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_halfedge_normals(const double _feature_angle) +{ + HalfedgeIter h_it(Kernel::halfedges_begin()), h_end(Kernel::halfedges_end()); + + for (; h_it != h_end; ++h_it) + this->set_normal(*h_it, calc_halfedge_normal(*h_it, _feature_angle)); +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_halfedge_normal(HalfedgeHandle _heh, const double _feature_angle) const +{ + if(Kernel::is_boundary(_heh)) + return Normal(0,0,0); + else + { + std::vector fhs; fhs.reserve(10); + + HalfedgeHandle heh = _heh; + + // collect CW face-handles + do + { + fhs.push_back(Kernel::face_handle(heh)); + + heh = Kernel::next_halfedge_handle(heh); + heh = Kernel::opposite_halfedge_handle(heh); + } + while(heh != _heh && !Kernel::is_boundary(heh) && !is_estimated_feature_edge(heh, _feature_angle)); + + // collect CCW face-handles + if(heh != _heh && !is_estimated_feature_edge(_heh, _feature_angle)) + { + heh = Kernel::opposite_halfedge_handle(_heh); + + if ( !Kernel::is_boundary(heh) ) { + do + { + + fhs.push_back(Kernel::face_handle(heh)); + + heh = Kernel::prev_halfedge_handle(heh); + heh = Kernel::opposite_halfedge_handle(heh); + } + while(!Kernel::is_boundary(heh) && !is_estimated_feature_edge(heh, _feature_angle)); + } + } + + Normal n(0,0,0); + for (unsigned int i = 0; i < fhs.size(); ++i) + n += Kernel::has_face_normals() ? Kernel::normal(fhs[i]) : calc_face_normal(fhs[i]); + + return normalize(n); + } +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_normal(HalfedgeHandle _heh, const double _feature_angle) const +{ + return calc_halfedge_normal(_heh, _feature_angle); +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_normal(EdgeHandle _eh) const +{ + Normal n(0, 0, 0); + for (int i = 0; i < 2; ++i) + { + const auto heh = this->halfedge_handle(_eh, i); + const auto fh = this->face_handle(heh); + if (fh.is_valid()) + n += calc_normal(fh); + } + const auto length = norm(n); + if (length != 0) + n /= length; + return n; +} + +//----------------------------------------------------------------------------- + + +template +bool +PolyMeshT:: +is_estimated_feature_edge(HalfedgeHandle _heh, const double _feature_angle) const +{ + EdgeHandle eh = Kernel::edge_handle(_heh); + + if(Kernel::has_edge_status()) + { + if(Kernel::status(eh).feature()) + return true; + } + + if(Kernel::is_boundary(eh)) + return false; + + // compute angle between faces + FaceHandle fh0 = Kernel::face_handle(_heh); + FaceHandle fh1 = Kernel::face_handle(Kernel::opposite_halfedge_handle(_heh)); + + Normal fn0 = Kernel::has_face_normals() ? Kernel::normal(fh0) : calc_face_normal(fh0); + Normal fn1 = Kernel::has_face_normals() ? Kernel::normal(fh1) : calc_face_normal(fh1); + + // dihedral angle above angle threshold + return ( dot(fn0,fn1) < cos(_feature_angle) ); +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_vertex_normal(VertexHandle _vh) const +{ + Normal n; + calc_vertex_normal_fast(_vh,n); + + Scalar length = norm(n); + if (length != 0.0) n *= (Scalar(1.0)/length); + + return n; +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const +{ + vectorize(_n, Scalar(0)); + for (ConstVertexFaceIter vf_it = this->cvf_iter(_vh); vf_it.is_valid(); ++vf_it) + _n += this->normal(*vf_it); +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const +{ + vectorize(_n, Scalar(0)); + ConstVertexIHalfedgeIter cvih_it = this->cvih_iter(_vh); + if (! cvih_it.is_valid() ) + {//don't crash on isolated vertices + return; + } + Normal in_he_vec; + calc_edge_vector(*cvih_it, in_he_vec); + for ( ; cvih_it.is_valid(); ++cvih_it) + {//calculates the sector normal defined by cvih_it and adds it to _n + if (this->is_boundary(*cvih_it)) + { + continue; + } + HalfedgeHandle out_heh(this->next_halfedge_handle(*cvih_it)); + Normal out_he_vec; + calc_edge_vector(out_heh, out_he_vec); + _n += cross(in_he_vec, out_he_vec);//sector area is taken into account + in_he_vec = out_he_vec; + in_he_vec *= -1;//change the orientation + } + Scalar length = norm(_n); + if (length != 0.0) + _n *= (Scalar(1.0)/length); +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const +{ + static const LoopSchemeMaskDouble& loop_scheme_mask__ = + LoopSchemeMaskDoubleSingleton::Instance(); + + Normal t_v(0.0,0.0,0.0), t_w(0.0,0.0,0.0); + unsigned int vh_val = this->valence(_vh); + unsigned int i = 0; + for (ConstVertexOHalfedgeIter cvoh_it = this->cvoh_iter(_vh); cvoh_it.is_valid(); ++cvoh_it, ++i) + { + VertexHandle r1_v( this->to_vertex_handle(*cvoh_it) ); + t_v += (typename vector_traits::value_type)(loop_scheme_mask__.tang0_weight(vh_val, i))*this->point(r1_v); + t_w += (typename vector_traits::value_type)(loop_scheme_mask__.tang1_weight(vh_val, i))*this->point(r1_v); + } + _n = cross(t_w, t_v);//hack: should be cross(t_v, t_w), but then the normals are reversed? +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_normal(VertexHandle _vh) const +{ + Normal n; + calc_vertex_normal_correct(_vh, n); + return n; +} + +//----------------------------------------------------------------------------- + +template +void +PolyMeshT:: +update_vertex_normals() +{ + VertexIter v_it(Kernel::vertices_begin()), v_end(Kernel::vertices_end()); + + for (; v_it!=v_end; ++v_it) + this->set_normal(*v_it, calc_vertex_normal(*v_it)); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh new file mode 100644 index 0000000..bb20234 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh @@ -0,0 +1,113 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS PolyMesh_ArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_POLY_MESH_ARRAY_KERNEL_HH +#define OPENMESH_POLY_MESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +template +class TriMesh_ArrayKernelT; +//== CLASS DEFINITION ========================================================= + +/// Helper class to build a PolyMesh-type +template +struct PolyMesh_ArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef PolyMeshT Mesh; +}; + + +/** \class PolyMesh_ArrayKernelT PolyMesh_ArrayKernelT.hh + + \ingroup mesh_types_group + Polygonal mesh based on the ArrayKernel. + \see OpenMesh::PolyMeshT + \see OpenMesh::ArrayKernel +*/ +template +class PolyMesh_ArrayKernelT + : public PolyMesh_ArrayKernel_GeneratorT::Mesh +{ +public: + PolyMesh_ArrayKernelT() {} + template + explicit PolyMesh_ArrayKernelT( const TriMesh_ArrayKernelT & t) + { + //assign the connectivity and standard properties + this->assign(t, true); + + } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_POLY_MESH_ARRAY_KERNEL_HH +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/SmartHandles.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/SmartHandles.hh new file mode 100644 index 0000000..409b685 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/SmartHandles.hh @@ -0,0 +1,484 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#ifndef OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE +#error Do not include this directly, include instead PolyConnectivity.hh +#endif//OPENMESH_POLYCONNECTIVITY_INTERFACE_INCLUDE + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== FORWARD DECLARATION ====================================================== + +struct SmartVertexHandle; +struct SmartHalfedgeHandle; +struct SmartEdgeHandle; +struct SmartFaceHandle; + + +//== CLASS DEFINITION ========================================================= + +/// Base class for all smart handle types +class OPENMESHDLLEXPORT SmartBaseHandle +{ +public: + explicit SmartBaseHandle(const PolyConnectivity* _mesh = nullptr) : mesh_(_mesh) {} + + /// Get the underlying mesh of this handle + const PolyConnectivity* mesh() const { return mesh_; } + + // TODO: should operators ==, !=, < look at mesh_? + +private: + const PolyConnectivity* mesh_; + +}; + +/// Base class for all smart handle types that contains status related methods +template +class SmartHandleStatusPredicates +{ +public: + /// Returns true iff the handle is marked as feature + bool feature() const; + /// Returns true iff the handle is marked as selected + bool selected() const; + /// Returns true iff the handle is marked as tagged + bool tagged() const; + /// Returns true iff the handle is marked as tagged2 + bool tagged2() const; + /// Returns true iff the handle is marked as locked + bool locked() const; + /// Returns true iff the handle is marked as hidden + bool hidden() const; + /// Returns true iff the handle is marked as deleted + bool deleted() const; +}; + +/// Base class for all smart handle types that contains status related methods +template +class SmartHandleBoundaryPredicate +{ +public: + /// Returns true iff the handle is boundary + bool is_boundary() const; +}; + +/// Smart version of VertexHandle contains a pointer to the corresponding mesh and allows easier access to navigation methods +struct OPENMESHDLLEXPORT SmartVertexHandle : public SmartBaseHandle, VertexHandle, SmartHandleStatusPredicates, SmartHandleBoundaryPredicate +{ + explicit SmartVertexHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), VertexHandle(_idx) {} + + /// Returns an outgoing halfedge + SmartHalfedgeHandle out() const; + /// Returns an outgoing halfedge + SmartHalfedgeHandle halfedge() const; // alias for out + /// Returns an incoming halfedge + SmartHalfedgeHandle in() const; + + /// Returns a range of faces incident to the vertex (PolyConnectivity::vf_range()) + PolyConnectivity::ConstVertexFaceRange faces() const; + /// Returns a range of faces incident to the vertex (PolyConnectivity::vf_cw_range()) + PolyConnectivity::ConstVertexFaceCWRange faces_cw() const; + /// Returns a range of faces incident to the vertex (PolyConnectivity::vf_ccw_range()) + PolyConnectivity::ConstVertexFaceCCWRange faces_ccw() const; + /// Returns a range of edges incident to the vertex (PolyConnectivity::ve_range()) + PolyConnectivity::ConstVertexEdgeRange edges() const; + /// Returns a range of edges incident to the vertex (PolyConnectivity::ve_cw_range()) + PolyConnectivity::ConstVertexEdgeCWRange edges_cw() const; + /// Returns a range of edges incident to the vertex (PolyConnectivity::ve_ccw_range()) + PolyConnectivity::ConstVertexEdgeCCWRange edges_ccw() const; + /// Returns a range of vertices adjacent to the vertex (PolyConnectivity::vv_range()) + PolyConnectivity::ConstVertexVertexRange vertices() const; + /// Returns a range of vertices adjacent to the vertex (PolyConnectivity::vv_cw_range()) + PolyConnectivity::ConstVertexVertexCWRange vertices_cw() const; + /// Returns a range of vertices adjacent to the vertex (PolyConnectivity::vv_ccw_range()) + PolyConnectivity::ConstVertexVertexCCWRange vertices_ccw() const; + /// Returns a range of outgoing halfedges incident to the vertex (PolyConnectivity::voh_range()) + PolyConnectivity::ConstVertexIHalfedgeRange incoming_halfedges() const; + /// Returns a range of outgoing halfedges incident to the vertex (PolyConnectivity::voh_cw_range()) + PolyConnectivity::ConstVertexIHalfedgeCWRange incoming_halfedges_cw() const; + /// Returns a range of outgoing halfedges incident to the vertex (PolyConnectivity::voh_ccw_range()) + PolyConnectivity::ConstVertexIHalfedgeCCWRange incoming_halfedges_ccw() const; + /// Returns a range of outgoing halfedges incident to the vertex (PolyConnectivity::vih_range()) + PolyConnectivity::ConstVertexIHalfedgeRange incoming_halfedges(HalfedgeHandle _heh) const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::vih_cw_range()) + PolyConnectivity::ConstVertexIHalfedgeCWRange incoming_halfedges_cw(HalfedgeHandle _heh) const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::vih_ccw_range()) + PolyConnectivity::ConstVertexIHalfedgeCCWRange incoming_halfedges_ccw(HalfedgeHandle _heh) const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_range()) + PolyConnectivity::ConstVertexOHalfedgeRange outgoing_halfedges() const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_cw_range()) + PolyConnectivity::ConstVertexOHalfedgeCWRange outgoing_halfedges_cw() const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_ccw_range()) + PolyConnectivity::ConstVertexOHalfedgeCCWRange outgoing_halfedges_ccw() const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_range()) + PolyConnectivity::ConstVertexOHalfedgeRange outgoing_halfedges(HalfedgeHandle _heh) const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_cw_range()) + PolyConnectivity::ConstVertexOHalfedgeCWRange outgoing_halfedges_cw(HalfedgeHandle _heh) const; + /// Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_ccw_range()) + PolyConnectivity::ConstVertexOHalfedgeCCWRange outgoing_halfedges_ccw(HalfedgeHandle _heh) const; + + /// Returns valence of the vertex + uint valence() const; + /// Returns true iff (the mesh at) the vertex is two-manifold ? + bool is_manifold() const; +}; + +struct OPENMESHDLLEXPORT SmartHalfedgeHandle : public SmartBaseHandle, HalfedgeHandle, SmartHandleStatusPredicates, SmartHandleBoundaryPredicate +{ + explicit SmartHalfedgeHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), HalfedgeHandle(_idx) {} + + /// Returns next halfedge handle + SmartHalfedgeHandle next() const; + /// Returns previous halfedge handle + SmartHalfedgeHandle prev() const; + /// Returns opposite halfedge handle + SmartHalfedgeHandle opp() const; + /// Returns vertex pointed to by halfedge + SmartVertexHandle to() const; + /// Returns vertex at start of halfedge + SmartVertexHandle from() const; + /// Returns incident edge of halfedge + SmartEdgeHandle edge() const; + /// Returns incident face of halfedge + SmartFaceHandle face() const; + + /// Returns a range of halfedges in the face of the halfedge (or along the boundary) (PolyConnectivity::hl_range()) + PolyConnectivity::ConstHalfedgeLoopRange loop() const; + /// Returns a range of halfedges in the face of the halfedge (or along the boundary) (PolyConnectivity::hl_cw_range()) + PolyConnectivity::ConstHalfedgeLoopCWRange loop_cw() const; + /// Returns a range of halfedges in the face of the halfedge (or along the boundary) (PolyConnectivity::hl_ccw_range()) + PolyConnectivity::ConstHalfedgeLoopCCWRange loop_ccw() const; +}; + +struct OPENMESHDLLEXPORT SmartEdgeHandle : public SmartBaseHandle, EdgeHandle, SmartHandleStatusPredicates, SmartHandleBoundaryPredicate +{ + explicit SmartEdgeHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), EdgeHandle(_idx) {} + + /// Returns one of the two halfedges of the edge + SmartHalfedgeHandle halfedge(unsigned int _i) const; + /// Shorthand for halfedge() + SmartHalfedgeHandle h(unsigned int _i) const; + /// Shorthand for halfedge(0) + SmartHalfedgeHandle h0() const; + /// Shorthand for halfedge(1) + SmartHalfedgeHandle h1() const; + /// Returns one of the two incident vertices of the edge + SmartVertexHandle vertex(unsigned int _i) const; + /// Shorthand for vertex() + SmartVertexHandle v(unsigned int _i) const; + /// Shorthand for vertex(0) + SmartVertexHandle v0() const; + /// Shorthand for vertex(1) + SmartVertexHandle v1() const; + + /// Returns a range of vertices incident to the edge (PolyConnectivity::ev_range()) + PolyConnectivity::ConstEdgeVertexRange vertices() const; + /// Returns a range of halfedges of the edge (PolyConnectivity::eh_range()) + PolyConnectivity::ConstEdgeHalfedgeRange halfedges() const; + /// Returns a range of halfedges of the edge (PolyConnectivity::eh_range()) + PolyConnectivity::ConstEdgeHalfedgeRange halfedges(HalfedgeHandle _heh) const; + /// Returns a range of faces incident to the edge (PolyConnectivity::ef_range()) + PolyConnectivity::ConstEdgeFaceRange faces() const; +}; + +struct OPENMESHDLLEXPORT SmartFaceHandle : public SmartBaseHandle, FaceHandle, SmartHandleStatusPredicates, SmartHandleBoundaryPredicate +{ + explicit SmartFaceHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), FaceHandle(_idx) {} + + /// Returns one of the halfedges of the face + SmartHalfedgeHandle halfedge() const; + + /// Returns a range of vertices incident to the face (PolyConnectivity::fv_range()) + PolyConnectivity::ConstFaceVertexRange vertices() const; + /// Returns a range of vertices incident to the face (PolyConnectivity::fv_cw_range()) + PolyConnectivity::ConstFaceVertexCWRange vertices_cw() const; + /// Returns a range of vertices incident to the face (PolyConnectivity::fv_ccw_range()) + PolyConnectivity::ConstFaceVertexCCWRange vertices_ccw() const; + /// Returns a range of halfedges of the face (PolyConnectivity::fh_range()) + PolyConnectivity::ConstFaceHalfedgeRange halfedges() const; + /// Returns a range of halfedges of the face (PolyConnectivity::fh_cw_range()) + PolyConnectivity::ConstFaceHalfedgeCWRange halfedges_cw() const; + /// Returns a range of halfedges of the face (PolyConnectivity::fh_ccw_range()) + PolyConnectivity::ConstFaceHalfedgeCCWRange halfedges_ccw() const; + /// Returns a range of edges of the face (PolyConnectivity::fv_range()) + PolyConnectivity::ConstFaceEdgeRange edges() const; + /// Returns a range of edges of the face (PolyConnectivity::fv_cw_range()) + PolyConnectivity::ConstFaceEdgeCWRange edges_cw() const; + /// Returns a range of edges of the face (PolyConnectivity::fv_ccw_range()) + PolyConnectivity::ConstFaceEdgeCCWRange edges_ccw() const; + /// Returns a range adjacent faces of the face (PolyConnectivity::ff_range()) + PolyConnectivity::ConstFaceFaceRange faces() const; + /// Returns a range adjacent faces of the face (PolyConnectivity::ff_cw_range()) + PolyConnectivity::ConstFaceFaceCWRange faces_cw() const; + /// Returns a range adjacent faces of the face (PolyConnectivity::ff_ccw_range()) + PolyConnectivity::ConstFaceFaceCCWRange faces_ccw() const; + + /// Returns the valence of the face + uint valence() const; +}; + + +/// Creats a SmartVertexHandle from a VertexHandle and a Mesh +inline SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity* _mesh) { return SmartVertexHandle (_vh.idx(), _mesh); } +/// Creats a SmartHalfedgeHandle from a HalfedgeHandle and a Mesh +inline SmartHalfedgeHandle make_smart(HalfedgeHandle _hh, const PolyConnectivity* _mesh) { return SmartHalfedgeHandle(_hh.idx(), _mesh); } +/// Creats a SmartEdgeHandle from an EdgeHandle and a Mesh +inline SmartEdgeHandle make_smart(EdgeHandle _eh, const PolyConnectivity* _mesh) { return SmartEdgeHandle (_eh.idx(), _mesh); } +/// Creats a SmartFaceHandle from a FaceHandle and a Mesh +inline SmartFaceHandle make_smart(FaceHandle _fh, const PolyConnectivity* _mesh) { return SmartFaceHandle (_fh.idx(), _mesh); } + +/// Creats a SmartVertexHandle from a VertexHandle and a Mesh +inline SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity& _mesh) { return SmartVertexHandle (_vh.idx(), &_mesh); } +/// Creats a SmartHalfedgeHandle from a HalfedgeHandle and a Mesh +inline SmartHalfedgeHandle make_smart(HalfedgeHandle _hh, const PolyConnectivity& _mesh) { return SmartHalfedgeHandle(_hh.idx(), &_mesh); } +/// Creats a SmartEdgeHandle from an EdgeHandle and a Mesh +inline SmartEdgeHandle make_smart(EdgeHandle _eh, const PolyConnectivity& _mesh) { return SmartEdgeHandle (_eh.idx(), &_mesh); } +/// Creats a SmartFaceHandle from a FaceHandle and a Mesh +inline SmartFaceHandle make_smart(FaceHandle _fh, const PolyConnectivity& _mesh) { return SmartFaceHandle (_fh.idx(), &_mesh); } + + +// helper to convert Handle Types to Smarthandle Types +template +struct SmartHandle; + +template <> struct SmartHandle { using type = SmartVertexHandle; }; +template <> struct SmartHandle { using type = SmartHalfedgeHandle; }; +template <> struct SmartHandle { using type = SmartEdgeHandle; }; +template <> struct SmartHandle { using type = SmartFaceHandle; }; + + +template +inline bool SmartHandleStatusPredicates::feature() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).feature(); +} + +template +inline bool SmartHandleStatusPredicates::selected() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).selected(); +} + +template +inline bool SmartHandleStatusPredicates::tagged() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).tagged(); +} + +template +inline bool SmartHandleStatusPredicates::tagged2() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).tagged2(); +} + +template +inline bool SmartHandleStatusPredicates::locked() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).locked(); +} + +template +inline bool SmartHandleStatusPredicates::hidden() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).hidden(); +} + +template +inline bool SmartHandleStatusPredicates::deleted() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->status(handle).deleted(); +} + +template +inline bool SmartHandleBoundaryPredicate::is_boundary() const +{ + const auto& handle = static_cast(*this); + assert(handle.mesh() != nullptr); + return handle.mesh()->is_boundary(handle); +} + +inline SmartHalfedgeHandle SmartVertexHandle::out() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->halfedge_handle(*this), mesh()); +} + +inline SmartHalfedgeHandle SmartVertexHandle::halfedge() const +{ + return out(); +} + +inline SmartHalfedgeHandle SmartVertexHandle::in() const +{ + return out().opp(); +} + +inline uint SmartVertexHandle::valence() const +{ + assert(mesh() != nullptr); + return mesh()->valence(*this); +} + +inline bool SmartVertexHandle::is_manifold() const +{ + assert(mesh() != nullptr); + return mesh()->is_manifold(*this); +} + +inline SmartHalfedgeHandle SmartHalfedgeHandle::next() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->next_halfedge_handle(*this), mesh()); +} + +inline SmartHalfedgeHandle SmartHalfedgeHandle::prev() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->prev_halfedge_handle(*this), mesh()); +} + +inline SmartHalfedgeHandle SmartHalfedgeHandle::opp() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->opposite_halfedge_handle(*this), mesh()); +} + +inline SmartVertexHandle SmartHalfedgeHandle::to() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->to_vertex_handle(*this), mesh()); +} + +inline SmartVertexHandle SmartHalfedgeHandle::from() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->from_vertex_handle(*this), mesh()); +} + +inline SmartEdgeHandle SmartHalfedgeHandle::edge() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->edge_handle(*this), mesh()); +} + +inline SmartFaceHandle SmartHalfedgeHandle::face() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->face_handle(*this), mesh()); +} + +inline SmartHalfedgeHandle SmartEdgeHandle::halfedge(unsigned int _i = 0) const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->halfedge_handle(*this, _i), mesh()); +} + +inline SmartHalfedgeHandle SmartEdgeHandle::h(unsigned int _i = 0) const +{ + return halfedge(_i); +} + +inline SmartHalfedgeHandle SmartEdgeHandle::h0() const +{ + return h(0); +} + +inline SmartHalfedgeHandle SmartEdgeHandle::h1() const +{ + return h(1); +} + +inline SmartVertexHandle SmartEdgeHandle::vertex(unsigned int _i) const +{ + return halfedge(_i).from(); +} + +inline SmartVertexHandle SmartEdgeHandle::v(unsigned int _i) const +{ + return vertex(_i); +} + +inline SmartVertexHandle SmartEdgeHandle::v0() const +{ + return v(0); +} + +inline SmartVertexHandle SmartEdgeHandle::v1() const +{ + return v(1); +} + +inline SmartHalfedgeHandle SmartFaceHandle::halfedge() const +{ + assert(mesh() != nullptr); + return make_smart(mesh()->halfedge_handle(*this), mesh()); +} + +inline uint SmartFaceHandle::valence() const +{ + assert(mesh() != nullptr); + return mesh()->valence(*this); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/SmartRange.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/SmartRange.hh new file mode 100644 index 0000000..00c121f --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/SmartRange.hh @@ -0,0 +1,496 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#pragma once + +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== FORWARD DECLARATION ====================================================== + +//== CLASS DEFINITION ========================================================= + +namespace { + +struct Identity +{ + template + T operator()(const T& _t) const { return _t; } +}; + +} + +template +struct FilteredSmartRangeT; + +/// Base class for all smart range types +template +struct SmartRangeT +{ + using Handle = HandleT; + using SmartRange = SmartRangeT; + using Range = RangeT; + + // TODO: Someone with better c++ knowledge may improve the code below. + + /** @brief Computes the sum of elements. + * + * Computes the sum of all elements in the range after applying the functor \p f. + * + * @param f Functor that is applied to all elements before computing the sum + */ + template + auto sum(Functor&& f) -> typename std::decay()))>::type + { + auto range = static_cast(this); + auto begin = range->begin(); + auto end = range->end(); + assert(begin != end); + typename std::decay::type result = f(*begin); + auto it = begin; + ++it; + for (; it != end; ++it) + result += f(*it); + return result; + } + + /** @brief Computes the average of elements. + * + * Computes the average of all elements in the range after applying the functor \p f. + * + * @param f Functor that is applied to all elements before computing the average. + */ + template + auto avg(Functor&& f) -> typename std::decay()))>::type + { + auto range = static_cast(this); + auto begin = range->begin(); + auto end = range->end(); + assert(begin != end); + typename std::decay::type result = f(*begin); + auto it = begin; + ++it; + int n_elements = 1; + for (; it != end; ++it) + { + result += f(*it); + ++n_elements; + } + return (1.0 / n_elements) * result; + } + + /** @brief Computes the weighted average of elements. + * + * Computes the weighted average of all elements in the range after applying the functor \p f. + * + * @param f Functor that is applied to all elements before computing the average. + * @param w Functor returning element weight. + */ + template + auto avg(Functor&& f, WeightFunctor&& w) -> typename std::decay())+w(std::declval())))*f(std::declval()))>::type + { + auto range = static_cast(this); + auto begin = range->begin(); + auto end = range->end(); + assert(begin != end); + typename std::decay::type weight = w(*begin); + typename std::decay::type result = weight * f(*begin); + typename std::decay::type weight_sum = weight; + auto it = begin; + ++it; + for (; it != end; ++it) + { + weight = w(*it); + result += weight*f(*it); + weight_sum += weight; + } + return (1.0 / weight_sum) * result; + } + + /** @brief Check if any element fulfils condition. + * + * Checks if functor \p f returns true for any of the elements in the range. + * Returns true if that is the case, false otherwise. + * + * @param f Functor that is evaluated for all elements. + */ + template + auto any_of(Functor&& f) -> bool + { + auto range = static_cast(this); + for (auto e : *range) + if (f(e)) + return true; + return false; + } + + /** @brief Check if all elements fulfil condition. + * + * Checks if functor \p f returns true for all of the elements in the range. + * Returns true if that is the case, false otherwise. + * + * @param f Functor that is evaluated for all elements. + */ + template + auto all_of(Functor&& f) -> bool + { + auto range = static_cast(this); + for (auto e : *range) + if (!f(e)) + return false; + return true; + } + + /** @brief Convert range to array. + * + * Converts the range of elements into an array of objects returned by functor \p f. + * The size of the array needs to be provided by the user. If the size is larger than the number of + * elements in the range, the remaining entries of the array will be uninitialized. + * + * @param f Functor that is applied to all elements before putting them into the array. If no functor is provided + * the array will contain the handles. + */ + template + auto to_array(Functor&& f = {}) -> std::array()))>::type, n> + { + auto range = static_cast(this); + std::array()))>::type, n> res; + auto it = range->begin(); + auto end = range->end(); + int i = 0; + while (i < n && it != end) + res[i++] = f(*(it++)); + return res; + } + + /** @brief Convert range to vector. + * + * Converts the range of elements into a vector of objects returned by functor \p f. + * + * @param f Functor that is applied to all elements before putting them into the vector. If no functor is provided + * the vector will contain the handles. + */ + template + auto to_vector(Functor&& f = {}) -> std::vector()))>::type> + { + auto range = static_cast(this); + std::vector()))>::type> res; + for (const auto& e : *range) + res.push_back(f(e)); + return res; + } + + /** @brief Convert range to set. + * + * Converts the range of elements into a set of objects returned by functor \p f. + * + * @param f Functor that is applied to all elements before putting them into the set. If no functor is provided + * the set will contain the handles. + */ + template + auto to_set(Functor&& f = {}) -> std::set()))>::type> + { + auto range = static_cast(this); + std::set()))>::type> res; + for (const auto& e : *range) + res.insert(f(e)); + return res; + } + + /** @brief Get the first element that fulfills a condition. + * + * Finds the first element of the range for which the functor \p f evaluates to true. + * Returns an invalid handle if none evaluates to true + * + * @param f Functor that is applied to all elements before putting them into the set. If no functor is provided + * the set will contain the handles. + */ + template + auto first(Functor&& f = {}) -> HandleT + { + auto range = static_cast(this); + for (const auto& e : *range) + if (f(e)) + return e; + return HandleT(); + } + + /** @brief Compute minimum. + * + * Computes the minimum of all objects returned by functor \p f. + * + * @param f Functor that is applied to all elements before computing minimum. + */ + template + auto min(Functor&& f) -> typename std::decay()))>::type + { + using std::min; + + auto range = static_cast(this); + auto it = range->begin(); + auto end = range->end(); + assert(it != end); + + typename std::decay()))>::type res = f(*it); + ++it; + + for (; it != end; ++it) + res = min(res, f(*it)); + + return res; + } + + /** @brief Compute minimal element. + * + * Computes the element that minimizes \p f. + * + * @param f Functor that is applied to all elements before comparing. + */ + template + auto argmin(Functor&& f) -> HandleT + { + auto range = static_cast(this); + auto it = range->begin(); + auto min_it = it; + auto end = range->end(); + assert(it != end); + + typename std::decay()))>::type curr_min = f(*it); + ++it; + + for (; it != end; ++it) + { + auto val = f(*it); + if (val < curr_min) + { + curr_min = val; + min_it = it; + } + } + + return *min_it; + } + + /** @brief Compute maximum. + * + * Computes the maximum of all objects returned by functor \p f. + * + * @param f Functor that is applied to all elements before computing maximum. + */ + template + auto max(Functor&& f) -> typename std::decay()))>::type + { + using std::max; + + auto range = static_cast(this); + auto it = range->begin(); + auto end = range->end(); + assert(it != end); + + typename std::decay()))>::type res = f(*it); + ++it; + + for (; it != end; ++it) + res = max(res, f(*it)); + + return res; + } + + + /** @brief Compute maximal element. + * + * Computes the element that maximizes \p f. + * + * @param f Functor that is applied to all elements before comparing. + */ + template + auto argmax(Functor&& f) -> HandleT + { + auto range = static_cast(this); + auto it = range->begin(); + auto max_it = it; + auto end = range->end(); + assert(it != end); + + typename std::decay()))>::type curr_max = f(*it); + ++it; + + for (; it != end; ++it) + { + auto val = f(*it); + if (val > curr_max) + { + curr_max = val; + max_it = it; + } + } + + return *max_it; + } + + /** @brief Computes minimum and maximum. + * + * Computes the minimum and maximum of all objects returned by functor \p f. Result is returned as std::pair + * containing minimum as first and maximum as second element. + * + * @param f Functor that is applied to all elements before computing maximum. + */ + template + auto minmax(Functor&& f) -> std::pair()))>::type, + typename std::decay()))>::type> + { + return std::make_pair(this->min(f), this->max(f)); + } + + + /** @brief Compute number of elements that satisfy a given predicate. + * + * Computes the numer of elements which satisfy functor \p f. + * + * @param f Predicate that elements have to satisfy in order to be counted. + */ + template + auto count_if(Functor&& f) -> int + { + int count = 0; + auto range = static_cast(this); + for (const auto& e : *range) + if (f(e)) + ++count; + return count; + } + + + /** @brief Apply a functor to each element. + * + * Calls functor \p f with each element as parameter + * + * @param f Functor that is called for each element. + */ + template + auto for_each(Functor&& f) -> void + { + auto range = static_cast(this); + for (const auto& e : *range) + f(e); + } + + + /** @brief Only iterate over a subset of elements + * + * Returns a smart range which skips all elements that do not satisfy functor \p f + * + * @param f Functor that needs to be evaluated to true if the element should not be skipped. + */ + template + auto filtered(Functor&& f) -> FilteredSmartRangeT + { + auto range = static_cast(this); + return FilteredSmartRangeT(std::forward(f), (*range).begin(), (*range).end()); + } +}; + + +/// Class which applies a filter when iterating over elements +template +struct FilteredSmartRangeT : public SmartRangeT, HandleT> +{ + using BaseRange = SmartRangeT, HandleT>; + using BaseIterator = decltype((std::declval().begin())); + + struct FilteredIterator : public BaseIterator + { + + FilteredIterator(Functor f, BaseIterator it, BaseIterator end): BaseIterator(it), f_(f), end_(end) + { + if (!BaseIterator::operator==(end_) && !f_(*(*this))) // if start is not valid go to first valid one + operator++(); + } + + FilteredIterator(const FilteredIterator& other) = default; + + FilteredIterator& operator=(const FilteredIterator& other) + { + BaseIterator::operator=(other); + end_ = other.end_; + return *this; + } + + FilteredIterator& operator++() + { + if (BaseIterator::operator==(end_)) // don't go past end + return *this; + + // go to next valid one + do + BaseIterator::operator++(); + while (BaseIterator::operator!=(end_) && !f_(*(*this))); + return *this; + } + + Functor f_; // Should iterators always get a reference to filter stored in range? + // Should iterators stay valid after range goes out of scope? + BaseIterator end_; + }; + + FilteredSmartRangeT(Functor&& f, BaseIterator begin, BaseIterator end) : f_(std::forward(f)), begin_(std::move(begin)), end_(std::move(end)){} + FilteredIterator begin() const { return FilteredIterator(f_, begin_, end_); } + FilteredIterator end() const { return FilteredIterator(f_, end_, end_); } + + Functor f_; + BaseIterator begin_; + BaseIterator end_; +}; + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Status.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Status.hh new file mode 100644 index 0000000..73f992a --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Status.hh @@ -0,0 +1,178 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS Status +// +//============================================================================= + + +#ifndef OPENMESH_ATTRIBUTE_STATUS_HH +#define OPENMESH_ATTRIBUTE_STATUS_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Attributes { + + +//== CLASS DEFINITION ======================================================== + + +/** Status bits used by the Status class. + * \see OpenMesh::Attributes::StatusInfo + */ +enum StatusBits { + + DELETED = 1, ///< Item has been deleted + LOCKED = 2, ///< Item is locked. + SELECTED = 4, ///< Item is selected. + HIDDEN = 8, ///< Item is hidden. + FEATURE = 16, ///< Item is a feature or belongs to a feature. + TAGGED = 32, ///< Item is tagged. + TAGGED2 = 64, ///< Alternate bit for tagging an item. + FIXEDNONMANIFOLD = 128, ///< Item was non-two-manifold and had to be fixed + UNUSED = 256 ///< Unused +}; + + +/** \class StatusInfo Status.hh + * + * Add status information to a base class. + * + * \see StatusBits + */ +class StatusInfo +{ +public: + + typedef unsigned int value_type; + + StatusInfo() : status_(0) {} + + /// is deleted ? + bool deleted() const { return is_bit_set(DELETED); } + /// set deleted + void set_deleted(bool _b) { change_bit(DELETED, _b); } + + + /// is locked ? + bool locked() const { return is_bit_set(LOCKED); } + /// set locked + void set_locked(bool _b) { change_bit(LOCKED, _b); } + + + /// is selected ? + bool selected() const { return is_bit_set(SELECTED); } + /// set selected + void set_selected(bool _b) { change_bit(SELECTED, _b); } + + + /// is hidden ? + bool hidden() const { return is_bit_set(HIDDEN); } + /// set hidden + void set_hidden(bool _b) { change_bit(HIDDEN, _b); } + + + /// is feature ? + bool feature() const { return is_bit_set(FEATURE); } + /// set feature + void set_feature(bool _b) { change_bit(FEATURE, _b); } + + + /// is tagged ? + bool tagged() const { return is_bit_set(TAGGED); } + /// set tagged + void set_tagged(bool _b) { change_bit(TAGGED, _b); } + + + /// is tagged2 ? This is just one more tag info. + bool tagged2() const { return is_bit_set(TAGGED2); } + /// set tagged + void set_tagged2(bool _b) { change_bit(TAGGED2, _b); } + + + /// is fixed non-manifold ? + bool fixed_nonmanifold() const { return is_bit_set(FIXEDNONMANIFOLD); } + /// set fixed non-manifold + void set_fixed_nonmanifold(bool _b) { change_bit(FIXEDNONMANIFOLD, _b); } + + + /// return whole status + unsigned int bits() const { return status_; } + /// set whole status at once + void set_bits(unsigned int _bits) { status_ = _bits; } + + + /// is a certain bit set ? + bool is_bit_set(unsigned int _s) const { return (status_ & _s) > 0; } + /// set a certain bit + void set_bit(unsigned int _s) { status_ |= _s; } + /// unset a certain bit + void unset_bit(unsigned int _s) { status_ &= ~_s; } + /// set or unset a certain bit + void change_bit(unsigned int _s, bool _b) { + if (_b) status_ |= _s; else status_ &= ~_s; } + + +private: + + value_type status_; +}; + + +//============================================================================= +} // namespace Attributes +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBUTE_STATUS_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Tags.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Tags.hh new file mode 100644 index 0000000..f71b6b6 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Tags.hh @@ -0,0 +1,52 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#pragma once + +namespace OpenMesh { + +/// Connectivity tag indicating that the tagged mesh has polygon connectivity. +struct PolyConnectivityTag {}; +/// Connectivity tag indicating that the tagged mesh has triangle connectivity. +struct TriConnectivityTag {}; + +} // namespace OpenMesh + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Traits.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Traits.hh new file mode 100644 index 0000000..f30a3a8 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/Traits.hh @@ -0,0 +1,258 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +/** \file Core/Mesh/Traits.hh + This file defines the default traits and some convenience macros. +*/ + + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_TRAITS_HH +#define OPENMESH_TRAITS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/// Macro for defining the vertex attributes. See \ref mesh_type. +#define VertexAttributes(_i) enum { VertexAttributes = _i } + +/// Macro for defining the halfedge attributes. See \ref mesh_type. +#define HalfedgeAttributes(_i) enum { HalfedgeAttributes = _i } + +/// Macro for defining the edge attributes. See \ref mesh_type. +#define EdgeAttributes(_i) enum { EdgeAttributes = _i } + +/// Macro for defining the face attributes. See \ref mesh_type. +#define FaceAttributes(_i) enum { FaceAttributes = _i } + +/// Macro for defining the vertex traits. See \ref mesh_type. +#define VertexTraits \ + template struct VertexT : public Base + +/// Macro for defining the halfedge traits. See \ref mesh_type. +#define HalfedgeTraits \ + template struct HalfedgeT : public Base + +/// Macro for defining the edge traits. See \ref mesh_type. +#define EdgeTraits \ + template struct EdgeT : public Base + +/// Macro for defining the face traits. See \ref mesh_type. +#define FaceTraits \ + template struct FaceT : public Base + + + +//== CLASS DEFINITION ========================================================= + + +/** \class DefaultTraits Traits.hh + + Base class for all traits. All user traits should be derived from + this class. You may enrich all basic items by additional + properties or define one or more of the types \c Point, \c Normal, + \c TexCoord, or \c Color. + + \see The Mesh docu section on \ref mesh_type. + \see Traits.hh for a list of macros for traits classes. +*/ +struct DefaultTraits +{ + /// The default coordinate type is OpenMesh::Vec3f. + typedef Vec3f Point; + + /// The default normal type is OpenMesh::Vec3f. + typedef Vec3f Normal; + + /// The default 1D texture coordinate type is float. + typedef float TexCoord1D; + /// The default 2D texture coordinate type is OpenMesh::Vec2f. + typedef Vec2f TexCoord2D; + /// The default 3D texture coordinate type is OpenMesh::Vec3f. + typedef Vec3f TexCoord3D; + + /// The default texture index type + typedef int TextureIndex; + + /// The default color type is OpenMesh::Vec3uc. + typedef Vec3uc Color; + +#ifndef DOXY_IGNORE_THIS + VertexTraits {}; + HalfedgeTraits {}; + EdgeTraits {}; + FaceTraits {}; +#endif + + VertexAttributes(0); + HalfedgeAttributes(Attributes::PrevHalfedge); + EdgeAttributes(0); + FaceAttributes(0); +}; + +/** \class DefaultTraitsDouble Traits.hh + + Version of Default Traits that uses double precision for points and + normals as well as floating point vectors for colors + + \see The Mesh docu section on \ref mesh_type. + \see Traits.hh for a list of macros for traits classes. +*/ +struct DefaultTraitsDouble : public DefaultTraits +{ + /// Use double precision points + typedef OpenMesh::Vec3d Point; + /// Use double precision Normals + typedef OpenMesh::Vec3d Normal; + /// Use RGBA Color + typedef OpenMesh::Vec4f Color; +}; + + +//== CLASS DEFINITION ========================================================= + + +/** Helper class to merge two mesh traits. + * \internal + * + * With the help of this class it's possible to merge two mesh traits. + * Whereby \c _Traits1 overrides equally named symbols of \c _Traits2. + * + * For your convenience use the provided defines \c OM_Merge_Traits + * and \c OM_Merge_Traits_In_Template instead. + * + * \see OM_Merge_Traits, OM_Merge_Traits_In_Template + */ +template struct MergeTraits +{ +#ifndef DOXY_IGNORE_THIS + struct Result + { + // Mipspro needs this (strange) typedef + typedef _Traits1 T1; + typedef _Traits2 T2; + + + VertexAttributes ( T1::VertexAttributes | T2::VertexAttributes ); + HalfedgeAttributes ( T1::HalfedgeAttributes | T2::HalfedgeAttributes ); + EdgeAttributes ( T1::EdgeAttributes | T2::EdgeAttributes ); + FaceAttributes ( T1::FaceAttributes | T2::FaceAttributes ); + + + typedef typename T1::Point Point; + typedef typename T1::Normal Normal; + typedef typename T1::Color Color; + typedef typename T1::TexCoord TexCoord; + + template class VertexT : + public T1::template VertexT< + typename T2::template VertexT, Refs> + {}; + + template class HalfedgeT : + public T1::template HalfedgeT< + typename T2::template HalfedgeT, Refs> + {}; + + + template class EdgeT : + public T1::template EdgeT< + typename T2::template EdgeT, Refs> + {}; + + + template class FaceT : + public T1::template FaceT< + typename T2::template FaceT, Refs> + {}; + }; +#endif +}; + + +/** + Macro for merging two traits classes _S1 and _S2 into one traits class _D. + Note that in case of ambiguities class _S1 overrides _S2, especially + the point/normal/color/texcoord type to be used is taken from _S1::Point / + _S1::Normal / _S1::Color / _S1::TexCoord +*/ +#define OM_Merge_Traits(_S1, _S2, _D) \ + typedef OpenMesh::MergeTraits<_S1, _S2>::Result _D; + + +/** + Macro for merging two traits classes _S1 and _S2 into one traits class _D. + Same as OM_Merge_Traits, but this can be used inside template classes. +*/ +#define OM_Merge_Traits_In_Template(_S1, _S2, _D) \ + typedef typename OpenMesh::MergeTraits<_S1, _S2>::Result _D; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_TRAITS_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriConnectivity.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriConnectivity.hh new file mode 100644 index 0000000..ddd90e0 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriConnectivity.hh @@ -0,0 +1,252 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_TRICONNECTIVITY_HH +#define OPENMESH_TRICONNECTIVITY_HH + +#include + +namespace OpenMesh { + +/** \brief Connectivity Class for Triangle Meshes +*/ +class OPENMESHDLLEXPORT TriConnectivity : public PolyConnectivity +{ +public: + + TriConnectivity() {} + virtual ~TriConnectivity() {} + + inline static bool is_triangles() + { return true; } + + /** assign_connectivity() methods. See ArrayKernel::assign_connectivity() + for more details. When the source connectivity is not triangles, in + addition "fan" connectivity triangulation is performed*/ + inline void assign_connectivity(const TriConnectivity& _other) + { PolyConnectivity::assign_connectivity(_other); } + + inline void assign_connectivity(const PolyConnectivity& _other) + { + PolyConnectivity::assign_connectivity(_other); + triangulate(); + } + + /** \name Addding items to a mesh + */ + + //@{ + + /** \brief Add a face with arbitrary valence to the triangle mesh + * + * Override OpenMesh::Mesh::PolyMeshT::add_face(). Faces that aren't + * triangles will be triangulated and added. In this case an + * invalid face handle will be returned. + * + * + * */ + SmartFaceHandle add_face(const VertexHandle* _vhandles, size_t _vhs_size); + + /** \brief Add a face with arbitrary valence to the triangle mesh + * + * Override OpenMesh::Mesh::PolyMeshT::add_face(). Faces that aren't + * triangles will be triangulated and added. In this case an + * invalid face handle will be returned. + * + * + * */ + SmartFaceHandle add_face(const std::vector& _vhandles); + + /** \brief Add a face with arbitrary valence to the triangle mesh + * + * Override OpenMesh::Mesh::PolyMeshT::add_face(). Faces that aren't + * triangles will be triangulated and added. In this case an + * invalid face handle will be returned. + * + * + * */ + SmartFaceHandle add_face(const std::vector& _vhandles); + + /** \brief Add a face to the mesh (triangle) + * + * This function adds a triangle to the mesh. The triangle is passed directly + * to the underlying PolyConnectivity as we don't explicitly need to triangulate something. + * + * @param _vh0 VertexHandle 1 + * @param _vh1 VertexHandle 2 + * @param _vh2 VertexHandle 3 + * @return FaceHandle of the added face (invalid, if the operation failed) + */ + SmartFaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2); + + //@} + + /** Returns the opposite vertex to the halfedge _heh in the face + referenced by _heh returns InvalidVertexHandle if the _heh is + boundary */ + inline VertexHandle opposite_vh(HalfedgeHandle _heh) const + { + return is_boundary(_heh) ? InvalidVertexHandle : + to_vertex_handle(next_halfedge_handle(_heh)); + } + + /** Returns the opposite vertex to the opposite halfedge of _heh in + the face referenced by it returns InvalidVertexHandle if the + opposite halfedge is boundary */ + VertexHandle opposite_he_opposite_vh(HalfedgeHandle _heh) const + { return opposite_vh(opposite_halfedge_handle(_heh)); } + + /** \name Topology modifying operators + */ + //@{ + + + /** Returns whether collapsing halfedge _heh is ok or would lead to + topological inconsistencies. + \attention This method need the Attributes::Status attribute and + changes the \em tagged bit. */ + bool is_collapse_ok(HalfedgeHandle _heh); + + /// Vertex Split: inverse operation to collapse(). + HalfedgeHandle vertex_split(VertexHandle v0, VertexHandle v1, + VertexHandle vl, VertexHandle vr); + + /// Check whether flipping _eh is topologically correct. + bool is_flip_ok(EdgeHandle _eh) const; + + /** Flip edge _eh. + Check for topological correctness first using is_flip_ok(). */ + void flip(EdgeHandle _eh); + + + /** \brief Edge split (= 2-to-4 split) + * + * + * The function will introduce two new faces ( non-boundary case) or + * one additional face (if edge is boundary) + * + * \note The properties of the new edges, halfedges, and faces will be undefined! + * + * @param _eh Edge handle that should be split + * @param _vh Vertex handle that will be inserted at the edge + */ + void split(EdgeHandle _eh, VertexHandle _vh); + + /** \brief Edge split (= 2-to-4 split) + * + * + * The function will introduce two new faces ( non-boundary case) or + * one additional face (if edge is boundary) + * + * \note The properties of the new edges, halfedges, and faces will be undefined! + * + * \note This is an override to prevent a direct call to PolyConnectivity split_edge, + * which would introduce a singular vertex with valence 2 which is not allowed + * on TriMeshes + * + * @param _eh Edge handle that should be split + * @param _vh Vertex handle that will be inserted at the edge + */ + inline void split_edge(EdgeHandle _eh, VertexHandle _vh) { TriConnectivity::split(_eh, _vh); } + + /** \brief Edge split (= 2-to-4 split) + * + * The function will introduce two new faces ( non-boundary case) or + * one additional face (if edge is boundary) + * + * \note The properties of the new edges and faces will be adjusted to the + * properties of the original edge and face + * \note The properties of the new halfedges will be undefined + * + * @param _eh Edge handle that should be split + * @param _vh Vertex handle that will be inserted at the edge + */ + void split_copy(EdgeHandle _eh, VertexHandle _vh); + + /** \brief Edge split (= 2-to-4 split) + * + * The function will introduce two new faces ( non-boundary case) or + * one additional face (if edge is boundary) + * + * \note The properties of the new edges and faces will be adjusted to the + * properties of the original edge and face + * \note The properties of the new halfedges will be undefined + * + * \note This is an override to prevent a direct call to PolyConnectivity split_edge_copy, + * which would introduce a singular vertex with valence 2 which is not allowed + * on TriMeshes + * + * @param _eh Edge handle that should be split + * @param _vh Vertex handle that will be inserted at the edge + */ + inline void split_edge_copy(EdgeHandle _eh, VertexHandle _vh) { TriConnectivity::split_copy(_eh, _vh); } + + /** \brief Face split (= 1-to-3) split, calls corresponding PolyMeshT function). + * + * @param _fh Face handle that should be split + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split(FaceHandle _fh, VertexHandle _vh) + { PolyConnectivity::split(_fh, _vh); } + + /** \brief Face split (= 1-to-3) split, calls corresponding PolyMeshT function). + * + * @param _fh Face handle that should be split + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split_copy(FaceHandle _fh, VertexHandle _vh) + { PolyConnectivity::split_copy(_fh, _vh); } + + //@} + +private: + /// Helper for vertex split + HalfedgeHandle insert_loop(HalfedgeHandle _hh); + /// Helper for vertex split + HalfedgeHandle insert_edge(VertexHandle _vh, + HalfedgeHandle _h0, HalfedgeHandle _h1); +}; + +} + +#endif//OPENMESH_TRICONNECTIVITY_HH diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriMeshT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriMeshT.hh new file mode 100644 index 0000000..0b7909f --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriMeshT.hh @@ -0,0 +1,453 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS TriMeshT +// +//============================================================================= + + +#ifndef OPENMESH_TRIMESH_HH +#define OPENMESH_TRIMESH_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class TriMeshT TriMeshT.hh + + Base type for a triangle mesh. + + Base type for a triangle mesh, parameterized by a mesh kernel. The + mesh inherits all methods from the kernel class and the + more general polygonal mesh PolyMeshT. Therefore it provides + the same types for items, handles, iterators and so on. + + \param Kernel: template argument for the mesh kernel + \note You should use the predefined mesh-kernel combinations in + \ref mesh_types_group + \see \ref mesh_type + \see OpenMesh::PolyMeshT +*/ + +template +class TriMeshT : public PolyMeshT +{ + +public: + + + // self + typedef TriMeshT This; + typedef PolyMeshT PolyMesh; + + //@{ + /// Determine whether this is a PolyMeshT or TriMeshT (This function does not check the per face vertex count! It only checks if the datatype is PolyMeshT or TriMeshT) + static constexpr bool is_polymesh() { return false; } + static constexpr bool is_trimesh() { return true; } + using ConnectivityTag = TriConnectivityTag; + enum { IsPolyMesh = 0 }; + enum { IsTriMesh = 1 }; + //@} + + //--- items --- + + typedef typename PolyMesh::Scalar Scalar; + typedef typename PolyMesh::Point Point; + typedef typename PolyMesh::Normal Normal; + typedef typename PolyMesh::Color Color; + typedef typename PolyMesh::TexCoord1D TexCoord1D; + typedef typename PolyMesh::TexCoord2D TexCoord2D; + typedef typename PolyMesh::TexCoord3D TexCoord3D; + typedef typename PolyMesh::Vertex Vertex; + typedef typename PolyMesh::Halfedge Halfedge; + typedef typename PolyMesh::Edge Edge; + typedef typename PolyMesh::Face Face; + + + //--- handles --- + + typedef typename PolyMesh::VertexHandle VertexHandle; + typedef typename PolyMesh::HalfedgeHandle HalfedgeHandle; + typedef typename PolyMesh::EdgeHandle EdgeHandle; + typedef typename PolyMesh::FaceHandle FaceHandle; + + + //--- iterators --- + + typedef typename PolyMesh::VertexIter VertexIter; + typedef typename PolyMesh::ConstVertexIter ConstVertexIter; + typedef typename PolyMesh::EdgeIter EdgeIter; + typedef typename PolyMesh::ConstEdgeIter ConstEdgeIter; + typedef typename PolyMesh::FaceIter FaceIter; + typedef typename PolyMesh::ConstFaceIter ConstFaceIter; + + + + //--- circulators --- + + typedef typename PolyMesh::VertexVertexIter VertexVertexIter; + typedef typename PolyMesh::VertexOHalfedgeIter VertexOHalfedgeIter; + typedef typename PolyMesh::VertexIHalfedgeIter VertexIHalfedgeIter; + typedef typename PolyMesh::VertexEdgeIter VertexEdgeIter; + typedef typename PolyMesh::VertexFaceIter VertexFaceIter; + typedef typename PolyMesh::FaceVertexIter FaceVertexIter; + typedef typename PolyMesh::FaceHalfedgeIter FaceHalfedgeIter; + typedef typename PolyMesh::FaceEdgeIter FaceEdgeIter; + typedef typename PolyMesh::FaceFaceIter FaceFaceIter; + typedef typename PolyMesh::ConstVertexVertexIter ConstVertexVertexIter; + typedef typename PolyMesh::ConstVertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef typename PolyMesh::ConstVertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef typename PolyMesh::ConstVertexEdgeIter ConstVertexEdgeIter; + typedef typename PolyMesh::ConstVertexFaceIter ConstVertexFaceIter; + typedef typename PolyMesh::ConstFaceVertexIter ConstFaceVertexIter; + typedef typename PolyMesh::ConstFaceHalfedgeIter ConstFaceHalfedgeIter; + typedef typename PolyMesh::ConstFaceEdgeIter ConstFaceEdgeIter; + typedef typename PolyMesh::ConstFaceFaceIter ConstFaceFaceIter; + + // --- constructor/destructor + + /// Default constructor + TriMeshT() : PolyMesh() {} + explicit TriMeshT(PolyMesh rhs) : PolyMesh((rhs.triangulate(), rhs)) + { + } + + /// Destructor + virtual ~TriMeshT() {} + + //--- halfedge collapse / vertex split --- + + /** \brief Vertex Split: inverse operation to collapse(). + * + * Insert the new vertex at position v0. The vertex will be added + * as the inverse of the edge collapse. The faces above the split + * will be correctly attached to the two new edges + * + *

+   *
+   * Before:
+   * v_l     v0     v_r
+   *  x      x      x
+   *   \           /
+   *    \         /
+   *     \       /
+   *      \     /
+   *       \   /
+   *        \ /
+   *         x
+   *         v1
+   *
+   * After:
+   * v_l    v0      v_r
+   *  x------x------x
+   *   \     |     /
+   *    \    |    /
+   *     \   |   /
+   *      \  |  /
+   *       \ | /
+   *        \|/
+   *         x
+   *         v1
+   *
+   * 
+ * + * @param _v0_point Point position for the new point + * @param _v1 Vertex that will be split + * @param _vl Left vertex handle + * @param _vr Right vertex handle + * @return Newly inserted halfedge + */ + inline HalfedgeHandle vertex_split(Point _v0_point, VertexHandle _v1, + VertexHandle _vl, VertexHandle _vr) + { return PolyMesh::vertex_split(this->add_vertex(_v0_point), _v1, _vl, _vr); } + + /** \brief Vertex Split: inverse operation to collapse(). + * + * Insert the new vertex at position v0. The vertex will be added + * as the inverse of the edge collapse. The faces above the split + * will be correctly attached to the two new edges + * + *
+   *
+   * Before:
+   * v_l     v0     v_r
+   *  x      x      x
+   *   \           /
+   *    \         /
+   *     \       /
+   *      \     /
+   *       \   /
+   *        \ /
+   *         x
+   *         v1
+   *
+   * After:
+   * v_l    v0      v_r
+   *  x------x------x
+   *   \     |     /
+   *    \    |    /
+   *     \   |   /
+   *      \  |  /
+   *       \ | /
+   *        \|/
+   *         x
+   *         v1
+   *
+   * 
+ * + * @param _v0 Vertex handle for the newly inserted point (Input has to be unconnected!) + * @param _v1 Vertex that will be split + * @param _vl Left vertex handle + * @param _vr Right vertex handle + * @return Newly inserted halfedge + */ + inline HalfedgeHandle vertex_split(VertexHandle _v0, VertexHandle _v1, + VertexHandle _vl, VertexHandle _vr) + { return PolyMesh::vertex_split(_v0, _v1, _vl, _vr); } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be undefined! + * + * + * @param _eh Edge handle that should be splitted + * @param _p New point position that will be inserted at the edge + * @return Vertex handle of the newly added vertex + */ + inline SmartVertexHandle split(EdgeHandle _eh, const Point& _p) + { + //Do not call PolyMeshT function below as this does the wrong operation + const SmartVertexHandle vh = this->add_vertex(_p); Kernel::split(_eh, vh); return vh; + } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be adjusted to the properties of the original edge + * + * @param _eh Edge handle that should be splitted + * @param _p New point position that will be inserted at the edge + * @return Vertex handle of the newly added vertex + */ + inline SmartVertexHandle split_copy(EdgeHandle _eh, const Point& _p) + { + //Do not call PolyMeshT function below as this does the wrong operation + const SmartVertexHandle vh = this->add_vertex(_p); Kernel::split_copy(_eh, vh); return vh; + } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be undefined! + * + * @param _eh Edge handle that should be splitted + * @param _vh Vertex handle that will be inserted at the edge + */ + inline void split(EdgeHandle _eh, VertexHandle _vh) + { + //Do not call PolyMeshT function below as this does the wrong operation + Kernel::split(_eh, _vh); + } + + /** \brief Edge split (= 2-to-4 split) + * + * The properties of the new edges will be adjusted to the properties of the original edge + * + * @param _eh Edge handle that should be splitted + * @param _vh Vertex handle that will be inserted at the edge + */ + inline void split_copy(EdgeHandle _eh, VertexHandle _vh) + { + //Do not call PolyMeshT function below as this does the wrong operation + Kernel::split_copy(_eh, _vh); + } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be undefined! + * + * @param _fh Face handle that should be splitted + * @param _p New point position that will be inserted in the face + * + * @return Vertex handle of the new vertex + */ + inline SmartVertexHandle split(FaceHandle _fh, const Point& _p) + { const SmartVertexHandle vh = this->add_vertex(_p); PolyMesh::split(_fh, vh); return vh; } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be adjusted to the properties of the original face + * + * @param _fh Face handle that should be splitted + * @param _p New point position that will be inserted in the face + * + * @return Vertex handle of the new vertex + */ + inline SmartVertexHandle split_copy(FaceHandle _fh, const Point& _p) + { const SmartVertexHandle vh = this->add_vertex(_p); PolyMesh::split_copy(_fh, vh); return vh; } + + + /** \brief Face split (= 1-to-4) split, splits edges at midpoints and adds 4 new faces in the interior). + * + * @param _fh Face handle that should be splitted + */ + inline void split(FaceHandle _fh) + { + // Collect halfedges of face + HalfedgeHandle he0 = this->halfedge_handle(_fh); + HalfedgeHandle he1 = this->next_halfedge_handle(he0); + HalfedgeHandle he2 = this->next_halfedge_handle(he1); + + EdgeHandle eh0 = this->edge_handle(he0); + EdgeHandle eh1 = this->edge_handle(he1); + EdgeHandle eh2 = this->edge_handle(he2); + + // Collect points of face + VertexHandle p0 = this->to_vertex_handle(he0); + VertexHandle p1 = this->to_vertex_handle(he1); + VertexHandle p2 = this->to_vertex_handle(he2); + + // Calculate midpoint coordinates + const Point new0 = (this->point(p0) + this->point(p2)) * static_cast::value_type >(0.5); + const Point new1 = (this->point(p0) + this->point(p1)) * static_cast::value_type >(0.5); + const Point new2 = (this->point(p1) + this->point(p2)) * static_cast::value_type >(0.5); + + // Add vertices at midpoint coordinates + VertexHandle v0 = this->add_vertex(new0); + VertexHandle v1 = this->add_vertex(new1); + VertexHandle v2 = this->add_vertex(new2); + + const bool split0 = !this->is_boundary(eh0); + const bool split1 = !this->is_boundary(eh1); + const bool split2 = !this->is_boundary(eh2); + + // delete original face + this->delete_face(_fh); + + // split boundary edges of deleted face ( if not boundary ) + if ( split0 ) { + this->split(eh0,v0); + } + + if ( split1 ) { + this->split(eh1,v1); + } + + if ( split2 ) { + this->split(eh2,v2); + } + + // Retriangulate + this->add_face(v0 , p0, v1); + this->add_face(p2, v0 , v2); + this->add_face(v2,v1,p1); + this->add_face(v2 , v0, v1); + } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be undefined! + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split(FaceHandle _fh, VertexHandle _vh) + { PolyMesh::split(_fh, _vh); } + + /** \brief Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + * + * The properties of the new faces will be adjusted to the properties of the original face + * + * @param _fh Face handle that should be splitted + * @param _vh Vertex handle that will be inserted at the face + */ + inline void split_copy(FaceHandle _fh, VertexHandle _vh) + { PolyMesh::split_copy(_fh, _vh); } + + /** \brief Calculates the area of a face + * + * @param _fh Handle of the face to calculate the area of + */ + Scalar calc_face_area(FaceHandle _fh) const + { + const HalfedgeHandle heh = this->halfedge_handle(_fh); + return this->calc_sector_area(heh); + } + + /** \name Normal vector computation + */ + //@{ + + /** Calculate normal vector for face _fh (specialized for TriMesh). */ + Normal calc_face_normal(FaceHandle _fh) const; + + //@} +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_TRIMESH_C) +#define OPENMESH_TRIMESH_TEMPLATES +#include "TriMeshT_impl.hh" +#endif +//============================================================================= +#endif // OPENMESH_TRIMESH_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriMeshT_impl.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriMeshT_impl.hh new file mode 100644 index 0000000..b6392ba --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriMeshT_impl.hh @@ -0,0 +1,88 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS TriMeshT - IMPLEMENTATION +// +//============================================================================= + + +#define OPENMESH_TRIMESH_C + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + +template +typename TriMeshT::Normal +TriMeshT:: +calc_face_normal(FaceHandle _fh) const +{ + assert(this->halfedge_handle(_fh).is_valid()); + ConstFaceVertexIter fv_it(this->cfv_iter(_fh)); + + const Point& p0(this->point(*fv_it)); ++fv_it; + const Point& p1(this->point(*fv_it)); ++fv_it; + const Point& p2(this->point(*fv_it)); + + return PolyMesh::calc_face_normal(p0, p1, p2); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh new file mode 100644 index 0000000..bb7f235 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh @@ -0,0 +1,112 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// CLASS TriMesh_ArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_TRIMESH_ARRAY_KERNEL_HH +#define OPENMESH_TRIMESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +template +class PolyMesh_ArrayKernelT; +//== CLASS DEFINITION ========================================================= + + +/// Helper class to create a TriMesh-type based on ArrayKernelT +template +struct TriMesh_ArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef TriMeshT Mesh; +}; + + + +/** \ingroup mesh_types_group + Triangle mesh based on the ArrayKernel. + \see OpenMesh::TriMeshT + \see OpenMesh::ArrayKernelT +*/ +template +class TriMesh_ArrayKernelT + : public TriMesh_ArrayKernel_GeneratorT::Mesh +{ +public: + TriMesh_ArrayKernelT() {} + template + explicit TriMesh_ArrayKernelT( const PolyMesh_ArrayKernelT & t) + { + //assign the connectivity and standard properties + this->assign(t,true); + } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_TRIMESH_ARRAY_KERNEL_HH +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/circulators_header.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/circulators_header.hh new file mode 100644 index 0000000..b795a00 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/circulators_header.hh @@ -0,0 +1,93 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_CIRCULATORS_HH +#define OPENMESH_CIRCULATORS_HH + +//============================================================================= +// +// Vertex and Face circulators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class VertexVertexIterT; +template class VertexIHalfedgeIterT; +template class VertexOHalfedgeIterT; +template class VertexEdgeIterT; +template class VertexFaceIterT; + +template class ConstVertexVertexIterT; +template class ConstVertexIHalfedgeIterT; +template class ConstVertexOHalfedgeIterT; +template class ConstVertexEdgeIterT; +template class ConstVertexFaceIterT; + +template class FaceVertexIterT; +template class FaceHalfedgeIterT; +template class FaceEdgeIterT; +template class FaceFaceIterT; + +template class ConstFaceVertexIterT; +template class ConstFaceHalfedgeIterT; +template class ConstFaceEdgeIterT; +template class ConstFaceFaceIterT; + + + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/circulators_template.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/circulators_template.hh new file mode 100644 index 0000000..97a2171 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/circulators_template.hh @@ -0,0 +1,190 @@ +//== CLASS DEFINITION ========================================================= + + +/** \class CirculatorT CirculatorsT.hh + Circulator. +*/ + +template +class CirculatorT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef TargetType value_type; + typedef TargetHandle value_handle; + +#if IsConst + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const TargetType& reference; + typedef const TargetType* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef TargetType& reference; + typedef TargetType* pointer; +#endif + + + + /// Default constructor + CirculatorT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a SourceHandle + CirculatorT(mesh_ref _mesh, SourceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { post_init; } + + + /// Construct with mesh and start halfedge + CirculatorT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { post_init; } + + + /// Copy constructor + CirculatorT(const CirculatorT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { post_init; } + + + /// Assignment operator + CirculatorT& operator=(const CirculatorT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if IsConst + /// construct from non-const circulator type + CirculatorT(const NonConstCircT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { post_init; } + + + /// assign from non-const circulator + CirculatorT& operator=(const NonConstCircT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstCircT; +#endif + + + /// Equal ? + bool operator==(const CirculatorT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const CirculatorT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + CirculatorT& operator++() { + assert(mesh_); + active_ = true; + increment; + return *this; + } + + + /// Pre-Decrement (next ccw target) + CirculatorT& operator--() { + assert(mesh_); + active_ = true; + decrement; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + TargetHandle handle() const { + assert(mesh_); + return get_handle; + } + + + /// Cast to the handle of the current target. + operator TargetHandle() const { + assert(mesh_); + return get_handle; + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +private: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/footer.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/footer.hh new file mode 100644 index 0000000..8e2a9c1 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/footer.hh @@ -0,0 +1,6 @@ +//============================================================================= +} // namespace Iterators +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/iterators_header.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/iterators_header.hh new file mode 100644 index 0000000..afdaca6 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/iterators_header.hh @@ -0,0 +1,82 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_ITERATORS_HH +#define OPENMESH_ITERATORS_HH + +//============================================================================= +// +// Iterators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class VertexIterT; +template class ConstVertexIterT; +template class HalfedgeIterT; +template class ConstHalfedgeIterT; +template class EdgeIterT; +template class ConstEdgeIterT; +template class FaceIterT; +template class ConstFaceIterT; + + + + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/iterators_template.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/iterators_template.hh new file mode 100644 index 0000000..99f54e0 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Mesh/gen/iterators_template.hh @@ -0,0 +1,162 @@ +//== CLASS DEFINITION ========================================================= + + +/** \class IteratorT IteratorsT.hh + Linear iterator. +*/ + +template +class IteratorT +{ +public: + + + //--- Typedefs --- + + typedef TargetType value_type; + typedef TargetHandle value_handle; + +#if IsConst + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + IteratorT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + IteratorT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + IteratorT(const IteratorT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + IteratorT& operator=(const IteratorT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if IsConst + + /// Construct from a non-const iterator + IteratorT(const NonConstIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + IteratorT& operator=(const NonConstIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const IteratorT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const IteratorT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + IteratorT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + IteratorT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_element_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_elements()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/OpenMeshDLLMacros.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/OpenMeshDLLMacros.hh new file mode 100644 index 0000000..4c1e804 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/OpenMeshDLLMacros.hh @@ -0,0 +1,65 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +// Disable the warnings about needs to have DLL interface as we have tons of vector templates +#ifdef _MSC_VER + #pragma warning( disable: 4251 ) +#endif + +#ifndef OPENMESHDLLEXPORT + #ifdef WIN32 + #ifdef OPENMESHDLL + #ifdef BUILDOPENMESHDLL + #define OPENMESHDLLEXPORT __declspec(dllexport) + #define OPENMESHDLLEXPORTONLY __declspec(dllexport) + #else + #define OPENMESHDLLEXPORT __declspec(dllimport) + #define OPENMESHDLLEXPORTONLY + #endif + #else + #define OPENMESHDLLEXPORT + #define OPENMESHDLLEXPORTONLY + #endif + #else + #define OPENMESHDLLEXPORT + #define OPENMESHDLLEXPORTONLY + #endif +#endif diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/compiler.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/compiler.hh new file mode 100644 index 0000000..3abf35f --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/compiler.hh @@ -0,0 +1,167 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +#ifndef OPENMESH_COMPILER_H +#define OPENMESH_COMPILER_H + +//============================================================================= + +#if defined(_DEBUG) || defined(DEBUG) +# define OM_DEBUG +#endif + +//============================================================================= + +// Workaround for Intel Compiler with MS VC++ 6 +#if defined(_MSC_VER) && \ + ( defined(__ICL) || defined(__INTEL_COMPILER) || defined(__ICC) ) +# if !defined(__INTEL_COMPILER) +# define __INTEL_COMPILER __ICL +# endif +# define OM_USE_INTEL_COMPILER 1 +#endif + +// --------------------------------------------------------- MS Visual C++ ---- +// Compiler _MSC_VER +// .NET 2002 1300 +// .NET 2003 1310 +// .NET 2005 1400 +#if defined(_MSC_VER) && !defined(OM_USE_INTEL_COMPILER) +# if (_MSC_VER == 1300) +# define OM_CC_MSVC +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 0 +# define OM_PARTIAL_SPECIALIZATION 0 +# define OM_INCLUDE_TEMPLATES 1 +# elif (_MSC_VER == 1310) +# define OM_CC_MSVC +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# elif (_MSC_VER >= 1400) // settings for .NET 2005 (NOTE: not fully tested) +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# else +# error "Version 7 (.NET 2002) or higher of the MS VC++ is required!" +# endif +// currently no windows dll supported +# define OM_STATIC_BUILD 1 +# if defined(_MT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "MSVC++" +# define OM_CC_VERSION _MSC_VER +// Does not work stable because the define _CPPRTTI sometimes does not exist, +// though the option /GR is set!? +# if defined(__cplusplus) && !defined(_CPPRTTI) +# error "Enable Runtime Type Information (Compiler Option /GR)!" +# endif +# if !defined(_USE_MATH_DEFINES) +# error "You have to define _USE_MATH_DEFINES in the compiler settings!" +# endif +// ------------------------------------------------------------- Borland C ---- +#elif defined(__BORLANDC__) +# error "Borland Compiler are not supported yet!" +// ------------------------------------------------------------- GNU C/C++ ---- +#elif defined(__GNUC__) && !defined(__ICC) +# define OM_CC_GCC +# define OM_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 ) +# define OM_GCC_MAJOR __GNUC__ +# define OM_GCC_MINOR __GNUC_MINOR__ +# if (OM_GCC_VERSION >= 30200) +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# else +# error "Version 3.2.0 or better of the GNU Compiler is required!" +# endif +# if defined(_REENTRANT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "GCC" +# define OM_CC_VERSION OM_GCC_VERSION +// ------------------------------------------------------------- Intel icc ---- +#elif defined(__ICC) || defined(__INTEL_COMPILER) +# define OM_CC_ICC +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# if defined(_REENTRANT) || defined(_MT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "ICC" +# define OM_CC_VERSION __INTEL_COMPILER +// currently no windows dll supported +# if defined(_MSC_VER) || defined(WIN32) +# define OM_STATIC_BUILD 1 +# endif +// ------------------------------------------------------ MIPSpro Compiler ---- +#elif defined(__MIPS_ISA) || defined(__mips) +// _MIPS_ISA +// _COMPILER_VERSION e.g. 730, 7 major, 3 minor +// _MIPS_FPSET 32|64 +// _MIPS_SZINT 32|64 +// _MIPS_SZLONG 32|64 +// _MIPS_SZPTR 32|64 +# define OM_CC_MIPS +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 0 +# define OM_CC "MIPS" +# define OM_CC_VERSION _COMPILER_VERSION +// ------------------------------------------------------------------ ???? ---- +#else +# error "You're using an unsupported compiler!" +#endif + +//============================================================================= +#endif // OPENMESH_COMPILER_H defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/config.h b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/config.h new file mode 100644 index 0000000..342caab --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/config.h @@ -0,0 +1,106 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/** \file config.h + * \todo Move content to config.hh and include it to be compatible with old + * source. + */ + +//============================================================================= + +#ifndef OPENMESH_CONFIG_H +#define OPENMESH_CONFIG_H + +//============================================================================= + +#include +#include +#include + +// ---------------------------------------------------------------------------- + + +#define OM_VERSION 0x0B0000 +//#define OM_VERSION 0x70200 + +#define OM_GET_VER ((OM_VERSION & 0xf0000) >> 16) +#define OM_GET_MAJ ((OM_VERSION & 0x0ff00) >> 8) +#define OM_GET_MIN (OM_VERSION & 0x000ff) + +#ifdef WIN32 +# ifdef min +# pragma message("Detected min macro! OpenMesh does not compile with min/max macros active! Please add a define NOMINMAX to your compiler flags or add #undef min before including OpenMesh headers !") +# error min macro active +# endif +# ifdef max +# pragma message("Detected max macro! OpenMesh does not compile with min/max macros active! Please add a define NOMINMAX to your compiler flags or add #undef max before including OpenMesh headers !") +# error max macro active +# endif +#endif + +//! define OM_SUPPRESS_DEPRECATED to suppress deprecated code warnings +#if defined(OM_SUPPRESS_DEPRECATED) +#pragma message( \ + "OpenMesh deprecated code warnings suppressed, please fix your code soon") +# define OM_DEPRECATED(msg) +#elif defined(_MSC_VER) +# define OM_DEPRECATED(msg) __declspec(deprecated(msg)) +#elif defined(__GNUC__) +# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40500 /* Test for GCC >= 4.5.0 */ +# define OM_DEPRECATED(msg) __attribute__ ((deprecated(msg))) +# else +# define OM_DEPRECATED(msg) __attribute__ ((deprecated)) +# endif +#elif defined(__clang__) +# define OM_DEPRECATED(msg) __attribute__ ((deprecated(msg))) +#else +# define OM_DEPRECATED(msg) +#endif + +typedef unsigned int uint; + +#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) +#define OM_HAS_HASH +#endif + +//============================================================================= +#endif // OPENMESH_CONFIG_H defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/config.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/config.hh new file mode 100644 index 0000000..4073290 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/config.hh @@ -0,0 +1,44 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#include diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/mostream.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/mostream.hh new file mode 100644 index 0000000..2b7e08e --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/mostream.hh @@ -0,0 +1,325 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// multiplex streams & ultilities +// +//============================================================================= + +#ifndef OPENMESH_MOSTREAM_HH +#define OPENMESH_MOSTREAM_HH + + +//== INCLUDES ================================================================= + +#include +#include +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 +# include +#else +# include +#endif +#include +#include +#include +#include + +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + #include +#endif + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +#ifndef DOXY_IGNORE_THIS + + +//== CLASS DEFINITION ========================================================= + + +class basic_multiplex_target +{ +public: + virtual ~basic_multiplex_target() {} + virtual void operator<<(const std::string& _s) = 0; +}; + + +template +class multiplex_target : public basic_multiplex_target +{ +public: + explicit multiplex_target(T& _t) : target_(_t) {} + virtual void operator<<(const std::string& _s) override { target_ << _s; } +private: + T& target_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 +# define STREAMBUF streambuf +# define INT_TYPE int +# define TRAITS_TYPE +#else +# define STREAMBUF std::basic_streambuf +#endif + +class multiplex_streambuf : public STREAMBUF +{ +public: + + typedef STREAMBUF base_type; +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 + typedef int int_type; + struct traits_type + { + static int_type eof() { return -1; } + static char to_char_type(int_type c) { return char(c); } + }; +#else + typedef base_type::int_type int_type; + typedef base_type::traits_type traits_type; +#endif + + // Constructor + multiplex_streambuf() : enabled_(true) { buffer_.reserve(100); } + + // Destructor + ~multiplex_streambuf() + { + tmap_iter t_it(target_map_.begin()), t_end(target_map_.end()); + for (; t_it!=t_end; ++t_it) + delete t_it->second; + } + + + // buffer enable/disable + bool is_enabled() const { return enabled_; } + void enable() { enabled_ = true; } + void disable() { enabled_ = false; } + + + // construct multiplex_target and add it to targets + template bool connect(T& _target) + { + void* key = (void*) &_target; + + if (target_map_.find(key) != target_map_.end()) + return false; + + target_type* mtarget = new multiplex_target(_target); + target_map_[key] = mtarget; + + __connect(mtarget); + return true; + } + + + // disconnect target from multiplexer + template bool disconnect(T& _target) + { + void* key = (void*) &_target; + tmap_iter t_it = target_map_.find(key); + + if (t_it != target_map_.end()) + { + __disconnect(t_it->second); + target_map_.erase(t_it); + return true; + } + + return false; + } + + +protected: + + // output what's in buffer_ + virtual int sync() + { + // If working on multiple threads, we need to serialize the output correctly (requires c++11 headers) + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + std::lock_guard lck (serializer_); + #endif + + if (!buffer_.empty()) + { + if (enabled_) multiplex(); +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 + buffer_ = ""; // member clear() not available! +#else + buffer_.clear(); +#endif + } + return base_type::sync(); + } + + + // take on char and add it to buffer_ + // if '\n' is encountered, trigger a sync() + virtual + int_type overflow(int_type _c = multiplex_streambuf::traits_type::eof()) + { + char c = traits_type::to_char_type(_c); + + // If working on multiple threads, we need to serialize the output correctly (requires c++11 headers) + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + { + std::lock_guard lck (serializer_); + buffer_.push_back(c); + } + #else + buffer_.push_back(c); + #endif + + if (c == '\n') sync(); + return 0; + } + + +private: + + typedef basic_multiplex_target target_type; + typedef std::vector target_list; + typedef target_list::iterator tlist_iter; + typedef std::map target_map; + typedef target_map::iterator tmap_iter; + + + // add _target to list of multiplex targets + void __connect(target_type* _target) { targets_.push_back(_target); } + + + // remove _target from list of multiplex targets + void __disconnect(target_type* _target) { + targets_.erase(std::find(targets_.begin(), targets_.end(), _target)); + } + + + // multiplex output of buffer_ to all targets + void multiplex() + { + tlist_iter t_it(targets_.begin()), t_end(targets_.end()); + for (; t_it!=t_end; ++t_it) + **t_it << buffer_; + } + + +private: + + target_list targets_; + target_map target_map_; + std::string buffer_; + bool enabled_; + + // If working on multiple threads, we need to serialize the output correctly (requires c++11 headers) + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined( __GXX_EXPERIMENTAL_CXX0X__ ) + std::mutex serializer_; + #endif + +}; + +#undef STREAMBUF + + +//== CLASS DEFINITION ========================================================= + + +/** \class mostream mostream.hh + + This class provides streams that can easily be multiplexed (using + the connect() method) and toggled on/off (using enable() / + disable()). + + \see omlog, omout, omerr +*/ + +class mostream : public std::ostream +{ +public: + + /// Explicit constructor + explicit mostream() : std::ostream(nullptr) { init(&streambuffer_); } + + + /// Connect target to multiplexer + template bool connect(T& _target) + { + return streambuffer_.connect(_target); + } + + + /// Disconnect target from multiplexer + template bool disconnect(T& _target) + { + return streambuffer_.disconnect(_target); + } + + + /// is buffer enabled + bool is_enabled() const { return streambuffer_.is_enabled(); } + + /// enable this buffer + void enable() { streambuffer_.enable(); } + + /// disable this buffer + void disable() { streambuffer_.disable(); } + + +private: + multiplex_streambuf streambuffer_; +}; + + +//============================================================================= +#endif +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MOSTREAM_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/omstream.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/omstream.hh new file mode 100644 index 0000000..18712f9 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/System/omstream.hh @@ -0,0 +1,78 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// OpenMesh streams: omlog, omout, omerr +// +//============================================================================= + +#ifndef OPENMESH_OMSTREAMS_HH +#define OPENMESH_OMSTREAMS_HH + + +//== INCLUDES ================================================================= + +#include + + +//== CLASS DEFINITION ========================================================= + +/** \file omstream.hh + This file provides the streams omlog, omout, and omerr. +*/ + +/** \name stream replacements + These stream provide replacements for clog, cout, and cerr. They have + the advantage that they can easily be multiplexed. + \see OpenMesh::mostream +*/ +//@{ +OPENMESHDLLEXPORT OpenMesh::mostream& omlog(); +OPENMESHDLLEXPORT OpenMesh::mostream& omout(); +OPENMESHDLLEXPORT OpenMesh::mostream& omerr(); +//@} + +//============================================================================= +#endif // OPENMESH_OMSTREAMS_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Templates/bla.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Templates/bla.hh new file mode 100644 index 0000000..7340366 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Templates/bla.hh @@ -0,0 +1,110 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// CLASS bla +// +//============================================================================= +#ifndef DOXY_IGNORE_THIS +#ifndef OPENMESH_NEWCLASST_HH +#define OPENMESH_NEWCLASST_HH + + +//== INCLUDES ================================================================= + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + + + +/** \class blaT blaT.hh + + Brief Description. + + A more elaborate description follows. +*/ + +template <> +class blaT +{ +public: + + /// Default constructor + blaT() {} + + /// Destructor + ~blaT() {} + + +private: + + /// Copy constructor (not used) + blaT(const blaT& _rhs); + + /// Assignment operator (not used) + blaT& operator=(const blaT& _rhs); + +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_BLA_C) +#define OPENMESH_BLA_TEMPLATES +#include "blaT_impl.hh" +#endif +//============================================================================= +#endif // OPENMESH_NEWCLASST_HH defined +#endif // DOXY_IGNORE_THIS +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Templates/blaT_impl.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Templates/blaT_impl.hh new file mode 100644 index 0000000..64c3b6d --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Templates/blaT_impl.hh @@ -0,0 +1,72 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//============================================================================= +// +// CLASS bla - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_BLA_C + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + + + +//----------------------------------------------------------------------------- + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/AutoPropertyHandleT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/AutoPropertyHandleT.hh new file mode 100644 index 0000000..1b2734c --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/AutoPropertyHandleT.hh @@ -0,0 +1,133 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_AutoPropertyHandleT_HH +#define OPENMESH_AutoPropertyHandleT_HH + +//== INCLUDES ================================================================= +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +template +class AutoPropertyHandleT : public PropertyHandle_ +{ +public: + typedef Mesh_ Mesh; + typedef PropertyHandle_ PropertyHandle; + typedef PropertyHandle Base; + typedef typename PropertyHandle::Value Value; + typedef AutoPropertyHandleT + Self; +protected: + Mesh* m_; + bool own_property_;//ref counting? + +public: + AutoPropertyHandleT() + : m_(nullptr), own_property_(false) + {} + + AutoPropertyHandleT(const Self& _other) + : Base(_other.idx()), m_(_other.m_), own_property_(false) + {} + + explicit AutoPropertyHandleT(Mesh& _m, const std::string& _pp_name = std::string()) + { add_property(_m, _pp_name); } + + AutoPropertyHandleT(Mesh& _m, PropertyHandle _pph) + : Base(_pph.idx()), m_(&_m), own_property_(false) + {} + + ~AutoPropertyHandleT() + { + if (own_property_) + { + m_->remove_property(*this); + } + } + + inline void add_property(Mesh& _m, const std::string& _pp_name = std::string()) + { + assert(!is_valid()); + m_ = &_m; + own_property_ = _pp_name.empty() || !m_->get_property_handle(*this, _pp_name); + if (own_property_) + { + m_->add_property(*this, _pp_name); + } + } + + inline void remove_property() + { + assert(own_property_);//only the owner can delete the property + m_->remove_property(*this); + own_property_ = false; + invalidate(); + } + + template + inline Value& operator [] (_Handle _hnd) + { return m_->property(*this, _hnd); } + + template + inline const Value& operator [] (_Handle _hnd) const + { return m_->property(*this, _hnd); } + + inline bool own_property() const + { return own_property_; } + + inline void free_property() + { own_property_ = false; } +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_AutoPropertyHandleT_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/BaseProperty.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/BaseProperty.hh new file mode 100644 index 0000000..252d2b7 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/BaseProperty.hh @@ -0,0 +1,191 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_BASEPROPERTY_HH +#define OPENMESH_BASEPROPERTY_HH + +#include +#include +#include + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +/** \class BaseProperty Property.hh + + Abstract class defining the basic interface of a dynamic property. +**/ + +class OPENMESHDLLEXPORT BaseProperty +{ +public: + + /// Indicates an error when a size is returned by a member. + static const size_t UnknownSize = size_t(-1); + +public: + + /// \brief Default constructor. + /// + /// In %OpenMesh all mesh data is stored in so-called properties. + /// We distinuish between standard properties, which can be defined at + /// compile time using the Attributes in the traits definition and + /// at runtime using the request property functions defined in one of + /// the kernels. + /// + /// If the property should be stored along with the default properties + /// in the OM-format one must name the property and enable the persistant + /// flag with set_persistent(). + /// + /// \param _name Optional textual name for the property. + /// \param _internal_type_name Internal type name which will be used when storing the data in OM format + /// + BaseProperty(const std::string& _name = "", const std::string& _internal_type_name = "" ) + : name_(_name), internal_type_name_(_internal_type_name), persistent_(false) + {} + + /// \brief Copy constructor + BaseProperty(const BaseProperty & _rhs) + : name_( _rhs.name_ ), internal_type_name_(_rhs.internal_type_name_), persistent_( _rhs.persistent_ ) {} + + /// Destructor. + virtual ~BaseProperty() {} + +public: // synchronized array interface + + /// Reserve memory for n elements. + virtual void reserve(size_t _n) = 0; + + /// Resize storage to hold n elements. + virtual void resize(size_t _n) = 0; + + /// Clear all elements and free memory. + virtual void clear() = 0; + + /// Extend the number of elements by one. + virtual void push_back() = 0; + + /// Let two elements swap their storage place. + virtual void swap(size_t _i0, size_t _i1) = 0; + + /// Copy one element to another + virtual void copy(size_t _io, size_t _i1) = 0; + + /// Return a deep copy of self. + virtual BaseProperty* clone () const = 0; + +public: // named property interface + + /// Return the name of the property + const std::string& name() const { return name_; } + + /// Return internal type name of the property for type safe casting alternative to runtime information + const std::string& internal_type_name() const { return internal_type_name_; } + + virtual void stats(std::ostream& _ostr) const; + +public: // I/O support + + /// Returns true if the persistent flag is enabled else false. + bool persistent(void) const { return persistent_; } + + /// Enable or disable persistency. Self must be a named property to enable + /// persistency. + virtual void set_persistent( bool _yn ) = 0; + + ///returns a unique string for the type of the elements + virtual std::string get_storage_name() const = 0; + + /// Number of elements in property + virtual size_t n_elements() const = 0; + + /// Size of one element in bytes or UnknownSize if not known. + virtual size_t element_size() const = 0; + + /// Return size of property in bytes + virtual size_t size_of() const + { + return size_of( n_elements() ); + } + + /// Estimated size of property if it has _n_elem elements. + /// The member returns UnknownSize if the size cannot be estimated. + virtual size_t size_of(size_t _n_elem) const + { + return (element_size()!=UnknownSize) + ? (_n_elem*element_size()) + : UnknownSize; + } + + /// Store self as one binary block + virtual size_t store( std::ostream& _ostr, bool _swap ) const = 0; + + /** Restore self from a binary block. Uses reserve() to set the + size of self before restoring. + **/ + virtual size_t restore( std::istream& _istr, bool _swap ) = 0; + +protected: + + // To be used in a derived class, when overloading set_persistent() + template < typename T > + void check_and_set_persistent( bool _yn ) + { + if ( _yn && !IO::is_streamable() ) + omerr() << "Warning! Type of property value is not binary storable!\n"; + persistent_ = IO::is_streamable() && _yn; + } + +private: + + std::string name_; + std::string internal_type_name_; + bool persistent_; +}; + +}//namespace OpenMesh + +#endif //OPENMESH_BASEPROPERTY_HH + + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Endian.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Endian.hh new file mode 100644 index 0000000..414142b --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Endian.hh @@ -0,0 +1,98 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_UTILS_ENDIAN_HH +#define OPENMESH_UTILS_ENDIAN_HH + + +//== INCLUDES ================================================================= + + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** Determine byte order of host system. + */ +class OPENMESHDLLEXPORT Endian +{ +public: + + enum Type { + LSB = 1, ///< Little endian (Intel family and clones) + MSB ///< big endian (Motorola's 68x family, DEC Alpha, MIPS) + }; + + /// Return endian type of host system. + static Type local() { return local_; } + + /// Return type _t as string. + static const char * as_string(Type _t); + +private: + static int one_; + static const Type local_; +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/GenProg.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/GenProg.hh new file mode 100644 index 0000000..12264cd --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/GenProg.hh @@ -0,0 +1,160 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Utils for generic/generative programming +// +//============================================================================= + +#ifndef OPENMESH_GENPROG_HH +#define OPENMESH_GENPROG_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +namespace GenProg { +#ifndef DOXY_IGNORE_THIS + +//== IMPLEMENTATION =========================================================== + + +/// This type maps \c true or \c false to different types. +template struct Bool2Type { enum { my_bool = b }; }; + +/// This class generates different types from different \c int 's. +template struct Int2Type { enum { my_int = i }; }; + +/// Handy typedef for Bool2Type classes +typedef Bool2Type TrueType; + +/// Handy typedef for Bool2Type classes +typedef Bool2Type FalseType; + +//----------------------------------------------------------------------------- +/// compile time assertions +template struct AssertCompile; +template <> struct AssertCompile {}; + + + +//--- Template "if" w/ partial specialization --------------------------------- +#if OM_PARTIAL_SPECIALIZATION + + +template +struct IF { typedef Then Result; }; + +/** Template \c IF w/ partial specialization +\code +typedef IF::Result ResultType; +\endcode +*/ +template +struct IF { typedef Else Result; }; + + + + + +//--- Template "if" w/o partial specialization -------------------------------- +#else + + +struct SelectThen +{ + template struct Select { + typedef Then Result; + }; +}; + +struct SelectElse +{ + template struct Select { + typedef Else Result; + }; +}; + +template struct ChooseSelector { + typedef SelectThen Result; +}; + +template <> struct ChooseSelector { + typedef SelectElse Result; +}; + + +/** Template \c IF w/o partial specialization. Use it like +\code +typedef IF::Result ResultType; +\endcode +*/ + +template +class IF +{ + typedef typename ChooseSelector::Result Selector; +public: + typedef typename Selector::template Select::Result Result; +}; + +#endif + +//============================================================================= +#endif +} // namespace GenProg +} // namespace OpenMesh + +#define assert_compile(EXPR) GenProg::AssertCompile<(EXPR)>(); + +//============================================================================= +#endif // OPENMESH_GENPROG_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/HandleToPropHandle.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/HandleToPropHandle.hh new file mode 100644 index 0000000..6e5f639 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/HandleToPropHandle.hh @@ -0,0 +1,45 @@ +#ifndef HANDLETOPROPHANDLE_HH_ +#define HANDLETOPROPHANDLE_HH_ + +#include +#include + +namespace OpenMesh { + + template + struct HandleToPropHandle { + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::VPropHandleT; + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::HPropHandleT; + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::EPropHandleT; + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::FPropHandleT; + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::MPropHandleT; + }; + + template + struct HandleToPropHandle { + using type = OpenMesh::MPropHandleT; + }; + +} // namespace OpenMesh + +#endif // HANDLETOPROPHANDLE_HH_ diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Noncopyable.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Noncopyable.hh new file mode 100644 index 0000000..928761c --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Noncopyable.hh @@ -0,0 +1,89 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements the Non-Copyable metapher +// +//============================================================================= + +#ifndef OPENMESH_NONCOPYABLE_HH +#define OPENMESH_NONCOPYABLE_HH + + +//----------------------------------------------------------------------------- + +#include + +//----------------------------------------------------------------------------- + +namespace OpenMesh { +namespace Utils { + +//----------------------------------------------------------------------------- + +/** This class demonstrates the non copyable idiom. In some cases it is + important an object can't be copied. Deriving from Noncopyable makes sure + all relevant constructor and operators are made inaccessable, for public + AND derived classes. +**/ +class Noncopyable +{ +public: + Noncopyable() { } + +private: + /// Prevent access to copy constructor + Noncopyable( const Noncopyable& ); + + /// Prevent access to assignment operator + const Noncopyable& operator=( const Noncopyable& ); +}; + +//============================================================================= +} // namespace Utils +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_NONCOPYABLE_HH +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Predicates.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Predicates.hh new file mode 100644 index 0000000..8d7f0fe --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Predicates.hh @@ -0,0 +1,293 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +namespace Predicates { + +//== FORWARD DECLARATION ====================================================== + +//== CLASS DEFINITION ========================================================= + +template +struct PredicateBase +{ +}; + +template +struct Predicate : public PredicateBase> +{ + Predicate(PredicateT _p) + : + p_(_p) + {} + + template + bool operator()(const T& _t) const { return p_(_t); } + + PredicateT p_; +}; + +template +Predicate make_predicate(PredicateT& _p) { return { _p }; } + +template +Predicate make_predicate(PredicateT&& _p) { return { _p }; } + +template +struct Disjunction : public PredicateBase> +{ + Disjunction(Predicate1T _p1, Predicate2T _p2) + : + p1_(_p1), + p2_(_p2) + {} + + template + bool operator()(const T& _t) const { return p1_( _t) || p2_( _t); } + + Predicate1T p1_; + Predicate2T p2_; +}; + +template +struct Conjunction : public PredicateBase> +{ + Conjunction(Predicate1T _p1, Predicate2T _p2) + : + p1_(_p1), + p2_(_p2) + {} + + template + bool operator()(const T& _t) const { return p1_( _t) && p2_( _t); } + + Predicate1T p1_; + Predicate2T p2_; +}; + + +template +struct Negation : public PredicateBase> +{ + Negation(const PredicateT& _p1) + : + p1_(_p1) + {} + + template + bool operator()(const T& _t) const { return !p1_( _t); } + + PredicateT p1_; +}; + +template +Disjunction operator||(PredicateBase& p1, PredicateBase& p2) +{ + return Disjunction(static_cast(p1), static_cast(p2)); +} + +template +Disjunction operator||(PredicateBase& p1, PredicateBase&& p2) +{ + return Disjunction(static_cast(p1), static_cast(p2)); +} + +template +Disjunction operator||(PredicateBase&& p1, PredicateBase& p2) +{ + return Disjunction(static_cast(p1), static_cast(p2)); +} + +template +Disjunction operator||(PredicateBase&& p1, PredicateBase&& p2) +{ + return Disjunction(static_cast(p1), static_cast(p2)); +} + +template +Conjunction operator&&(PredicateBase& p1, PredicateBase& p2) +{ + return Conjunction(static_cast(p1), static_cast(p2)); +} + +template +Conjunction operator&&(PredicateBase& p1, PredicateBase&& p2) +{ + return Conjunction(static_cast(p1), static_cast(p2)); +} + +template +Conjunction operator&&(PredicateBase&& p1, PredicateBase& p2) +{ + return Conjunction(static_cast(p1), static_cast(p2)); +} + +template +Conjunction operator&&(PredicateBase&& p1, PredicateBase&& p2) +{ + return Conjunction(static_cast(p1), static_cast(p2)); +} + +template +Negation operator!(PredicateBase

& p) +{ + return Negation(static_cast(p)); +} + +template +Negation

operator!(PredicateBase

&& p) +{ + return Negation

(static_cast(p)); +} + +struct Feature : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.feature(); } +}; + +struct Selected : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.selected(); } +}; + +struct Tagged : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.tagged(); } +}; + +struct Tagged2 : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.tagged2(); } +}; + +struct Locked : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.locked(); } +}; + +struct Hidden : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.hidden(); } +}; + +struct Deleted : public PredicateBase +{ + template + bool operator()(const SmartHandleStatusPredicates& _h) const { return _h.deleted(); } +}; + +struct Boundary : public PredicateBase +{ + template + bool operator()(const SmartHandleBoundaryPredicate& _h) const { return _h.is_boundary(); } +}; + +template +struct Regular: public PredicateBase> +{ + bool operator()(const SmartVertexHandle& _vh) const { return _vh.valence() == (_vh.is_boundary() ? boundary_reg : inner_reg); } +}; + +using RegularQuad = Regular<4,3>; +using RegularTri = Regular<6,4>; + + +/// Wrapper object to hold an object and a member function pointer, +/// and provides operator() to call that member function for that object with one argument +template +struct MemberFunctionWrapper +{ + T t_; // Objects whose member function we want to call + MF mf_; // pointer to member function + + MemberFunctionWrapper(T _t, MF _mf) + : + t_(_t), + mf_(_mf) + {} + + template + auto operator()(const O& _o) -> decltype ((t_.*mf_)(_o)) + { + return (t_.*mf_)(_o); + } +}; + +/// Helper to create a MemberFunctionWrapper without explicitely naming the types +template +MemberFunctionWrapper make_member_function_wrapper(T&& _t, MF _mf) +{ + return MemberFunctionWrapper(std::forward(_t), _mf); +} + +/// Convenience macro to create a MemberFunctionWrapper for *this object +#define OM_MFW(member_function) OpenMesh::Predicates::make_member_function_wrapper(*this, &std::decay::type::member_function) + + + +//============================================================================= +} // namespace Predicates + +} // namespace OpenMesh +//============================================================================= + +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Property.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Property.hh new file mode 100644 index 0000000..26bcb99 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/Property.hh @@ -0,0 +1,522 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +//#ifndef OPENMESH_PROPERTY_HH +//#define OPENMESH_PROPERTY_HH +#pragma once + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +/** \class PropertyT Property.hh + * + * \brief Default property class for any type T. + * + * The default property class for any type T. + * + * The property supports persistency if T is a "fundamental" type: + * - integer fundamental types except bool: + * char, short, int, long, long long (__int64 for MS VC++) and + * their unsigned companions. + * - float fundamentals except long double: + * float, double + * - %OpenMesh vector types + * + * Persistency of non-fundamental types is supported if and only if a + * specialization of struct IO::binary<> exists for the wanted type. + */ + +// TODO: it might be possible to define Property using kind of a runtime info +// structure holding the size of T. Then reserve, swap, resize, etc can be written +// in pure malloc() style w/o virtual overhead. Template member function proved per +// element access to the properties, asserting dynamic_casts in debug + +template +class PropertyT : public BaseProperty +{ +public: + + typedef T Value; + typedef std::vector vector_type; + typedef T value_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + +public: + + /// Default constructor + explicit PropertyT( + const std::string& _name = "", + const std::string& _internal_type_name = "") + : BaseProperty(_name, _internal_type_name) + {} + + /// Copy constructor + PropertyT(const PropertyT & _rhs) + : BaseProperty( _rhs ), data_( _rhs.data_ ) {} + +public: // inherited from BaseProperty + + virtual void reserve(size_t _n) override { data_.reserve(_n); } + virtual void resize(size_t _n) override { data_.resize(_n); } + virtual void clear() override { data_.clear(); vector_type().swap(data_); } + virtual void push_back() override { data_.emplace_back(); } + virtual void swap(size_t _i0, size_t _i1) override + { std::swap(data_[_i0], data_[_i1]); } + virtual void copy(size_t _i0, size_t _i1) override + { data_[_i1] = data_[_i0]; } + +public: + + virtual void set_persistent( bool _yn ) override + { check_and_set_persistent( _yn ); } + + virtual size_t n_elements() const override { return data_.size(); } + virtual size_t element_size() const override { return IO::size_of(); } + +#ifndef DOXY_IGNORE_THIS + struct plus { + size_t operator () ( size_t _b, const T& _v ) + { return _b + IO::size_of(_v); } + }; +#endif + + virtual size_t size_of(void) const override + { + if (element_size() != IO::UnknownSize) + return this->BaseProperty::size_of(n_elements()); + return std::accumulate(data_.begin(), data_.end(), size_t(0), plus()); + } + + virtual size_t size_of(size_t _n_elem) const override + { return this->BaseProperty::size_of(_n_elem); } + + virtual size_t store( std::ostream& _ostr, bool _swap ) const override + { + if (IO::is_streamable() && element_size() != IO::UnknownSize) + return IO::store(_ostr, data_, _swap, false); //does not need to store its length + + size_t bytes = 0; + for (size_t i=0; i() && element_size() != IO::UnknownSize) + return IO::restore(_istr, data_, _swap, false); //does not need to restore its length + + size_t bytes = 0; + for (size_t i=0; i* clone() const override + { + PropertyT* p = new PropertyT( *this ); + return p; + } + + std::string get_storage_name() const override + { + return OpenMesh::IO::binary::type_identifier(); + } + +private: + + vector_type data_; +}; + +//----------------------------------------------------------------------------- + + +/** Property specialization for bool type. + + The data will be stored as a bitset. + */ +template <> +class PropertyT : public BaseProperty +{ +public: + + typedef std::vector vector_type; + typedef bool value_type; + typedef vector_type::reference reference; + typedef vector_type::const_reference const_reference; + +public: + + explicit PropertyT(const std::string& _name = "", const std::string& _internal_type_name="" ) + : BaseProperty(_name, _internal_type_name) + { } + +public: // inherited from BaseProperty + + virtual void reserve(size_t _n) override { data_.reserve(_n); } + virtual void resize(size_t _n) override { data_.resize(_n); } + virtual void clear() override { data_.clear(); vector_type().swap(data_); } + virtual void push_back() override { data_.push_back(bool()); } + virtual void swap(size_t _i0, size_t _i1) override + { bool t(data_[_i0]); data_[_i0]=data_[_i1]; data_[_i1]=t; } + virtual void copy(size_t _i0, size_t _i1) override + { data_[_i1] = data_[_i0]; } + +public: + + virtual void set_persistent( bool _yn ) override + { + check_and_set_persistent( _yn ); + } + + virtual size_t n_elements() const override { return data_.size(); } + virtual size_t element_size() const override { return UnknownSize; } + virtual size_t size_of() const override { return size_of( n_elements() ); } + virtual size_t size_of(size_t _n_elem) const override + { + return _n_elem / 8 + ((_n_elem % 8)!=0); + } + + size_t store( std::ostream& _ostr, bool /* _swap */ ) const override + { + size_t bytes = 0; + + size_t N = data_.size() / 8; + size_t R = data_.size() % 8; + + size_t idx; // element index + size_t bidx; + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + bits = static_cast(data_[bidx]) + | (static_cast(data_[bidx+1]) << 1) + | (static_cast(data_[bidx+2]) << 2) + | (static_cast(data_[bidx+3]) << 3) + | (static_cast(data_[bidx+4]) << 4) + | (static_cast(data_[bidx+5]) << 5) + | (static_cast(data_[bidx+6]) << 6) + | (static_cast(data_[bidx+7]) << 7); + _ostr << bits; + } + bytes = N; + + if (R) + { + bits = 0; + for (idx=0; idx < R; ++idx) + bits |= static_cast(data_[bidx+idx]) << idx; + _ostr << bits; + ++bytes; + } + + assert( bytes == size_of() ); + + return bytes; + } + + size_t restore( std::istream& _istr, bool /* _swap */ ) override + { + size_t bytes = 0; + + size_t N = data_.size() / 8; + size_t R = data_.size() % 8; + + size_t idx; // element index + size_t bidx; // + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + _istr >> bits; + data_[bidx+0] = (bits & 0x01) != 0; + data_[bidx+1] = (bits & 0x02) != 0; + data_[bidx+2] = (bits & 0x04) != 0; + data_[bidx+3] = (bits & 0x08) != 0; + data_[bidx+4] = (bits & 0x10) != 0; + data_[bidx+5] = (bits & 0x20) != 0; + data_[bidx+6] = (bits & 0x40) != 0; + data_[bidx+7] = (bits & 0x80) != 0; + } + bytes = N; + + if (R) + { + _istr >> bits; + for (idx=0; idx < R; ++idx) + data_[bidx+idx] = (bits & (1<* clone() const override + { + PropertyT* p = new PropertyT( *this ); + return p; + } + + std::string get_storage_name() const override + { + return OpenMesh::IO::binary::type_identifier(); + } + + +private: + + vector_type data_; +}; + + +//----------------------------------------------------------------------------- + + +/// Base property handle. +template +struct BasePropHandleT : public BaseHandle +{ + typedef T Value; + typedef std::vector vector_type; + typedef T value_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + + explicit BasePropHandleT(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a vertex property + */ +template +struct VPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + typedef VertexHandle Handle; + + explicit VPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit VPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a halfedge property + */ +template +struct HPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + typedef HalfedgeHandle Handle; + + explicit HPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit HPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing an edge property + */ +template +struct EPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + typedef EdgeHandle Handle; + + explicit EPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit EPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a face property + */ +template +struct FPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + typedef FaceHandle Handle; + + explicit FPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit FPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a mesh property + */ +template +struct MPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + typedef MeshHandle Handle; + + explicit MPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit MPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + +template +struct PropHandle; + +template <> +struct PropHandle { + template + using type = VPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = HPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = EPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = FPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = MPropHandleT; +}; + +} // namespace OpenMesh +//============================================================================= +//#endif // OPENMESH_PROPERTY_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/PropertyContainer.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/PropertyContainer.hh new file mode 100644 index 0000000..6460413 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/PropertyContainer.hh @@ -0,0 +1,357 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + +#ifndef OPENMESH_PROPERTYCONTAINER +#define OPENMESH_PROPERTYCONTAINER + +#include +#include + +//----------------------------------------------------------------------------- +namespace OpenMesh +{ +//== FORWARDDECLARATIONS ====================================================== + class BaseKernel; + +//== CLASS DEFINITION ========================================================= +/// A a container for properties. +class PropertyContainer +{ +public: + + //-------------------------------------------------- constructor / destructor + + PropertyContainer() {} + virtual ~PropertyContainer() { std::for_each(properties_.begin(), properties_.end(), Delete()); } + + + //------------------------------------------------------------- info / access + + typedef std::vector Properties; + const Properties& properties() const { return properties_; } + size_t size() const { return properties_.size(); } + + + + //--------------------------------------------------------- copy / assignment + + PropertyContainer(const PropertyContainer& _rhs) { operator=(_rhs); } + + PropertyContainer& operator=(const PropertyContainer& _rhs) + { + // The assignment below relies on all previous BaseProperty* elements having been deleted + std::for_each(properties_.begin(), properties_.end(), Delete()); + properties_ = _rhs.properties_; + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + for (; p_it!=p_end; ++p_it) + if (*p_it) + *p_it = (*p_it)->clone(); + return *this; + } + + + + //--------------------------------------------------------- manage properties + + template + BasePropHandleT add(const T&, const std::string& _name="") + { + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + int idx=0; + for ( ; p_it!=p_end && *p_it!=nullptr; ++p_it, ++idx ) {}; + if (p_it==p_end) properties_.push_back(nullptr); + properties_[idx] = new PropertyT(_name, get_type_name() ); // create a new property with requested name and given (system dependent) internal typename + return BasePropHandleT(idx); + } + + + template + BasePropHandleT handle(const T&, const std::string& _name) const + { + Properties::const_iterator p_it = properties_.begin(); + for (int idx=0; p_it != properties_.end(); ++p_it, ++idx) + { + if (*p_it != nullptr && + (*p_it)->name() == _name //skip deleted properties + && (*p_it)->internal_type_name() == get_type_name() // new check type + ) + { + return BasePropHandleT(idx); + } + } + return BasePropHandleT(); + } + + BaseProperty* property( const std::string& _name ) const + { + Properties::const_iterator p_it = properties_.begin(); + for (int idx=0; p_it != properties_.end(); ++p_it, ++idx) + { + if (*p_it != nullptr && (*p_it)->name() == _name) //skip deleted properties + { + return *p_it; + } + } + return nullptr; + } + + template PropertyT& property(BasePropHandleT _h) + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + assert(properties_[_h.idx()] != nullptr); + assert( properties_[_h.idx()]->internal_type_name() == get_type_name() ); + PropertyT *p = static_cast< PropertyT* > (properties_[_h.idx()]); + assert(p != nullptr); + return *p; + } + + + template const PropertyT& property(BasePropHandleT _h) const + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + assert(properties_[_h.idx()] != nullptr); + assert( properties_[_h.idx()]->internal_type_name() == get_type_name() ); + PropertyT *p = static_cast< PropertyT* > (properties_[_h.idx()]); + assert(p != nullptr); + return *p; + } + + + template void remove(BasePropHandleT _h) + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + delete properties_[_h.idx()]; + properties_[_h.idx()] = nullptr; + } + + + void clear() + { + // Clear properties vector: + // Replaced the old version with new one + // which performs a swap to clear values and + // deallocate memory. + + // Old version (changed 22.07.09) { + // std::for_each(properties_.begin(), properties_.end(), Delete()); + // } + + std::for_each(properties_.begin(), properties_.end(), ClearAll()); + } + + + //---------------------------------------------------- synchronize properties + +/* + * In C++11 an beyond we can introduce more efficient and more legible + * implementations of the following methods. + */ +#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) + /** + * Reserves space for \p _n elements in all property vectors. + */ + void reserve(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p) p->reserve(_n); }); + } + + /** + * Resizes all property vectors to the specified size. + */ + void resize(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p) p->resize(_n); }); + } + + /** + * Same as resize() but ignores property vectors that have a size larger + * than \p _n. + * + * Use this method instead of resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ + void resize_if_smaller(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), + [_n](BaseProperty* p) { if (p && p->n_elements() < _n) p->resize(_n); }); + } + + /** + * Swaps the items with index \p _i0 and index \p _i1 in all property + * vectors. + */ + void swap(size_t _i0, size_t _i1) const { + std::for_each(properties_.begin(), properties_.end(), + [_i0, _i1](BaseProperty* p) { if (p) p->swap(_i0, _i1); }); + } +#else + /** + * Reserves space for \p _n elements in all property vectors. + */ + void reserve(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), Reserve(_n)); + } + + /** + * Resizes all property vectors to the specified size. + */ + void resize(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), Resize(_n)); + } + + /** + * Same as \sa resize() but ignores property vectors that have a size + * larger than \p _n. + * + * Use this method instead of \sa resize() if you plan to frequently reduce + * and enlarge the property container and you don't want to waste time + * reallocating the property vectors every time. + */ + void resize_if_smaller(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), ResizeIfSmaller(_n)); + } + + /** + * Swaps the items with index \p _i0 and index \p _i1 in all property + * vectors. + */ + void swap(size_t _i0, size_t _i1) const { + std::for_each(properties_.begin(), properties_.end(), Swap(_i0, _i1)); + } +#endif + + + +protected: // generic add/get + + size_t _add( BaseProperty* _bp ) + { + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + size_t idx=0; + for (; p_it!=p_end && *p_it!=nullptr; ++p_it, ++idx) {}; + if (p_it==p_end) properties_.push_back(nullptr); + properties_[idx] = _bp; + return idx; + } + + BaseProperty& _property( size_t _idx ) + { + assert( _idx < properties_.size()); + assert( properties_[_idx] != nullptr); + BaseProperty *p = properties_[_idx]; + assert( p != nullptr ); + return *p; + } + + const BaseProperty& _property( size_t _idx ) const + { + assert( _idx < properties_.size()); + assert( properties_[_idx] != nullptr); + BaseProperty *p = properties_[_idx]; + assert( p != nullptr ); + return *p; + } + + + typedef Properties::iterator iterator; + typedef Properties::const_iterator const_iterator; + iterator begin() { return properties_.begin(); } + iterator end() { return properties_.end(); } + const_iterator begin() const { return properties_.begin(); } + const_iterator end() const { return properties_.end(); } + + friend class BaseKernel; + +private: + + //-------------------------------------------------- synchronization functors + +#ifndef DOXY_IGNORE_THIS + struct Reserve + { + explicit Reserve(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p) _p->reserve(n_); } + size_t n_; + }; + + struct Resize + { + explicit Resize(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p) _p->resize(n_); } + size_t n_; + }; + + struct ResizeIfSmaller + { + explicit ResizeIfSmaller(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p && _p->n_elements() < n_) _p->resize(n_); } + size_t n_; + }; + + struct ClearAll + { + ClearAll() {} + void operator()(BaseProperty* _p) const { if (_p) _p->clear(); } + }; + + struct Swap + { + Swap(size_t _i0, size_t _i1) : i0_(_i0), i1_(_i1) {} + void operator()(BaseProperty* _p) const { if (_p) _p->swap(i0_, i1_); } + size_t i0_, i1_; + }; + + struct Delete + { + Delete() {} + void operator()(BaseProperty* _p) const { if (_p) delete _p; } + }; +#endif + + Properties properties_; +}; + +}//namespace OpenMesh + +#endif//OPENMESH_PROPERTYCONTAINER + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/PropertyCreator.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/PropertyCreator.hh new file mode 100644 index 0000000..459452d --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/PropertyCreator.hh @@ -0,0 +1,242 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace OpenMesh { + +#define OM_CONCAT_IMPL(a, b) a##b +#define OM_CONCAT(a, b) OM_CONCAT_IMPL(a, b) + +/** \brief Base class for property creators + * + * A PropertyCreator can add a named property to a mesh. + * The type of the property is specified in the classes derived from this class. + * + * */ +class OPENMESHDLLEXPORT PropertyCreator +{ +public: + + /// The string that corresponds to the type this property creator can create + virtual std::string type_string() = 0; + + virtual std::string type_id_string() = 0; + + /// Returns true iff the given _type_name corresponds to the string the derived class can create a property for + bool can_you_create(const std::string &_type_name); + + /// Create a vertex property on _mesh with name _property_name + virtual void create_vertex_property (BaseKernel& _mesh, const std::string& _property_name) = 0; + + /// Create a halfedge property on _mesh with name _property_name + virtual void create_halfedge_property(BaseKernel& _mesh, const std::string& _property_name) = 0; + + /// Create an edge property on _mesh with name _property_name + virtual void create_edge_property (BaseKernel& _mesh, const std::string& _property_name) = 0; + + /// Create a face property on _mesh with name _property_name + virtual void create_face_property (BaseKernel& _mesh, const std::string& _property_name) = 0; + + /// Create a mesh property on _mesh with name _property_name + virtual void create_mesh_property (BaseKernel& _mesh, const std::string& _property_name) = 0; + + + /// Create a property for the element of type HandleT on _mesh with name _property_name + template + void create_property(BaseKernel& _mesh, const std::string& _property_name); + + virtual ~PropertyCreator() {} + +protected: + PropertyCreator() {} + +}; + +template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_vertex_property (_mesh, _property_name); } +template <> inline void PropertyCreator::create_property(BaseKernel& _mesh, const std::string& _property_name) { create_halfedge_property(_mesh, _property_name); } +template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_edge_property (_mesh, _property_name); } +template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_face_property (_mesh, _property_name); } +template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_mesh_property (_mesh, _property_name); } + +/// Helper class that contains the implementation of the create__property methods. +/// Implementation is injected into PropertyCreatorT. +template +class PropertyCreatorImpl : public PropertyCreator +{ +public: + std::string type_id_string() override { return get_type_name(); } + + template + void create_prop(BaseKernel& _mesh, const std::string& _property_name) + { + using PHandle = typename PropHandle::template type; + PHandle prop; + if (!_mesh.get_property_handle(prop, _property_name)) + _mesh.add_property(prop, _property_name); + } + + void create_vertex_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name); } + void create_halfedge_property(BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} + void create_edge_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} + void create_face_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} + void create_mesh_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} + + ~PropertyCreatorImpl() override {} +protected: + PropertyCreatorImpl() {} +}; + +/// Actual PropertyCreators specialize this class in order to add properties of type T +namespace { +template +class PropertyCreatorT : public PropertyCreatorImpl> +{ +}; +} + +///used to register custom type, where typename.hh does provide a string for type recognition + +#define OM_REGISTER_PROPERTY_TYPE(ClassName) \ +namespace OpenMesh { \ +namespace { /* ensure internal linkage of class */ \ +template <> \ +class PropertyCreatorT : public PropertyCreatorImpl> \ +{ \ +public: \ + using type = ClassName; \ + std::string type_string() override { return OpenMesh::IO::binary::type_identifier(); } \ + \ + PropertyCreatorT() \ + { \ + PropertyCreationManager::instance().register_property_creator(this); \ + } \ + ~PropertyCreatorT() override {} \ +}; \ +} \ +/* static to ensure internal linkage of object */ \ +static PropertyCreatorT OM_CONCAT(property_creator_registration_object_, __LINE__); \ +} + +/** \brief Class for adding properties based on strings + * + * The PropertyCreationManager holds all PropertyCreators and dispatches the property creation + * to them if they are able to create a property for a given string. + * + * If you want to be able to store your custom properties into a file and automatically load + * them without manually adding the property yourself you can register your type by calling the + * OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString) + * */ +class OPENMESHDLLEXPORT PropertyCreationManager +{ +public: + + static PropertyCreationManager& instance(); + + template + void create_property(BaseKernel& _mesh, const std::string& _type_name, const std::string& _property_name) + { + + auto can_create = [_type_name](OpenMesh::PropertyCreator* pc){ + return pc->can_you_create(_type_name); + }; + + std::vector::iterator pc_iter = std::find_if(property_creators_.begin(), + property_creators_.end(), can_create); + if (pc_iter != property_creators_.end()) + { + const auto& pc = *pc_iter; + pc->create_property(_mesh, _property_name); + return; + } + + omerr() << "No property creator registered that can create a property of type " << _type_name << std::endl; + omerr() << "You need to register your custom type using OM_REGISTER_PROPERTY_TYPE(ClassName) and declare the struct binary.\ + See documentation for more details." << std::endl; + omerr() << "Adding property failed." << std::endl; + } + + void register_property_creator(PropertyCreator* _property_creator) + { + for (auto pc : property_creators_) + if (pc->type_string() == _property_creator->type_string()) + { + if (pc->type_id_string() != _property_creator->type_id_string()) + { + omerr() << "And it looks like you are trying to add a different type with an already existing string identification." << std::endl; + omerr() << "Type id of existing type is " << pc->type_id_string() << " trying to add for " << _property_creator->type_id_string() << std::endl; + } + return; + } + property_creators_.push_back(_property_creator); + } + +private: + + PropertyCreationManager() {} + ~PropertyCreationManager() {} + + std::vector property_creators_; +}; + +/** \brief Create a property with type corresponding to _type_name on _mesh with name _property_name + * + * For user defined types you need to register the type using OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString) + * */ +template +void create_property_from_string(BaseKernel& _mesh, const std::string& _type_name, const std::string& _property_name) +{ + PropertyCreationManager::instance().create_property(_mesh, _type_name, _property_name); +} + +} /* namespace OpenMesh */ diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/PropertyManager.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/PropertyManager.hh new file mode 100644 index 0000000..7145230 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/PropertyManager.hh @@ -0,0 +1,955 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#ifndef PROPERTYMANAGER_HH_ +#define PROPERTYMANAGER_HH_ + +#include +#include +#include +#include +#include +#include + +namespace OpenMesh { + +/** + * This class is intended to manage the lifecycle of properties. + * It also defines convenience operators to access the encapsulated + * property's value. + * + * Note that the second template parameter is depcretated. + * + * \code + * { + * TriMesh mesh; + * auto visited = makeTemporaryProperty(mesh); + * + * for (auto vh : mesh.vertices()) { + * if (!visited[vh]) { + * visitComponent(mesh, vh, visited); + * } + * } + * // The property is automatically removed at the end of the scope + * } + * \endcode + */ +template +class PropertyManager { + + public: + using Value = typename PROPTYPE::Value; + using value_type = typename PROPTYPE::value_type; + using Handle = typename PROPTYPE::Handle; + using Self = PropertyManager; + using Reference = typename PROPTYPE::reference; + using ConstReference = typename PROPTYPE::const_reference; + + private: + // Mesh properties (MPropHandleT<...>) are stored differently than the other properties. + // This class implements different behavior when initializing a property or when + // copying or swapping data from one property manager to a another one. + template + struct StorageT; + + // specialization for Mesh Properties + template + struct StorageT> { + static void initialize(PropertyManager& pm, const Value& initial_value ) { + pm() = initial_value; + } + static void copy(const PropertyManager& from, PropertyManager2& to) { + *to = *from; + } + static void swap(PropertyManager& from, PropertyManager2& to) { + std::swap(*to, *from); + } + static ConstReference access_property_const(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle&) { + return mesh.property(prop_handle); + } + static Reference access_property(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle&) { + return mesh.property(prop_handle); + } + }; + + // definition for other Mesh Properties + template + struct StorageT { + static void initialize(PropertyManager& pm, const Value& initial_value ) { + pm.set_range(pm.mesh_.template all_elements(), initial_value); + } + static void copy(const PropertyManager& from, PropertyManager2& to) { + from.copy_to(from.mesh_.template all_elements(), to, to.mesh_.template all_elements()); + } + static void swap(PropertyManager& lhs, PropertyManager2& rhs) { + std::swap(lhs.mesh().property(lhs.prop_).data_vector(), rhs.mesh().property(rhs.prop_).data_vector()); + // resize the property to the correct size + lhs.mesh().property(lhs.prop_).resize(lhs.mesh().template n_elements()); + rhs.mesh().property(rhs.prop_).resize(rhs.mesh().template n_elements()); + } + static ConstReference access_property_const(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle& handle) { + return mesh.property(prop_handle, handle); + } + static Reference access_property(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle& handle) { + return mesh.property(prop_handle, handle); + } + }; + + using Storage = StorageT; + + public: + + /** + * @deprecated Use a constructor without \p existing and check existance with hasProperty() instead. + * + * Constructor. + * + * Throws an \p std::runtime_error if \p existing is true and + * no property named \p propname of the appropriate property type + * exists. + * + * @param mesh The mesh on which to create the property. + * @param propname The name of the property. + * @param existing If false, a new property is created and its lifecycle is managed (i.e. + * the property is deleted upon destruction of the PropertyManager instance). If true, + * the instance merely acts as a convenience wrapper around an existing property with no + * lifecycle management whatsoever. + * + * @see PropertyManager::getOrMakeProperty, PropertyManager::getProperty, + * PropertyManager::makeTemporaryProperty + */ + OM_DEPRECATED("Use the constructor without parameter 'existing' instead. Check for existance with hasProperty") // As long as this overload exists, initial value must be first parameter due to ambiguity for properties of type bool + PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing) : mesh_(mesh), retain_(existing), name_(propname) { + if (existing) { + if (!PropertyManager::mesh().get_property_handle(prop_, propname)) { + std::ostringstream oss; + oss << "Requested property handle \"" << propname << "\" does not exist."; + throw std::runtime_error(oss.str()); + } + } else { + PropertyManager::mesh().add_property(prop_, propname); + } + } + + /** + * Constructor. + * + * Asks for a property with name propname and creates one if none exists. Lifetime is not managed. + * + * @param mesh The mesh on which to create the property. + * @param propname The name of the property. + */ + PropertyManager(PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) { + if (!PropertyManager::mesh().get_property_handle(prop_, propname)) { + PropertyManager::mesh().add_property(prop_, propname); + } + } + + /** + * Constructor. + * + * Asks for a property with name propname and creates one if none exists. Lifetime is not managed. + * + * @param initial_value If the proeprty is newly created, it will be initialized with initial_value. + * If the property already existed, nothing is changes. + * @param mesh The mesh on which to create the property. + * @param propname The name of the property. + */ + PropertyManager(const Value& initial_value, PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) { + if (!mesh_.get_property_handle(prop_, propname)) { + PropertyManager::mesh().add_property(prop_, propname); + Storage::initialize(*this, initial_value); + } + } + + /** + * Constructor. + * + * Create an anonymous property. Lifetime is managed. + * + * @param mesh The mesh on which to create the property. + */ + explicit PropertyManager(const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { + PropertyManager::mesh().add_property(prop_, name_); + } + + /** + * Constructor. + * + * Create an anonymous property. Lifetime is managed. + * + * @param initial_value The property will be initialized with initial_value. + * @param mesh The mesh on which to create the property. + */ + PropertyManager(const Value& initial_value, const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { + PropertyManager::mesh().add_property(prop_, name_); + Storage::initialize(*this, initial_value); + } + + /** + * Constructor. + * + * Create a wrapper around an existing property. Lifetime is not managed. + * + * @param mesh The mesh on which to create the property. + * @param property_handle Handle to an existing property that should be wrapped. + */ + PropertyManager(PolyConnectivity& mesh, PROPTYPE property_handle) : mesh_(mesh), prop_(property_handle), retain_(true), name_() { + } + + PropertyManager() = delete; + + PropertyManager(const PropertyManager& rhs) + : + mesh_(rhs.mesh_), + prop_(), + retain_(rhs.retain_), + name_(rhs.name_) + { + if (rhs.retain_) // named property -> create a property manager referring to the same + { + prop_ = rhs.prop_; + } + else // unnamed property -> create a property manager refering to a new property and copy the contents + { + PropertyManager::mesh().add_property(prop_, name_); + Storage::copy(rhs, *this); + } + } + + + /** + * Create property manager referring to a copy of the current property. + * This can be used to explicitely create a copy of a named property. The cloned property + * will be unnamed. + */ + PropertyManager clone() + { + PropertyManager result(this->mesh()); + Storage::copy(*this, result); + return result; + } + + PropertyManager& operator=(const PropertyManager& rhs) + { + if (&mesh_ == &rhs.mesh_ && prop_ == rhs.prop_) + ; // nothing to do + else + Storage::copy(rhs, *this); + return *this; + } + + ~PropertyManager() { + deleteProperty(); + } + + void swap(PropertyManager &rhs) { + // swap the data stored in the properties + Storage::swap(rhs, *this); + } + + static bool propertyExists(const PolyConnectivity &mesh, const char *propname) { + PROPTYPE dummy; + return mesh.get_property_handle(dummy, propname); + } + + bool isValid() const { return prop_.is_valid(); } + operator bool() const { return isValid(); } + + const PROPTYPE &getRawProperty() const { return prop_; } + + const std::string &getName() const { return name_; } + + /** + * Get the mesh corresponding to the property. + * + * If you use PropertyManager without second template parameter (recommended) + * you need to specify the actual mesh type when using this function, e.g.: + * \code + * { + * TriMesh mesh; + * auto visited = VProp(mesh); + * TriMesh& mesh_ref = visited.getMesh(); + * } + * + */ + template + const MeshType& getMesh() const { return dynamic_cast(mesh_); } + + const MeshT& getMesh() const { return dynamic_cast(mesh_); } + + + /** + * @deprecated This method no longer has any effect. Instead, named properties are always retained, while unnamed ones are not + * + * Tells the PropertyManager whether lifetime should be managed or not. + */ + OM_DEPRECATED("retain no longer has any effect. Instead, named properties are always retained, while unnamed ones are not.") + void retain(bool = true) {} + + /** + * Move constructor. Transfers ownership (delete responsibility). + */ + PropertyManager(PropertyManager &&rhs) + : + mesh_(rhs.mesh_), + prop_(rhs.prop_), + retain_(rhs.retain_), + name_(rhs.name_) + { + if (!rhs.retain_) + rhs.prop_.invalidate(); // only invalidate unnamed properties + } + + /** + * Move assignment. Transfers ownership (delete responsibility). + */ + PropertyManager& operator=(PropertyManager&& rhs) + { + if ((&mesh_ != &rhs.mesh_) || (prop_ != rhs.prop_)) + { + if (rhs.retain_) + { + // retained properties cannot be invalidated. Copy instead + Storage::copy(rhs, *this); + } + else + { + // swap the data stored in the properties + Storage::swap(rhs, *this); + // remove the property from rhs + rhs.mesh().remove_property(rhs.prop_); + // invalidate prop_ + rhs.prop_.invalidate(); + } + } + return *this; + } + + /** + * Create a property manager for the supplied property and mesh. + * If the property doesn't exist, it is created. In any case, + * lifecycle management is disabled. + * + * @see makePropertyManagerFromExistingOrNew + */ + static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname) { + return PropertyManager(mesh, propname); + } + + /** + * Like createIfNotExists() with two parameters except, if the property + * doesn't exist, it is initialized with the supplied value over + * the supplied range after creation. If the property already exists, + * this method has the exact same effect as the two parameter version. + * Lifecycle management is disabled in any case. + * + * @see makePropertyManagerFromExistingOrNew + */ + template + static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname, + const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, + const PROP_VALUE &init_value) { + const bool exists = propertyExists(mesh, propname); + PropertyManager pm(mesh, propname, exists); + pm.retain(); + if (!exists) + pm.set_range(begin, end, init_value); + return std::move(pm); + } + + /** + * Like createIfNotExists() with two parameters except, if the property + * doesn't exist, it is initialized with the supplied value over + * the supplied range after creation. If the property already exists, + * this method has the exact same effect as the two parameter version. + * Lifecycle management is disabled in any case. + * + * @see makePropertyManagerFromExistingOrNew + */ + template + static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname, + const ITERATOR_RANGE &range, const PROP_VALUE &init_value) { + return createIfNotExists( + mesh, propname, range.begin(), range.end(), init_value); + } + + + /** + * Access the value of the encapsulated mesh property. + * + * Example: + * @code + * PolyMesh m; + * auto description = getOrMakeProperty(m, "description"); + * *description = "This is a very nice mesh."; + * @endcode + * + * @note This method is only used for mesh properties. + */ + typename PROPTYPE::reference& operator*() { + return mesh().mproperty(prop_)[0]; + } + + /** + * Access the value of the encapsulated mesh property. + * + * Example: + * @code + * PolyMesh m; + * auto description = getProperty(m, "description"); + * std::cout << *description << std::endl; + * @endcode + * + * @note This method is only used for mesh properties. + */ + typename PROPTYPE::const_reference& operator*() const { + return mesh().mproperty(prop_)[0]; + } + + /** + * Enables convenient access to the encapsulated property. + * + * For a usage example see this class' documentation. + * + * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) + */ + inline typename PROPTYPE::reference operator[] (Handle handle) { + return mesh().property(prop_, handle); + } + + /** + * Enables convenient access to the encapsulated property. + * + * For a usage example see this class' documentation. + * + * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) + */ + inline typename PROPTYPE::const_reference operator[] (const Handle& handle) const { + return mesh().property(prop_, handle); + } + + /** + * Enables convenient access to the encapsulated property. + * + * For a usage example see this class' documentation. + * + * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) + */ + inline typename PROPTYPE::reference operator() (const Handle& handle = Handle()) { +// return mesh().property(prop_, handle); + return Storage::access_property(mesh(), prop_, handle); + } + + /** + * Enables convenient access to the encapsulated property. + * + * For a usage example see this class' documentation. + * + * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.) + */ + inline typename PROPTYPE::const_reference operator() (const Handle& handle = Handle()) const { +// return mesh().property(prop_, handle); + return Storage::access_property_const(mesh(), prop_, handle); + } + + /** + * Conveniently set the property for an entire range of values. + * + * Examples: + * \code + * MeshT mesh; + * PropertyManager> distance( + * mesh, "distance.plugin-example.i8.informatik.rwth-aachen.de"); + * distance.set_range( + * mesh.vertices_begin(), mesh.vertices_end(), + * std::numeric_limits::infinity()); + * \endcode + * or + * \code + * MeshT::VertexHandle vh; + * distance.set_range( + * mesh.vv_begin(vh), mesh.vv_end(vh), + * std::numeric_limits::infinity()); + * \endcode + * + * @param begin Start iterator. Needs to dereference to HandleType. + * @param end End iterator. (Exclusive.) + * @param value The value the range will be set to. + */ + template + void set_range(HandleTypeIterator begin, HandleTypeIterator end, + const PROP_VALUE &value) { + for (; begin != end; ++begin) + (*this)[*begin] = value; + } + +#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) + template + void set_range(const HandleTypeIteratorRange &range, + const PROP_VALUE &value) { + set_range(range.begin(), range.end(), value); + } +#endif + + /** + * Conveniently transfer the values managed by one property manager + * onto the values managed by a different property manager. + * + * @param begin Start iterator. Needs to dereference to HandleType. Will + * be used with this property manager. + * @param end End iterator. (Exclusive.) Will be used with this property + * manager. + * @param dst_propmanager The destination property manager. + * @param dst_begin Start iterator. Needs to dereference to the + * HandleType of dst_propmanager. Will be used with dst_propmanager. + * @param dst_end End iterator. (Exclusive.) + * Will be used with dst_propmanager. Used to double check the bounds. + */ + template + void copy_to(HandleTypeIterator begin, HandleTypeIterator end, + PropertyManager2 &dst_propmanager, + HandleTypeIterator2 dst_begin, HandleTypeIterator2 dst_end) const { + + for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) { + dst_propmanager[*dst_begin] = (*this)[*begin]; + } + } + + template + void copy_to(const RangeType &range, + PropertyManager2 &dst_propmanager, + const RangeType2 &dst_range) const { + copy_to(range.begin(), range.end(), dst_propmanager, + dst_range.begin(), dst_range.end()); + } + + + /** + * Copy the values of a property from a source range to + * a target range. The source range must not be smaller than the + * target range. + * + * @param prop_name Name of the property to copy. Must exist on the + * source mesh. Will be created on the target mesh if it doesn't exist. + * + * @param src_mesh Source mesh from which to copy. + * @param src_range Source range which to copy. Must not be smaller than + * dst_range. + * @param dst_mesh Destination mesh on which to copy. + * @param dst_range Destination range. + */ + template + static void copy(const char *prop_name, + PolyConnectivity &src_mesh, const RangeType &src_range, + PolyConnectivity &dst_mesh, const RangeType2 &dst_range) { + + typedef OpenMesh::PropertyManager DstPM; + DstPM dst(DstPM::createIfNotExists(dst_mesh, prop_name)); + + typedef OpenMesh::PropertyManager SrcPM; + SrcPM src(src_mesh, prop_name, true); + + src.copy_to(src_range, dst, dst_range); + } + + /** + * Mark whether this property should be stored when mesh is written + * to a file + * + * @param _persistence Property will be stored iff _persistence is true + */ + void set_persistent(bool _persistence = true) + { + mesh().property(getRawProperty()).set_persistent(_persistence); + } + + private: + void deleteProperty() { + if (!retain_ && prop_.is_valid()) + mesh().remove_property(prop_); + } + + PolyConnectivity& mesh() const + { + return const_cast(mesh_); + } + + private: + const PolyConnectivity& mesh_; + PROPTYPE prop_; + bool retain_; + std::string name_; +}; + +template +class ConstPropertyViewer +{ +public: + using Value = typename PropertyT::Value; + using value_type = typename PropertyT::value_type; + using Handle = typename PropertyT::Handle; + + ConstPropertyViewer(const PolyConnectivity& mesh, const PropertyT& property_handle) + : + mesh_(mesh), + prop_(property_handle) + {} + + inline const typename PropertyT::const_reference operator() (const Handle& handle) + { + return mesh_.property(prop_, handle); + } + + inline const typename PropertyT::const_reference operator[] (const Handle& handle) + { + return mesh_.property(prop_, handle); + } + +private: + const PolyConnectivity& mesh_; + PropertyT prop_; +}; + +/** @relates PropertyManager + * + * @deprecated Temporary properties should not have a name. + * + * Creates a new property whose lifetime is limited to the current scope. + * + * Used for temporary properties. Shadows any existing properties of + * matching name and type. + * + * Example: + * @code + * PolyMesh m; + * { + * auto is_quad = makeTemporaryProperty(m); + * for (auto& fh : m.faces()) { + * is_quad[fh] = (m.valence(fh) == 4); + * } + * // The property is automatically removed from the mesh at the end of the scope. + * } + * @endcode + * + * @param mesh The mesh on which the property is created + * @param propname (optional) The name of the created property + * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the created property, e.g., \p double, \p int, etc. + * @returns A PropertyManager handling the lifecycle of the property + */ +template +PropertyManager::type> +OM_DEPRECATED("Named temporary properties are deprecated. Either create a temporary without name or a non-temporary with name") +makeTemporaryProperty(PolyConnectivity &mesh, const char *propname) { + return PropertyManager::type>(mesh, propname, false); +} + +/** @relates PropertyManager + * + * Creates a new property whose lifetime is limited to the current scope. + * + * Used for temporary properties. Shadows any existing properties of + * matching name and type. + * + * Example: + * @code + * PolyMesh m; + * { + * auto is_quad = makeTemporaryProperty(m); + * for (auto& fh : m.faces()) { + * is_quad[fh] = (m.valence(fh) == 4); + * } + * // The property is automatically removed from the mesh at the end of the scope. + * } + * @endcode + * + * @param mesh The mesh on which the property is created + * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the created property, e.g., \p double, \p int, etc. + * @returns A PropertyManager handling the lifecycle of the property + */ +template +PropertyManager::type> +makeTemporaryProperty(PolyConnectivity &mesh) { + return PropertyManager::type>(mesh); +} + + +/** @relates PropertyManager + * + * Tests whether a property with the given element type, value type, and name is + * present on the given mesh. + * + * * Example: + * @code + * PolyMesh m; + * if (hasProperty(m, "is_quad")) { + * // We now know the property exists: getProperty won't throw. + * auto is_quad = getProperty(m, "is_quad"); + * // Use is_quad here. + * } + * @endcode + * + * @param mesh The mesh in question + * @param propname The property name of the expected property + * @tparam ElementT Element type of the expected property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the expected property, e.g., \p double, \p int, etc. + * @tparam MeshT Type of the mesh. Can often be inferred from \p mesh + */ +template +bool +hasProperty(const PolyConnectivity &mesh, const char *propname) { + typename HandleToPropHandle::type ph; + return mesh.get_property_handle(ph, propname); +} + +/** @relates PropertyManager + * + * Obtains a handle to a named property. + * + * Example: + * @code + * PolyMesh m; + * { + * try { + * auto is_quad = getProperty(m, "is_quad"); + * // Use is_quad here. + * } + * catch (const std::runtime_error& e) { + * // There is no is_quad face property on the mesh. + * } + * } + * @endcode + * + * @pre Property with the name \p propname of matching type exists. + * @throws std::runtime_error if no property with the name \p propname of + * matching type exists. + * @param mesh The mesh on which the property is created + * @param propname The name of the created property + * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the created property, e.g., \p double, \p int, etc. + * @returns A PropertyManager wrapping the property + */ +template +PropertyManager::type> +getProperty(PolyConnectivity &mesh, const char *propname) { + if (!hasProperty(mesh, propname)) + { + std::ostringstream oss; + oss << "Requested property handle \"" << propname << "\" does not exist."; + throw std::runtime_error(oss.str()); + } + return PropertyManager::type>(mesh, propname); +} + +/** @relates PropertyManager + * + * Obtains a handle to a named property if it exists or creates a new one otherwise. + * + * Used for creating or accessing permanent properties. + * + * Example: + * @code + * PolyMesh m; + * { + * auto is_quad = getOrMakeProperty(m, "is_quad"); + * for (auto& fh : m.faces()) { + * is_quad[fh] = (m.valence(fh) == 4); + * } + * // The property remains on the mesh after the end of the scope. + * } + * { + * // Retrieve the property from the previous scope. + * auto is_quad = getOrMakeProperty(m, "is_quad"); + * // Use is_quad here. + * } + * @endcode + * + * @param mesh The mesh on which the property is created + * @param propname The name of the created property + * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the created property, e.g., \p double, \p int, etc. + * @returns A PropertyManager wrapping the property + */ +template +PropertyManager::type> +getOrMakeProperty(PolyConnectivity &mesh, const char *propname) { + return PropertyManager::type>::createIfNotExists(mesh, propname); +} + +/** @relates PropertyManager + * @deprecated Use makeTemporaryProperty() instead. + * + * Creates a new property whose lifecycle is managed by the returned + * PropertyManager. + * + * Intended for temporary properties. Shadows any existing properties of + * matching name and type. + */ +template +OM_DEPRECATED("Use makeTemporaryProperty instead.") +PropertyManager makePropertyManagerFromNew(PolyConnectivity &mesh, const char *propname) +{ + return PropertyManager(mesh, propname, false); +} + +/** \relates PropertyManager + * @deprecated Use getProperty() instead. + * + * Creates a non-owning wrapper for an existing mesh property (no lifecycle + * management). + * + * Intended for convenient access. + * + * @pre Property with the name \p propname of matching type exists. + * @throws std::runtime_error if no property with the name \p propname of + * matching type exists. + */ +template +OM_DEPRECATED("Use getProperty instead.") +PropertyManager makePropertyManagerFromExisting(PolyConnectivity &mesh, const char *propname) +{ + return PropertyManager(mesh, propname, true); +} + +/** @relates PropertyManager + * @deprecated Use getOrMakeProperty() instead. + * + * Creates a non-owning wrapper for a mesh property (no lifecycle management). + * If the given property does not exist, it is created. + * + * Intended for creating or accessing persistent properties. + */ +template +OM_DEPRECATED("Use getOrMakeProperty instead.") +PropertyManager makePropertyManagerFromExistingOrNew(PolyConnectivity &mesh, const char *propname) +{ + return PropertyManager::createIfNotExists(mesh, propname); +} + +/** @relates PropertyManager + * Like the two parameter version of makePropertyManagerFromExistingOrNew() + * except it initializes the property with the specified value over the + * specified range if it needs to be created. If the property already exists, + * this function has the exact same effect as the two parameter version. + * + * Creates a non-owning wrapper for a mesh property (no lifecycle management). + * If the given property does not exist, it is created. + * + * Intended for creating or accessing persistent properties. + */ +template +OM_DEPRECATED("Use getOrMakeProperty instead.") +PropertyManager makePropertyManagerFromExistingOrNew( + PolyConnectivity &mesh, const char *propname, + const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, + const PROP_VALUE &init_value) { + return PropertyManager::createIfNotExists( + mesh, propname, begin, end, init_value); +} + +/** @relates PropertyManager + * Like the two parameter version of makePropertyManagerFromExistingOrNew() + * except it initializes the property with the specified value over the + * specified range if it needs to be created. If the property already exists, + * this function has the exact same effect as the two parameter version. + * + * Creates a non-owning wrapper for a mesh property (no lifecycle management). + * If the given property does not exist, it is created. + * + * Intended for creating or accessing persistent properties. + */ +template +OM_DEPRECATED("Use getOrMakeProperty instead.") +PropertyManager makePropertyManagerFromExistingOrNew( + PolyConnectivity &mesh, const char *propname, + const ITERATOR_RANGE &range, + const PROP_VALUE &init_value) { + return makePropertyManagerFromExistingOrNew( + mesh, propname, range.begin(), range.end(), init_value); +} + + +/** @relates PropertyManager + * Returns a convenience wrapper around the points property of a mesh. + */ +template +PropertyManager> +getPointsProperty(MeshT &mesh) { + return PropertyManager>(mesh, mesh.points_property_handle()); +} + +/** @relates PropertyManager + * Returns a convenience wrapper around the points property of a mesh that only allows const access. + */ +template +ConstPropertyViewer> +getPointsProperty(const MeshT &mesh) { + using PropType = OpenMesh::VPropHandleT; + return ConstPropertyViewer(mesh, mesh.points_property_handle()); +} + +template +using Prop = PropertyManager::template type>; + +template +using VProp = PropertyManager>; + +template +using HProp = PropertyManager>; + +template +using EProp = PropertyManager>; + +template +using FProp = PropertyManager>; + +template +using MProp = PropertyManager>; + + +} /* namespace OpenMesh */ +#endif /* PROPERTYMANAGER_HH_ */ diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/RandomNumberGenerator.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/RandomNumberGenerator.hh new file mode 100644 index 0000000..3861f14 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/RandomNumberGenerator.hh @@ -0,0 +1,109 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +//============================================================================= +// +// Helper Functions for generating a random number between 0.0 and 1.0 with +// a guaranteed resolution +// +//============================================================================= + + +#ifndef OPENMESH_UTILS_RANDOMNUMBERGENERATOR_HH +#define OPENMESH_UTILS_RANDOMNUMBERGENERATOR_HH + + +//== INCLUDES ================================================================= + + +#include +#include + + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** Generate a random number between 0.0 and 1.0 with a guaranteed resolution + * ( Number of possible values ) + * + * Especially useful on windows, as there MAX_RAND is often only 32k which is + * not enough resolution for a lot of applications + */ +class OPENMESHDLLEXPORT RandomNumberGenerator +{ +public: + + /** \brief Constructor + * + * @param _resolution specifies the desired resolution for the random number generated + */ + explicit RandomNumberGenerator(const size_t _resolution); + + /// returns a random double between 0.0 and 1.0 with a guaranteed resolution + double getRand() const; + + double resolution() const; + +private: + + /// desired resolution + const size_t resolution_; + + /// number of "blocks" of RAND_MAX that make up the desired _resolution + size_t iterations_; + + /// maximum random number generated, which is used for normalization + double maxNum_; +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_UTILS_RANDOMNUMBERGENERATOR_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/SingletonT.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/SingletonT.hh new file mode 100644 index 0000000..67a113e --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/SingletonT.hh @@ -0,0 +1,144 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a simple singleton template +// +//============================================================================= + +#pragma once + +//=== INCLUDES ================================================================ + +// OpenMesh +#include + +// STL +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//=== IMPLEMENTATION ========================================================== + + +/** A simple singleton template. + Encapsulates an arbitrary class and enforces its uniqueness. +*/ + +template +class SingletonT +{ +public: + + /** Singleton access function. + Use this function to obtain a reference to the instance of the + encapsulated class. Note that this instance is unique and created + on the first call to Instance(). + */ + + static T& Instance() + { + if (!pInstance__) + { + // check if singleton alive + if (destroyed__) + { + OnDeadReference(); + } + // first time request -> initialize + else + { + Create(); + } + } + return *pInstance__; + } + + +private: + + // Disable constructors/assignment to enforce uniqueness + SingletonT(); + SingletonT(const SingletonT&); + SingletonT& operator=(const SingletonT&); + + // Create a new singleton and store its pointer + static void Create() + { + static T theInstance; + pInstance__ = &theInstance; + } + + // Will be called if instance is accessed after its lifetime has expired + static void OnDeadReference() + { + throw std::runtime_error("[Singelton error] - Dead reference detected!\n"); + } + + virtual ~SingletonT() + { + pInstance__ = 0; + destroyed__ = true; + } + + static T* pInstance__; + static bool destroyed__; +}; + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SINGLETON_C) +# define OPENMESH_SINGLETON_TEMPLATES +# include "SingletonT_impl.hh" +#endif +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/SingletonT_impl.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/SingletonT_impl.hh new file mode 100644 index 0000000..dd5cc4c --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/SingletonT_impl.hh @@ -0,0 +1,80 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Implements a simple singleton template +// +//============================================================================= + + +#define OPENMESH_SINGLETON_C + + +//== INCLUDES ================================================================= + + +// header +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== SINGLETON'S DATA ========================================================= + + +template +T* SingletonT::pInstance__ = 0; + +template +bool SingletonT::destroyed__ = false; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/color_cast.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/color_cast.hh new file mode 100644 index 0000000..e6a1dfb --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/color_cast.hh @@ -0,0 +1,394 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_COLOR_CAST_HH +#define OPENMESH_COLOR_CAST_HH + + +//== INCLUDES ================================================================= + + +#include +#include + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Cast vector type to another vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- +#ifndef DOXY_IGNORE_THIS + +/// Cast one color vector to another. +template +struct color_caster +{ + typedef dst_t return_type; + + inline static return_type cast(const src_t& _src) + { + dst_t dst; + vector_cast(_src, dst, GenProg::Int2Type::size_>()); + return dst; + } +}; + + +template <> +struct color_caster +{ + typedef Vec3uc return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec3uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3uc return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec3uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3i return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec3i( (int)(_src[0]* 255.0f + 0.5f), + (int)(_src[1]* 255.0f + 0.5f), + (int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3i return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec3i( (int)(_src[0]* 255.0f + 0.5f), + (int)(_src[1]* 255.0f + 0.5f), + (int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4i return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec4i( (int)(_src[0]* 255.0f + 0.5f), + (int)(_src[1]* 255.0f + 0.5f), + (int)(_src[2]* 255.0f + 0.5f), + (int)(_src[3]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3ui return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec3ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3ui return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec3ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4ui return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec4ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f), + (unsigned int)(_src[3]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec4uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f), + (unsigned char)(255) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4ui return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec4ui( (unsigned int)(_src[0]* 255.0f + 0.5f), + (unsigned int)(_src[1]* 255.0f + 0.5f), + (unsigned int)(_src[2]* 255.0f + 0.5f), + (unsigned int)(255) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec4f( _src[0], + _src[1], + _src[2], + 1.0f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4ui return_type; + + inline static return_type cast(const Vec3uc& _src) + { + return Vec4ui(_src[0], + _src[1], + _src[2], + 255 ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec3i& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0]*f, _src[1]*f, _src[2]*f, 1.0f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec4uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f), + (unsigned char)(_src[3]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec4i& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f( _src[0] * f, _src[1] * f, _src[2] * f , _src[3] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec3uc& _src) + { + return Vec4uc( _src[0], _src[1], _src[2], 255 ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3f return_type; + + inline static return_type cast(const Vec3uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec3f(_src[0] * f, _src[1] * f, _src[2] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3f return_type; + + inline static return_type cast(const Vec4uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec3f(_src[0] * f, _src[1] * f, _src[2] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec3uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0] * f, _src[1] * f, _src[2] * f, 1.0f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec4uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0] * f, _src[1] * f, _src[2] * f, _src[3] * f ); + } +}; + +// ---------------------------------------------------------------------------- + + +#ifndef DOXY_IGNORE_THIS + +#if !defined(OM_CC_MSVC) +template +struct color_caster +{ + typedef const dst_t& return_type; + + inline static return_type cast(const dst_t& _src) + { + return _src; + } +}; +#endif + +#endif + +//----------------------------------------------------------------------------- + + +template +inline +typename color_caster::return_type +color_cast(const src_t& _src ) +{ + return color_caster::cast(_src); +} + +#endif +//----------------------------------------------------------------------------- + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_COLOR_CAST_HH defined +//============================================================================= + diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/typename.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/typename.hh new file mode 100644 index 0000000..0ac7c3c --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/typename.hh @@ -0,0 +1,29 @@ +#pragma once + +/// Get an internal name for a type +/// Important, this is depends on compilers and versions, do NOT use in file formats! +/// This provides property type safety when only limited RTTI is available +/// Solution adapted from OpenVolumeMesh + +#include +#include +#include +#include +#include + +namespace OpenMesh { + +template +std::string get_type_name() +{ +#ifdef _MSC_VER + // MSVC'S type_name returns only a friendly name with name() method, + // to get a unique name use raw_name() method instead + return typeid(T).raw_name(); +#else + // GCC and clang curently return mangled name as name(), there is no raw_name() method + return typeid(T).name(); +#endif +} + +}//namespace OpenMesh diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/vector_cast.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/vector_cast.hh new file mode 100644 index 0000000..35d1e08 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/vector_cast.hh @@ -0,0 +1,158 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_VECTORCAST_HH +#define OPENMESH_VECTORCAST_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Cast vector type to another vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- + +template +inline void vector_cast( const src_t &_src, dst_t &_dst, GenProg::Int2Type ) +{ + assert_compile(vector_traits::size_ <= vector_traits::size_) + vector_cast(_src,_dst, GenProg::Int2Type()); + _dst[n-1] = static_cast::value_type >(_src[n-1]); +} + +template +inline void vector_cast( const src_t & /*_src*/, dst_t & /*_dst*/, GenProg::Int2Type<0> ) +{ +} + +template +inline void vector_copy( const src_t &_src, dst_t &_dst, GenProg::Int2Type ) +{ + assert_compile(vector_traits::size_ <= vector_traits::size_) + vector_copy(_src,_dst, GenProg::Int2Type()); + _dst[n-1] = _src[n-1]; +} + +template +inline void vector_copy( const src_t & /*_src*/, dst_t & /*_dst*/ , GenProg::Int2Type<0> ) +{ +} + + + +//----------------------------------------------------------------------------- +#ifndef DOXY_IGNORE_THIS + +template +struct vector_caster +{ + typedef dst_t return_type; + + inline static return_type cast(const src_t& _src) + { + dst_t dst; + vector_cast(_src, dst, GenProg::Int2Type::size_>()); + return dst; + } +}; + +#if !defined(OM_CC_MSVC) +template +struct vector_caster +{ + typedef const dst_t& return_type; + + inline static return_type cast(const dst_t& _src) + { + return _src; + } +}; +#endif + +#endif +//----------------------------------------------------------------------------- + + +/// Cast vector type to another vector type by copying the vector elements +template +inline +typename vector_caster::return_type +vector_cast(const src_t& _src ) +{ + return vector_caster::cast(_src); +} + + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/vector_traits.hh b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/vector_traits.hh new file mode 100644 index 0000000..430e9e5 --- /dev/null +++ b/Sources/OpenMeshCore/Headers/OpenMesh/Core/Utils/vector_traits.hh @@ -0,0 +1,110 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2025, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + + + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_VECTOR_TRAITS_HH +#define OPENMESH_VECTOR_TRAITS_HH + + +//== INCLUDES ================================================================= + +#include +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Provide a standardized access to relevant information about a + vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- + +/** Helper class providing information about a vector type. + * + * If want to use a different vector type than the one provided %OpenMesh + * you need to supply a specialization of this class for the new vector type. + */ +template +struct vector_traits +{ + /// Type of the vector class + typedef typename T::vector_type vector_type; + + /// Type of the scalar value + typedef typename T::value_type value_type; + + /// size/dimension of the vector + static const size_t size_ = T::size_; + + /// size/dimension of the vector + static size_t size() { return size_; } +}; + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/Sources/OpenMeshCore/LICENSE.txt b/Sources/OpenMeshCore/LICENSE.txt new file mode 100644 index 0000000..ddcf79b --- /dev/null +++ b/Sources/OpenMeshCore/LICENSE.txt @@ -0,0 +1,2 @@ +Placeholder for the OpenMesh license text from the upstream external/OpenMesh directory. +Replace this file with the exact text to preserve notices. diff --git a/Sources/OpenMeshCore/include/OpenMeshCoreShim.h b/Sources/OpenMeshCore/include/OpenMeshCoreShim.h new file mode 100644 index 0000000..98ba8c5 --- /dev/null +++ b/Sources/OpenMeshCore/include/OpenMeshCoreShim.h @@ -0,0 +1,4 @@ +// Intentionally empty. SwiftPM requires a public headers directory, but the +// OpenMesh headers themselves must NOT be exposed here: as a Clang module they +// fail to build (headers #include each other inside open namespaces). They are +// consumed textually via the "Headers" search path instead — see Package.swift. diff --git a/Tests/MeshDenoiserKitTests/DenoiseContractTests.swift b/Tests/MeshDenoiserKitTests/DenoiseContractTests.swift new file mode 100644 index 0000000..5a9e6b7 --- /dev/null +++ b/Tests/MeshDenoiserKitTests/DenoiseContractTests.swift @@ -0,0 +1,121 @@ +import os +import simd +import XCTest +@testable import MeshDenoiserKit + +final class DenoiseContractTests: XCTestCase { + + /// Octahedron with deterministic per-vertex noise; closed manifold, 8 faces. + static func noisyOctahedron() -> (positions: [SIMD3], indices: [UInt32]) { + let base: [SIMD3] = [ + [1, 0, 0], [-1, 0, 0], + [0, 1, 0], [0, -1, 0], + [0, 0, 1], [0, 0, -1], + ] + // Fixed offsets stand in for noise; keeps the test deterministic. + let noise: [SIMD3] = [ + [0.03, -0.02, 0.01], [-0.01, 0.04, -0.03], + [0.02, 0.01, -0.04], [-0.03, -0.01, 0.02], + [0.01, -0.04, 0.03], [-0.02, 0.03, -0.01], + ] + let positions = zip(base, noise).map { $0 + $1 } + let indices: [UInt32] = [ + 0, 2, 4, 2, 1, 4, 1, 3, 4, 3, 0, 4, + 2, 0, 5, 1, 2, 5, 3, 1, 5, 0, 3, 5, + ] + return (positions, indices) + } + + func testDenoisePreservesVertexCountAndMovesVertices() async throws { + let (positions, indices) = Self.noisyOctahedron() + let result = try await MeshDenoiser.denoise(positions: positions, indices: indices) + + XCTAssertEqual(result.count, positions.count) + for p in result { + XCTAssertTrue(p.x.isFinite && p.y.isFinite && p.z.isFinite) + } + // Denoising must actually move something... + let maxDisplacement = zip(result, positions).map { length($0 - $1) }.max()! + XCTAssertGreaterThan(maxDisplacement, 0) + // ...but stay close to the input (closeness term). + XCTAssertLessThan(maxDisplacement, 1.0) + } + + func testNaNInputThrowsInvalidInput() async { + var (positions, indices) = Self.noisyOctahedron() + positions[2].y = .nan + await assertThrows(MeshDenoiseError.invalidInput) { + _ = try await MeshDenoiser.denoise(positions: positions, indices: indices) + } + } + + func testOutOfRangeIndexThrowsInvalidInput() async { + var (positions, indices) = Self.noisyOctahedron() + indices[5] = UInt32(positions.count) // one past the end + await assertThrows(MeshDenoiseError.invalidInput) { + _ = try await MeshDenoiser.denoise(positions: positions, indices: indices) + } + } + + func testEmptyInputThrowsInvalidInput() async { + await assertThrows(MeshDenoiseError.invalidInput) { + _ = try await MeshDenoiser.denoise(positions: [], indices: []) + } + } + + func testNegativeLambdaThrowsInvalidParameters() async { + let (positions, indices) = Self.noisyOctahedron() + var params = MeshDenoiseParameters() + params.lambda = -1 + await assertThrows(MeshDenoiseError.invalidParameters) { + _ = try await MeshDenoiser.denoise(positions: positions, indices: indices, parameters: params) + } + } + + func testCancellationThrowsCancellationError() async { + let (positions, indices) = Self.noisyOctahedron() + var params = MeshDenoiseParameters() + params.outerIterations = 50 // cancellation is checked after each outer iteration + + let task = Task { + try await MeshDenoiser.denoise(positions: positions, indices: indices, parameters: params) + } + task.cancel() + do { + _ = try await task.value + XCTFail("Expected CancellationError") + } catch is CancellationError { + // expected + } catch { + XCTFail("Expected CancellationError, got \(error)") + } + } + + func testProgressReportsMonotonicallyToOne() async throws { + let (positions, indices) = Self.noisyOctahedron() + var params = MeshDenoiseParameters() + params.outerIterations = 3 + + let recorded = OSAllocatedUnfairLock(initialState: [Double]()) + _ = try await MeshDenoiser.denoise(positions: positions, indices: indices, parameters: params) { p in + recorded.withLock { $0.append(p) } + } + let values = recorded.withLock { $0 } + XCTAssertEqual(values, [1.0 / 3.0, 2.0 / 3.0, 1.0]) + } + + private func assertThrows( + _ expected: E, + file: StaticString = #filePath, line: UInt = #line, + _ body: () async throws -> Void + ) async { + do { + try await body() + XCTFail("Expected \(expected) to be thrown", file: file, line: line) + } catch let error as E { + XCTAssertEqual(error, expected, file: file, line: line) + } catch { + XCTFail("Expected \(expected), got \(error)", file: file, line: line) + } + } +} diff --git a/Tests/MeshDenoiserKitTests/Fixtures/golden_denoised.obj b/Tests/MeshDenoiserKitTests/Fixtures/golden_denoised.obj new file mode 100644 index 0000000..deb94ee --- /dev/null +++ b/Tests/MeshDenoiserKitTests/Fixtures/golden_denoised.obj @@ -0,0 +1,483 @@ +# 162 vertices, 320 faces +v -0.5364053151594960 0.8681385378813857 -0.0002333599021879 +v 0.5015634821929089 0.8086415042965187 0.0006851103331693 +v -0.5323929014717225 -0.8572194780941386 -0.0009695731856251 +v 0.5092190474092957 -0.8249011694935996 0.0000111114731183 +v -0.0005020600054213 -0.5261701246354139 0.8497073929649782 +v -0.0002917102669355 0.5224660186706404 0.8442419241801470 +v 0.0014360266281552 -0.5312290332363868 -0.8614106129186546 +v 0.0009294737934426 0.5188511190230075 -0.8391595988132036 +v 0.8274144009468103 -0.0003777951033492 -0.5126805560104687 +v 0.8389911081914169 0.0014738232065552 0.5174601658469496 +v -0.8766788134928738 -0.0007447442808811 -0.5409410356770826 +v -0.8302807877546208 0.0000451400809504 0.5113356705776076 +v -0.7973378693421445 0.4930153513021704 0.3055807823238093 +v -0.5053488948441072 0.3134920870219444 0.8182030607988134 +v -0.3160545953709374 0.8290039530495665 0.5115117013995683 +v 0.3260249882346142 0.8512115698067837 0.5241910726086917 +v 0.0006692505133046 1.0239797191113740 0.0008350584958808 +v 0.3114794003592481 0.8144599531599999 -0.5034655310833266 +v -0.3116286479972097 0.8200432933839296 -0.5073516588893044 +v -0.5074226692104999 0.3134545198031552 -0.8220883001299307 +v -0.7791479998976173 0.4817977532919565 -0.2960083216063844 +v -1.0199460266006768 0.0017413673686337 0.0002287605246473 +v 0.5136263844066872 0.3173901938598242 0.8291813549992850 +v 0.8534780936851235 0.5290951078060533 0.3249255343305655 +v -0.4959352712685299 -0.3067153804017774 0.8021472716709597 +v -0.0011374925799462 -0.0013408677529469 0.9905596238720106 +v -0.8280405951159973 -0.5123467571376820 -0.3150866388364970 +v -0.8228947559547989 -0.5101808526651691 0.3145852834729481 +v 0.0000403025934962 0.0005480068824767 -0.9665979897524207 +v -0.4745827502376003 -0.2936923149609133 -0.7700977110433533 +v 0.8356673865055521 0.5179496592879784 -0.3189134118042944 +v 0.4771332364133929 0.2932636934281531 -0.7707738605016943 +v 0.8160392591283784 -0.5032886442626541 0.3102876283117262 +v 0.4864315284832664 -0.2996483854340916 0.7877673769659850 +v 0.3126187829629047 -0.8180043960994059 0.5057909833049468 +v -0.3075284589027049 -0.8050046144813520 0.4991619917326204 +v 0.0013517905354608 -0.9781326602496667 -0.0032515401926700 +v -0.3010006277308518 -0.7877906670455962 -0.4868576588641578 +v 0.3092037001063429 -0.8119414899444932 -0.4999548348033009 +v 0.5140350605115707 -0.3158126407212509 -0.8303002297474930 +v 0.7900213205093380 -0.4879768372157918 -0.3032981151787843 +v 1.0494478426676312 0.0003382324417128 0.0008184384673456 +v -0.7192116411297376 0.7286086540686975 0.1658217647053339 +v -0.5800115625043081 0.6792532842346467 0.4185445639490680 +v -0.4443784413613792 0.8837937085165399 0.2652357659834860 +v -0.6765882940440011 0.1548051541333482 0.6675631133257665 +v -0.6970237245020113 0.4300038731407576 0.5943737279891682 +v -0.8689941307665962 0.2612061098596563 0.4373431607343399 +v -0.1632397219817891 0.7079261513544177 0.7161102350629436 +v -0.4387979958100825 0.6075783036003634 0.7111045248557696 +v -0.2578458812964836 0.4319412013367681 0.8605503717511390 +v -0.1682878106743118 0.9856731506371296 0.2729369642015497 +v -0.2749678366321044 0.9688965886660583 0.0000092443437687 +v 0.1545317319695998 0.6652667239423221 0.6720824988515031 +v 0.0011092323392002 0.8455539515740168 0.5230049317063266 +v 0.2588112695014181 0.9164270649399029 0.0001350734140557 +v 0.1639875958154111 0.9600067087323315 0.2661977719972473 +v 0.4231319772642033 0.8407452444462802 0.2567777979070923 +v -0.1561136847744242 0.9200042574075518 -0.2556699332178263 +v -0.4452648189757724 0.8879026900400648 -0.2675893019319543 +v 0.4123401587502973 0.8194224964146773 -0.2499678403734961 +v 0.1578034352445511 0.9195366965354128 -0.2554443683072170 +v -0.1552793580452587 0.6723879699202344 -0.6797001607855555 +v 0.0005951571994168 0.8842126979899120 -0.5482444900484723 +v 0.1605162210949194 0.6986339693991636 -0.7058569100804538 +v -0.5795467384274211 0.6822055560620305 -0.4204539834726503 +v -0.6831456655419025 0.6922916065918469 -0.1575210922506871 +v -0.2494986976670845 0.4171621237965413 -0.8294196533926467 +v -0.4231603050154367 0.5856151088714096 -0.6851525043841454 +v -0.8367368819804369 0.2496816343686331 -0.4202880868872003 +v -0.6676676892925790 0.4129216886307193 -0.5727996113507592 +v -0.6826576397231318 0.1555539585995593 -0.6755352848346187 +v -0.8850723886740591 0.5473197331788782 0.0026212193839840 +v -0.9929163144572849 -0.0006291753684485 -0.2811234817639046 +v -0.9411049574171496 0.2596623545945059 -0.1596746036693570 +v -0.9612113784462046 0.2655562406958766 0.1650464255673991 +v -0.9248652330513218 -0.0007212110375449 0.2632981221282468 +v 0.6160551502409740 0.7195138654135427 0.4463077031037609 +v 0.6716657663644905 0.6770149859285105 0.1558867027964669 +v 0.2562392520597075 0.4270312380542208 0.8470084319003055 +v 0.4373443503433225 0.6027362493078484 0.7045813536582834 +v 0.8857036477093436 0.2680077998993928 0.4443507329487705 +v 0.7106542379722951 0.4388415206759996 0.6054574556931196 +v 0.6821983276564204 0.1567296765858253 0.6734070094183062 +v -0.2697127433754645 0.1648004943195360 0.9697445851444154 +v -0.0007616463640214 0.2605490735864517 0.9174974557932027 +v -0.7321186575266092 -0.1683571752910039 0.7207775878310947 +v -0.5034425985386543 -0.0003678463297157 0.8139667352089486 +v -0.0004273917828919 -0.2675320331060850 0.9380323840797034 +v -0.2771249743790293 -0.1717133762624247 1.0013620501364398 +v -0.2662770359020301 -0.4441361675969895 0.8828118901993123 +v -0.9071381186320673 -0.2504469509744961 0.1549987781799676 +v -0.8454851636884529 -0.2553060214406591 0.4244826513619036 +v -0.8734478291560782 -0.2630120064059294 -0.4382573695077004 +v -0.9229550884065705 -0.2551183681489760 -0.1568205763733448 +v -0.7246717483292138 -0.7322393732481171 0.1676368629978330 +v -0.8381398140827196 -0.5200594125708499 -0.0003174602935297 +v -0.7242460507098638 -0.7325378576439567 -0.1673229787843207 +v -0.5240219923928334 0.0013660213242222 -0.8501181236869918 +v -0.6753369227411524 -0.1536307797933895 -0.6673003870242558 +v 0.0011876519017017 0.2810352294921478 -0.9879369982369827 +v -0.2522985233923040 0.1567176169968253 -0.9143364159565407 +v -0.2645263835260869 -0.4453435098318883 -0.8857213711652068 +v -0.2590357959520941 -0.1593779636348757 -0.9372151725993567 +v 0.0009740096034250 -0.2628225689222473 -0.9276819863073208 +v 0.4098227149651120 0.5666077282573864 -0.6618042883816702 +v 0.2530690766567665 0.4234238486007069 -0.8437924884874743 +v 0.6725753093856875 0.6765748774978024 -0.1566737427390275 +v 0.6019184518152316 0.7026634441241630 -0.4371929957214175 +v 0.7129626271215888 0.1630118169350141 -0.7067931606574297 +v 0.6778148060842535 0.4180456454251307 -0.5786553967246078 +v 0.8377880001742646 0.2533735458862159 -0.4220414062741948 +v 0.7047540096039170 -0.7136609517264211 0.1640147292536830 +v 0.5852356259395989 -0.6867620053721639 0.4225284546784108 +v 0.4516063727468591 -0.8969695367209561 0.2704645111966936 +v 0.6831429482382054 -0.1549207810164221 0.6750077054914131 +v 0.6583472655412328 -0.4054088980074720 0.5616864142454703 +v 0.8660383404367815 -0.2591837091636804 0.4344352826361557 +v 0.1684567499457808 -0.7292296438572654 0.7379680789526680 +v 0.4169539188102280 -0.5791045824151352 0.6781413513112033 +v 0.2575033723300186 -0.4309505204166495 0.8571822116961537 +v 0.1575328968230867 -0.9062581144851921 0.2505543391708957 +v 0.2708790469869253 -0.9504560108002135 -0.0001034531225754 +v -0.1643306060370389 -0.7136316974591204 0.7227814383495611 +v 0.0016032663295617 -0.8224686724924862 0.5106914308224276 +v -0.2685599612110486 -0.9431082054697064 -0.0019382653375591 +v -0.1581957026009787 -0.9225921719977496 0.2548026229082566 +v -0.4279522942755425 -0.8485016745716294 0.2555286843789719 +v 0.1679119051904562 -0.9872820879532935 -0.2729808559766860 +v 0.4511374732240824 -0.8995877715923238 -0.2715891578631763 +v -0.4406612127214549 -0.8755198630068523 -0.2639802484444785 +v -0.1638454657593225 -0.9571102614867312 -0.2653301584143425 +v 0.1580888482437308 -0.6882413836144071 -0.6966119096558817 +v -0.0013950846971398 -0.8651910805624088 -0.5335605586326442 +v -0.1637922593173330 -0.7133601312906689 -0.7219199063823818 +v 0.6074271644232401 -0.7112403777790717 -0.4401397220147253 +v 0.6826011678489685 -0.6917839987840612 -0.1586887973413122 +v 0.2578907420474610 -0.4272311496795536 -0.8523298361872849 +v 0.4080367691685099 -0.5608231557024088 -0.6595558451705058 +v 0.8592066054535269 -0.2602130940070967 -0.4339145333487033 +v 0.6926608515671603 -0.4279598994427660 -0.5930343497903171 +v 0.6834690027452351 -0.1570097457051601 -0.6762695836970107 +v 0.8530291837330894 -0.5259820256410972 0.0003865983720093 +v 0.9904380799022973 -0.0002725329502096 -0.2795396191296175 +v 0.9769186958601355 -0.2690150405050586 -0.1672409849990844 +v 0.9962280471873044 -0.2745770481261283 0.1708693779270146 +v 1.0043843511235253 0.0013043315071932 0.2857384120709369 +v 0.2742523568552263 -0.1701017226701834 0.9905957244835105 +v 0.5346209582165707 0.0010013510422795 0.8664034096100760 +v 0.2606469728783589 0.1594582905900362 0.9377456689734730 +v -0.5961228090792876 -0.6990573691377557 0.4317626802363013 +v -0.4432445369529677 -0.6165339975193169 0.7200868504053765 +v -0.6599076372801379 -0.4091123163260332 0.5638872443804432 +v -0.4054603858950094 -0.5623059685677130 -0.6575968909879775 +v -0.5752674883180686 -0.6743945825362507 -0.4145780200998341 +v -0.6855365965048270 -0.4232034743803925 -0.5823814327384776 +v 0.5376269256772516 0.0002288662646034 -0.8706075133943527 +v 0.2540621911441039 -0.1559049417893950 -0.9152760310677003 +v 0.2658349036128418 0.1627284404604485 -0.9602265974747486 +v 0.9624563913140499 0.2667011829805045 0.1644543011329935 +v 0.9687328530621530 0.2685147568828392 -0.1651773778649483 +v 0.8861579210469851 0.5455691199007933 0.0001940740085294 +f 1 43 45 +f 13 44 43 +f 15 45 44 +f 43 44 45 +f 12 46 48 +f 14 47 46 +f 13 48 47 +f 46 47 48 +f 6 49 51 +f 15 50 49 +f 14 51 50 +f 49 50 51 +f 13 47 44 +f 14 50 47 +f 15 44 50 +f 47 50 44 +f 1 45 53 +f 15 52 45 +f 17 53 52 +f 45 52 53 +f 6 54 49 +f 16 55 54 +f 15 49 55 +f 54 55 49 +f 2 56 58 +f 17 57 56 +f 16 58 57 +f 56 57 58 +f 15 55 52 +f 16 57 55 +f 17 52 57 +f 55 57 52 +f 1 53 60 +f 17 59 53 +f 19 60 59 +f 53 59 60 +f 2 61 56 +f 18 62 61 +f 17 56 62 +f 61 62 56 +f 8 63 65 +f 19 64 63 +f 18 65 64 +f 63 64 65 +f 17 62 59 +f 18 64 62 +f 19 59 64 +f 62 64 59 +f 1 60 67 +f 19 66 60 +f 21 67 66 +f 60 66 67 +f 8 68 63 +f 20 69 68 +f 19 63 69 +f 68 69 63 +f 11 70 72 +f 21 71 70 +f 20 72 71 +f 70 71 72 +f 19 69 66 +f 20 71 69 +f 21 66 71 +f 69 71 66 +f 1 67 43 +f 21 73 67 +f 13 43 73 +f 67 73 43 +f 11 74 70 +f 22 75 74 +f 21 70 75 +f 74 75 70 +f 12 48 77 +f 13 76 48 +f 22 77 76 +f 48 76 77 +f 21 75 73 +f 22 76 75 +f 13 73 76 +f 75 76 73 +f 2 58 79 +f 16 78 58 +f 24 79 78 +f 58 78 79 +f 6 80 54 +f 23 81 80 +f 16 54 81 +f 80 81 54 +f 10 82 84 +f 24 83 82 +f 23 84 83 +f 82 83 84 +f 16 81 78 +f 23 83 81 +f 24 78 83 +f 81 83 78 +f 6 51 86 +f 14 85 51 +f 26 86 85 +f 51 85 86 +f 12 87 46 +f 25 88 87 +f 14 46 88 +f 87 88 46 +f 5 89 91 +f 26 90 89 +f 25 91 90 +f 89 90 91 +f 14 88 85 +f 25 90 88 +f 26 85 90 +f 88 90 85 +f 12 77 93 +f 22 92 77 +f 28 93 92 +f 77 92 93 +f 11 94 74 +f 27 95 94 +f 22 74 95 +f 94 95 74 +f 3 96 98 +f 28 97 96 +f 27 98 97 +f 96 97 98 +f 22 95 92 +f 27 97 95 +f 28 92 97 +f 95 97 92 +f 11 72 100 +f 20 99 72 +f 30 100 99 +f 72 99 100 +f 8 101 68 +f 29 102 101 +f 20 68 102 +f 101 102 68 +f 7 103 105 +f 30 104 103 +f 29 105 104 +f 103 104 105 +f 20 102 99 +f 29 104 102 +f 30 99 104 +f 102 104 99 +f 8 65 107 +f 18 106 65 +f 32 107 106 +f 65 106 107 +f 2 108 61 +f 31 109 108 +f 18 61 109 +f 108 109 61 +f 9 110 112 +f 32 111 110 +f 31 112 111 +f 110 111 112 +f 18 109 106 +f 31 111 109 +f 32 106 111 +f 109 111 106 +f 4 113 115 +f 33 114 113 +f 35 115 114 +f 113 114 115 +f 10 116 118 +f 34 117 116 +f 33 118 117 +f 116 117 118 +f 5 119 121 +f 35 120 119 +f 34 121 120 +f 119 120 121 +f 33 117 114 +f 34 120 117 +f 35 114 120 +f 117 120 114 +f 4 115 123 +f 35 122 115 +f 37 123 122 +f 115 122 123 +f 5 124 119 +f 36 125 124 +f 35 119 125 +f 124 125 119 +f 3 126 128 +f 37 127 126 +f 36 128 127 +f 126 127 128 +f 35 125 122 +f 36 127 125 +f 37 122 127 +f 125 127 122 +f 4 123 130 +f 37 129 123 +f 39 130 129 +f 123 129 130 +f 3 131 126 +f 38 132 131 +f 37 126 132 +f 131 132 126 +f 7 133 135 +f 39 134 133 +f 38 135 134 +f 133 134 135 +f 37 132 129 +f 38 134 132 +f 39 129 134 +f 132 134 129 +f 4 130 137 +f 39 136 130 +f 41 137 136 +f 130 136 137 +f 7 138 133 +f 40 139 138 +f 39 133 139 +f 138 139 133 +f 9 140 142 +f 41 141 140 +f 40 142 141 +f 140 141 142 +f 39 139 136 +f 40 141 139 +f 41 136 141 +f 139 141 136 +f 4 137 113 +f 41 143 137 +f 33 113 143 +f 137 143 113 +f 9 144 140 +f 42 145 144 +f 41 140 145 +f 144 145 140 +f 10 118 147 +f 33 146 118 +f 42 147 146 +f 118 146 147 +f 41 145 143 +f 42 146 145 +f 33 143 146 +f 145 146 143 +f 5 121 89 +f 34 148 121 +f 26 89 148 +f 121 148 89 +f 10 84 116 +f 23 149 84 +f 34 116 149 +f 84 149 116 +f 6 86 80 +f 26 150 86 +f 23 80 150 +f 86 150 80 +f 34 149 148 +f 23 150 149 +f 26 148 150 +f 149 150 148 +f 3 128 96 +f 36 151 128 +f 28 96 151 +f 128 151 96 +f 5 91 124 +f 25 152 91 +f 36 124 152 +f 91 152 124 +f 12 93 87 +f 28 153 93 +f 25 87 153 +f 93 153 87 +f 36 152 151 +f 25 153 152 +f 28 151 153 +f 152 153 151 +f 7 135 103 +f 38 154 135 +f 30 103 154 +f 135 154 103 +f 3 98 131 +f 27 155 98 +f 38 131 155 +f 98 155 131 +f 11 100 94 +f 30 156 100 +f 27 94 156 +f 100 156 94 +f 38 155 154 +f 27 156 155 +f 30 154 156 +f 155 156 154 +f 9 142 110 +f 40 157 142 +f 32 110 157 +f 142 157 110 +f 7 105 138 +f 29 158 105 +f 40 138 158 +f 105 158 138 +f 8 107 101 +f 32 159 107 +f 29 101 159 +f 107 159 101 +f 40 158 157 +f 29 159 158 +f 32 157 159 +f 158 159 157 +f 10 147 82 +f 42 160 147 +f 24 82 160 +f 147 160 82 +f 9 112 144 +f 31 161 112 +f 42 144 161 +f 112 161 144 +f 2 79 108 +f 24 162 79 +f 31 108 162 +f 79 162 108 +f 42 161 160 +f 31 162 161 +f 24 160 162 +f 161 162 160 diff --git a/Tests/MeshDenoiserKitTests/Fixtures/noisy_icosphere.obj b/Tests/MeshDenoiserKitTests/Fixtures/noisy_icosphere.obj new file mode 100644 index 0000000..0f2c6db --- /dev/null +++ b/Tests/MeshDenoiserKitTests/Fixtures/noisy_icosphere.obj @@ -0,0 +1,482 @@ +v -0.533888041973114 0.8638489842414856 0.0 +v 0.5154696106910706 0.8340473175048828 0.0 +v -0.5349293351173401 -0.8655338287353516 0.0 +v 0.505057692527771 -0.8172005414962769 0.0 +v 0.0 -0.5266025066375732 0.8520607352256775 +v 0.0 0.5251878499984741 0.8497717976570129 +v 0.0 -0.5311183929443359 -0.8593676090240479 +v 0.0 0.5188942551612854 -0.8395885229110718 +v 0.8299516439437866 0.0 -0.5129383206367493 +v 0.8399481177330017 0.0 0.5191164612770081 +v -0.8783467411994934 0.0 -0.5428481101989746 +v -0.822810709476471 0.0 0.5085249543190002 +v -0.7926596403121948 0.48989060521125793 0.3027690351009369 +v -0.5071765184402466 0.3134523332118988 0.8206288814544678 +v -0.31796783208847046 0.8324505686759949 0.5144827365875244 +v 0.32409119606018066 0.8484817743301392 0.5243905782699585 +v 0.0 1.0300570726394653 0.0 +v 0.3079124689102173 0.8061253428459167 -0.4982128441333771 +v -0.3102221190929413 0.8121720552444458 -0.5019499063491821 +v -0.5062746405601501 0.31289494037628174 -0.8191695809364319 +v -0.7887909412384033 0.4874995946884155 -0.3012913167476654 +v -1.0203888416290283 0.0 0.0 +v 0.5108141899108887 0.3157005310058594 0.826514720916748 +v 0.8478108048439026 0.5239758491516113 0.3238348960876465 +v -0.49145108461380005 -0.3037334680557251 0.7951845526695251 +v 0.0 0.0 0.9945457577705383 +v -0.8258770108222961 -0.5104200839996338 -0.31545695662498474 +v -0.828424870967865 -0.5119947195053101 0.31643015146255493 +v 0.0 0.0 -0.9672778248786926 +v -0.4757852554321289 -0.29405146837234497 -0.7698367238044739 +v 0.8318780064582825 0.5141288638114929 -0.31774911284446716 +v 0.47706031799316406 0.2948395013809204 -0.7718998193740845 +v 0.8168994784355164 -0.5048716068267822 0.31202784180641174 +v 0.4872848689556122 -0.301158607006073 0.7884434461593628 +v 0.3107617497444153 -0.8135848045349121 0.5028230547904968 +v -0.3094872832298279 -0.8102482557296753 0.5007609724998474 +v 0.0 -0.989745020866394 0.0 +v -0.2992092967033386 -0.7833401560783386 -0.4841308295726776 +v 0.31352731585502625 -0.8208251595497131 -0.5072978734970093 +v 0.5108271837234497 -0.31570857763290405 -0.8265357613563538 +v 0.793236494064331 -0.49024710059165955 -0.3029893636703491 +v 1.0471478700637817 0.0 0.0 +v -0.7169896960258484 0.7255321741104126 0.16599535942077637 +v -0.5813249945640564 0.680627167224884 0.42065075039863586 +v -0.4427777826786041 0.8803422451019287 0.2652164101600647 +v -0.6757559180259705 0.15460699796676636 0.6677995324134827 +v -0.6956072449684143 0.4299089312553406 0.5941195487976074 +v -0.8669021129608154 0.26116734743118286 0.4360179305076599 +v -0.16383260488510132 0.707647979259491 0.7160791754722595 +v -0.4425080120563507 0.6115310192108154 0.7159929871559143 +v -0.25721174478530884 0.4294140338897705 0.8537721037864685 +v -0.16785860061645508 0.9826613664627075 0.2716009318828583 +v -0.2765038013458252 0.973334014415741 0.0 +v 0.15285038948059082 0.6602121591567993 0.6680781841278076 +v 0.0 0.84001624584198 0.5191586017608643 +v 0.26259735226631165 0.9243812561035156 0.0 +v 0.16343870759010315 0.9567868709564209 0.2644493877887726 +v 0.42825597524642944 0.8514696359634399 0.25651809573173523 +v -0.15677164494991302 0.9177571535110474 -0.2536618411540985 +v -0.4470658302307129 0.8888678550720215 -0.26778486371040344 +v 0.415325403213501 0.8257607221603394 -0.24877288937568665 +v 0.15572954714298248 0.9116566777229309 -0.2519757151603699 +v -0.15575438737869263 0.6727554798126221 -0.680770993232727 +v 0.0 0.8845367431640625 -0.5466737747192383 +v 0.16141192615032196 0.6971923112869263 -0.7054989337921143 +v -0.5871328711509705 0.6874271035194397 -0.4248533248901367 +v -0.6851946711540222 0.6933583617210388 -0.1586342751979828 +v -0.24949461221694946 0.4165303111076355 -0.8281563520431519 +v -0.42334386706352234 0.5850468277931213 -0.6849848031997681 +v -0.8461459875106812 0.254914253950119 -0.42557838559150696 +v -0.679732084274292 0.4200975298881531 -0.5805605053901672 +v -0.6755562424659729 0.15456131100654602 -0.6676021814346313 +v -0.8885376453399658 0.5491464734077454 0.0 +v -0.9900205135345459 0.0 -0.28124406933784485 +v -0.9448071718215942 0.26113829016685486 -0.16139233112335205 +v -0.9572772979736328 0.2645849287509918 0.16352248191833496 +v -0.9158701300621033 0.0 0.2601795196533203 +v 0.6148391366004944 0.719866156578064 0.4449017643928528 +v 0.670164167881012 0.6781488060951233 0.15515446662902832 +v 0.25596797466278076 0.4273375868797302 0.8496436476707458 +v 0.43590226769447327 0.6024020910263062 0.7053046822547913 +v 0.8816587328910828 0.26561301946640015 0.44343993067741394 +v 0.7110438346862793 0.4394492506980896 0.6073039174079895 +v 0.6797952651977539 0.1555311530828476 0.6717912554740906 +v -0.2680840492248535 0.1656850427389145 0.9699371457099915 +v 0.0 0.2610301375389099 0.9188644289970398 +v -0.7365325689315796 -0.16851215064525604 0.7278605699539185 +v -0.5010470151901245 0.0 0.8107110857963562 +v 0.0 -0.2639860212802887 0.929269552230835 +v -0.27586448192596436 -0.17049361765384674 0.9980870485305786 +v -0.2644830644130707 -0.4415534436702728 0.8779079914093018 +v -0.9072316288948059 -0.25075265765190125 0.15497367084026337 +v -0.8403623700141907 -0.2531718611717224 0.4226694703102112 +v -0.8746810555458069 -0.26351088285446167 -0.43993040919303894 +v -0.9185222387313843 -0.2538733184337616 -0.15690232813358307 +v -0.7221626043319702 -0.7307667136192322 0.1671929806470871 +v -0.8454495072364807 -0.5225165486335754 0.0 +v -0.7189165353775024 -0.7274819612503052 -0.16644145548343658 +v -0.5256432294845581 0.0 -0.8505086302757263 +v -0.6784165501594543 -0.15521572530269623 -0.6704287528991699 +v 0.0 0.2809424102306366 -0.9889585375785828 +v -0.24981972575187683 0.15439708530902863 -0.9038562774658203 +v -0.26759999990463257 -0.4467571973800659 -0.8882542252540588 +v -0.25742873549461365 -0.15909969806671143 -0.93138587474823 +v 0.0 -0.2631530165672302 -0.9263373613357544 +v 0.4133360683917999 0.5712164044380188 -0.6687917709350586 +v 0.2585875391960144 0.4317108988761902 -0.8583388328552246 +v 0.6759744882583618 0.6840283274650574 -0.15649963915348053 +v 0.6019704937934875 0.7047993540763855 -0.4355899691581726 +v 0.7170665264129639 0.16405850648880005 -0.7086237668991089 +v 0.673176646232605 0.41604605317115784 -0.5749614834785461 +v 0.8376213908195496 0.25234609842300415 -0.4212908446788788 +v 0.7057338356971741 -0.7141422033309937 0.1633894443511963 +v 0.5936604142189026 -0.6950697302818298 0.42957669496536255 +v 0.4503971338272095 -0.8954912424087524 0.2697802782058716 +v 0.6820083260536194 -0.15603749454021454 0.6739782691001892 +v 0.6629670262336731 -0.40973615646362305 0.566241443157196 +v 0.8676659464836121 -0.26139748096466064 0.4364020824432373 +v 0.1684541404247284 -0.7276099324226379 0.7362789511680603 +v 0.42241033911705017 -0.5837567448616028 0.6834743022918701 +v 0.2567264437675476 -0.4286038279533386 0.8521612286567688 +v 0.15531769394874573 -0.9092456698417664 0.2513093054294586 +v 0.26740729808807373 -0.9413129687309265 0.0 +v -0.16424305737018585 -0.7094208598136902 0.717873215675354 +v 0.0 -0.8270292282104492 0.5111321806907654 +v -0.2692170739173889 -0.9476836919784546 0.0 +v -0.16122537851333618 -0.9438298344612122 0.2608681619167328 +v -0.42867422103881836 -0.8523011803627014 0.2567686140537262 +v 0.16714978218078613 -0.9785118699073792 -0.2704540193080902 +v 0.4517883062362671 -0.8982571959495544 -0.27061355113983154 +v -0.43954959511756897 -0.8739238977432251 -0.26328277587890625 +v -0.16208437085151672 -0.9488584399223328 -0.26225802302360535 +v 0.16174769401550293 -0.6986425518989563 -0.7069664597511292 +v 0.0 -0.8611603379249573 -0.5322263836860657 +v -0.16462072730064392 -0.7110521197319031 -0.7195239067077637 +v 0.6113921999931335 -0.7158305048942566 -0.4424075782299042 +v 0.6871304512023926 -0.6953171491622925 -0.15908244252204895 +v 0.25602832436561584 -0.42743831872940063 -0.8498439192771912 +v 0.40617698431015015 -0.561322808265686 -0.6572082042694092 +v 0.8572628498077393 -0.25826337933540344 -0.4311697483062744 +v 0.685041069984436 -0.42337867617607117 -0.5850949287414551 +v 0.6789819598197937 -0.15534508228302002 -0.6709875464439392 +v 0.8638250827789307 -0.5338732600212097 0.0 +v 1.002509355545044 0.0 -0.2847919166088104 +v 0.9786203503608704 -0.2704840302467346 -0.16716831922531128 +v 0.9938020706176758 -0.27468013763427734 0.16976165771484375 +v 1.0025068521499634 0.0 0.2847912013530731 +v 0.27423444390296936 -0.16948620975017548 0.9921895265579224 +v 0.5341629385948181 0.0 0.8642937541007996 +v 0.2628101110458374 0.16242557764053345 0.9508559107780457 +v -0.595456063747406 -0.6971721053123474 0.4308760464191437 +v -0.44533586502075195 -0.6154390573501587 0.7205685973167419 +v -0.6576508283615112 -0.4064505696296692 0.5617008805274963 +v -0.4052702784538269 -0.560069739818573 -0.6557410955429077 +v -0.5770425796508789 -0.6756132245063782 -0.4175519347190857 +v -0.6957763433456421 -0.43001341819763184 -0.5942639708518982 +v 0.5336335301399231 0.0 -0.8634372353553772 +v 0.2528163194656372 -0.15624907612800598 -0.91469806432724 +v 0.26542967557907104 0.1640445590019226 -0.9603335857391357 +v 0.9592060446739197 0.2651180326938629 0.16385194659233093 +v 0.9714686870574951 0.26850736141204834 -0.16594666242599487 +v 0.8851014971733093 0.547022819519043 0.0 +f 1 43 45 +f 13 44 43 +f 15 45 44 +f 43 44 45 +f 12 46 48 +f 14 47 46 +f 13 48 47 +f 46 47 48 +f 6 49 51 +f 15 50 49 +f 14 51 50 +f 49 50 51 +f 13 47 44 +f 14 50 47 +f 15 44 50 +f 47 50 44 +f 1 45 53 +f 15 52 45 +f 17 53 52 +f 45 52 53 +f 6 54 49 +f 16 55 54 +f 15 49 55 +f 54 55 49 +f 2 56 58 +f 17 57 56 +f 16 58 57 +f 56 57 58 +f 15 55 52 +f 16 57 55 +f 17 52 57 +f 55 57 52 +f 1 53 60 +f 17 59 53 +f 19 60 59 +f 53 59 60 +f 2 61 56 +f 18 62 61 +f 17 56 62 +f 61 62 56 +f 8 63 65 +f 19 64 63 +f 18 65 64 +f 63 64 65 +f 17 62 59 +f 18 64 62 +f 19 59 64 +f 62 64 59 +f 1 60 67 +f 19 66 60 +f 21 67 66 +f 60 66 67 +f 8 68 63 +f 20 69 68 +f 19 63 69 +f 68 69 63 +f 11 70 72 +f 21 71 70 +f 20 72 71 +f 70 71 72 +f 19 69 66 +f 20 71 69 +f 21 66 71 +f 69 71 66 +f 1 67 43 +f 21 73 67 +f 13 43 73 +f 67 73 43 +f 11 74 70 +f 22 75 74 +f 21 70 75 +f 74 75 70 +f 12 48 77 +f 13 76 48 +f 22 77 76 +f 48 76 77 +f 21 75 73 +f 22 76 75 +f 13 73 76 +f 75 76 73 +f 2 58 79 +f 16 78 58 +f 24 79 78 +f 58 78 79 +f 6 80 54 +f 23 81 80 +f 16 54 81 +f 80 81 54 +f 10 82 84 +f 24 83 82 +f 23 84 83 +f 82 83 84 +f 16 81 78 +f 23 83 81 +f 24 78 83 +f 81 83 78 +f 6 51 86 +f 14 85 51 +f 26 86 85 +f 51 85 86 +f 12 87 46 +f 25 88 87 +f 14 46 88 +f 87 88 46 +f 5 89 91 +f 26 90 89 +f 25 91 90 +f 89 90 91 +f 14 88 85 +f 25 90 88 +f 26 85 90 +f 88 90 85 +f 12 77 93 +f 22 92 77 +f 28 93 92 +f 77 92 93 +f 11 94 74 +f 27 95 94 +f 22 74 95 +f 94 95 74 +f 3 96 98 +f 28 97 96 +f 27 98 97 +f 96 97 98 +f 22 95 92 +f 27 97 95 +f 28 92 97 +f 95 97 92 +f 11 72 100 +f 20 99 72 +f 30 100 99 +f 72 99 100 +f 8 101 68 +f 29 102 101 +f 20 68 102 +f 101 102 68 +f 7 103 105 +f 30 104 103 +f 29 105 104 +f 103 104 105 +f 20 102 99 +f 29 104 102 +f 30 99 104 +f 102 104 99 +f 8 65 107 +f 18 106 65 +f 32 107 106 +f 65 106 107 +f 2 108 61 +f 31 109 108 +f 18 61 109 +f 108 109 61 +f 9 110 112 +f 32 111 110 +f 31 112 111 +f 110 111 112 +f 18 109 106 +f 31 111 109 +f 32 106 111 +f 109 111 106 +f 4 113 115 +f 33 114 113 +f 35 115 114 +f 113 114 115 +f 10 116 118 +f 34 117 116 +f 33 118 117 +f 116 117 118 +f 5 119 121 +f 35 120 119 +f 34 121 120 +f 119 120 121 +f 33 117 114 +f 34 120 117 +f 35 114 120 +f 117 120 114 +f 4 115 123 +f 35 122 115 +f 37 123 122 +f 115 122 123 +f 5 124 119 +f 36 125 124 +f 35 119 125 +f 124 125 119 +f 3 126 128 +f 37 127 126 +f 36 128 127 +f 126 127 128 +f 35 125 122 +f 36 127 125 +f 37 122 127 +f 125 127 122 +f 4 123 130 +f 37 129 123 +f 39 130 129 +f 123 129 130 +f 3 131 126 +f 38 132 131 +f 37 126 132 +f 131 132 126 +f 7 133 135 +f 39 134 133 +f 38 135 134 +f 133 134 135 +f 37 132 129 +f 38 134 132 +f 39 129 134 +f 132 134 129 +f 4 130 137 +f 39 136 130 +f 41 137 136 +f 130 136 137 +f 7 138 133 +f 40 139 138 +f 39 133 139 +f 138 139 133 +f 9 140 142 +f 41 141 140 +f 40 142 141 +f 140 141 142 +f 39 139 136 +f 40 141 139 +f 41 136 141 +f 139 141 136 +f 4 137 113 +f 41 143 137 +f 33 113 143 +f 137 143 113 +f 9 144 140 +f 42 145 144 +f 41 140 145 +f 144 145 140 +f 10 118 147 +f 33 146 118 +f 42 147 146 +f 118 146 147 +f 41 145 143 +f 42 146 145 +f 33 143 146 +f 145 146 143 +f 5 121 89 +f 34 148 121 +f 26 89 148 +f 121 148 89 +f 10 84 116 +f 23 149 84 +f 34 116 149 +f 84 149 116 +f 6 86 80 +f 26 150 86 +f 23 80 150 +f 86 150 80 +f 34 149 148 +f 23 150 149 +f 26 148 150 +f 149 150 148 +f 3 128 96 +f 36 151 128 +f 28 96 151 +f 128 151 96 +f 5 91 124 +f 25 152 91 +f 36 124 152 +f 91 152 124 +f 12 93 87 +f 28 153 93 +f 25 87 153 +f 93 153 87 +f 36 152 151 +f 25 153 152 +f 28 151 153 +f 152 153 151 +f 7 135 103 +f 38 154 135 +f 30 103 154 +f 135 154 103 +f 3 98 131 +f 27 155 98 +f 38 131 155 +f 98 155 131 +f 11 100 94 +f 30 156 100 +f 27 94 156 +f 100 156 94 +f 38 155 154 +f 27 156 155 +f 30 154 156 +f 155 156 154 +f 9 142 110 +f 40 157 142 +f 32 110 157 +f 142 157 110 +f 7 105 138 +f 29 158 105 +f 40 138 158 +f 105 158 138 +f 8 107 101 +f 32 159 107 +f 29 101 159 +f 107 159 101 +f 40 158 157 +f 29 159 158 +f 32 157 159 +f 158 159 157 +f 10 147 82 +f 42 160 147 +f 24 82 160 +f 147 160 82 +f 9 112 144 +f 31 161 112 +f 42 144 161 +f 112 161 144 +f 2 79 108 +f 24 162 79 +f 31 108 162 +f 79 162 108 +f 42 161 160 +f 31 162 161 +f 24 160 162 +f 161 162 160 diff --git a/Tests/MeshDenoiserKitTests/GoldenParityTests.swift b/Tests/MeshDenoiserKitTests/GoldenParityTests.swift new file mode 100644 index 0000000..04dcf8d --- /dev/null +++ b/Tests/MeshDenoiserKitTests/GoldenParityTests.swift @@ -0,0 +1,37 @@ +import XCTest +@testable import MeshDenoiserKit + +final class GoldenParityTests: XCTestCase { + + /// MeshDenoiserKit must reproduce the CLI's output on the same input with + /// the same (default) parameters in deterministic mode. + /// Regenerate fixtures with scripts/generate_test_fixture.py + the CLI + /// (`MeshDenoiser --deterministic`) whenever the + /// algorithm intentionally changes. + func testMatchesCLIGoldenOutput() async throws { + let fixtures = Bundle.module.resourceURL!.appendingPathComponent("Fixtures") + let input = try OBJLoader.load(fixtures.appendingPathComponent("noisy_icosphere.obj")) + let golden = try OBJLoader.load(fixtures.appendingPathComponent("golden_denoised.obj")) + + XCTAssertEqual(input.positions.count, 162) + XCTAssertEqual(golden.positions.count, input.positions.count) + XCTAssertEqual(golden.indices, input.indices) + + var params = MeshDenoiseParameters() // defaults == CLI built-in defaults + params.deterministic = true + + let result = try await MeshDenoiser.denoise( + positions: input.positions.map { SIMD3(Float($0.x), Float($0.y), Float($0.z)) }, + indices: input.indices, + parameters: params + ) + + var maxError = 0.0 + for (got, want) in zip(result, golden.positions) { + maxError = max(maxError, abs(Double(got.x) - want.x)) + maxError = max(maxError, abs(Double(got.y) - want.y)) + maxError = max(maxError, abs(Double(got.z) - want.z)) + } + XCTAssertLessThan(maxError, 1e-6, "Kit output diverged from CLI golden output") + } +} diff --git a/Tests/MeshDenoiserKitTests/OBJLoader.swift b/Tests/MeshDenoiserKitTests/OBJLoader.swift new file mode 100644 index 0000000..a5cc712 --- /dev/null +++ b/Tests/MeshDenoiserKitTests/OBJLoader.swift @@ -0,0 +1,25 @@ +import Foundation + +/// Minimal OBJ reader for test fixtures: `v x y z` and `f a b c` (1-based, no slashes) only. +enum OBJLoader { + static func load(_ url: URL) throws -> (positions: [SIMD3], indices: [UInt32]) { + var positions: [SIMD3] = [] + var indices: [UInt32] = [] + for line in try String(contentsOf: url, encoding: .utf8).split(separator: "\n") { + let parts = line.split(separator: " ") + guard parts.count == 4 else { continue } + if parts[0] == "v" { + guard let x = Double(parts[1]), let y = Double(parts[2]), let z = Double(parts[3]) else { + throw CocoaError(.fileReadCorruptFile) + } + positions.append([x, y, z]) + } else if parts[0] == "f" { + guard let a = UInt32(parts[1]), let b = UInt32(parts[2]), let c = UInt32(parts[3]) else { + throw CocoaError(.fileReadCorruptFile) + } + indices += [a - 1, b - 1, c - 1] + } + } + return (positions, indices) + } +} diff --git a/Vendor/eigen/COPYING.APACHE b/Vendor/eigen/COPYING.APACHE new file mode 100644 index 0000000..61e948d --- /dev/null +++ b/Vendor/eigen/COPYING.APACHE @@ -0,0 +1,203 @@ +/* + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ \ No newline at end of file diff --git a/Vendor/eigen/COPYING.BSD b/Vendor/eigen/COPYING.BSD new file mode 100644 index 0000000..8964ddf --- /dev/null +++ b/Vendor/eigen/COPYING.BSD @@ -0,0 +1,26 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff --git a/Vendor/eigen/COPYING.GPL b/Vendor/eigen/COPYING.GPL new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/Vendor/eigen/COPYING.GPL @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Vendor/eigen/COPYING.LGPL b/Vendor/eigen/COPYING.LGPL new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/Vendor/eigen/COPYING.LGPL @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Vendor/eigen/COPYING.MINPACK b/Vendor/eigen/COPYING.MINPACK new file mode 100644 index 0000000..132cc3f --- /dev/null +++ b/Vendor/eigen/COPYING.MINPACK @@ -0,0 +1,51 @@ +Minpack Copyright Notice (1999) University of Chicago. All rights reserved + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above +copyright notice, this list of conditions and the following +disclaimer. + +2. Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials +provided with the distribution. + +3. The end-user documentation included with the +redistribution, if any, must include the following +acknowledgment: + + "This product includes software developed by the + University of Chicago, as Operator of Argonne National + Laboratory. + +Alternately, this acknowledgment may appear in the software +itself, if and wherever such third-party acknowledgments +normally appear. + +4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" +WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE +UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND +THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE +OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY +OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR +USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF +THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) +DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION +UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL +BE CORRECTED. + +5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT +HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF +ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, +INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF +ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF +PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER +SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT +(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, +EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE +POSSIBILITY OF SUCH LOSS OR DAMAGES. diff --git a/Vendor/eigen/COPYING.MPL2 b/Vendor/eigen/COPYING.MPL2 new file mode 100644 index 0000000..14e2f77 --- /dev/null +++ b/Vendor/eigen/COPYING.MPL2 @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/Vendor/eigen/COPYING.README b/Vendor/eigen/COPYING.README new file mode 100644 index 0000000..de5b632 --- /dev/null +++ b/Vendor/eigen/COPYING.README @@ -0,0 +1,18 @@ +Eigen is primarily MPL2 licensed. See COPYING.MPL2 and these links: + http://www.mozilla.org/MPL/2.0/ + http://www.mozilla.org/MPL/2.0/FAQ.html + +Some files contain third-party code under BSD or LGPL licenses, whence the other +COPYING.* files here. + +All the LGPL code is either LGPL 2.1-only, or LGPL 2.1-or-later. +For this reason, the COPYING.LGPL file contains the LGPL 2.1 text. + +If you want to guarantee that the Eigen code that you are #including is licensed +under the MPL2 and possibly more permissive licenses (like BSD), #define this +preprocessor symbol: + EIGEN_MPL2_ONLY +For example, with most compilers, you could add this to your project CXXFLAGS: + -DEIGEN_MPL2_ONLY +This will cause a compilation error to be generated if you #include any code that is +LGPL licensed. diff --git a/Vendor/eigen/Eigen/Cholesky b/Vendor/eigen/Eigen/Cholesky new file mode 100644 index 0000000..a318ceb --- /dev/null +++ b/Vendor/eigen/Eigen/Cholesky @@ -0,0 +1,45 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CHOLESKY_MODULE_H +#define EIGEN_CHOLESKY_MODULE_H + +#include "Core" +#include "Jacobi" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \defgroup Cholesky_Module Cholesky module + * + * + * + * This module provides two variants of the Cholesky decomposition for selfadjoint (hermitian) matrices. + * Those decompositions are also accessible via the following methods: + * - MatrixBase::llt() + * - MatrixBase::ldlt() + * - SelfAdjointView::llt() + * - SelfAdjointView::ldlt() + * + * \code + * #include + * \endcode + */ + +#include "src/Cholesky/LLT.h" +#include "src/Cholesky/LDLT.h" +#ifdef EIGEN_USE_LAPACKE +#ifdef EIGEN_USE_MKL +#include "mkl_lapacke.h" +#else +#include "src/misc/lapacke.h" +#endif +#include "src/Cholesky/LLT_LAPACKE.h" +#endif + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_CHOLESKY_MODULE_H diff --git a/Vendor/eigen/Eigen/CholmodSupport b/Vendor/eigen/Eigen/CholmodSupport new file mode 100644 index 0000000..bed8924 --- /dev/null +++ b/Vendor/eigen/Eigen/CholmodSupport @@ -0,0 +1,48 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CHOLMODSUPPORT_MODULE_H +#define EIGEN_CHOLMODSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +extern "C" { + #include +} + +/** \ingroup Support_modules + * \defgroup CholmodSupport_Module CholmodSupport module + * + * This module provides an interface to the Cholmod library which is part of the suitesparse package. + * It provides the two following main factorization classes: + * - class CholmodSupernodalLLT: a supernodal LLT Cholesky factorization. + * - class CholmodDecomposiiton: a general L(D)LT Cholesky factorization with automatic or explicit runtime selection of the underlying factorization method (supernodal or simplicial). + * + * For the sake of completeness, this module also propose the two following classes: + * - class CholmodSimplicialLLT + * - class CholmodSimplicialLDLT + * Note that these classes does not bring any particular advantage compared to the built-in + * SimplicialLLT and SimplicialLDLT factorization classes. + * + * \code + * #include + * \endcode + * + * In order to use this module, the cholmod headers must be accessible from the include paths, and your binary must be linked to the cholmod library and its dependencies. + * The dependencies depend on how cholmod has been compiled. + * For a cmake based project, you can use our FindCholmod.cmake module to help you in this task. + * + */ + +#include "src/CholmodSupport/CholmodSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_CHOLMODSUPPORT_MODULE_H + diff --git a/Vendor/eigen/Eigen/Core b/Vendor/eigen/Eigen/Core new file mode 100644 index 0000000..5921e15 --- /dev/null +++ b/Vendor/eigen/Eigen/Core @@ -0,0 +1,384 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2007-2011 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CORE_H +#define EIGEN_CORE_H + +// first thing Eigen does: stop the compiler from reporting useless warnings. +#include "src/Core/util/DisableStupidWarnings.h" + +// then include this file where all our macros are defined. It's really important to do it first because +// it's where we do all the compiler/OS/arch detections and define most defaults. +#include "src/Core/util/Macros.h" + +// This detects SSE/AVX/NEON/etc. and configure alignment settings +#include "src/Core/util/ConfigureVectorization.h" + +// We need cuda_runtime.h/hip_runtime.h to ensure that +// the EIGEN_USING_STD macro works properly on the device side +#if defined(EIGEN_CUDACC) + #include +#elif defined(EIGEN_HIPCC) + #include +#endif + + +#ifdef EIGEN_EXCEPTIONS + #include +#endif + +// Disable the ipa-cp-clone optimization flag with MinGW 6.x or newer (enabled by default with -O3) +// See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=556 for details. +#if EIGEN_COMP_MINGW && EIGEN_GNUC_AT_LEAST(4,6) && EIGEN_GNUC_AT_MOST(5,5) + #pragma GCC optimize ("-fno-ipa-cp-clone") +#endif + +// Prevent ICC from specializing std::complex operators that silently fail +// on device. This allows us to use our own device-compatible specializations +// instead. +#if defined(EIGEN_COMP_ICC) && defined(EIGEN_GPU_COMPILE_PHASE) \ + && !defined(_OVERRIDE_COMPLEX_SPECIALIZATION_) +#define _OVERRIDE_COMPLEX_SPECIALIZATION_ 1 +#endif +#include + +// this include file manages BLAS and MKL related macros +// and inclusion of their respective header files +#include "src/Core/util/MKL_support.h" + + +#if defined(EIGEN_HAS_CUDA_FP16) || defined(EIGEN_HAS_HIP_FP16) + #define EIGEN_HAS_GPU_FP16 +#endif + +#if defined(EIGEN_HAS_CUDA_BF16) || defined(EIGEN_HAS_HIP_BF16) + #define EIGEN_HAS_GPU_BF16 +#endif + +#if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE) + #define EIGEN_HAS_OPENMP +#endif + +#ifdef EIGEN_HAS_OPENMP +#include +#endif + +// MSVC for windows mobile does not have the errno.h file +#if !(EIGEN_COMP_MSVC && EIGEN_OS_WINCE) && !EIGEN_COMP_ARM +#define EIGEN_HAS_ERRNO +#endif + +#ifdef EIGEN_HAS_ERRNO +#include +#endif +#include +#include +#include +#include +#include +#include +#ifndef EIGEN_NO_IO + #include +#endif +#include +#include +#include +#include // for CHAR_BIT +// for min/max: +#include + +#if EIGEN_HAS_CXX11 +#include +#endif + +// for std::is_nothrow_move_assignable +#ifdef EIGEN_INCLUDE_TYPE_TRAITS +#include +#endif + +// for outputting debug info +#ifdef EIGEN_DEBUG_ASSIGN +#include +#endif + +// required for __cpuid, needs to be included after cmath +#if EIGEN_COMP_MSVC && EIGEN_ARCH_i386_OR_x86_64 && !EIGEN_OS_WINCE + #include +#endif + +#if defined(EIGEN_USE_SYCL) + #undef min + #undef max + #undef isnan + #undef isinf + #undef isfinite + #include + #include + #include + #include + #include + #ifndef EIGEN_SYCL_LOCAL_THREAD_DIM0 + #define EIGEN_SYCL_LOCAL_THREAD_DIM0 16 + #endif + #ifndef EIGEN_SYCL_LOCAL_THREAD_DIM1 + #define EIGEN_SYCL_LOCAL_THREAD_DIM1 16 + #endif +#endif + + +#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS || defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API || defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS || defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API || defined EIGEN2_SUPPORT +// This will generate an error message: +#error Eigen2-support is only available up to version 3.2. Please go to "http://eigen.tuxfamily.org/index.php?title=Eigen2" for further information +#endif + +namespace Eigen { + +// we use size_t frequently and we'll never remember to prepend it with std:: every time just to +// ensure QNX/QCC support +using std::size_t; +// gcc 4.6.0 wants std:: for ptrdiff_t +using std::ptrdiff_t; + +} + +/** \defgroup Core_Module Core module + * This is the main module of Eigen providing dense matrix and vector support + * (both fixed and dynamic size) with all the features corresponding to a BLAS library + * and much more... + * + * \code + * #include + * \endcode + */ + +#include "src/Core/util/Constants.h" +#include "src/Core/util/Meta.h" +#include "src/Core/util/ForwardDeclarations.h" +#include "src/Core/util/StaticAssert.h" +#include "src/Core/util/XprHelper.h" +#include "src/Core/util/Memory.h" +#include "src/Core/util/IntegralConstant.h" +#include "src/Core/util/SymbolicIndex.h" + +#include "src/Core/NumTraits.h" +#include "src/Core/MathFunctions.h" +#include "src/Core/GenericPacketMath.h" +#include "src/Core/MathFunctionsImpl.h" +#include "src/Core/arch/Default/ConjHelper.h" +// Generic half float support +#include "src/Core/arch/Default/Half.h" +#include "src/Core/arch/Default/BFloat16.h" +#include "src/Core/arch/Default/TypeCasting.h" +#include "src/Core/arch/Default/GenericPacketMathFunctionsFwd.h" + +#if defined EIGEN_VECTORIZE_AVX512 + #include "src/Core/arch/SSE/PacketMath.h" + #include "src/Core/arch/SSE/TypeCasting.h" + #include "src/Core/arch/SSE/Complex.h" + #include "src/Core/arch/AVX/PacketMath.h" + #include "src/Core/arch/AVX/TypeCasting.h" + #include "src/Core/arch/AVX/Complex.h" + #include "src/Core/arch/AVX512/PacketMath.h" + #include "src/Core/arch/AVX512/TypeCasting.h" + #include "src/Core/arch/AVX512/Complex.h" + #include "src/Core/arch/SSE/MathFunctions.h" + #include "src/Core/arch/AVX/MathFunctions.h" + #include "src/Core/arch/AVX512/MathFunctions.h" +#elif defined EIGEN_VECTORIZE_AVX + // Use AVX for floats and doubles, SSE for integers + #include "src/Core/arch/SSE/PacketMath.h" + #include "src/Core/arch/SSE/TypeCasting.h" + #include "src/Core/arch/SSE/Complex.h" + #include "src/Core/arch/AVX/PacketMath.h" + #include "src/Core/arch/AVX/TypeCasting.h" + #include "src/Core/arch/AVX/Complex.h" + #include "src/Core/arch/SSE/MathFunctions.h" + #include "src/Core/arch/AVX/MathFunctions.h" +#elif defined EIGEN_VECTORIZE_SSE + #include "src/Core/arch/SSE/PacketMath.h" + #include "src/Core/arch/SSE/TypeCasting.h" + #include "src/Core/arch/SSE/MathFunctions.h" + #include "src/Core/arch/SSE/Complex.h" +#elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX) + #include "src/Core/arch/AltiVec/PacketMath.h" + #include "src/Core/arch/AltiVec/MathFunctions.h" + #include "src/Core/arch/AltiVec/Complex.h" +#elif defined EIGEN_VECTORIZE_NEON + #include "src/Core/arch/NEON/PacketMath.h" + #include "src/Core/arch/NEON/TypeCasting.h" + #include "src/Core/arch/NEON/MathFunctions.h" + #include "src/Core/arch/NEON/Complex.h" +#elif defined EIGEN_VECTORIZE_SVE + #include "src/Core/arch/SVE/PacketMath.h" + #include "src/Core/arch/SVE/TypeCasting.h" + #include "src/Core/arch/SVE/MathFunctions.h" +#elif defined EIGEN_VECTORIZE_ZVECTOR + #include "src/Core/arch/ZVector/PacketMath.h" + #include "src/Core/arch/ZVector/MathFunctions.h" + #include "src/Core/arch/ZVector/Complex.h" +#elif defined EIGEN_VECTORIZE_MSA + #include "src/Core/arch/MSA/PacketMath.h" + #include "src/Core/arch/MSA/MathFunctions.h" + #include "src/Core/arch/MSA/Complex.h" +#endif + +#if defined EIGEN_VECTORIZE_GPU + #include "src/Core/arch/GPU/PacketMath.h" + #include "src/Core/arch/GPU/MathFunctions.h" + #include "src/Core/arch/GPU/TypeCasting.h" +#endif + +#if defined(EIGEN_USE_SYCL) + #include "src/Core/arch/SYCL/SyclMemoryModel.h" + #include "src/Core/arch/SYCL/InteropHeaders.h" +#if !defined(EIGEN_DONT_VECTORIZE_SYCL) + #include "src/Core/arch/SYCL/PacketMath.h" + #include "src/Core/arch/SYCL/MathFunctions.h" + #include "src/Core/arch/SYCL/TypeCasting.h" +#endif +#endif + +#include "src/Core/arch/Default/Settings.h" +// This file provides generic implementations valid for scalar as well +#include "src/Core/arch/Default/GenericPacketMathFunctions.h" + +#include "src/Core/functors/TernaryFunctors.h" +#include "src/Core/functors/BinaryFunctors.h" +#include "src/Core/functors/UnaryFunctors.h" +#include "src/Core/functors/NullaryFunctors.h" +#include "src/Core/functors/StlFunctors.h" +#include "src/Core/functors/AssignmentFunctors.h" + +// Specialized functors to enable the processing of complex numbers +// on CUDA devices +#ifdef EIGEN_CUDACC +#include "src/Core/arch/CUDA/Complex.h" +#endif + +#include "src/Core/util/IndexedViewHelper.h" +#include "src/Core/util/ReshapedHelper.h" +#include "src/Core/ArithmeticSequence.h" +#ifndef EIGEN_NO_IO + #include "src/Core/IO.h" +#endif +#include "src/Core/DenseCoeffsBase.h" +#include "src/Core/DenseBase.h" +#include "src/Core/MatrixBase.h" +#include "src/Core/EigenBase.h" + +#include "src/Core/Product.h" +#include "src/Core/CoreEvaluators.h" +#include "src/Core/AssignEvaluator.h" + +#ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 + // at least confirmed with Doxygen 1.5.5 and 1.5.6 + #include "src/Core/Assign.h" +#endif + +#include "src/Core/ArrayBase.h" +#include "src/Core/util/BlasUtil.h" +#include "src/Core/DenseStorage.h" +#include "src/Core/NestByValue.h" + +// #include "src/Core/ForceAlignedAccess.h" + +#include "src/Core/ReturnByValue.h" +#include "src/Core/NoAlias.h" +#include "src/Core/PlainObjectBase.h" +#include "src/Core/Matrix.h" +#include "src/Core/Array.h" +#include "src/Core/CwiseTernaryOp.h" +#include "src/Core/CwiseBinaryOp.h" +#include "src/Core/CwiseUnaryOp.h" +#include "src/Core/CwiseNullaryOp.h" +#include "src/Core/CwiseUnaryView.h" +#include "src/Core/SelfCwiseBinaryOp.h" +#include "src/Core/Dot.h" +#include "src/Core/StableNorm.h" +#include "src/Core/Stride.h" +#include "src/Core/MapBase.h" +#include "src/Core/Map.h" +#include "src/Core/Ref.h" +#include "src/Core/Block.h" +#include "src/Core/VectorBlock.h" +#include "src/Core/IndexedView.h" +#include "src/Core/Reshaped.h" +#include "src/Core/Transpose.h" +#include "src/Core/DiagonalMatrix.h" +#include "src/Core/Diagonal.h" +#include "src/Core/DiagonalProduct.h" +#include "src/Core/Redux.h" +#include "src/Core/Visitor.h" +#include "src/Core/Fuzzy.h" +#include "src/Core/Swap.h" +#include "src/Core/CommaInitializer.h" +#include "src/Core/GeneralProduct.h" +#include "src/Core/Solve.h" +#include "src/Core/Inverse.h" +#include "src/Core/SolverBase.h" +#include "src/Core/PermutationMatrix.h" +#include "src/Core/Transpositions.h" +#include "src/Core/TriangularMatrix.h" +#include "src/Core/SelfAdjointView.h" +#include "src/Core/products/GeneralBlockPanelKernel.h" +#include "src/Core/products/Parallelizer.h" +#include "src/Core/ProductEvaluators.h" +#include "src/Core/products/GeneralMatrixVector.h" +#include "src/Core/products/GeneralMatrixMatrix.h" +#include "src/Core/SolveTriangular.h" +#include "src/Core/products/GeneralMatrixMatrixTriangular.h" +#include "src/Core/products/SelfadjointMatrixVector.h" +#include "src/Core/products/SelfadjointMatrixMatrix.h" +#include "src/Core/products/SelfadjointProduct.h" +#include "src/Core/products/SelfadjointRank2Update.h" +#include "src/Core/products/TriangularMatrixVector.h" +#include "src/Core/products/TriangularMatrixMatrix.h" +#include "src/Core/products/TriangularSolverMatrix.h" +#include "src/Core/products/TriangularSolverVector.h" +#include "src/Core/BandMatrix.h" +#include "src/Core/CoreIterators.h" +#include "src/Core/ConditionEstimator.h" + +#if defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX) + #include "src/Core/arch/AltiVec/MatrixProduct.h" +#elif defined EIGEN_VECTORIZE_NEON + #include "src/Core/arch/NEON/GeneralBlockPanelKernel.h" +#endif + +#include "src/Core/BooleanRedux.h" +#include "src/Core/Select.h" +#include "src/Core/VectorwiseOp.h" +#include "src/Core/PartialReduxEvaluator.h" +#include "src/Core/Random.h" +#include "src/Core/Replicate.h" +#include "src/Core/Reverse.h" +#include "src/Core/ArrayWrapper.h" +#include "src/Core/StlIterators.h" + +#ifdef EIGEN_USE_BLAS +#include "src/Core/products/GeneralMatrixMatrix_BLAS.h" +#include "src/Core/products/GeneralMatrixVector_BLAS.h" +#include "src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h" +#include "src/Core/products/SelfadjointMatrixMatrix_BLAS.h" +#include "src/Core/products/SelfadjointMatrixVector_BLAS.h" +#include "src/Core/products/TriangularMatrixMatrix_BLAS.h" +#include "src/Core/products/TriangularMatrixVector_BLAS.h" +#include "src/Core/products/TriangularSolverMatrix_BLAS.h" +#endif // EIGEN_USE_BLAS + +#ifdef EIGEN_USE_MKL_VML +#include "src/Core/Assign_MKL.h" +#endif + +#include "src/Core/GlobalFunctions.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_CORE_H diff --git a/Vendor/eigen/Eigen/Dense b/Vendor/eigen/Eigen/Dense new file mode 100644 index 0000000..5768910 --- /dev/null +++ b/Vendor/eigen/Eigen/Dense @@ -0,0 +1,7 @@ +#include "Core" +#include "LU" +#include "Cholesky" +#include "QR" +#include "SVD" +#include "Geometry" +#include "Eigenvalues" diff --git a/Vendor/eigen/Eigen/Eigen b/Vendor/eigen/Eigen/Eigen new file mode 100644 index 0000000..654c8dc --- /dev/null +++ b/Vendor/eigen/Eigen/Eigen @@ -0,0 +1,2 @@ +#include "Dense" +#include "Sparse" diff --git a/Vendor/eigen/Eigen/Eigenvalues b/Vendor/eigen/Eigen/Eigenvalues new file mode 100644 index 0000000..5467a2e --- /dev/null +++ b/Vendor/eigen/Eigen/Eigenvalues @@ -0,0 +1,60 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_EIGENVALUES_MODULE_H +#define EIGEN_EIGENVALUES_MODULE_H + +#include "Core" + +#include "Cholesky" +#include "Jacobi" +#include "Householder" +#include "LU" +#include "Geometry" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \defgroup Eigenvalues_Module Eigenvalues module + * + * + * + * This module mainly provides various eigenvalue solvers. + * This module also provides some MatrixBase methods, including: + * - MatrixBase::eigenvalues(), + * - MatrixBase::operatorNorm() + * + * \code + * #include + * \endcode + */ + +#include "src/misc/RealSvd2x2.h" +#include "src/Eigenvalues/Tridiagonalization.h" +#include "src/Eigenvalues/RealSchur.h" +#include "src/Eigenvalues/EigenSolver.h" +#include "src/Eigenvalues/SelfAdjointEigenSolver.h" +#include "src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h" +#include "src/Eigenvalues/HessenbergDecomposition.h" +#include "src/Eigenvalues/ComplexSchur.h" +#include "src/Eigenvalues/ComplexEigenSolver.h" +#include "src/Eigenvalues/RealQZ.h" +#include "src/Eigenvalues/GeneralizedEigenSolver.h" +#include "src/Eigenvalues/MatrixBaseEigenvalues.h" +#ifdef EIGEN_USE_LAPACKE +#ifdef EIGEN_USE_MKL +#include "mkl_lapacke.h" +#else +#include "src/misc/lapacke.h" +#endif +#include "src/Eigenvalues/RealSchur_LAPACKE.h" +#include "src/Eigenvalues/ComplexSchur_LAPACKE.h" +#include "src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h" +#endif + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_EIGENVALUES_MODULE_H diff --git a/Vendor/eigen/Eigen/Geometry b/Vendor/eigen/Eigen/Geometry new file mode 100644 index 0000000..bc78110 --- /dev/null +++ b/Vendor/eigen/Eigen/Geometry @@ -0,0 +1,59 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_GEOMETRY_MODULE_H +#define EIGEN_GEOMETRY_MODULE_H + +#include "Core" + +#include "SVD" +#include "LU" +#include + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \defgroup Geometry_Module Geometry module + * + * This module provides support for: + * - fixed-size homogeneous transformations + * - translation, scaling, 2D and 3D rotations + * - \link Quaternion quaternions \endlink + * - cross products (\ref MatrixBase::cross, \ref MatrixBase::cross3) + * - orthognal vector generation (\ref MatrixBase::unitOrthogonal) + * - some linear components: \link ParametrizedLine parametrized-lines \endlink and \link Hyperplane hyperplanes \endlink + * - \link AlignedBox axis aligned bounding boxes \endlink + * - \link umeyama least-square transformation fitting \endlink + * + * \code + * #include + * \endcode + */ + +#include "src/Geometry/OrthoMethods.h" +#include "src/Geometry/EulerAngles.h" + +#include "src/Geometry/Homogeneous.h" +#include "src/Geometry/RotationBase.h" +#include "src/Geometry/Rotation2D.h" +#include "src/Geometry/Quaternion.h" +#include "src/Geometry/AngleAxis.h" +#include "src/Geometry/Transform.h" +#include "src/Geometry/Translation.h" +#include "src/Geometry/Scaling.h" +#include "src/Geometry/Hyperplane.h" +#include "src/Geometry/ParametrizedLine.h" +#include "src/Geometry/AlignedBox.h" +#include "src/Geometry/Umeyama.h" + +// Use the SSE optimized version whenever possible. +#if (defined EIGEN_VECTORIZE_SSE) || (defined EIGEN_VECTORIZE_NEON) +#include "src/Geometry/arch/Geometry_SIMD.h" +#endif + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_GEOMETRY_MODULE_H diff --git a/Vendor/eigen/Eigen/Householder b/Vendor/eigen/Eigen/Householder new file mode 100644 index 0000000..f2fa799 --- /dev/null +++ b/Vendor/eigen/Eigen/Householder @@ -0,0 +1,29 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_HOUSEHOLDER_MODULE_H +#define EIGEN_HOUSEHOLDER_MODULE_H + +#include "Core" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \defgroup Householder_Module Householder module + * This module provides Householder transformations. + * + * \code + * #include + * \endcode + */ + +#include "src/Householder/Householder.h" +#include "src/Householder/HouseholderSequence.h" +#include "src/Householder/BlockHouseholder.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_HOUSEHOLDER_MODULE_H diff --git a/Vendor/eigen/Eigen/IterativeLinearSolvers b/Vendor/eigen/Eigen/IterativeLinearSolvers new file mode 100644 index 0000000..957d575 --- /dev/null +++ b/Vendor/eigen/Eigen/IterativeLinearSolvers @@ -0,0 +1,48 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ITERATIVELINEARSOLVERS_MODULE_H +#define EIGEN_ITERATIVELINEARSOLVERS_MODULE_H + +#include "SparseCore" +#include "OrderingMethods" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** + * \defgroup IterativeLinearSolvers_Module IterativeLinearSolvers module + * + * This module currently provides iterative methods to solve problems of the form \c A \c x = \c b, where \c A is a squared matrix, usually very large and sparse. + * Those solvers are accessible via the following classes: + * - ConjugateGradient for selfadjoint (hermitian) matrices, + * - LeastSquaresConjugateGradient for rectangular least-square problems, + * - BiCGSTAB for general square matrices. + * + * These iterative solvers are associated with some preconditioners: + * - IdentityPreconditioner - not really useful + * - DiagonalPreconditioner - also called Jacobi preconditioner, work very well on diagonal dominant matrices. + * - IncompleteLUT - incomplete LU factorization with dual thresholding + * + * Such problems can also be solved using the direct sparse decomposition modules: SparseCholesky, CholmodSupport, UmfPackSupport, SuperLUSupport. + * + \code + #include + \endcode + */ + +#include "src/IterativeLinearSolvers/SolveWithGuess.h" +#include "src/IterativeLinearSolvers/IterativeSolverBase.h" +#include "src/IterativeLinearSolvers/BasicPreconditioners.h" +#include "src/IterativeLinearSolvers/ConjugateGradient.h" +#include "src/IterativeLinearSolvers/LeastSquareConjugateGradient.h" +#include "src/IterativeLinearSolvers/BiCGSTAB.h" +#include "src/IterativeLinearSolvers/IncompleteLUT.h" +#include "src/IterativeLinearSolvers/IncompleteCholesky.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_ITERATIVELINEARSOLVERS_MODULE_H diff --git a/Vendor/eigen/Eigen/Jacobi b/Vendor/eigen/Eigen/Jacobi new file mode 100644 index 0000000..43edc7a --- /dev/null +++ b/Vendor/eigen/Eigen/Jacobi @@ -0,0 +1,32 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_JACOBI_MODULE_H +#define EIGEN_JACOBI_MODULE_H + +#include "Core" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \defgroup Jacobi_Module Jacobi module + * This module provides Jacobi and Givens rotations. + * + * \code + * #include + * \endcode + * + * In addition to listed classes, it defines the two following MatrixBase methods to apply a Jacobi or Givens rotation: + * - MatrixBase::applyOnTheLeft() + * - MatrixBase::applyOnTheRight(). + */ + +#include "src/Jacobi/Jacobi.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_JACOBI_MODULE_H + diff --git a/Vendor/eigen/Eigen/KLUSupport b/Vendor/eigen/Eigen/KLUSupport new file mode 100644 index 0000000..b23d905 --- /dev/null +++ b/Vendor/eigen/Eigen/KLUSupport @@ -0,0 +1,41 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_KLUSUPPORT_MODULE_H +#define EIGEN_KLUSUPPORT_MODULE_H + +#include + +#include + +extern "C" { +#include +#include + } + +/** \ingroup Support_modules + * \defgroup KLUSupport_Module KLUSupport module + * + * This module provides an interface to the KLU library which is part of the suitesparse package. + * It provides the following factorization class: + * - class KLU: a sparse LU factorization, well-suited for circuit simulation. + * + * \code + * #include + * \endcode + * + * In order to use this module, the klu and btf headers must be accessible from the include paths, and your binary must be linked to the klu library and its dependencies. + * The dependencies depend on how umfpack has been compiled. + * For a cmake based project, you can use our FindKLU.cmake module to help you in this task. + * + */ + +#include "src/KLUSupport/KLUSupport.h" + +#include + +#endif // EIGEN_KLUSUPPORT_MODULE_H diff --git a/Vendor/eigen/Eigen/LU b/Vendor/eigen/Eigen/LU new file mode 100644 index 0000000..1236ceb --- /dev/null +++ b/Vendor/eigen/Eigen/LU @@ -0,0 +1,47 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_LU_MODULE_H +#define EIGEN_LU_MODULE_H + +#include "Core" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \defgroup LU_Module LU module + * This module includes %LU decomposition and related notions such as matrix inversion and determinant. + * This module defines the following MatrixBase methods: + * - MatrixBase::inverse() + * - MatrixBase::determinant() + * + * \code + * #include + * \endcode + */ + +#include "src/misc/Kernel.h" +#include "src/misc/Image.h" +#include "src/LU/FullPivLU.h" +#include "src/LU/PartialPivLU.h" +#ifdef EIGEN_USE_LAPACKE +#ifdef EIGEN_USE_MKL +#include "mkl_lapacke.h" +#else +#include "src/misc/lapacke.h" +#endif +#include "src/LU/PartialPivLU_LAPACKE.h" +#endif +#include "src/LU/Determinant.h" +#include "src/LU/InverseImpl.h" + +#if defined EIGEN_VECTORIZE_SSE || defined EIGEN_VECTORIZE_NEON + #include "src/LU/arch/InverseSize4.h" +#endif + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_LU_MODULE_H diff --git a/Vendor/eigen/Eigen/MetisSupport b/Vendor/eigen/Eigen/MetisSupport new file mode 100644 index 0000000..85c41bf --- /dev/null +++ b/Vendor/eigen/Eigen/MetisSupport @@ -0,0 +1,35 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_METISSUPPORT_MODULE_H +#define EIGEN_METISSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +extern "C" { +#include +} + + +/** \ingroup Support_modules + * \defgroup MetisSupport_Module MetisSupport module + * + * \code + * #include + * \endcode + * This module defines an interface to the METIS reordering package (http://glaros.dtc.umn.edu/gkhome/views/metis). + * It can be used just as any other built-in method as explained in \link OrderingMethods_Module here. \endlink + */ + + +#include "src/MetisSupport/MetisSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_METISSUPPORT_MODULE_H diff --git a/Vendor/eigen/Eigen/OrderingMethods b/Vendor/eigen/Eigen/OrderingMethods new file mode 100644 index 0000000..29691a6 --- /dev/null +++ b/Vendor/eigen/Eigen/OrderingMethods @@ -0,0 +1,70 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ORDERINGMETHODS_MODULE_H +#define EIGEN_ORDERINGMETHODS_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** + * \defgroup OrderingMethods_Module OrderingMethods module + * + * This module is currently for internal use only + * + * It defines various built-in and external ordering methods for sparse matrices. + * They are typically used to reduce the number of elements during + * the sparse matrix decomposition (LLT, LU, QR). + * Precisely, in a preprocessing step, a permutation matrix P is computed using + * those ordering methods and applied to the columns of the matrix. + * Using for instance the sparse Cholesky decomposition, it is expected that + * the nonzeros elements in LLT(A*P) will be much smaller than that in LLT(A). + * + * + * Usage : + * \code + * #include + * \endcode + * + * A simple usage is as a template parameter in the sparse decomposition classes : + * + * \code + * SparseLU > solver; + * \endcode + * + * \code + * SparseQR > solver; + * \endcode + * + * It is possible as well to call directly a particular ordering method for your own purpose, + * \code + * AMDOrdering ordering; + * PermutationMatrix perm; + * SparseMatrix A; + * //Fill the matrix ... + * + * ordering(A, perm); // Call AMD + * \endcode + * + * \note Some of these methods (like AMD or METIS), need the sparsity pattern + * of the input matrix to be symmetric. When the matrix is structurally unsymmetric, + * Eigen computes internally the pattern of \f$A^T*A\f$ before calling the method. + * If your matrix is already symmetric (at leat in structure), you can avoid that + * by calling the method with a SelfAdjointView type. + * + * \code + * // Call the ordering on the pattern of the lower triangular matrix A + * ordering(A.selfadjointView(), perm); + * \endcode + */ + +#include "src/OrderingMethods/Amd.h" +#include "src/OrderingMethods/Ordering.h" +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_ORDERINGMETHODS_MODULE_H diff --git a/Vendor/eigen/Eigen/PaStiXSupport b/Vendor/eigen/Eigen/PaStiXSupport new file mode 100644 index 0000000..234619a --- /dev/null +++ b/Vendor/eigen/Eigen/PaStiXSupport @@ -0,0 +1,49 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PASTIXSUPPORT_MODULE_H +#define EIGEN_PASTIXSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +extern "C" { +#include +#include +} + +#ifdef complex +#undef complex +#endif + +/** \ingroup Support_modules + * \defgroup PaStiXSupport_Module PaStiXSupport module + * + * This module provides an interface to the PaSTiX library. + * PaSTiX is a general \b supernodal, \b parallel and \b opensource sparse solver. + * It provides the two following main factorization classes: + * - class PastixLLT : a supernodal, parallel LLt Cholesky factorization. + * - class PastixLDLT: a supernodal, parallel LDLt Cholesky factorization. + * - class PastixLU : a supernodal, parallel LU factorization (optimized for a symmetric pattern). + * + * \code + * #include + * \endcode + * + * In order to use this module, the PaSTiX headers must be accessible from the include paths, and your binary must be linked to the PaSTiX library and its dependencies. + * This wrapper resuires PaStiX version 5.x compiled without MPI support. + * The dependencies depend on how PaSTiX has been compiled. + * For a cmake based project, you can use our FindPaSTiX.cmake module to help you in this task. + * + */ + +#include "src/PaStiXSupport/PaStiXSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_PASTIXSUPPORT_MODULE_H diff --git a/Vendor/eigen/Eigen/PardisoSupport b/Vendor/eigen/Eigen/PardisoSupport new file mode 100644 index 0000000..340edf5 --- /dev/null +++ b/Vendor/eigen/Eigen/PardisoSupport @@ -0,0 +1,35 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PARDISOSUPPORT_MODULE_H +#define EIGEN_PARDISOSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include + +/** \ingroup Support_modules + * \defgroup PardisoSupport_Module PardisoSupport module + * + * This module brings support for the Intel(R) MKL PARDISO direct sparse solvers. + * + * \code + * #include + * \endcode + * + * In order to use this module, the MKL headers must be accessible from the include paths, and your binary must be linked to the MKL library and its dependencies. + * See this \ref TopicUsingIntelMKL "page" for more information on MKL-Eigen integration. + * + */ + +#include "src/PardisoSupport/PardisoSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_PARDISOSUPPORT_MODULE_H diff --git a/Vendor/eigen/Eigen/QR b/Vendor/eigen/Eigen/QR new file mode 100644 index 0000000..8465b62 --- /dev/null +++ b/Vendor/eigen/Eigen/QR @@ -0,0 +1,50 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_QR_MODULE_H +#define EIGEN_QR_MODULE_H + +#include "Core" + +#include "Cholesky" +#include "Jacobi" +#include "Householder" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \defgroup QR_Module QR module + * + * + * + * This module provides various QR decompositions + * This module also provides some MatrixBase methods, including: + * - MatrixBase::householderQr() + * - MatrixBase::colPivHouseholderQr() + * - MatrixBase::fullPivHouseholderQr() + * + * \code + * #include + * \endcode + */ + +#include "src/QR/HouseholderQR.h" +#include "src/QR/FullPivHouseholderQR.h" +#include "src/QR/ColPivHouseholderQR.h" +#include "src/QR/CompleteOrthogonalDecomposition.h" +#ifdef EIGEN_USE_LAPACKE +#ifdef EIGEN_USE_MKL +#include "mkl_lapacke.h" +#else +#include "src/misc/lapacke.h" +#endif +#include "src/QR/HouseholderQR_LAPACKE.h" +#include "src/QR/ColPivHouseholderQR_LAPACKE.h" +#endif + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_QR_MODULE_H diff --git a/Vendor/eigen/Eigen/QtAlignedMalloc b/Vendor/eigen/Eigen/QtAlignedMalloc new file mode 100644 index 0000000..6fe8237 --- /dev/null +++ b/Vendor/eigen/Eigen/QtAlignedMalloc @@ -0,0 +1,39 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_QTMALLOC_MODULE_H +#define EIGEN_QTMALLOC_MODULE_H + +#include "Core" + +#if (!EIGEN_MALLOC_ALREADY_ALIGNED) + +#include "src/Core/util/DisableStupidWarnings.h" + +void *qMalloc(std::size_t size) +{ + return Eigen::internal::aligned_malloc(size); +} + +void qFree(void *ptr) +{ + Eigen::internal::aligned_free(ptr); +} + +void *qRealloc(void *ptr, std::size_t size) +{ + void* newPtr = Eigen::internal::aligned_malloc(size); + std::memcpy(newPtr, ptr, size); + Eigen::internal::aligned_free(ptr); + return newPtr; +} + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif + +#endif // EIGEN_QTMALLOC_MODULE_H diff --git a/Vendor/eigen/Eigen/SPQRSupport b/Vendor/eigen/Eigen/SPQRSupport new file mode 100644 index 0000000..f70390c --- /dev/null +++ b/Vendor/eigen/Eigen/SPQRSupport @@ -0,0 +1,34 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPQRSUPPORT_MODULE_H +#define EIGEN_SPQRSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include "SuiteSparseQR.hpp" + +/** \ingroup Support_modules + * \defgroup SPQRSupport_Module SuiteSparseQR module + * + * This module provides an interface to the SPQR library, which is part of the suitesparse package. + * + * \code + * #include + * \endcode + * + * In order to use this module, the SPQR headers must be accessible from the include paths, and your binary must be linked to the SPQR library and its dependencies (Cholmod, AMD, COLAMD,...). + * For a cmake based project, you can use our FindSPQR.cmake and FindCholmod.Cmake modules + * + */ + +#include "src/CholmodSupport/CholmodSupport.h" +#include "src/SPQRSupport/SuiteSparseQRSupport.h" + +#endif diff --git a/Vendor/eigen/Eigen/SVD b/Vendor/eigen/Eigen/SVD new file mode 100644 index 0000000..3451794 --- /dev/null +++ b/Vendor/eigen/Eigen/SVD @@ -0,0 +1,50 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SVD_MODULE_H +#define EIGEN_SVD_MODULE_H + +#include "QR" +#include "Householder" +#include "Jacobi" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** \defgroup SVD_Module SVD module + * + * + * + * This module provides SVD decomposition for matrices (both real and complex). + * Two decomposition algorithms are provided: + * - JacobiSVD implementing two-sided Jacobi iterations is numerically very accurate, fast for small matrices, but very slow for larger ones. + * - BDCSVD implementing a recursive divide & conquer strategy on top of an upper-bidiagonalization which remains fast for large problems. + * These decompositions are accessible via the respective classes and following MatrixBase methods: + * - MatrixBase::jacobiSvd() + * - MatrixBase::bdcSvd() + * + * \code + * #include + * \endcode + */ + +#include "src/misc/RealSvd2x2.h" +#include "src/SVD/UpperBidiagonalization.h" +#include "src/SVD/SVDBase.h" +#include "src/SVD/JacobiSVD.h" +#include "src/SVD/BDCSVD.h" +#if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT) +#ifdef EIGEN_USE_MKL +#include "mkl_lapacke.h" +#else +#include "src/misc/lapacke.h" +#endif +#include "src/SVD/JacobiSVD_LAPACKE.h" +#endif + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SVD_MODULE_H diff --git a/Vendor/eigen/Eigen/Sparse b/Vendor/eigen/Eigen/Sparse new file mode 100644 index 0000000..a2ef7a6 --- /dev/null +++ b/Vendor/eigen/Eigen/Sparse @@ -0,0 +1,34 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSE_MODULE_H +#define EIGEN_SPARSE_MODULE_H + +/** \defgroup Sparse_Module Sparse meta-module + * + * Meta-module including all related modules: + * - \ref SparseCore_Module + * - \ref OrderingMethods_Module + * - \ref SparseCholesky_Module + * - \ref SparseLU_Module + * - \ref SparseQR_Module + * - \ref IterativeLinearSolvers_Module + * + \code + #include + \endcode + */ + +#include "SparseCore" +#include "OrderingMethods" +#include "SparseCholesky" +#include "SparseLU" +#include "SparseQR" +#include "IterativeLinearSolvers" + +#endif // EIGEN_SPARSE_MODULE_H + diff --git a/Vendor/eigen/Eigen/SparseCholesky b/Vendor/eigen/Eigen/SparseCholesky new file mode 100644 index 0000000..d2b1f12 --- /dev/null +++ b/Vendor/eigen/Eigen/SparseCholesky @@ -0,0 +1,37 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2013 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSECHOLESKY_MODULE_H +#define EIGEN_SPARSECHOLESKY_MODULE_H + +#include "SparseCore" +#include "OrderingMethods" + +#include "src/Core/util/DisableStupidWarnings.h" + +/** + * \defgroup SparseCholesky_Module SparseCholesky module + * + * This module currently provides two variants of the direct sparse Cholesky decomposition for selfadjoint (hermitian) matrices. + * Those decompositions are accessible via the following classes: + * - SimplicialLLt, + * - SimplicialLDLt + * + * Such problems can also be solved using the ConjugateGradient solver from the IterativeLinearSolvers module. + * + * \code + * #include + * \endcode + */ + +#include "src/SparseCholesky/SimplicialCholesky.h" +#include "src/SparseCholesky/SimplicialCholesky_impl.h" +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SPARSECHOLESKY_MODULE_H diff --git a/Vendor/eigen/Eigen/SparseCore b/Vendor/eigen/Eigen/SparseCore new file mode 100644 index 0000000..76966c4 --- /dev/null +++ b/Vendor/eigen/Eigen/SparseCore @@ -0,0 +1,69 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSECORE_MODULE_H +#define EIGEN_SPARSECORE_MODULE_H + +#include "Core" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include +#include +#include +#include +#include + +/** + * \defgroup SparseCore_Module SparseCore module + * + * This module provides a sparse matrix representation, and basic associated matrix manipulations + * and operations. + * + * See the \ref TutorialSparse "Sparse tutorial" + * + * \code + * #include + * \endcode + * + * This module depends on: Core. + */ + +#include "src/SparseCore/SparseUtil.h" +#include "src/SparseCore/SparseMatrixBase.h" +#include "src/SparseCore/SparseAssign.h" +#include "src/SparseCore/CompressedStorage.h" +#include "src/SparseCore/AmbiVector.h" +#include "src/SparseCore/SparseCompressedBase.h" +#include "src/SparseCore/SparseMatrix.h" +#include "src/SparseCore/SparseMap.h" +#include "src/SparseCore/MappedSparseMatrix.h" +#include "src/SparseCore/SparseVector.h" +#include "src/SparseCore/SparseRef.h" +#include "src/SparseCore/SparseCwiseUnaryOp.h" +#include "src/SparseCore/SparseCwiseBinaryOp.h" +#include "src/SparseCore/SparseTranspose.h" +#include "src/SparseCore/SparseBlock.h" +#include "src/SparseCore/SparseDot.h" +#include "src/SparseCore/SparseRedux.h" +#include "src/SparseCore/SparseView.h" +#include "src/SparseCore/SparseDiagonalProduct.h" +#include "src/SparseCore/ConservativeSparseSparseProduct.h" +#include "src/SparseCore/SparseSparseProductWithPruning.h" +#include "src/SparseCore/SparseProduct.h" +#include "src/SparseCore/SparseDenseProduct.h" +#include "src/SparseCore/SparseSelfAdjointView.h" +#include "src/SparseCore/SparseTriangularView.h" +#include "src/SparseCore/TriangularSolver.h" +#include "src/SparseCore/SparsePermutation.h" +#include "src/SparseCore/SparseFuzzy.h" +#include "src/SparseCore/SparseSolverBase.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SPARSECORE_MODULE_H + diff --git a/Vendor/eigen/Eigen/SparseLU b/Vendor/eigen/Eigen/SparseLU new file mode 100644 index 0000000..37c4a5c --- /dev/null +++ b/Vendor/eigen/Eigen/SparseLU @@ -0,0 +1,50 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2012 Désiré Nuentsa-Wakam +// Copyright (C) 2012 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSELU_MODULE_H +#define EIGEN_SPARSELU_MODULE_H + +#include "SparseCore" + +/** + * \defgroup SparseLU_Module SparseLU module + * This module defines a supernodal factorization of general sparse matrices. + * The code is fully optimized for supernode-panel updates with specialized kernels. + * Please, see the documentation of the SparseLU class for more details. + */ + +// Ordering interface +#include "OrderingMethods" + +#include "src/Core/util/DisableStupidWarnings.h" + +#include "src/SparseLU/SparseLU_gemm_kernel.h" + +#include "src/SparseLU/SparseLU_Structs.h" +#include "src/SparseLU/SparseLU_SupernodalMatrix.h" +#include "src/SparseLU/SparseLUImpl.h" +#include "src/SparseCore/SparseColEtree.h" +#include "src/SparseLU/SparseLU_Memory.h" +#include "src/SparseLU/SparseLU_heap_relax_snode.h" +#include "src/SparseLU/SparseLU_relax_snode.h" +#include "src/SparseLU/SparseLU_pivotL.h" +#include "src/SparseLU/SparseLU_panel_dfs.h" +#include "src/SparseLU/SparseLU_kernel_bmod.h" +#include "src/SparseLU/SparseLU_panel_bmod.h" +#include "src/SparseLU/SparseLU_column_dfs.h" +#include "src/SparseLU/SparseLU_column_bmod.h" +#include "src/SparseLU/SparseLU_copy_to_ucol.h" +#include "src/SparseLU/SparseLU_pruneL.h" +#include "src/SparseLU/SparseLU_Utils.h" +#include "src/SparseLU/SparseLU.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SPARSELU_MODULE_H diff --git a/Vendor/eigen/Eigen/SparseQR b/Vendor/eigen/Eigen/SparseQR new file mode 100644 index 0000000..f5fc5fa --- /dev/null +++ b/Vendor/eigen/Eigen/SparseQR @@ -0,0 +1,36 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SPARSEQR_MODULE_H +#define EIGEN_SPARSEQR_MODULE_H + +#include "SparseCore" +#include "OrderingMethods" +#include "src/Core/util/DisableStupidWarnings.h" + +/** \defgroup SparseQR_Module SparseQR module + * \brief Provides QR decomposition for sparse matrices + * + * This module provides a simplicial version of the left-looking Sparse QR decomposition. + * The columns of the input matrix should be reordered to limit the fill-in during the + * decomposition. Built-in methods (COLAMD, AMD) or external methods (METIS) can be used to this end. + * See the \link OrderingMethods_Module OrderingMethods\endlink module for the list + * of built-in and external ordering methods. + * + * \code + * #include + * \endcode + * + * + */ + +#include "src/SparseCore/SparseColEtree.h" +#include "src/SparseQR/SparseQR.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif diff --git a/Vendor/eigen/Eigen/StdDeque b/Vendor/eigen/Eigen/StdDeque new file mode 100644 index 0000000..bc68397 --- /dev/null +++ b/Vendor/eigen/Eigen/StdDeque @@ -0,0 +1,27 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009 Hauke Heibel +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_STDDEQUE_MODULE_H +#define EIGEN_STDDEQUE_MODULE_H + +#include "Core" +#include + +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ + +#define EIGEN_DEFINE_STL_DEQUE_SPECIALIZATION(...) + +#else + +#include "src/StlSupport/StdDeque.h" + +#endif + +#endif // EIGEN_STDDEQUE_MODULE_H diff --git a/Vendor/eigen/Eigen/StdList b/Vendor/eigen/Eigen/StdList new file mode 100644 index 0000000..4c6262c --- /dev/null +++ b/Vendor/eigen/Eigen/StdList @@ -0,0 +1,26 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Hauke Heibel +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_STDLIST_MODULE_H +#define EIGEN_STDLIST_MODULE_H + +#include "Core" +#include + +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ + +#define EIGEN_DEFINE_STL_LIST_SPECIALIZATION(...) + +#else + +#include "src/StlSupport/StdList.h" + +#endif + +#endif // EIGEN_STDLIST_MODULE_H diff --git a/Vendor/eigen/Eigen/StdVector b/Vendor/eigen/Eigen/StdVector new file mode 100644 index 0000000..0c4697a --- /dev/null +++ b/Vendor/eigen/Eigen/StdVector @@ -0,0 +1,27 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009 Hauke Heibel +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_STDVECTOR_MODULE_H +#define EIGEN_STDVECTOR_MODULE_H + +#include "Core" +#include + +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ + +#define EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(...) + +#else + +#include "src/StlSupport/StdVector.h" + +#endif + +#endif // EIGEN_STDVECTOR_MODULE_H diff --git a/Vendor/eigen/Eigen/SuperLUSupport b/Vendor/eigen/Eigen/SuperLUSupport new file mode 100644 index 0000000..59312a8 --- /dev/null +++ b/Vendor/eigen/Eigen/SuperLUSupport @@ -0,0 +1,64 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SUPERLUSUPPORT_MODULE_H +#define EIGEN_SUPERLUSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +#ifdef EMPTY +#define EIGEN_EMPTY_WAS_ALREADY_DEFINED +#endif + +typedef int int_t; +#include +#include +#include + +// slu_util.h defines a preprocessor token named EMPTY which is really polluting, +// so we remove it in favor of a SUPERLU_EMPTY token. +// If EMPTY was already defined then we don't undef it. + +#if defined(EIGEN_EMPTY_WAS_ALREADY_DEFINED) +# undef EIGEN_EMPTY_WAS_ALREADY_DEFINED +#elif defined(EMPTY) +# undef EMPTY +#endif + +#define SUPERLU_EMPTY (-1) + +namespace Eigen { struct SluMatrix; } + +/** \ingroup Support_modules + * \defgroup SuperLUSupport_Module SuperLUSupport module + * + * This module provides an interface to the SuperLU library. + * It provides the following factorization class: + * - class SuperLU: a supernodal sequential LU factorization. + * - class SuperILU: a supernodal sequential incomplete LU factorization (to be used as a preconditioner for iterative methods). + * + * \warning This wrapper requires at least versions 4.0 of SuperLU. The 3.x versions are not supported. + * + * \warning When including this module, you have to use SUPERLU_EMPTY instead of EMPTY which is no longer defined because it is too polluting. + * + * \code + * #include + * \endcode + * + * In order to use this module, the superlu headers must be accessible from the include paths, and your binary must be linked to the superlu library and its dependencies. + * The dependencies depend on how superlu has been compiled. + * For a cmake based project, you can use our FindSuperLU.cmake module to help you in this task. + * + */ + +#include "src/SuperLUSupport/SuperLUSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_SUPERLUSUPPORT_MODULE_H diff --git a/Vendor/eigen/Eigen/UmfPackSupport b/Vendor/eigen/Eigen/UmfPackSupport new file mode 100644 index 0000000..00eec80 --- /dev/null +++ b/Vendor/eigen/Eigen/UmfPackSupport @@ -0,0 +1,40 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_UMFPACKSUPPORT_MODULE_H +#define EIGEN_UMFPACKSUPPORT_MODULE_H + +#include "SparseCore" + +#include "src/Core/util/DisableStupidWarnings.h" + +extern "C" { +#include +} + +/** \ingroup Support_modules + * \defgroup UmfPackSupport_Module UmfPackSupport module + * + * This module provides an interface to the UmfPack library which is part of the suitesparse package. + * It provides the following factorization class: + * - class UmfPackLU: a multifrontal sequential LU factorization. + * + * \code + * #include + * \endcode + * + * In order to use this module, the umfpack headers must be accessible from the include paths, and your binary must be linked to the umfpack library and its dependencies. + * The dependencies depend on how umfpack has been compiled. + * For a cmake based project, you can use our FindUmfPack.cmake module to help you in this task. + * + */ + +#include "src/UmfPackSupport/UmfPackSupport.h" + +#include "src/Core/util/ReenableStupidWarnings.h" + +#endif // EIGEN_UMFPACKSUPPORT_MODULE_H diff --git a/Vendor/eigen/Eigen/src/Cholesky/LDLT.h b/Vendor/eigen/Eigen/src/Cholesky/LDLT.h new file mode 100644 index 0000000..1013ca0 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Cholesky/LDLT.h @@ -0,0 +1,688 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2011 Gael Guennebaud +// Copyright (C) 2009 Keir Mierle +// Copyright (C) 2009 Benoit Jacob +// Copyright (C) 2011 Timothy E. Holy +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_LDLT_H +#define EIGEN_LDLT_H + +namespace Eigen { + +namespace internal { + template struct traits > + : traits<_MatrixType> + { + typedef MatrixXpr XprKind; + typedef SolverStorage StorageKind; + typedef int StorageIndex; + enum { Flags = 0 }; + }; + + template struct LDLT_Traits; + + // PositiveSemiDef means positive semi-definite and non-zero; same for NegativeSemiDef + enum SignMatrix { PositiveSemiDef, NegativeSemiDef, ZeroSign, Indefinite }; +} + +/** \ingroup Cholesky_Module + * + * \class LDLT + * + * \brief Robust Cholesky decomposition of a matrix with pivoting + * + * \tparam _MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition + * \tparam _UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. + * The other triangular part won't be read. + * + * Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite + * matrix \f$ A \f$ such that \f$ A = P^TLDL^*P \f$, where P is a permutation matrix, L + * is lower triangular with a unit diagonal and D is a diagonal matrix. + * + * The decomposition uses pivoting to ensure stability, so that D will have + * zeros in the bottom right rank(A) - n submatrix. Avoiding the square root + * on D also stabilizes the computation. + * + * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky + * decomposition to determine whether a system of equations has a solution. + * + * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism. + * + * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt(), class LLT + */ +template class LDLT + : public SolverBase > +{ + public: + typedef _MatrixType MatrixType; + typedef SolverBase Base; + friend class SolverBase; + + EIGEN_GENERIC_PUBLIC_INTERFACE(LDLT) + enum { + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + UpLo = _UpLo + }; + typedef Matrix TmpMatrixType; + + typedef Transpositions TranspositionType; + typedef PermutationMatrix PermutationType; + + typedef internal::LDLT_Traits Traits; + + /** \brief Default Constructor. + * + * The default constructor is useful in cases in which the user intends to + * perform decompositions via LDLT::compute(const MatrixType&). + */ + LDLT() + : m_matrix(), + m_transpositions(), + m_sign(internal::ZeroSign), + m_isInitialized(false) + {} + + /** \brief Default Constructor with memory preallocation + * + * Like the default constructor but with preallocation of the internal data + * according to the specified problem \a size. + * \sa LDLT() + */ + explicit LDLT(Index size) + : m_matrix(size, size), + m_transpositions(size), + m_temporary(size), + m_sign(internal::ZeroSign), + m_isInitialized(false) + {} + + /** \brief Constructor with decomposition + * + * This calculates the decomposition for the input \a matrix. + * + * \sa LDLT(Index size) + */ + template + explicit LDLT(const EigenBase& matrix) + : m_matrix(matrix.rows(), matrix.cols()), + m_transpositions(matrix.rows()), + m_temporary(matrix.rows()), + m_sign(internal::ZeroSign), + m_isInitialized(false) + { + compute(matrix.derived()); + } + + /** \brief Constructs a LDLT factorization from a given matrix + * + * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when \c MatrixType is a Eigen::Ref. + * + * \sa LDLT(const EigenBase&) + */ + template + explicit LDLT(EigenBase& matrix) + : m_matrix(matrix.derived()), + m_transpositions(matrix.rows()), + m_temporary(matrix.rows()), + m_sign(internal::ZeroSign), + m_isInitialized(false) + { + compute(matrix.derived()); + } + + /** Clear any existing decomposition + * \sa rankUpdate(w,sigma) + */ + void setZero() + { + m_isInitialized = false; + } + + /** \returns a view of the upper triangular matrix U */ + inline typename Traits::MatrixU matrixU() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return Traits::getU(m_matrix); + } + + /** \returns a view of the lower triangular matrix L */ + inline typename Traits::MatrixL matrixL() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return Traits::getL(m_matrix); + } + + /** \returns the permutation matrix P as a transposition sequence. + */ + inline const TranspositionType& transpositionsP() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return m_transpositions; + } + + /** \returns the coefficients of the diagonal matrix D */ + inline Diagonal vectorD() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return m_matrix.diagonal(); + } + + /** \returns true if the matrix is positive (semidefinite) */ + inline bool isPositive() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign; + } + + /** \returns true if the matrix is negative (semidefinite) */ + inline bool isNegative(void) const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign; + } + + #ifdef EIGEN_PARSED_BY_DOXYGEN + /** \returns a solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * This function also supports in-place solves using the syntax x = decompositionObject.solve(x) . + * + * \note_about_checking_solutions + * + * More precisely, this method solves \f$ A x = b \f$ using the decomposition \f$ A = P^T L D L^* P \f$ + * by solving the systems \f$ P^T y_1 = b \f$, \f$ L y_2 = y_1 \f$, \f$ D y_3 = y_2 \f$, + * \f$ L^* y_4 = y_3 \f$ and \f$ P x = y_4 \f$ in succession. If the matrix \f$ A \f$ is singular, then + * \f$ D \f$ will also be singular (all the other matrices are invertible). In that case, the + * least-square solution of \f$ D y_3 = y_2 \f$ is computed. This does not mean that this function + * computes the least-square solution of \f$ A x = b \f$ if \f$ A \f$ is singular. + * + * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt() + */ + template + inline const Solve + solve(const MatrixBase& b) const; + #endif + + template + bool solveInPlace(MatrixBase &bAndX) const; + + template + LDLT& compute(const EigenBase& matrix); + + /** \returns an estimate of the reciprocal condition number of the matrix of + * which \c *this is the LDLT decomposition. + */ + RealScalar rcond() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return internal::rcond_estimate_helper(m_l1_norm, *this); + } + + template + LDLT& rankUpdate(const MatrixBase& w, const RealScalar& alpha=1); + + /** \returns the internal LDLT decomposition matrix + * + * TODO: document the storage layout + */ + inline const MatrixType& matrixLDLT() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return m_matrix; + } + + MatrixType reconstructedMatrix() const; + + /** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix is self-adjoint. + * + * This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as: + * \code x = decomposition.adjoint().solve(b) \endcode + */ + const LDLT& adjoint() const { return *this; }; + + EIGEN_DEVICE_FUNC inline EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC inline EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT { return m_matrix.cols(); } + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was successful, + * \c NumericalIssue if the factorization failed because of a zero pivot. + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return m_info; + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + void _solve_impl(const RhsType &rhs, DstType &dst) const; + + template + void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const; + #endif + + protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + /** \internal + * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. + * The strict upper part is used during the decomposition, the strict lower + * part correspond to the coefficients of L (its diagonal is equal to 1 and + * is not stored), and the diagonal entries correspond to D. + */ + MatrixType m_matrix; + RealScalar m_l1_norm; + TranspositionType m_transpositions; + TmpMatrixType m_temporary; + internal::SignMatrix m_sign; + bool m_isInitialized; + ComputationInfo m_info; +}; + +namespace internal { + +template struct ldlt_inplace; + +template<> struct ldlt_inplace +{ + template + static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) + { + using std::abs; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename TranspositionType::StorageIndex IndexType; + eigen_assert(mat.rows()==mat.cols()); + const Index size = mat.rows(); + bool found_zero_pivot = false; + bool ret = true; + + if (size <= 1) + { + transpositions.setIdentity(); + if(size==0) sign = ZeroSign; + else if (numext::real(mat.coeff(0,0)) > static_cast(0) ) sign = PositiveSemiDef; + else if (numext::real(mat.coeff(0,0)) < static_cast(0)) sign = NegativeSemiDef; + else sign = ZeroSign; + return true; + } + + for (Index k = 0; k < size; ++k) + { + // Find largest diagonal element + Index index_of_biggest_in_corner; + mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); + index_of_biggest_in_corner += k; + + transpositions.coeffRef(k) = IndexType(index_of_biggest_in_corner); + if(k != index_of_biggest_in_corner) + { + // apply the transposition while taking care to consider only + // the lower triangular part + Index s = size-index_of_biggest_in_corner-1; // trailing size after the biggest element + mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); + mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); + std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner)); + for(Index i=k+1;i::IsComplex) + mat.coeffRef(index_of_biggest_in_corner,k) = numext::conj(mat.coeff(index_of_biggest_in_corner,k)); + } + + // partition the matrix: + // A00 | - | - + // lu = A10 | A11 | - + // A20 | A21 | A22 + Index rs = size - k - 1; + Block A21(mat,k+1,k,rs,1); + Block A10(mat,k,0,1,k); + Block A20(mat,k+1,0,rs,k); + + if(k>0) + { + temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint(); + mat.coeffRef(k,k) -= (A10 * temp.head(k)).value(); + if(rs>0) + A21.noalias() -= A20 * temp.head(k); + } + + // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot + // was smaller than the cutoff value. However, since LDLT is not rank-revealing + // we should only make sure that we do not introduce INF or NaN values. + // Remark that LAPACK also uses 0 as the cutoff value. + RealScalar realAkk = numext::real(mat.coeffRef(k,k)); + bool pivot_is_valid = (abs(realAkk) > RealScalar(0)); + + if(k==0 && !pivot_is_valid) + { + // The entire diagonal is zero, there is nothing more to do + // except filling the transpositions, and checking whether the matrix is zero. + sign = ZeroSign; + for(Index j = 0; j0) && pivot_is_valid) + A21 /= realAkk; + else if(rs>0) + ret = ret && (A21.array()==Scalar(0)).all(); + + if(found_zero_pivot && pivot_is_valid) ret = false; // factorization failed + else if(!pivot_is_valid) found_zero_pivot = true; + + if (sign == PositiveSemiDef) { + if (realAkk < static_cast(0)) sign = Indefinite; + } else if (sign == NegativeSemiDef) { + if (realAkk > static_cast(0)) sign = Indefinite; + } else if (sign == ZeroSign) { + if (realAkk > static_cast(0)) sign = PositiveSemiDef; + else if (realAkk < static_cast(0)) sign = NegativeSemiDef; + } + } + + return ret; + } + + // Reference for the algorithm: Davis and Hager, "Multiple Rank + // Modifications of a Sparse Cholesky Factorization" (Algorithm 1) + // Trivial rearrangements of their computations (Timothy E. Holy) + // allow their algorithm to work for rank-1 updates even if the + // original matrix is not of full rank. + // Here only rank-1 updates are implemented, to reduce the + // requirement for intermediate storage and improve accuracy + template + static bool updateInPlace(MatrixType& mat, MatrixBase& w, const typename MatrixType::RealScalar& sigma=1) + { + using numext::isfinite; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + + const Index size = mat.rows(); + eigen_assert(mat.cols() == size && w.size()==size); + + RealScalar alpha = 1; + + // Apply the update + for (Index j = 0; j < size; j++) + { + // Check for termination due to an original decomposition of low-rank + if (!(isfinite)(alpha)) + break; + + // Update the diagonal terms + RealScalar dj = numext::real(mat.coeff(j,j)); + Scalar wj = w.coeff(j); + RealScalar swj2 = sigma*numext::abs2(wj); + RealScalar gamma = dj*alpha + swj2; + + mat.coeffRef(j,j) += swj2/alpha; + alpha += swj2/dj; + + + // Update the terms of L + Index rs = size-j-1; + w.tail(rs) -= wj * mat.col(j).tail(rs); + if(gamma != 0) + mat.col(j).tail(rs) += (sigma*numext::conj(wj)/gamma)*w.tail(rs); + } + return true; + } + + template + static bool update(MatrixType& mat, const TranspositionType& transpositions, Workspace& tmp, const WType& w, const typename MatrixType::RealScalar& sigma=1) + { + // Apply the permutation to the input w + tmp = transpositions * w; + + return ldlt_inplace::updateInPlace(mat,tmp,sigma); + } +}; + +template<> struct ldlt_inplace +{ + template + static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) + { + Transpose matt(mat); + return ldlt_inplace::unblocked(matt, transpositions, temp, sign); + } + + template + static EIGEN_STRONG_INLINE bool update(MatrixType& mat, TranspositionType& transpositions, Workspace& tmp, WType& w, const typename MatrixType::RealScalar& sigma=1) + { + Transpose matt(mat); + return ldlt_inplace::update(matt, transpositions, tmp, w.conjugate(), sigma); + } +}; + +template struct LDLT_Traits +{ + typedef const TriangularView MatrixL; + typedef const TriangularView MatrixU; + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } +}; + +template struct LDLT_Traits +{ + typedef const TriangularView MatrixL; + typedef const TriangularView MatrixU; + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } +}; + +} // end namespace internal + +/** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix + */ +template +template +LDLT& LDLT::compute(const EigenBase& a) +{ + check_template_parameters(); + + eigen_assert(a.rows()==a.cols()); + const Index size = a.rows(); + + m_matrix = a.derived(); + + // Compute matrix L1 norm = max abs column sum. + m_l1_norm = RealScalar(0); + // TODO move this code to SelfAdjointView + for (Index col = 0; col < size; ++col) { + RealScalar abs_col_sum; + if (_UpLo == Lower) + abs_col_sum = m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>(); + else + abs_col_sum = m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>(); + if (abs_col_sum > m_l1_norm) + m_l1_norm = abs_col_sum; + } + + m_transpositions.resize(size); + m_isInitialized = false; + m_temporary.resize(size); + m_sign = internal::ZeroSign; + + m_info = internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, m_sign) ? Success : NumericalIssue; + + m_isInitialized = true; + return *this; +} + +/** Update the LDLT decomposition: given A = L D L^T, efficiently compute the decomposition of A + sigma w w^T. + * \param w a vector to be incorporated into the decomposition. + * \param sigma a scalar, +1 for updates and -1 for "downdates," which correspond to removing previously-added column vectors. Optional; default value is +1. + * \sa setZero() + */ +template +template +LDLT& LDLT::rankUpdate(const MatrixBase& w, const typename LDLT::RealScalar& sigma) +{ + typedef typename TranspositionType::StorageIndex IndexType; + const Index size = w.rows(); + if (m_isInitialized) + { + eigen_assert(m_matrix.rows()==size); + } + else + { + m_matrix.resize(size,size); + m_matrix.setZero(); + m_transpositions.resize(size); + for (Index i = 0; i < size; i++) + m_transpositions.coeffRef(i) = IndexType(i); + m_temporary.resize(size); + m_sign = sigma>=0 ? internal::PositiveSemiDef : internal::NegativeSemiDef; + m_isInitialized = true; + } + + internal::ldlt_inplace::update(m_matrix, m_transpositions, m_temporary, w, sigma); + + return *this; +} + +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + _solve_impl_transposed(rhs, dst); +} + +template +template +void LDLT<_MatrixType,_UpLo>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const +{ + // dst = P b + dst = m_transpositions * rhs; + + // dst = L^-1 (P b) + // dst = L^-*T (P b) + matrixL().template conjugateIf().solveInPlace(dst); + + // dst = D^-* (L^-1 P b) + // dst = D^-1 (L^-*T P b) + // more precisely, use pseudo-inverse of D (see bug 241) + using std::abs; + const typename Diagonal::RealReturnType vecD(vectorD()); + // In some previous versions, tolerance was set to the max of 1/highest (or rather numeric_limits::min()) + // and the maximal diagonal entry * epsilon as motivated by LAPACK's xGELSS: + // RealScalar tolerance = numext::maxi(vecD.array().abs().maxCoeff() * NumTraits::epsilon(),RealScalar(1) / NumTraits::highest()); + // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest + // diagonal element is not well justified and leads to numerical issues in some cases. + // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. + // Using numeric_limits::min() gives us more robustness to denormals. + RealScalar tolerance = (std::numeric_limits::min)(); + for (Index i = 0; i < vecD.size(); ++i) + { + if(abs(vecD(i)) > tolerance) + dst.row(i) /= vecD(i); + else + dst.row(i).setZero(); + } + + // dst = L^-* (D^-* L^-1 P b) + // dst = L^-T (D^-1 L^-*T P b) + matrixL().transpose().template conjugateIf().solveInPlace(dst); + + // dst = P^T (L^-* D^-* L^-1 P b) = A^-1 b + // dst = P^-T (L^-T D^-1 L^-*T P b) = A^-1 b + dst = m_transpositions.transpose() * dst; +} +#endif + +/** \internal use x = ldlt_object.solve(x); + * + * This is the \em in-place version of solve(). + * + * \param bAndX represents both the right-hand side matrix b and result x. + * + * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. + * + * This version avoids a copy when the right hand side matrix b is not + * needed anymore. + * + * \sa LDLT::solve(), MatrixBase::ldlt() + */ +template +template +bool LDLT::solveInPlace(MatrixBase &bAndX) const +{ + eigen_assert(m_isInitialized && "LDLT is not initialized."); + eigen_assert(m_matrix.rows() == bAndX.rows()); + + bAndX = this->solve(bAndX); + + return true; +} + +/** \returns the matrix represented by the decomposition, + * i.e., it returns the product: P^T L D L^* P. + * This function is provided for debug purpose. */ +template +MatrixType LDLT::reconstructedMatrix() const +{ + eigen_assert(m_isInitialized && "LDLT is not initialized."); + const Index size = m_matrix.rows(); + MatrixType res(size,size); + + // P + res.setIdentity(); + res = transpositionsP() * res; + // L^* P + res = matrixU() * res; + // D(L^*P) + res = vectorD().real().asDiagonal() * res; + // L(DL^*P) + res = matrixL() * res; + // P^T (LDL^*P) + res = transpositionsP().transpose() * res; + + return res; +} + +/** \cholesky_module + * \returns the Cholesky decomposition with full pivoting without square root of \c *this + * \sa MatrixBase::ldlt() + */ +template +inline const LDLT::PlainObject, UpLo> +SelfAdjointView::ldlt() const +{ + return LDLT(m_matrix); +} + +/** \cholesky_module + * \returns the Cholesky decomposition with full pivoting without square root of \c *this + * \sa SelfAdjointView::ldlt() + */ +template +inline const LDLT::PlainObject> +MatrixBase::ldlt() const +{ + return LDLT(derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_LDLT_H diff --git a/Vendor/eigen/Eigen/src/Cholesky/LLT.h b/Vendor/eigen/Eigen/src/Cholesky/LLT.h new file mode 100644 index 0000000..8c9b2b3 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Cholesky/LLT.h @@ -0,0 +1,558 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_LLT_H +#define EIGEN_LLT_H + +namespace Eigen { + +namespace internal{ + +template struct traits > + : traits<_MatrixType> +{ + typedef MatrixXpr XprKind; + typedef SolverStorage StorageKind; + typedef int StorageIndex; + enum { Flags = 0 }; +}; + +template struct LLT_Traits; +} + +/** \ingroup Cholesky_Module + * + * \class LLT + * + * \brief Standard Cholesky decomposition (LL^T) of a matrix and associated features + * + * \tparam _MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition + * \tparam _UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. + * The other triangular part won't be read. + * + * This class performs a LL^T Cholesky decomposition of a symmetric, positive definite + * matrix A such that A = LL^* = U^*U, where L is lower triangular. + * + * While the Cholesky decomposition is particularly useful to solve selfadjoint problems like D^*D x = b, + * for that purpose, we recommend the Cholesky decomposition without square root which is more stable + * and even faster. Nevertheless, this standard Cholesky decomposition remains useful in many other + * situations like generalised eigen problems with hermitian matrices. + * + * Remember that Cholesky decompositions are not rank-revealing. This LLT decomposition is only stable on positive definite matrices, + * use LDLT instead for the semidefinite case. Also, do not use a Cholesky decomposition to determine whether a system of equations + * has a solution. + * + * Example: \include LLT_example.cpp + * Output: \verbinclude LLT_example.out + * + * \b Performance: for best performance, it is recommended to use a column-major storage format + * with the Lower triangular part (the default), or, equivalently, a row-major storage format + * with the Upper triangular part. Otherwise, you might get a 20% slowdown for the full factorization + * step, and rank-updates can be up to 3 times slower. + * + * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism. + * + * Note that during the decomposition, only the lower (or upper, as defined by _UpLo) triangular part of A is considered. + * Therefore, the strict lower part does not have to store correct values. + * + * \sa MatrixBase::llt(), SelfAdjointView::llt(), class LDLT + */ +template class LLT + : public SolverBase > +{ + public: + typedef _MatrixType MatrixType; + typedef SolverBase Base; + friend class SolverBase; + + EIGEN_GENERIC_PUBLIC_INTERFACE(LLT) + enum { + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime + }; + + enum { + PacketSize = internal::packet_traits::size, + AlignmentMask = int(PacketSize)-1, + UpLo = _UpLo + }; + + typedef internal::LLT_Traits Traits; + + /** + * \brief Default Constructor. + * + * The default constructor is useful in cases in which the user intends to + * perform decompositions via LLT::compute(const MatrixType&). + */ + LLT() : m_matrix(), m_isInitialized(false) {} + + /** \brief Default Constructor with memory preallocation + * + * Like the default constructor but with preallocation of the internal data + * according to the specified problem \a size. + * \sa LLT() + */ + explicit LLT(Index size) : m_matrix(size, size), + m_isInitialized(false) {} + + template + explicit LLT(const EigenBase& matrix) + : m_matrix(matrix.rows(), matrix.cols()), + m_isInitialized(false) + { + compute(matrix.derived()); + } + + /** \brief Constructs a LLT factorization from a given matrix + * + * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when + * \c MatrixType is a Eigen::Ref. + * + * \sa LLT(const EigenBase&) + */ + template + explicit LLT(EigenBase& matrix) + : m_matrix(matrix.derived()), + m_isInitialized(false) + { + compute(matrix.derived()); + } + + /** \returns a view of the upper triangular matrix U */ + inline typename Traits::MatrixU matrixU() const + { + eigen_assert(m_isInitialized && "LLT is not initialized."); + return Traits::getU(m_matrix); + } + + /** \returns a view of the lower triangular matrix L */ + inline typename Traits::MatrixL matrixL() const + { + eigen_assert(m_isInitialized && "LLT is not initialized."); + return Traits::getL(m_matrix); + } + + #ifdef EIGEN_PARSED_BY_DOXYGEN + /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. + * + * Since this LLT class assumes anyway that the matrix A is invertible, the solution + * theoretically exists and is unique regardless of b. + * + * Example: \include LLT_solve.cpp + * Output: \verbinclude LLT_solve.out + * + * \sa solveInPlace(), MatrixBase::llt(), SelfAdjointView::llt() + */ + template + inline const Solve + solve(const MatrixBase& b) const; + #endif + + template + void solveInPlace(const MatrixBase &bAndX) const; + + template + LLT& compute(const EigenBase& matrix); + + /** \returns an estimate of the reciprocal condition number of the matrix of + * which \c *this is the Cholesky decomposition. + */ + RealScalar rcond() const + { + eigen_assert(m_isInitialized && "LLT is not initialized."); + eigen_assert(m_info == Success && "LLT failed because matrix appears to be negative"); + return internal::rcond_estimate_helper(m_l1_norm, *this); + } + + /** \returns the LLT decomposition matrix + * + * TODO: document the storage layout + */ + inline const MatrixType& matrixLLT() const + { + eigen_assert(m_isInitialized && "LLT is not initialized."); + return m_matrix; + } + + MatrixType reconstructedMatrix() const; + + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was successful, + * \c NumericalIssue if the matrix.appears not to be positive definite. + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "LLT is not initialized."); + return m_info; + } + + /** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix is self-adjoint. + * + * This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as: + * \code x = decomposition.adjoint().solve(b) \endcode + */ + const LLT& adjoint() const EIGEN_NOEXCEPT { return *this; }; + + inline EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT { return m_matrix.rows(); } + inline EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT { return m_matrix.cols(); } + + template + LLT & rankUpdate(const VectorType& vec, const RealScalar& sigma = 1); + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + void _solve_impl(const RhsType &rhs, DstType &dst) const; + + template + void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const; + #endif + + protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + /** \internal + * Used to compute and store L + * The strict upper part is not used and even not initialized. + */ + MatrixType m_matrix; + RealScalar m_l1_norm; + bool m_isInitialized; + ComputationInfo m_info; +}; + +namespace internal { + +template struct llt_inplace; + +template +static Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) +{ + using std::sqrt; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::ColXpr ColXpr; + typedef typename internal::remove_all::type ColXprCleaned; + typedef typename ColXprCleaned::SegmentReturnType ColXprSegment; + typedef Matrix TempVectorType; + typedef typename TempVectorType::SegmentReturnType TempVecSegment; + + Index n = mat.cols(); + eigen_assert(mat.rows()==n && vec.size()==n); + + TempVectorType temp; + + if(sigma>0) + { + // This version is based on Givens rotations. + // It is faster than the other one below, but only works for updates, + // i.e., for sigma > 0 + temp = sqrt(sigma) * vec; + + for(Index i=0; i g; + g.makeGivens(mat(i,i), -temp(i), &mat(i,i)); + + Index rs = n-i-1; + if(rs>0) + { + ColXprSegment x(mat.col(i).tail(rs)); + TempVecSegment y(temp.tail(rs)); + apply_rotation_in_the_plane(x, y, g); + } + } + } + else + { + temp = vec; + RealScalar beta = 1; + for(Index j=0; j struct llt_inplace +{ + typedef typename NumTraits::Real RealScalar; + template + static Index unblocked(MatrixType& mat) + { + using std::sqrt; + + eigen_assert(mat.rows()==mat.cols()); + const Index size = mat.rows(); + for(Index k = 0; k < size; ++k) + { + Index rs = size-k-1; // remaining size + + Block A21(mat,k+1,k,rs,1); + Block A10(mat,k,0,1,k); + Block A20(mat,k+1,0,rs,k); + + RealScalar x = numext::real(mat.coeff(k,k)); + if (k>0) x -= A10.squaredNorm(); + if (x<=RealScalar(0)) + return k; + mat.coeffRef(k,k) = x = sqrt(x); + if (k>0 && rs>0) A21.noalias() -= A20 * A10.adjoint(); + if (rs>0) A21 /= x; + } + return -1; + } + + template + static Index blocked(MatrixType& m) + { + eigen_assert(m.rows()==m.cols()); + Index size = m.rows(); + if(size<32) + return unblocked(m); + + Index blockSize = size/8; + blockSize = (blockSize/16)*16; + blockSize = (std::min)((std::max)(blockSize,Index(8)), Index(128)); + + for (Index k=0; k A11(m,k, k, bs,bs); + Block A21(m,k+bs,k, rs,bs); + Block A22(m,k+bs,k+bs,rs,rs); + + Index ret; + if((ret=unblocked(A11))>=0) return k+ret; + if(rs>0) A11.adjoint().template triangularView().template solveInPlace(A21); + if(rs>0) A22.template selfadjointView().rankUpdate(A21,typename NumTraits::Literal(-1)); // bottleneck + } + return -1; + } + + template + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) + { + return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); + } +}; + +template struct llt_inplace +{ + typedef typename NumTraits::Real RealScalar; + + template + static EIGEN_STRONG_INLINE Index unblocked(MatrixType& mat) + { + Transpose matt(mat); + return llt_inplace::unblocked(matt); + } + template + static EIGEN_STRONG_INLINE Index blocked(MatrixType& mat) + { + Transpose matt(mat); + return llt_inplace::blocked(matt); + } + template + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) + { + Transpose matt(mat); + return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); + } +}; + +template struct LLT_Traits +{ + typedef const TriangularView MatrixL; + typedef const TriangularView MatrixU; + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } + static bool inplace_decomposition(MatrixType& m) + { return llt_inplace::blocked(m)==-1; } +}; + +template struct LLT_Traits +{ + typedef const TriangularView MatrixL; + typedef const TriangularView MatrixU; + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } + static bool inplace_decomposition(MatrixType& m) + { return llt_inplace::blocked(m)==-1; } +}; + +} // end namespace internal + +/** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix + * + * \returns a reference to *this + * + * Example: \include TutorialLinAlgComputeTwice.cpp + * Output: \verbinclude TutorialLinAlgComputeTwice.out + */ +template +template +LLT& LLT::compute(const EigenBase& a) +{ + check_template_parameters(); + + eigen_assert(a.rows()==a.cols()); + const Index size = a.rows(); + m_matrix.resize(size, size); + if (!internal::is_same_dense(m_matrix, a.derived())) + m_matrix = a.derived(); + + // Compute matrix L1 norm = max abs column sum. + m_l1_norm = RealScalar(0); + // TODO move this code to SelfAdjointView + for (Index col = 0; col < size; ++col) { + RealScalar abs_col_sum; + if (_UpLo == Lower) + abs_col_sum = m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>(); + else + abs_col_sum = m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>(); + if (abs_col_sum > m_l1_norm) + m_l1_norm = abs_col_sum; + } + + m_isInitialized = true; + bool ok = Traits::inplace_decomposition(m_matrix); + m_info = ok ? Success : NumericalIssue; + + return *this; +} + +/** Performs a rank one update (or dowdate) of the current decomposition. + * If A = LL^* before the rank one update, + * then after it we have LL^* = A + sigma * v v^* where \a v must be a vector + * of same dimension. + */ +template +template +LLT<_MatrixType,_UpLo> & LLT<_MatrixType,_UpLo>::rankUpdate(const VectorType& v, const RealScalar& sigma) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorType); + eigen_assert(v.size()==m_matrix.cols()); + eigen_assert(m_isInitialized); + if(internal::llt_inplace::rankUpdate(m_matrix,v,sigma)>=0) + m_info = NumericalIssue; + else + m_info = Success; + + return *this; +} + +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void LLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + _solve_impl_transposed(rhs, dst); +} + +template +template +void LLT<_MatrixType,_UpLo>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const +{ + dst = rhs; + + matrixL().template conjugateIf().solveInPlace(dst); + matrixU().template conjugateIf().solveInPlace(dst); +} +#endif + +/** \internal use x = llt_object.solve(x); + * + * This is the \em in-place version of solve(). + * + * \param bAndX represents both the right-hand side matrix b and result x. + * + * This version avoids a copy when the right hand side matrix b is not needed anymore. + * + * \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here. + * This function will const_cast it, so constness isn't honored here. + * + * \sa LLT::solve(), MatrixBase::llt() + */ +template +template +void LLT::solveInPlace(const MatrixBase &bAndX) const +{ + eigen_assert(m_isInitialized && "LLT is not initialized."); + eigen_assert(m_matrix.rows()==bAndX.rows()); + matrixL().solveInPlace(bAndX); + matrixU().solveInPlace(bAndX); +} + +/** \returns the matrix represented by the decomposition, + * i.e., it returns the product: L L^*. + * This function is provided for debug purpose. */ +template +MatrixType LLT::reconstructedMatrix() const +{ + eigen_assert(m_isInitialized && "LLT is not initialized."); + return matrixL() * matrixL().adjoint().toDenseMatrix(); +} + +/** \cholesky_module + * \returns the LLT decomposition of \c *this + * \sa SelfAdjointView::llt() + */ +template +inline const LLT::PlainObject> +MatrixBase::llt() const +{ + return LLT(derived()); +} + +/** \cholesky_module + * \returns the LLT decomposition of \c *this + * \sa SelfAdjointView::llt() + */ +template +inline const LLT::PlainObject, UpLo> +SelfAdjointView::llt() const +{ + return LLT(m_matrix); +} + +} // end namespace Eigen + +#endif // EIGEN_LLT_H diff --git a/Vendor/eigen/Eigen/src/Cholesky/LLT_LAPACKE.h b/Vendor/eigen/Eigen/src/Cholesky/LLT_LAPACKE.h new file mode 100644 index 0000000..bc6489e --- /dev/null +++ b/Vendor/eigen/Eigen/src/Cholesky/LLT_LAPACKE.h @@ -0,0 +1,99 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to LAPACKe + * LLt decomposition based on LAPACKE_?potrf function. + ******************************************************************************** +*/ + +#ifndef EIGEN_LLT_LAPACKE_H +#define EIGEN_LLT_LAPACKE_H + +namespace Eigen { + +namespace internal { + +template struct lapacke_llt; + +#define EIGEN_LAPACKE_LLT(EIGTYPE, BLASTYPE, LAPACKE_PREFIX) \ +template<> struct lapacke_llt \ +{ \ + template \ + static inline Index potrf(MatrixType& m, char uplo) \ + { \ + lapack_int matrix_order; \ + lapack_int size, lda, info, StorageOrder; \ + EIGTYPE* a; \ + eigen_assert(m.rows()==m.cols()); \ + /* Set up parameters for ?potrf */ \ + size = convert_index(m.rows()); \ + StorageOrder = MatrixType::Flags&RowMajorBit?RowMajor:ColMajor; \ + matrix_order = StorageOrder==RowMajor ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ + a = &(m.coeffRef(0,0)); \ + lda = convert_index(m.outerStride()); \ +\ + info = LAPACKE_##LAPACKE_PREFIX##potrf( matrix_order, uplo, size, (BLASTYPE*)a, lda ); \ + info = (info==0) ? -1 : info>0 ? info-1 : size; \ + return info; \ + } \ +}; \ +template<> struct llt_inplace \ +{ \ + template \ + static Index blocked(MatrixType& m) \ + { \ + return lapacke_llt::potrf(m, 'L'); \ + } \ + template \ + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ + { return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); } \ +}; \ +template<> struct llt_inplace \ +{ \ + template \ + static Index blocked(MatrixType& m) \ + { \ + return lapacke_llt::potrf(m, 'U'); \ + } \ + template \ + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ + { \ + Transpose matt(mat); \ + return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); \ + } \ +}; + +EIGEN_LAPACKE_LLT(double, double, d) +EIGEN_LAPACKE_LLT(float, float, s) +EIGEN_LAPACKE_LLT(dcomplex, lapack_complex_double, z) +EIGEN_LAPACKE_LLT(scomplex, lapack_complex_float, c) + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_LLT_LAPACKE_H diff --git a/Vendor/eigen/Eigen/src/CholmodSupport/CholmodSupport.h b/Vendor/eigen/Eigen/src/CholmodSupport/CholmodSupport.h new file mode 100644 index 0000000..adaf528 --- /dev/null +++ b/Vendor/eigen/Eigen/src/CholmodSupport/CholmodSupport.h @@ -0,0 +1,682 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CHOLMODSUPPORT_H +#define EIGEN_CHOLMODSUPPORT_H + +namespace Eigen { + +namespace internal { + +template struct cholmod_configure_matrix; + +template<> struct cholmod_configure_matrix { + template + static void run(CholmodType& mat) { + mat.xtype = CHOLMOD_REAL; + mat.dtype = CHOLMOD_DOUBLE; + } +}; + +template<> struct cholmod_configure_matrix > { + template + static void run(CholmodType& mat) { + mat.xtype = CHOLMOD_COMPLEX; + mat.dtype = CHOLMOD_DOUBLE; + } +}; + +// Other scalar types are not yet supported by Cholmod +// template<> struct cholmod_configure_matrix { +// template +// static void run(CholmodType& mat) { +// mat.xtype = CHOLMOD_REAL; +// mat.dtype = CHOLMOD_SINGLE; +// } +// }; +// +// template<> struct cholmod_configure_matrix > { +// template +// static void run(CholmodType& mat) { +// mat.xtype = CHOLMOD_COMPLEX; +// mat.dtype = CHOLMOD_SINGLE; +// } +// }; + +} // namespace internal + +/** Wraps the Eigen sparse matrix \a mat into a Cholmod sparse matrix object. + * Note that the data are shared. + */ +template +cholmod_sparse viewAsCholmod(Ref > mat) +{ + cholmod_sparse res; + res.nzmax = mat.nonZeros(); + res.nrow = mat.rows(); + res.ncol = mat.cols(); + res.p = mat.outerIndexPtr(); + res.i = mat.innerIndexPtr(); + res.x = mat.valuePtr(); + res.z = 0; + res.sorted = 1; + if(mat.isCompressed()) + { + res.packed = 1; + res.nz = 0; + } + else + { + res.packed = 0; + res.nz = mat.innerNonZeroPtr(); + } + + res.dtype = 0; + res.stype = -1; + + if (internal::is_same<_StorageIndex,int>::value) + { + res.itype = CHOLMOD_INT; + } + else if (internal::is_same<_StorageIndex,SuiteSparse_long>::value) + { + res.itype = CHOLMOD_LONG; + } + else + { + eigen_assert(false && "Index type not supported yet"); + } + + // setup res.xtype + internal::cholmod_configure_matrix<_Scalar>::run(res); + + res.stype = 0; + + return res; +} + +template +const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& mat) +{ + cholmod_sparse res = viewAsCholmod(Ref >(mat.const_cast_derived())); + return res; +} + +template +const cholmod_sparse viewAsCholmod(const SparseVector<_Scalar,_Options,_Index>& mat) +{ + cholmod_sparse res = viewAsCholmod(Ref >(mat.const_cast_derived())); + return res; +} + +/** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix. + * The data are not copied but shared. */ +template +cholmod_sparse viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) +{ + cholmod_sparse res = viewAsCholmod(Ref >(mat.matrix().const_cast_derived())); + + if(UpLo==Upper) res.stype = 1; + if(UpLo==Lower) res.stype = -1; + // swap stype for rowmajor matrices (only works for real matrices) + EIGEN_STATIC_ASSERT((_Options & RowMajorBit) == 0 || NumTraits<_Scalar>::IsComplex == 0, THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + if(_Options & RowMajorBit) res.stype *=-1; + + return res; +} + +/** Returns a view of the Eigen \b dense matrix \a mat as Cholmod dense matrix. + * The data are not copied but shared. */ +template +cholmod_dense viewAsCholmod(MatrixBase& mat) +{ + EIGEN_STATIC_ASSERT((internal::traits::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + typedef typename Derived::Scalar Scalar; + + cholmod_dense res; + res.nrow = mat.rows(); + res.ncol = mat.cols(); + res.nzmax = res.nrow * res.ncol; + res.d = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().outerStride(); + res.x = (void*)(mat.derived().data()); + res.z = 0; + + internal::cholmod_configure_matrix::run(res); + + return res; +} + +/** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix. + * The data are not copied but shared. */ +template +MappedSparseMatrix viewAsEigen(cholmod_sparse& cm) +{ + return MappedSparseMatrix + (cm.nrow, cm.ncol, static_cast(cm.p)[cm.ncol], + static_cast(cm.p), static_cast(cm.i),static_cast(cm.x) ); +} + +namespace internal { + +// template specializations for int and long that call the correct cholmod method + +#define EIGEN_CHOLMOD_SPECIALIZE0(ret, name) \ + template inline ret cm_ ## name (cholmod_common &Common) { return cholmod_ ## name (&Common); } \ + template<> inline ret cm_ ## name (cholmod_common &Common) { return cholmod_l_ ## name (&Common); } + +#define EIGEN_CHOLMOD_SPECIALIZE1(ret, name, t1, a1) \ + template inline ret cm_ ## name (t1& a1, cholmod_common &Common) { return cholmod_ ## name (&a1, &Common); } \ + template<> inline ret cm_ ## name (t1& a1, cholmod_common &Common) { return cholmod_l_ ## name (&a1, &Common); } + +EIGEN_CHOLMOD_SPECIALIZE0(int, start) +EIGEN_CHOLMOD_SPECIALIZE0(int, finish) + +EIGEN_CHOLMOD_SPECIALIZE1(int, free_factor, cholmod_factor*, L) +EIGEN_CHOLMOD_SPECIALIZE1(int, free_dense, cholmod_dense*, X) +EIGEN_CHOLMOD_SPECIALIZE1(int, free_sparse, cholmod_sparse*, A) + +EIGEN_CHOLMOD_SPECIALIZE1(cholmod_factor*, analyze, cholmod_sparse, A) + +template inline cholmod_dense* cm_solve (int sys, cholmod_factor& L, cholmod_dense& B, cholmod_common &Common) { return cholmod_solve (sys, &L, &B, &Common); } +template<> inline cholmod_dense* cm_solve (int sys, cholmod_factor& L, cholmod_dense& B, cholmod_common &Common) { return cholmod_l_solve (sys, &L, &B, &Common); } + +template inline cholmod_sparse* cm_spsolve (int sys, cholmod_factor& L, cholmod_sparse& B, cholmod_common &Common) { return cholmod_spsolve (sys, &L, &B, &Common); } +template<> inline cholmod_sparse* cm_spsolve (int sys, cholmod_factor& L, cholmod_sparse& B, cholmod_common &Common) { return cholmod_l_spsolve (sys, &L, &B, &Common); } + +template +inline int cm_factorize_p (cholmod_sparse* A, double beta[2], _StorageIndex* fset, std::size_t fsize, cholmod_factor* L, cholmod_common &Common) { return cholmod_factorize_p (A, beta, fset, fsize, L, &Common); } +template<> +inline int cm_factorize_p (cholmod_sparse* A, double beta[2], SuiteSparse_long* fset, std::size_t fsize, cholmod_factor* L, cholmod_common &Common) { return cholmod_l_factorize_p (A, beta, fset, fsize, L, &Common); } + +#undef EIGEN_CHOLMOD_SPECIALIZE0 +#undef EIGEN_CHOLMOD_SPECIALIZE1 + +} // namespace internal + + +enum CholmodMode { + CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt +}; + + +/** \ingroup CholmodSupport_Module + * \class CholmodBase + * \brief The base class for the direct Cholesky factorization of Cholmod + * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT + */ +template +class CholmodBase : public SparseSolverBase +{ + protected: + typedef SparseSolverBase Base; + using Base::derived; + using Base::m_isInitialized; + public: + typedef _MatrixType MatrixType; + enum { UpLo = _UpLo }; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef MatrixType CholMatrixType; + typedef typename MatrixType::StorageIndex StorageIndex; + enum { + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime + }; + + public: + + CholmodBase() + : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) + { + EIGEN_STATIC_ASSERT((internal::is_same::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY); + m_shiftOffset[0] = m_shiftOffset[1] = 0.0; + internal::cm_start(m_cholmod); + } + + explicit CholmodBase(const MatrixType& matrix) + : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) + { + EIGEN_STATIC_ASSERT((internal::is_same::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY); + m_shiftOffset[0] = m_shiftOffset[1] = 0.0; + internal::cm_start(m_cholmod); + compute(matrix); + } + + ~CholmodBase() + { + if(m_cholmodFactor) + internal::cm_free_factor(m_cholmodFactor, m_cholmod); + internal::cm_finish(m_cholmod); + } + + inline StorageIndex cols() const { return internal::convert_index(m_cholmodFactor->n); } + inline StorageIndex rows() const { return internal::convert_index(m_cholmodFactor->n); } + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was successful, + * \c NumericalIssue if the matrix.appears to be negative. + */ + ComputationInfo info() const + { + eigen_assert(m_isInitialized && "Decomposition is not initialized."); + return m_info; + } + + /** Computes the sparse Cholesky decomposition of \a matrix */ + Derived& compute(const MatrixType& matrix) + { + analyzePattern(matrix); + factorize(matrix); + return derived(); + } + + /** Performs a symbolic decomposition on the sparsity pattern of \a matrix. + * + * This function is particularly useful when solving for several problems having the same structure. + * + * \sa factorize() + */ + void analyzePattern(const MatrixType& matrix) + { + if(m_cholmodFactor) + { + internal::cm_free_factor(m_cholmodFactor, m_cholmod); + m_cholmodFactor = 0; + } + cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView()); + m_cholmodFactor = internal::cm_analyze(A, m_cholmod); + + this->m_isInitialized = true; + this->m_info = Success; + m_analysisIsOk = true; + m_factorizationIsOk = false; + } + + /** Performs a numeric decomposition of \a matrix + * + * The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been performed. + * + * \sa analyzePattern() + */ + void factorize(const MatrixType& matrix) + { + eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); + cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView()); + internal::cm_factorize_p(&A, m_shiftOffset, 0, 0, m_cholmodFactor, m_cholmod); + + // If the factorization failed, minor is the column at which it did. On success minor == n. + this->m_info = (m_cholmodFactor->minor == m_cholmodFactor->n ? Success : NumericalIssue); + m_factorizationIsOk = true; + } + + /** Returns a reference to the Cholmod's configuration structure to get a full control over the performed operations. + * See the Cholmod user guide for details. */ + cholmod_common& cholmod() { return m_cholmod; } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal */ + template + void _solve_impl(const MatrixBase &b, MatrixBase &dest) const + { + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + const Index size = m_cholmodFactor->n; + EIGEN_UNUSED_VARIABLE(size); + eigen_assert(size==b.rows()); + + // Cholmod needs column-major storage without inner-stride, which corresponds to the default behavior of Ref. + Ref > b_ref(b.derived()); + + cholmod_dense b_cd = viewAsCholmod(b_ref); + cholmod_dense* x_cd = internal::cm_solve(CHOLMOD_A, *m_cholmodFactor, b_cd, m_cholmod); + if(!x_cd) + { + this->m_info = NumericalIssue; + return; + } + // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) + // NOTE Actually, the copy can be avoided by calling cholmod_solve2 instead of cholmod_solve + dest = Matrix::Map(reinterpret_cast(x_cd->x),b.rows(),b.cols()); + internal::cm_free_dense(x_cd, m_cholmod); + } + + /** \internal */ + template + void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &dest) const + { + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + const Index size = m_cholmodFactor->n; + EIGEN_UNUSED_VARIABLE(size); + eigen_assert(size==b.rows()); + + // note: cs stands for Cholmod Sparse + Ref > b_ref(b.const_cast_derived()); + cholmod_sparse b_cs = viewAsCholmod(b_ref); + cholmod_sparse* x_cs = internal::cm_spsolve(CHOLMOD_A, *m_cholmodFactor, b_cs, m_cholmod); + if(!x_cs) + { + this->m_info = NumericalIssue; + return; + } + // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) + // NOTE cholmod_spsolve in fact just calls the dense solver for blocks of 4 columns at a time (similar to Eigen's sparse solver) + dest.derived() = viewAsEigen(*x_cs); + internal::cm_free_sparse(x_cs, m_cholmod); + } + #endif // EIGEN_PARSED_BY_DOXYGEN + + + /** Sets the shift parameter that will be used to adjust the diagonal coefficients during the numerical factorization. + * + * During the numerical factorization, an offset term is added to the diagonal coefficients:\n + * \c d_ii = \a offset + \c d_ii + * + * The default is \a offset=0. + * + * \returns a reference to \c *this. + */ + Derived& setShift(const RealScalar& offset) + { + m_shiftOffset[0] = double(offset); + return derived(); + } + + /** \returns the determinant of the underlying matrix from the current factorization */ + Scalar determinant() const + { + using std::exp; + return exp(logDeterminant()); + } + + /** \returns the log determinant of the underlying matrix from the current factorization */ + Scalar logDeterminant() const + { + using std::log; + using numext::real; + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + + RealScalar logDet = 0; + Scalar *x = static_cast(m_cholmodFactor->x); + if (m_cholmodFactor->is_super) + { + // Supernodal factorization stored as a packed list of dense column-major blocs, + // as described by the following structure: + + // super[k] == index of the first column of the j-th super node + StorageIndex *super = static_cast(m_cholmodFactor->super); + // pi[k] == offset to the description of row indices + StorageIndex *pi = static_cast(m_cholmodFactor->pi); + // px[k] == offset to the respective dense block + StorageIndex *px = static_cast(m_cholmodFactor->px); + + Index nb_super_nodes = m_cholmodFactor->nsuper; + for (Index k=0; k < nb_super_nodes; ++k) + { + StorageIndex ncols = super[k + 1] - super[k]; + StorageIndex nrows = pi[k + 1] - pi[k]; + + Map, 0, InnerStride<> > sk(x + px[k], ncols, InnerStride<>(nrows+1)); + logDet += sk.real().log().sum(); + } + } + else + { + // Simplicial factorization stored as standard CSC matrix. + StorageIndex *p = static_cast(m_cholmodFactor->p); + Index size = m_cholmodFactor->n; + for (Index k=0; kis_ll) + logDet *= 2.0; + return logDet; + }; + + template + void dumpMemory(Stream& /*s*/) + {} + + protected: + mutable cholmod_common m_cholmod; + cholmod_factor* m_cholmodFactor; + double m_shiftOffset[2]; + mutable ComputationInfo m_info; + int m_factorizationIsOk; + int m_analysisIsOk; +}; + +/** \ingroup CholmodSupport_Module + * \class CholmodSimplicialLLT + * \brief A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod + * + * This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization + * using the Cholmod library. + * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Therefore, it has little practical interest. + * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices + * X and B can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + * \implsparsesolverconcept + * + * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. + * + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLLT + */ +template +class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> > +{ + typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT> Base; + using Base::m_cholmod; + + public: + + typedef _MatrixType MatrixType; + + CholmodSimplicialLLT() : Base() { init(); } + + CholmodSimplicialLLT(const MatrixType& matrix) : Base() + { + init(); + this->compute(matrix); + } + + ~CholmodSimplicialLLT() {} + protected: + void init() + { + m_cholmod.final_asis = 0; + m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; + m_cholmod.final_ll = 1; + } +}; + + +/** \ingroup CholmodSupport_Module + * \class CholmodSimplicialLDLT + * \brief A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod + * + * This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization + * using the Cholmod library. + * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Therefore, it has little practical interest. + * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices + * X and B can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + * \implsparsesolverconcept + * + * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. + * + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLDLT + */ +template +class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> > +{ + typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT> Base; + using Base::m_cholmod; + + public: + + typedef _MatrixType MatrixType; + + CholmodSimplicialLDLT() : Base() { init(); } + + CholmodSimplicialLDLT(const MatrixType& matrix) : Base() + { + init(); + this->compute(matrix); + } + + ~CholmodSimplicialLDLT() {} + protected: + void init() + { + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; + } +}; + +/** \ingroup CholmodSupport_Module + * \class CholmodSupernodalLLT + * \brief A supernodal Cholesky (LLT) factorization and solver based on Cholmod + * + * This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization + * using the Cholmod library. + * This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM. + * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices + * X and B can be either dense or sparse. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + * \implsparsesolverconcept + * + * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. + * + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept + */ +template +class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> > +{ + typedef CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT> Base; + using Base::m_cholmod; + + public: + + typedef _MatrixType MatrixType; + + CholmodSupernodalLLT() : Base() { init(); } + + CholmodSupernodalLLT(const MatrixType& matrix) : Base() + { + init(); + this->compute(matrix); + } + + ~CholmodSupernodalLLT() {} + protected: + void init() + { + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_SUPERNODAL; + } +}; + +/** \ingroup CholmodSupport_Module + * \class CholmodDecomposition + * \brief A general Cholesky factorization and solver based on Cholmod + * + * This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization + * using the Cholmod library. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices + * X and B can be either dense or sparse. + * + * This variant permits to change the underlying Cholesky method at runtime. + * On the other hand, it does not provide access to the result of the factorization. + * The default is to let Cholmod automatically choose between a simplicial and supernodal factorization. + * + * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower + * or Upper. Default is Lower. + * + * \implsparsesolverconcept + * + * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. + * + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept + */ +template +class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> > +{ + typedef CholmodBase<_MatrixType, _UpLo, CholmodDecomposition> Base; + using Base::m_cholmod; + + public: + + typedef _MatrixType MatrixType; + + CholmodDecomposition() : Base() { init(); } + + CholmodDecomposition(const MatrixType& matrix) : Base() + { + init(); + this->compute(matrix); + } + + ~CholmodDecomposition() {} + + void setMode(CholmodMode mode) + { + switch(mode) + { + case CholmodAuto: + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_AUTO; + break; + case CholmodSimplicialLLt: + m_cholmod.final_asis = 0; + m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; + m_cholmod.final_ll = 1; + break; + case CholmodSupernodalLLt: + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_SUPERNODAL; + break; + case CholmodLDLt: + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; + break; + default: + break; + } + } + protected: + void init() + { + m_cholmod.final_asis = 1; + m_cholmod.supernodal = CHOLMOD_AUTO; + } +}; + +} // end namespace Eigen + +#endif // EIGEN_CHOLMODSUPPORT_H diff --git a/Vendor/eigen/Eigen/src/Core/ArithmeticSequence.h b/Vendor/eigen/Eigen/src/Core/ArithmeticSequence.h new file mode 100644 index 0000000..b6200fa --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/ArithmeticSequence.h @@ -0,0 +1,413 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ARITHMETIC_SEQUENCE_H +#define EIGEN_ARITHMETIC_SEQUENCE_H + +namespace Eigen { + +namespace internal { + +#if (!EIGEN_HAS_CXX11) || !((!EIGEN_COMP_GNUC) || EIGEN_COMP_GNUC>=48) +template struct aseq_negate {}; + +template<> struct aseq_negate { + typedef Index type; +}; + +template struct aseq_negate > { + typedef FixedInt<-N> type; +}; + +// Compilation error in the following case: +template<> struct aseq_negate > {}; + +template::value, + bool SizeIsSymbolic =symbolic::is_symbolic::value> +struct aseq_reverse_first_type { + typedef Index type; +}; + +template +struct aseq_reverse_first_type { + typedef symbolic::AddExpr > >, + symbolic::ValueExpr > + > type; +}; + +template +struct aseq_reverse_first_type_aux { + typedef Index type; +}; + +template +struct aseq_reverse_first_type_aux::type> { + typedef FixedInt<(SizeType::value-1)*IncrType::value> type; +}; + +template +struct aseq_reverse_first_type { + typedef typename aseq_reverse_first_type_aux::type Aux; + typedef symbolic::AddExpr > type; +}; + +template +struct aseq_reverse_first_type { + typedef symbolic::AddExpr > >, + symbolic::ValueExpr >, + symbolic::ValueExpr<> > type; +}; +#endif + +// Helper to cleanup the type of the increment: +template struct cleanup_seq_incr { + typedef typename cleanup_index_type::type type; +}; + +} + +//-------------------------------------------------------------------------------- +// seq(first,last,incr) and seqN(first,size,incr) +//-------------------------------------------------------------------------------- + +template > +class ArithmeticSequence; + +template +ArithmeticSequence::type, + typename internal::cleanup_index_type::type, + typename internal::cleanup_seq_incr::type > +seqN(FirstType first, SizeType size, IncrType incr); + +/** \class ArithmeticSequence + * \ingroup Core_Module + * + * This class represents an arithmetic progression \f$ a_0, a_1, a_2, ..., a_{n-1}\f$ defined by + * its \em first value \f$ a_0 \f$, its \em size (aka length) \em n, and the \em increment (aka stride) + * that is equal to \f$ a_{i+1}-a_{i}\f$ for any \em i. + * + * It is internally used as the return type of the Eigen::seq and Eigen::seqN functions, and as the input arguments + * of DenseBase::operator()(const RowIndices&, const ColIndices&), and most of the time this is the + * only way it is used. + * + * \tparam FirstType type of the first element, usually an Index, + * but internally it can be a symbolic expression + * \tparam SizeType type representing the size of the sequence, usually an Index + * or a compile time integral constant. Internally, it can also be a symbolic expression + * \tparam IncrType type of the increment, can be a runtime Index, or a compile time integral constant (default is compile-time 1) + * + * \sa Eigen::seq, Eigen::seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView + */ +template +class ArithmeticSequence +{ +public: + ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {} + ArithmeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} + + enum { + SizeAtCompileTime = internal::get_fixed_value::value, + IncrAtCompileTime = internal::get_fixed_value::value + }; + + /** \returns the size, i.e., number of elements, of the sequence */ + Index size() const { return m_size; } + + /** \returns the first element \f$ a_0 \f$ in the sequence */ + Index first() const { return m_first; } + + /** \returns the value \f$ a_i \f$ at index \a i in the sequence. */ + Index operator[](Index i) const { return m_first + i * m_incr; } + + const FirstType& firstObject() const { return m_first; } + const SizeType& sizeObject() const { return m_size; } + const IncrType& incrObject() const { return m_incr; } + +protected: + FirstType m_first; + SizeType m_size; + IncrType m_incr; + +public: + +#if EIGEN_HAS_CXX11 && ((!EIGEN_COMP_GNUC) || EIGEN_COMP_GNUC>=48) + auto reverse() const -> decltype(Eigen::seqN(m_first+(m_size+fix<-1>())*m_incr,m_size,-m_incr)) { + return seqN(m_first+(m_size+fix<-1>())*m_incr,m_size,-m_incr); + } +#else +protected: + typedef typename internal::aseq_negate::type ReverseIncrType; + typedef typename internal::aseq_reverse_first_type::type ReverseFirstType; +public: + ArithmeticSequence + reverse() const { + return seqN(m_first+(m_size+fix<-1>())*m_incr,m_size,-m_incr); + } +#endif +}; + +/** \returns an ArithmeticSequence starting at \a first, of length \a size, and increment \a incr + * + * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ +template +ArithmeticSequence::type,typename internal::cleanup_index_type::type,typename internal::cleanup_seq_incr::type > +seqN(FirstType first, SizeType size, IncrType incr) { + return ArithmeticSequence::type,typename internal::cleanup_index_type::type,typename internal::cleanup_seq_incr::type>(first,size,incr); +} + +/** \returns an ArithmeticSequence starting at \a first, of length \a size, and unit increment + * + * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */ +template +ArithmeticSequence::type,typename internal::cleanup_index_type::type > +seqN(FirstType first, SizeType size) { + return ArithmeticSequence::type,typename internal::cleanup_index_type::type>(first,size); +} + +#ifdef EIGEN_PARSED_BY_DOXYGEN + +/** \returns an ArithmeticSequence starting at \a f, up (or down) to \a l, and with positive (or negative) increment \a incr + * + * It is essentially an alias to: + * \code + * seqN(f, (l-f+incr)/incr, incr); + * \endcode + * + * \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) + */ +template +auto seq(FirstType f, LastType l, IncrType incr); + +/** \returns an ArithmeticSequence starting at \a f, up (or down) to \a l, and unit increment + * + * It is essentially an alias to: + * \code + * seqN(f,l-f+1); + * \endcode + * + * \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) + */ +template +auto seq(FirstType f, LastType l); + +#else // EIGEN_PARSED_BY_DOXYGEN + +#if EIGEN_HAS_CXX11 +template +auto seq(FirstType f, LastType l) -> decltype(seqN(typename internal::cleanup_index_type::type(f), + ( typename internal::cleanup_index_type::type(l) + - typename internal::cleanup_index_type::type(f)+fix<1>()))) +{ + return seqN(typename internal::cleanup_index_type::type(f), + (typename internal::cleanup_index_type::type(l) + -typename internal::cleanup_index_type::type(f)+fix<1>())); +} + +template +auto seq(FirstType f, LastType l, IncrType incr) + -> decltype(seqN(typename internal::cleanup_index_type::type(f), + ( typename internal::cleanup_index_type::type(l) + - typename internal::cleanup_index_type::type(f)+typename internal::cleanup_seq_incr::type(incr) + ) / typename internal::cleanup_seq_incr::type(incr), + typename internal::cleanup_seq_incr::type(incr))) +{ + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; + return seqN(typename internal::cleanup_index_type::type(f), + ( typename internal::cleanup_index_type::type(l) + -typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr)) / CleanedIncrType(incr), + CleanedIncrType(incr)); +} + +#else // EIGEN_HAS_CXX11 + +template +typename internal::enable_if::value || symbolic::is_symbolic::value), + ArithmeticSequence::type,Index> >::type +seq(FirstType f, LastType l) +{ + return seqN(typename internal::cleanup_index_type::type(f), + Index((typename internal::cleanup_index_type::type(l)-typename internal::cleanup_index_type::type(f)+fix<1>()))); +} + +template +typename internal::enable_if::value, + ArithmeticSequence,symbolic::ValueExpr<> >, + symbolic::ValueExpr > > > >::type +seq(const symbolic::BaseExpr &f, LastType l) +{ + return seqN(f.derived(),(typename internal::cleanup_index_type::type(l)-f.derived()+fix<1>())); +} + +template +typename internal::enable_if::value, + ArithmeticSequence::type, + symbolic::AddExpr >, + symbolic::ValueExpr > > > >::type +seq(FirstType f, const symbolic::BaseExpr &l) +{ + return seqN(typename internal::cleanup_index_type::type(f),(l.derived()-typename internal::cleanup_index_type::type(f)+fix<1>())); +} + +template +ArithmeticSequence >,symbolic::ValueExpr > > > +seq(const symbolic::BaseExpr &f, const symbolic::BaseExpr &l) +{ + return seqN(f.derived(),(l.derived()-f.derived()+fix<1>())); +} + + +template +typename internal::enable_if::value || symbolic::is_symbolic::value), + ArithmeticSequence::type,Index,typename internal::cleanup_seq_incr::type> >::type +seq(FirstType f, LastType l, IncrType incr) +{ + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; + return seqN(typename internal::cleanup_index_type::type(f), + Index((typename internal::cleanup_index_type::type(l)-typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr))/CleanedIncrType(incr)), incr); +} + +template +typename internal::enable_if::value, + ArithmeticSequence, + symbolic::ValueExpr<> >, + symbolic::ValueExpr::type> >, + symbolic::ValueExpr::type> >, + typename internal::cleanup_seq_incr::type> >::type +seq(const symbolic::BaseExpr &f, LastType l, IncrType incr) +{ + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; + return seqN(f.derived(),(typename internal::cleanup_index_type::type(l)-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} + +template +typename internal::enable_if::value, + ArithmeticSequence::type, + symbolic::QuotientExpr >, + symbolic::ValueExpr::type> >, + symbolic::ValueExpr::type> >, + typename internal::cleanup_seq_incr::type> >::type +seq(FirstType f, const symbolic::BaseExpr &l, IncrType incr) +{ + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; + return seqN(typename internal::cleanup_index_type::type(f), + (l.derived()-typename internal::cleanup_index_type::type(f)+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} + +template +ArithmeticSequence >, + symbolic::ValueExpr::type> >, + symbolic::ValueExpr::type> >, + typename internal::cleanup_seq_incr::type> +seq(const symbolic::BaseExpr &f, const symbolic::BaseExpr &l, IncrType incr) +{ + typedef typename internal::cleanup_seq_incr::type CleanedIncrType; + return seqN(f.derived(),(l.derived()-f.derived()+CleanedIncrType(incr))/CleanedIncrType(incr), incr); +} +#endif // EIGEN_HAS_CXX11 + +#endif // EIGEN_PARSED_BY_DOXYGEN + + +#if EIGEN_HAS_CXX11 || defined(EIGEN_PARSED_BY_DOXYGEN) +/** \cpp11 + * \returns a symbolic ArithmeticSequence representing the last \a size elements with increment \a incr. + * + * It is a shortcut for: \code seqN(last-(size-fix<1>)*incr, size, incr) \endcode + * + * \sa lastN(SizeType), seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */ +template +auto lastN(SizeType size, IncrType incr) +-> decltype(seqN(Eigen::last-(size-fix<1>())*incr, size, incr)) +{ + return seqN(Eigen::last-(size-fix<1>())*incr, size, incr); +} + +/** \cpp11 + * \returns a symbolic ArithmeticSequence representing the last \a size elements with a unit increment. + * + * It is a shortcut for: \code seq(last+fix<1>-size, last) \endcode + * + * \sa lastN(SizeType,IncrType, seqN(FirstType,SizeType), seq(FirstType,LastType) */ +template +auto lastN(SizeType size) +-> decltype(seqN(Eigen::last+fix<1>()-size, size)) +{ + return seqN(Eigen::last+fix<1>()-size, size); +} +#endif + +namespace internal { + +// Convert a symbolic span into a usable one (i.e., remove last/end "keywords") +template +struct make_size_type { + typedef typename internal::conditional::value, Index, T>::type type; +}; + +template +struct IndexedViewCompatibleType, XprSize> { + typedef ArithmeticSequence::type,IncrType> type; +}; + +template +ArithmeticSequence::type,IncrType> +makeIndexedViewCompatible(const ArithmeticSequence& ids, Index size,SpecializedType) { + return ArithmeticSequence::type,IncrType>( + eval_expr_given_size(ids.firstObject(),size),eval_expr_given_size(ids.sizeObject(),size),ids.incrObject()); +} + +template +struct get_compile_time_incr > { + enum { value = get_fixed_value::value }; +}; + +} // end namespace internal + +/** \namespace Eigen::indexing + * \ingroup Core_Module + * + * The sole purpose of this namespace is to be able to import all functions + * and symbols that are expected to be used within operator() for indexing + * and slicing. If you already imported the whole Eigen namespace: + * \code using namespace Eigen; \endcode + * then you are already all set. Otherwise, if you don't want/cannot import + * the whole Eigen namespace, the following line: + * \code using namespace Eigen::indexing; \endcode + * is equivalent to: + * \code + using Eigen::all; + using Eigen::seq; + using Eigen::seqN; + using Eigen::lastN; // c++11 only + using Eigen::last; + using Eigen::lastp1; + using Eigen::fix; + \endcode + */ +namespace indexing { + using Eigen::all; + using Eigen::seq; + using Eigen::seqN; + #if EIGEN_HAS_CXX11 + using Eigen::lastN; + #endif + using Eigen::last; + using Eigen::lastp1; + using Eigen::fix; +} + +} // end namespace Eigen + +#endif // EIGEN_ARITHMETIC_SEQUENCE_H diff --git a/Vendor/eigen/Eigen/src/Core/Array.h b/Vendor/eigen/Eigen/src/Core/Array.h new file mode 100644 index 0000000..20c789b --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Array.h @@ -0,0 +1,417 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ARRAY_H +#define EIGEN_ARRAY_H + +namespace Eigen { + +namespace internal { +template +struct traits > : traits > +{ + typedef ArrayXpr XprKind; + typedef ArrayBase > XprBase; +}; +} + +/** \class Array + * \ingroup Core_Module + * + * \brief General-purpose arrays with easy API for coefficient-wise operations + * + * The %Array class is very similar to the Matrix class. It provides + * general-purpose one- and two-dimensional arrays. The difference between the + * %Array and the %Matrix class is primarily in the API: the API for the + * %Array class provides easy access to coefficient-wise operations, while the + * API for the %Matrix class provides easy access to linear-algebra + * operations. + * + * See documentation of class Matrix for detailed information on the template parameters + * storage layout. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN. + * + * \sa \blank \ref TutorialArrayClass, \ref TopicClassHierarchy + */ +template +class Array + : public PlainObjectBase > +{ + public: + + typedef PlainObjectBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Array) + + enum { Options = _Options }; + typedef typename Base::PlainObject PlainObject; + + protected: + template + friend struct internal::conservative_resize_like_impl; + + using Base::m_storage; + + public: + + using Base::base; + using Base::coeff; + using Base::coeffRef; + + /** + * The usage of + * using Base::operator=; + * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped + * the usage of 'using'. This should be done only for operator=. + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const EigenBase &other) + { + return Base::operator=(other); + } + + /** Set all the entries to \a value. + * \sa DenseBase::setConstant(), DenseBase::fill() + */ + /* This overload is needed because the usage of + * using Base::operator=; + * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped + * the usage of 'using'. This should be done only for operator=. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const Scalar &value) + { + Base::setConstant(value); + return *this; + } + + /** Copies the value of the expression \a other into \c *this with automatic resizing. + * + * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), + * it will be initialized. + * + * Note that copying a row-vector into a vector (and conversely) is allowed. + * The resizing, if any, is then done in the appropriate way so that row-vectors + * remain row-vectors and vectors remain vectors. + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const DenseBase& other) + { + return Base::_set(other); + } + + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const Array& other) + { + return Base::_set(other); + } + + /** Default constructor. + * + * For fixed-size matrices, does nothing. + * + * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix + * is called a null matrix. This constructor is the unique way to create null matrices: resizing + * a matrix to 0 is not supported. + * + * \sa resize(Index,Index) + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array() : Base() + { + Base::_check_template_params(); + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + // FIXME is it still needed ?? + /** \internal */ + EIGEN_DEVICE_FUNC + Array(internal::constructor_without_unaligned_array_assert) + : Base(internal::constructor_without_unaligned_array_assert()) + { + Base::_check_template_params(); + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } +#endif + +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + Array(Array&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_constructible::value) + : Base(std::move(other)) + { + Base::_check_template_params(); + } + EIGEN_DEVICE_FUNC + Array& operator=(Array&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_assignable::value) + { + Base::operator=(std::move(other)); + return *this; + } +#endif + + #if EIGEN_HAS_CXX11 + /** \copydoc PlainObjectBase(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) + * + * Example: \include Array_variadic_ctor_cxx11.cpp + * Output: \verbinclude Array_variadic_ctor_cxx11.out + * + * \sa Array(const std::initializer_list>&) + * \sa Array(const Scalar&), Array(const Scalar&,const Scalar&) + */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Array(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) + : Base(a0, a1, a2, a3, args...) {} + + /** \brief Constructs an array and initializes it from the coefficients given as initializer-lists grouped by row. \cpp11 + * + * In the general case, the constructor takes a list of rows, each row being represented as a list of coefficients: + * + * Example: \include Array_initializer_list_23_cxx11.cpp + * Output: \verbinclude Array_initializer_list_23_cxx11.out + * + * Each of the inner initializer lists must contain the exact same number of elements, otherwise an assertion is triggered. + * + * In the case of a compile-time column 1D array, implicit transposition from a single row is allowed. + * Therefore Array{{1,2,3,4,5}} is legal and the more verbose syntax + * Array{{1},{2},{3},{4},{5}} can be avoided: + * + * Example: \include Array_initializer_list_vector_cxx11.cpp + * Output: \verbinclude Array_initializer_list_vector_cxx11.out + * + * In the case of fixed-sized arrays, the initializer list sizes must exactly match the array sizes, + * and implicit transposition is allowed for compile-time 1D arrays only. + * + * \sa Array(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array(const std::initializer_list>& list) : Base(list) {} + #endif // end EIGEN_HAS_CXX11 + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Array(const T& x) + { + Base::_check_template_params(); + Base::template _init1(x); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array(const T0& val0, const T1& val1) + { + Base::_check_template_params(); + this->template _init2(val0, val1); + } + + #else + /** \brief Constructs a fixed-sized array initialized with coefficients starting at \a data */ + EIGEN_DEVICE_FUNC explicit Array(const Scalar *data); + /** Constructs a vector or row-vector with given dimension. \only_for_vectors + * + * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass the dimension here, so it makes more sense to use the default + * constructor Array() instead. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Array(Index dim); + /** constructs an initialized 1x1 Array with the given coefficient + * \sa const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args */ + Array(const Scalar& value); + /** constructs an uninitialized array with \a rows rows and \a cols columns. + * + * This is useful for dynamic-size arrays. For fixed-size arrays, + * it is redundant to pass these parameters, so one should use the default constructor + * Array() instead. */ + Array(Index rows, Index cols); + /** constructs an initialized 2D vector with given coefficients + * \sa Array(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) */ + Array(const Scalar& val0, const Scalar& val1); + #endif // end EIGEN_PARSED_BY_DOXYGEN + + /** constructs an initialized 3D vector with given coefficients + * \sa Array(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 3) + m_storage.data()[0] = val0; + m_storage.data()[1] = val1; + m_storage.data()[2] = val2; + } + /** constructs an initialized 4D vector with given coefficients + * \sa Array(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2, const Scalar& val3) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 4) + m_storage.data()[0] = val0; + m_storage.data()[1] = val1; + m_storage.data()[2] = val2; + m_storage.data()[3] = val3; + } + + /** Copy constructor */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array(const Array& other) + : Base(other) + { } + + private: + struct PrivateType {}; + public: + + /** \sa MatrixBase::operator=(const EigenBase&) */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array(const EigenBase &other, + typename internal::enable_if::value, + PrivateType>::type = PrivateType()) + : Base(other.derived()) + { } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index innerStride() const EIGEN_NOEXCEPT{ return 1; } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index outerStride() const EIGEN_NOEXCEPT { return this->innerSize(); } + + #ifdef EIGEN_ARRAY_PLUGIN + #include EIGEN_ARRAY_PLUGIN + #endif + + private: + + template + friend struct internal::matrix_swap_impl; +}; + +/** \defgroup arraytypedefs Global array typedefs + * \ingroup Core_Module + * + * %Eigen defines several typedef shortcuts for most common 1D and 2D array types. + * + * The general patterns are the following: + * + * \c ArrayRowsColsType where \c Rows and \c Cols can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size, + * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd + * for complex double. + * + * For example, \c Array33d is a fixed-size 3x3 array type of doubles, and \c ArrayXXf is a dynamic-size matrix of floats. + * + * There are also \c ArraySizeType which are self-explanatory. For example, \c Array4cf is + * a fixed-size 1D array of 4 complex floats. + * + * With \cpp11, template alias are also defined for common sizes. + * They follow the same pattern as above except that the scalar type suffix is replaced by a + * template parameter, i.e.: + * - `ArrayRowsCols` where `Rows` and `Cols` can be \c 2,\c 3,\c 4, or \c X for fixed or dynamic size. + * - `ArraySize` where `Size` can be \c 2,\c 3,\c 4 or \c X for fixed or dynamic size 1D arrays. + * + * \sa class Array + */ + +#define EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ +/** \ingroup arraytypedefs */ \ +typedef Array Array##SizeSuffix##SizeSuffix##TypeSuffix; \ +/** \ingroup arraytypedefs */ \ +typedef Array Array##SizeSuffix##TypeSuffix; + +#define EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \ +/** \ingroup arraytypedefs */ \ +typedef Array Array##Size##X##TypeSuffix; \ +/** \ingroup arraytypedefs */ \ +typedef Array Array##X##Size##TypeSuffix; + +#define EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ +EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 2, 2) \ +EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 3, 3) \ +EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 4, 4) \ +EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \ +EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \ +EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \ +EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 4) + +EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(int, i) +EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(float, f) +EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(double, d) +EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex, cf) +EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex, cd) + +#undef EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES +#undef EIGEN_MAKE_ARRAY_TYPEDEFS +#undef EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS + +#if EIGEN_HAS_CXX11 + +#define EIGEN_MAKE_ARRAY_TYPEDEFS(Size, SizeSuffix) \ +/** \ingroup arraytypedefs */ \ +/** \brief \cpp11 */ \ +template \ +using Array##SizeSuffix##SizeSuffix = Array; \ +/** \ingroup arraytypedefs */ \ +/** \brief \cpp11 */ \ +template \ +using Array##SizeSuffix = Array; + +#define EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Size) \ +/** \ingroup arraytypedefs */ \ +/** \brief \cpp11 */ \ +template \ +using Array##Size##X = Array; \ +/** \ingroup arraytypedefs */ \ +/** \brief \cpp11 */ \ +template \ +using Array##X##Size = Array; + +EIGEN_MAKE_ARRAY_TYPEDEFS(2, 2) +EIGEN_MAKE_ARRAY_TYPEDEFS(3, 3) +EIGEN_MAKE_ARRAY_TYPEDEFS(4, 4) +EIGEN_MAKE_ARRAY_TYPEDEFS(Dynamic, X) +EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(2) +EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(3) +EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(4) + +#undef EIGEN_MAKE_ARRAY_TYPEDEFS +#undef EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS + +#endif // EIGEN_HAS_CXX11 + +#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \ +using Eigen::Matrix##SizeSuffix##TypeSuffix; \ +using Eigen::Vector##SizeSuffix##TypeSuffix; \ +using Eigen::RowVector##SizeSuffix##TypeSuffix; + +#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(TypeSuffix) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \ + +#define EIGEN_USING_ARRAY_TYPEDEFS \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(i) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(f) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(d) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cf) \ +EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cd) + +} // end namespace Eigen + +#endif // EIGEN_ARRAY_H diff --git a/Vendor/eigen/Eigen/src/Core/ArrayBase.h b/Vendor/eigen/Eigen/src/Core/ArrayBase.h new file mode 100644 index 0000000..ea3dd1c --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/ArrayBase.h @@ -0,0 +1,226 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ARRAYBASE_H +#define EIGEN_ARRAYBASE_H + +namespace Eigen { + +template class MatrixWrapper; + +/** \class ArrayBase + * \ingroup Core_Module + * + * \brief Base class for all 1D and 2D array, and related expressions + * + * An array is similar to a dense vector or matrix. While matrices are mathematical + * objects with well defined linear algebra operators, an array is just a collection + * of scalar values arranged in a one or two dimensionnal fashion. As the main consequence, + * all operations applied to an array are performed coefficient wise. Furthermore, + * arrays support scalar math functions of the c++ standard library (e.g., std::sin(x)), and convenient + * constructors allowing to easily write generic code working for both scalar values + * and arrays. + * + * This class is the base that is inherited by all array expression types. + * + * \tparam Derived is the derived type, e.g., an array or an expression type. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAYBASE_PLUGIN. + * + * \sa class MatrixBase, \ref TopicClassHierarchy + */ +template class ArrayBase + : public DenseBase +{ + public: +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** The base class for a given storage type. */ + typedef ArrayBase StorageBaseType; + + typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + + typedef DenseBase Base; + using Base::RowsAtCompileTime; + using Base::ColsAtCompileTime; + using Base::SizeAtCompileTime; + using Base::MaxRowsAtCompileTime; + using Base::MaxColsAtCompileTime; + using Base::MaxSizeAtCompileTime; + using Base::IsVectorAtCompileTime; + using Base::Flags; + + using Base::derived; + using Base::const_cast_derived; + using Base::rows; + using Base::cols; + using Base::size; + using Base::coeff; + using Base::coeffRef; + using Base::lazyAssign; + using Base::operator-; + using Base::operator=; + using Base::operator+=; + using Base::operator-=; + using Base::operator*=; + using Base::operator/=; + + typedef typename Base::CoeffReturnType CoeffReturnType; + +#endif // not EIGEN_PARSED_BY_DOXYGEN + +#ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Base::PlainObject PlainObject; + + /** \internal Represents a matrix with all coefficients equal to one another*/ + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; +#endif // not EIGEN_PARSED_BY_DOXYGEN + +#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase +#define EIGEN_DOC_UNARY_ADDONS(X,Y) +# include "../plugins/MatrixCwiseUnaryOps.h" +# include "../plugins/ArrayCwiseUnaryOps.h" +# include "../plugins/CommonCwiseBinaryOps.h" +# include "../plugins/MatrixCwiseBinaryOps.h" +# include "../plugins/ArrayCwiseBinaryOps.h" +# ifdef EIGEN_ARRAYBASE_PLUGIN +# include EIGEN_ARRAYBASE_PLUGIN +# endif +#undef EIGEN_CURRENT_STORAGE_BASE_CLASS +#undef EIGEN_DOC_UNARY_ADDONS + + /** Special case of the template operator=, in order to prevent the compiler + * from generating a default operator= (issue hit with g++ 4.1) + */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator=(const ArrayBase& other) + { + internal::call_assignment(derived(), other.derived()); + return derived(); + } + + /** Set all the entries to \a value. + * \sa DenseBase::setConstant(), DenseBase::fill() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator=(const Scalar &value) + { Base::setConstant(value); return derived(); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator+=(const Scalar& scalar); + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator-=(const Scalar& scalar); + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator+=(const ArrayBase& other); + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator-=(const ArrayBase& other); + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator*=(const ArrayBase& other); + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator/=(const ArrayBase& other); + + public: + EIGEN_DEVICE_FUNC + ArrayBase& array() { return *this; } + EIGEN_DEVICE_FUNC + const ArrayBase& array() const { return *this; } + + /** \returns an \link Eigen::MatrixBase Matrix \endlink expression of this array + * \sa MatrixBase::array() */ + EIGEN_DEVICE_FUNC + MatrixWrapper matrix() { return MatrixWrapper(derived()); } + EIGEN_DEVICE_FUNC + const MatrixWrapper matrix() const { return MatrixWrapper(derived()); } + +// template +// inline void evalTo(Dest& dst) const { dst = matrix(); } + + protected: + EIGEN_DEFAULT_COPY_CONSTRUCTOR(ArrayBase) + EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(ArrayBase) + + private: + explicit ArrayBase(Index); + ArrayBase(Index,Index); + template explicit ArrayBase(const ArrayBase&); + protected: + // mixing arrays and matrices is not legal + template Derived& operator+=(const MatrixBase& ) + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} + // mixing arrays and matrices is not legal + template Derived& operator-=(const MatrixBase& ) + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} +}; + +/** replaces \c *this by \c *this - \a other. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & +ArrayBase::operator-=(const ArrayBase &other) +{ + call_assignment(derived(), other.derived(), internal::sub_assign_op()); + return derived(); +} + +/** replaces \c *this by \c *this + \a other. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & +ArrayBase::operator+=(const ArrayBase& other) +{ + call_assignment(derived(), other.derived(), internal::add_assign_op()); + return derived(); +} + +/** replaces \c *this by \c *this * \a other coefficient wise. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & +ArrayBase::operator*=(const ArrayBase& other) +{ + call_assignment(derived(), other.derived(), internal::mul_assign_op()); + return derived(); +} + +/** replaces \c *this by \c *this / \a other coefficient wise. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & +ArrayBase::operator/=(const ArrayBase& other) +{ + call_assignment(derived(), other.derived(), internal::div_assign_op()); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_ARRAYBASE_H diff --git a/Vendor/eigen/Eigen/src/Core/ArrayWrapper.h b/Vendor/eigen/Eigen/src/Core/ArrayWrapper.h new file mode 100644 index 0000000..2e9555b --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/ArrayWrapper.h @@ -0,0 +1,209 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ARRAYWRAPPER_H +#define EIGEN_ARRAYWRAPPER_H + +namespace Eigen { + +/** \class ArrayWrapper + * \ingroup Core_Module + * + * \brief Expression of a mathematical vector or matrix as an array object + * + * This class is the return type of MatrixBase::array(), and most of the time + * this is the only way it is use. + * + * \sa MatrixBase::array(), class MatrixWrapper + */ + +namespace internal { +template +struct traits > + : public traits::type > +{ + typedef ArrayXpr XprKind; + // Let's remove NestByRefBit + enum { + Flags0 = traits::type >::Flags, + LvalueBitFlag = is_lvalue::value ? LvalueBit : 0, + Flags = (Flags0 & ~(NestByRefBit | LvalueBit)) | LvalueBitFlag + }; +}; +} + +template +class ArrayWrapper : public ArrayBase > +{ + public: + typedef ArrayBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) + typedef typename internal::remove_all::type NestedExpression; + + typedef typename internal::conditional< + internal::is_lvalue::value, + Scalar, + const Scalar + >::type ScalarWithConstIfNotLvalue; + + typedef typename internal::ref_selector::non_const_type NestedExpressionType; + + using Base::coeffRef; + + EIGEN_DEVICE_FUNC + explicit EIGEN_STRONG_INLINE ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index rows() const EIGEN_NOEXCEPT { return m_expression.rows(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index cols() const EIGEN_NOEXCEPT { return m_expression.cols(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index outerStride() const EIGEN_NOEXCEPT { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index innerStride() const EIGEN_NOEXCEPT { return m_expression.innerStride(); } + + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } + EIGEN_DEVICE_FUNC + inline const Scalar* data() const { return m_expression.data(); } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return m_expression.coeffRef(rowId, colId); + } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index index) const + { + return m_expression.coeffRef(index); + } + + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& dst) const { dst = m_expression; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + nestedExpression() const + { + return m_expression; + } + + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index) */ + EIGEN_DEVICE_FUNC + void resize(Index newSize) { m_expression.resize(newSize); } + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index,Index)*/ + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { m_expression.resize(rows,cols); } + + protected: + NestedExpressionType m_expression; +}; + +/** \class MatrixWrapper + * \ingroup Core_Module + * + * \brief Expression of an array as a mathematical vector or matrix + * + * This class is the return type of ArrayBase::matrix(), and most of the time + * this is the only way it is use. + * + * \sa MatrixBase::matrix(), class ArrayWrapper + */ + +namespace internal { +template +struct traits > + : public traits::type > +{ + typedef MatrixXpr XprKind; + // Let's remove NestByRefBit + enum { + Flags0 = traits::type >::Flags, + LvalueBitFlag = is_lvalue::value ? LvalueBit : 0, + Flags = (Flags0 & ~(NestByRefBit | LvalueBit)) | LvalueBitFlag + }; +}; +} + +template +class MatrixWrapper : public MatrixBase > +{ + public: + typedef MatrixBase > Base; + EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper) + typedef typename internal::remove_all::type NestedExpression; + + typedef typename internal::conditional< + internal::is_lvalue::value, + Scalar, + const Scalar + >::type ScalarWithConstIfNotLvalue; + + typedef typename internal::ref_selector::non_const_type NestedExpressionType; + + using Base::coeffRef; + + EIGEN_DEVICE_FUNC + explicit inline MatrixWrapper(ExpressionType& matrix) : m_expression(matrix) {} + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index rows() const EIGEN_NOEXCEPT { return m_expression.rows(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index cols() const EIGEN_NOEXCEPT { return m_expression.cols(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index outerStride() const EIGEN_NOEXCEPT { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index innerStride() const EIGEN_NOEXCEPT { return m_expression.innerStride(); } + + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } + EIGEN_DEVICE_FUNC + inline const Scalar* data() const { return m_expression.data(); } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return m_expression.derived().coeffRef(rowId, colId); + } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index index) const + { + return m_expression.coeffRef(index); + } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + nestedExpression() const + { + return m_expression; + } + + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index) */ + EIGEN_DEVICE_FUNC + void resize(Index newSize) { m_expression.resize(newSize); } + /** Forwards the resizing request to the nested expression + * \sa DenseBase::resize(Index,Index)*/ + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { m_expression.resize(rows,cols); } + + protected: + NestedExpressionType m_expression; +}; + +} // end namespace Eigen + +#endif // EIGEN_ARRAYWRAPPER_H diff --git a/Vendor/eigen/Eigen/src/Core/Assign.h b/Vendor/eigen/Eigen/src/Core/Assign.h new file mode 100644 index 0000000..655412e --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Assign.h @@ -0,0 +1,90 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007 Michael Olbrich +// Copyright (C) 2006-2010 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ASSIGN_H +#define EIGEN_ASSIGN_H + +namespace Eigen { + +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase + ::lazyAssign(const DenseBase& other) +{ + enum{ + SameType = internal::is_same::value + }; + + EIGEN_STATIC_ASSERT_LVALUE(Derived) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived) + EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) + + eigen_assert(rows() == other.rows() && cols() == other.cols()); + internal::call_assignment_no_alias(derived(),other.derived()); + + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) +{ + internal::call_assignment(derived(), other.derived()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) +{ + other.derived().evalTo(derived()); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_H diff --git a/Vendor/eigen/Eigen/src/Core/AssignEvaluator.h b/Vendor/eigen/Eigen/src/Core/AssignEvaluator.h new file mode 100644 index 0000000..7d76f0c --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/AssignEvaluator.h @@ -0,0 +1,1010 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Benoit Jacob +// Copyright (C) 2011-2014 Gael Guennebaud +// Copyright (C) 2011-2012 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ASSIGN_EVALUATOR_H +#define EIGEN_ASSIGN_EVALUATOR_H + +namespace Eigen { + +// This implementation is based on Assign.h + +namespace internal { + +/*************************************************************************** +* Part 1 : the logic deciding a strategy for traversal and unrolling * +***************************************************************************/ + +// copy_using_evaluator_traits is based on assign_traits + +template +struct copy_using_evaluator_traits +{ + typedef typename DstEvaluator::XprType Dst; + typedef typename Dst::Scalar DstScalar; + + enum { + DstFlags = DstEvaluator::Flags, + SrcFlags = SrcEvaluator::Flags + }; + +public: + enum { + DstAlignment = DstEvaluator::Alignment, + SrcAlignment = SrcEvaluator::Alignment, + DstHasDirectAccess = (DstFlags & DirectAccessBit) == DirectAccessBit, + JointAlignment = EIGEN_PLAIN_ENUM_MIN(DstAlignment,SrcAlignment) + }; + +private: + enum { + InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) + : int(DstFlags)&RowMajorBit ? int(Dst::ColsAtCompileTime) + : int(Dst::RowsAtCompileTime), + InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) + : int(DstFlags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) + : int(Dst::MaxRowsAtCompileTime), + RestrictedInnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(InnerSize,MaxPacketSize), + RestrictedLinearSize = EIGEN_SIZE_MIN_PREFER_FIXED(Dst::SizeAtCompileTime,MaxPacketSize), + OuterStride = int(outer_stride_at_compile_time::ret), + MaxSizeAtCompileTime = Dst::SizeAtCompileTime + }; + + // TODO distinguish between linear traversal and inner-traversals + typedef typename find_best_packet::type LinearPacketType; + typedef typename find_best_packet::type InnerPacketType; + + enum { + LinearPacketSize = unpacket_traits::size, + InnerPacketSize = unpacket_traits::size + }; + +public: + enum { + LinearRequiredAlignment = unpacket_traits::alignment, + InnerRequiredAlignment = unpacket_traits::alignment + }; + +private: + enum { + DstIsRowMajor = DstFlags&RowMajorBit, + SrcIsRowMajor = SrcFlags&RowMajorBit, + StorageOrdersAgree = (int(DstIsRowMajor) == int(SrcIsRowMajor)), + MightVectorize = bool(StorageOrdersAgree) + && (int(DstFlags) & int(SrcFlags) & ActualPacketAccessBit) + && bool(functor_traits::PacketAccess), + MayInnerVectorize = MightVectorize + && int(InnerSize)!=Dynamic && int(InnerSize)%int(InnerPacketSize)==0 + && int(OuterStride)!=Dynamic && int(OuterStride)%int(InnerPacketSize)==0 + && (EIGEN_UNALIGNED_VECTORIZE || int(JointAlignment)>=int(InnerRequiredAlignment)), + MayLinearize = bool(StorageOrdersAgree) && (int(DstFlags) & int(SrcFlags) & LinearAccessBit), + MayLinearVectorize = bool(MightVectorize) && bool(MayLinearize) && bool(DstHasDirectAccess) + && (EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment)) || MaxSizeAtCompileTime == Dynamic), + /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, + so it's only good for large enough sizes. */ + MaySliceVectorize = bool(MightVectorize) && bool(DstHasDirectAccess) + && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=(EIGEN_UNALIGNED_VECTORIZE?InnerPacketSize:(3*InnerPacketSize))) + /* slice vectorization can be slow, so we only want it if the slices are big, which is + indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block + in a fixed-size matrix + However, with EIGEN_UNALIGNED_VECTORIZE and unrolling, slice vectorization is still worth it */ + }; + +public: + enum { + Traversal = int(Dst::SizeAtCompileTime) == 0 ? int(AllAtOnceTraversal) // If compile-size is zero, traversing will fail at compile-time. + : (int(MayLinearVectorize) && (LinearPacketSize>InnerPacketSize)) ? int(LinearVectorizedTraversal) + : int(MayInnerVectorize) ? int(InnerVectorizedTraversal) + : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) + : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) + : int(MayLinearize) ? int(LinearTraversal) + : int(DefaultTraversal), + Vectorized = int(Traversal) == InnerVectorizedTraversal + || int(Traversal) == LinearVectorizedTraversal + || int(Traversal) == SliceVectorizedTraversal + }; + + typedef typename conditional::type PacketType; + +private: + enum { + ActualPacketSize = int(Traversal)==LinearVectorizedTraversal ? LinearPacketSize + : Vectorized ? InnerPacketSize + : 1, + UnrollingLimit = EIGEN_UNROLLING_LIMIT * ActualPacketSize, + MayUnrollCompletely = int(Dst::SizeAtCompileTime) != Dynamic + && int(Dst::SizeAtCompileTime) * (int(DstEvaluator::CoeffReadCost)+int(SrcEvaluator::CoeffReadCost)) <= int(UnrollingLimit), + MayUnrollInner = int(InnerSize) != Dynamic + && int(InnerSize) * (int(DstEvaluator::CoeffReadCost)+int(SrcEvaluator::CoeffReadCost)) <= int(UnrollingLimit) + }; + +public: + enum { + Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) + ? ( + int(MayUnrollCompletely) ? int(CompleteUnrolling) + : int(MayUnrollInner) ? int(InnerUnrolling) + : int(NoUnrolling) + ) + : int(Traversal) == int(LinearVectorizedTraversal) + ? ( bool(MayUnrollCompletely) && ( EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment))) + ? int(CompleteUnrolling) + : int(NoUnrolling) ) + : int(Traversal) == int(LinearTraversal) + ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) + : int(NoUnrolling) ) +#if EIGEN_UNALIGNED_VECTORIZE + : int(Traversal) == int(SliceVectorizedTraversal) + ? ( bool(MayUnrollInner) ? int(InnerUnrolling) + : int(NoUnrolling) ) +#endif + : int(NoUnrolling) + }; + +#ifdef EIGEN_DEBUG_ASSIGN + static void debug() + { + std::cerr << "DstXpr: " << typeid(typename DstEvaluator::XprType).name() << std::endl; + std::cerr << "SrcXpr: " << typeid(typename SrcEvaluator::XprType).name() << std::endl; + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "DstFlags" << " = " << DstFlags << " (" << demangle_flags(DstFlags) << " )" << std::endl; + std::cerr << "SrcFlags" << " = " << SrcFlags << " (" << demangle_flags(SrcFlags) << " )" << std::endl; + std::cerr.unsetf(std::ios::hex); + EIGEN_DEBUG_VAR(DstAlignment) + EIGEN_DEBUG_VAR(SrcAlignment) + EIGEN_DEBUG_VAR(LinearRequiredAlignment) + EIGEN_DEBUG_VAR(InnerRequiredAlignment) + EIGEN_DEBUG_VAR(JointAlignment) + EIGEN_DEBUG_VAR(InnerSize) + EIGEN_DEBUG_VAR(InnerMaxSize) + EIGEN_DEBUG_VAR(LinearPacketSize) + EIGEN_DEBUG_VAR(InnerPacketSize) + EIGEN_DEBUG_VAR(ActualPacketSize) + EIGEN_DEBUG_VAR(StorageOrdersAgree) + EIGEN_DEBUG_VAR(MightVectorize) + EIGEN_DEBUG_VAR(MayLinearize) + EIGEN_DEBUG_VAR(MayInnerVectorize) + EIGEN_DEBUG_VAR(MayLinearVectorize) + EIGEN_DEBUG_VAR(MaySliceVectorize) + std::cerr << "Traversal" << " = " << Traversal << " (" << demangle_traversal(Traversal) << ")" << std::endl; + EIGEN_DEBUG_VAR(SrcEvaluator::CoeffReadCost) + EIGEN_DEBUG_VAR(DstEvaluator::CoeffReadCost) + EIGEN_DEBUG_VAR(Dst::SizeAtCompileTime) + EIGEN_DEBUG_VAR(UnrollingLimit) + EIGEN_DEBUG_VAR(MayUnrollCompletely) + EIGEN_DEBUG_VAR(MayUnrollInner) + std::cerr << "Unrolling" << " = " << Unrolling << " (" << demangle_unrolling(Unrolling) << ")" << std::endl; + std::cerr << std::endl; + } +#endif +}; + +/*************************************************************************** +* Part 2 : meta-unrollers +***************************************************************************/ + +/************************ +*** Default traversal *** +************************/ + +template +struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling +{ + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? + typedef typename Kernel::DstEvaluatorType DstEvaluatorType; + typedef typename DstEvaluatorType::XprType DstXprType; + + enum { + outer = Index / DstXprType::InnerSizeAtCompileTime, + inner = Index % DstXprType::InnerSizeAtCompileTime + }; + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + kernel.assignCoeffByOuterInner(outer, inner); + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +template +struct copy_using_evaluator_DefaultTraversal_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer) + { + kernel.assignCoeffByOuterInner(outer, Index_); + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } +}; + +template +struct copy_using_evaluator_DefaultTraversal_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index) { } +}; + +/*********************** +*** Linear traversal *** +***********************/ + +template +struct copy_using_evaluator_LinearTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel& kernel) + { + kernel.assignCoeff(Index); + copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_LinearTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +/************************** +*** Inner vectorization *** +**************************/ + +template +struct copy_using_evaluator_innervec_CompleteUnrolling +{ + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? + typedef typename Kernel::DstEvaluatorType DstEvaluatorType; + typedef typename DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::PacketType PacketType; + + enum { + outer = Index / DstXprType::InnerSizeAtCompileTime, + inner = Index % DstXprType::InnerSizeAtCompileTime, + SrcAlignment = Kernel::AssignmentTraits::SrcAlignment, + DstAlignment = Kernel::AssignmentTraits::DstAlignment + }; + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + kernel.template assignPacketByOuterInner(outer, inner); + enum { NextIndex = Index + unpacket_traits::size }; + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_innervec_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +template +struct copy_using_evaluator_innervec_InnerUnrolling +{ + typedef typename Kernel::PacketType PacketType; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer) + { + kernel.template assignPacketByOuterInner(outer, Index_); + enum { NextIndex = Index_ + unpacket_traits::size }; + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + } +}; + +template +struct copy_using_evaluator_innervec_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &, Index) { } +}; + +/*************************************************************************** +* Part 3 : implementation of all cases +***************************************************************************/ + +// dense_assignment_loop is based on assign_impl + +template +struct dense_assignment_loop; + +/************************ +***** Special Cases ***** +************************/ + +// Zero-sized assignment is a no-op. +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static void EIGEN_STRONG_INLINE run(Kernel& /*kernel*/) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + EIGEN_STATIC_ASSERT(int(DstXprType::SizeAtCompileTime) == 0, + EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT) + } +}; + +/************************ +*** Default traversal *** +************************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static void EIGEN_STRONG_INLINE run(Kernel &kernel) + { + for(Index outer = 0; outer < kernel.outerSize(); ++outer) { + for(Index inner = 0; inner < kernel.innerSize(); ++inner) { + kernel.assignCoeffByOuterInner(outer, inner); + } + } + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + + const Index outerSize = kernel.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } +}; + +/*************************** +*** Linear vectorization *** +***************************/ + + +// The goal of unaligned_dense_assignment_loop is simply to factorize the handling +// of the non vectorizable beginning and ending parts + +template +struct unaligned_dense_assignment_loop +{ + // if IsAligned = true, then do nothing + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index, Index) {} +}; + +template <> +struct unaligned_dense_assignment_loop +{ + // MSVC must not inline this functions. If it does, it fails to optimize the + // packet access path. + // FIXME check which version exhibits this issue +#if EIGEN_COMP_MSVC + template + static EIGEN_DONT_INLINE void run(Kernel &kernel, + Index start, + Index end) +#else + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, + Index start, + Index end) +#endif + { + for (Index index = start; index < end; ++index) + kernel.assignCoeff(index); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index size = kernel.size(); + typedef typename Kernel::Scalar Scalar; + typedef typename Kernel::PacketType PacketType; + enum { + requestedAlignment = Kernel::AssignmentTraits::LinearRequiredAlignment, + packetSize = unpacket_traits::size, + dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment), + dstAlignment = packet_traits::AlignedOnScalar ? int(requestedAlignment) + : int(Kernel::AssignmentTraits::DstAlignment), + srcAlignment = Kernel::AssignmentTraits::JointAlignment + }; + const Index alignedStart = dstIsAligned ? 0 : internal::first_aligned(kernel.dstDataPtr(), size); + const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; + + unaligned_dense_assignment_loop::run(kernel, 0, alignedStart); + + for(Index index = alignedStart; index < alignedEnd; index += packetSize) + kernel.template assignPacket(index); + + unaligned_dense_assignment_loop<>::run(kernel, alignedEnd, size); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::PacketType PacketType; + + enum { size = DstXprType::SizeAtCompileTime, + packetSize =unpacket_traits::size, + alignedSize = (int(size)/packetSize)*packetSize }; + + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +/************************** +*** Inner vectorization *** +**************************/ + +template +struct dense_assignment_loop +{ + typedef typename Kernel::PacketType PacketType; + enum { + SrcAlignment = Kernel::AssignmentTraits::SrcAlignment, + DstAlignment = Kernel::AssignmentTraits::DstAlignment + }; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index innerSize = kernel.innerSize(); + const Index outerSize = kernel.outerSize(); + const Index packetSize = unpacket_traits::size; + for(Index outer = 0; outer < outerSize; ++outer) + for(Index inner = 0; inner < innerSize; inner+=packetSize) + kernel.template assignPacketByOuterInner(outer, inner); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::AssignmentTraits Traits; + const Index outerSize = kernel.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + } +}; + +/*********************** +*** Linear traversal *** +***********************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index size = kernel.size(); + for(Index i = 0; i < size; ++i) + kernel.assignCoeff(i); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); + } +}; + +/************************** +*** Slice vectorization *** +***************************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::Scalar Scalar; + typedef typename Kernel::PacketType PacketType; + enum { + packetSize = unpacket_traits::size, + requestedAlignment = int(Kernel::AssignmentTraits::InnerRequiredAlignment), + alignable = packet_traits::AlignedOnScalar || int(Kernel::AssignmentTraits::DstAlignment)>=sizeof(Scalar), + dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment), + dstAlignment = alignable ? int(requestedAlignment) + : int(Kernel::AssignmentTraits::DstAlignment) + }; + const Scalar *dst_ptr = kernel.dstDataPtr(); + if((!bool(dstIsAligned)) && (UIntPtr(dst_ptr) % sizeof(Scalar))>0) + { + // the pointer is not aligned-on scalar, so alignment is not possible + return dense_assignment_loop::run(kernel); + } + const Index packetAlignedMask = packetSize - 1; + const Index innerSize = kernel.innerSize(); + const Index outerSize = kernel.outerSize(); + const Index alignedStep = alignable ? (packetSize - kernel.outerStride() % packetSize) & packetAlignedMask : 0; + Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); + + for(Index outer = 0; outer < outerSize; ++outer) + { + const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); + // do the non-vectorizable part of the assignment + for(Index inner = 0; inner(outer, inner); + + // do the non-vectorizable part of the assignment + for(Index inner = alignedEnd; inner +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::PacketType PacketType; + + enum { innerSize = DstXprType::InnerSizeAtCompileTime, + packetSize =unpacket_traits::size, + vectorizableSize = (int(innerSize) / int(packetSize)) * int(packetSize), + size = DstXprType::SizeAtCompileTime }; + + for(Index outer = 0; outer < kernel.outerSize(); ++outer) + { + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } + } +}; +#endif + + +/*************************************************************************** +* Part 4 : Generic dense assignment kernel +***************************************************************************/ + +// This class generalize the assignment of a coefficient (or packet) from one dense evaluator +// to another dense writable evaluator. +// It is parametrized by the two evaluators, and the actual assignment functor. +// This abstraction level permits to keep the evaluation loops as simple and as generic as possible. +// One can customize the assignment using this generic dense_assignment_kernel with different +// functors, or by completely overloading it, by-passing a functor. +template +class generic_dense_assignment_kernel +{ +protected: + typedef typename DstEvaluatorTypeT::XprType DstXprType; + typedef typename SrcEvaluatorTypeT::XprType SrcXprType; +public: + + typedef DstEvaluatorTypeT DstEvaluatorType; + typedef SrcEvaluatorTypeT SrcEvaluatorType; + typedef typename DstEvaluatorType::Scalar Scalar; + typedef copy_using_evaluator_traits AssignmentTraits; + typedef typename AssignmentTraits::PacketType PacketType; + + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + generic_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + : m_dst(dst), m_src(src), m_functor(func), m_dstExpr(dstExpr) + { + #ifdef EIGEN_DEBUG_ASSIGN + AssignmentTraits::debug(); + #endif + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT { return m_dstExpr.size(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index innerSize() const EIGEN_NOEXCEPT { return m_dstExpr.innerSize(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index outerSize() const EIGEN_NOEXCEPT { return m_dstExpr.outerSize(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT { return m_dstExpr.rows(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT { return m_dstExpr.cols(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index outerStride() const EIGEN_NOEXCEPT { return m_dstExpr.outerStride(); } + + EIGEN_DEVICE_FUNC DstEvaluatorType& dstEvaluator() EIGEN_NOEXCEPT { return m_dst; } + EIGEN_DEVICE_FUNC const SrcEvaluatorType& srcEvaluator() const EIGEN_NOEXCEPT { return m_src; } + + /// Assign src(row,col) to dst(row,col) through the assignment functor. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index row, Index col) + { + m_functor.assignCoeff(m_dst.coeffRef(row,col), m_src.coeff(row,col)); + } + + /// \sa assignCoeff(Index,Index) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index index) + { + m_functor.assignCoeff(m_dst.coeffRef(index), m_src.coeff(index)); + } + + /// \sa assignCoeff(Index,Index) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeffByOuterInner(Index outer, Index inner) + { + Index row = rowIndexByOuterInner(outer, inner); + Index col = colIndexByOuterInner(outer, inner); + assignCoeff(row, col); + } + + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index row, Index col) + { + m_functor.template assignPacket(&m_dst.coeffRef(row,col), m_src.template packet(row,col)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index index) + { + m_functor.template assignPacket(&m_dst.coeffRef(index), m_src.template packet(index)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacketByOuterInner(Index outer, Index inner) + { + Index row = rowIndexByOuterInner(outer, inner); + Index col = colIndexByOuterInner(outer, inner); + assignPacket(row, col); + } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) + { + typedef typename DstEvaluatorType::ExpressionTraits Traits; + return int(Traits::RowsAtCompileTime) == 1 ? 0 + : int(Traits::ColsAtCompileTime) == 1 ? inner + : int(DstEvaluatorType::Flags)&RowMajorBit ? outer + : inner; + } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) + { + typedef typename DstEvaluatorType::ExpressionTraits Traits; + return int(Traits::ColsAtCompileTime) == 1 ? 0 + : int(Traits::RowsAtCompileTime) == 1 ? inner + : int(DstEvaluatorType::Flags)&RowMajorBit ? inner + : outer; + } + + EIGEN_DEVICE_FUNC const Scalar* dstDataPtr() const + { + return m_dstExpr.data(); + } + +protected: + DstEvaluatorType& m_dst; + const SrcEvaluatorType& m_src; + const Functor &m_functor; + // TODO find a way to avoid the needs of the original expression + DstXprType& m_dstExpr; +}; + +// Special kernel used when computing small products whose operands have dynamic dimensions. It ensures that the +// PacketSize used is no larger than 4, thereby increasing the chance that vectorized instructions will be used +// when computing the product. + +template +class restricted_packet_dense_assignment_kernel : public generic_dense_assignment_kernel +{ +protected: + typedef generic_dense_assignment_kernel Base; + public: + typedef typename Base::Scalar Scalar; + typedef typename Base::DstXprType DstXprType; + typedef copy_using_evaluator_traits AssignmentTraits; + typedef typename AssignmentTraits::PacketType PacketType; + + EIGEN_DEVICE_FUNC restricted_packet_dense_assignment_kernel(DstEvaluatorTypeT &dst, const SrcEvaluatorTypeT &src, const Functor &func, DstXprType& dstExpr) + : Base(dst, src, func, dstExpr) + { + } + }; + +/*************************************************************************** +* Part 5 : Entry point for dense rectangular assignment +***************************************************************************/ + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const Functor &/*func*/) +{ + EIGEN_ONLY_USED_FOR_DEBUG(dst); + EIGEN_ONLY_USED_FOR_DEBUG(src); + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const internal::assign_op &/*func*/) +{ + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if(((dst.rows()!=dstRows) || (dst.cols()!=dstCols))) + dst.resize(dstRows, dstCols); + eigen_assert(dst.rows() == dstRows && dst.cols() == dstCols); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src, const Functor &func) +{ + typedef evaluator DstEvaluatorType; + typedef evaluator SrcEvaluatorType; + + SrcEvaluatorType srcEvaluator(src); + + // NOTE To properly handle A = (A*A.transpose())/s with A rectangular, + // we need to resize the destination after the source evaluator has been created. + resize_if_allowed(dst, src, func); + + DstEvaluatorType dstEvaluator(dst); + + typedef generic_dense_assignment_kernel Kernel; + Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); + + dense_assignment_loop::run(kernel); +} + +// Specialization for filling the destination with a constant value. +#ifndef EIGEN_GPU_COMPILE_PHASE +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const Eigen::CwiseNullaryOp, DstXprType>& src, const internal::assign_op& func) +{ + resize_if_allowed(dst, src, func); + std::fill_n(dst.data(), dst.size(), src.functor()()); +} +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src) +{ + call_dense_assignment_loop(dst, src, internal::assign_op()); +} + +/*************************************************************************** +* Part 6 : Generic assignment +***************************************************************************/ + +// Based on the respective shapes of the destination and source, +// the class AssignmentKind determine the kind of assignment mechanism. +// AssignmentKind must define a Kind typedef. +template struct AssignmentKind; + +// Assignment kind defined in this file: +struct Dense2Dense {}; +struct EigenBase2EigenBase {}; + +template struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; +template<> struct AssignmentKind { typedef Dense2Dense Kind; }; + +// This is the main assignment class +template< typename DstXprType, typename SrcXprType, typename Functor, + typename Kind = typename AssignmentKind< typename evaluator_traits::Shape , typename evaluator_traits::Shape >::Kind, + typename EnableIf = void> +struct Assignment; + + +// The only purpose of this call_assignment() function is to deal with noalias() / "assume-aliasing" and automatic transposition. +// Indeed, I (Gael) think that this concept of "assume-aliasing" was a mistake, and it makes thing quite complicated. +// So this intermediate function removes everything related to "assume-aliasing" such that Assignment +// does not has to bother about these annoying details. + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op()); +} +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(const Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op()); +} + +// Deal with "assume-aliasing" +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if< evaluator_assume_aliasing::value, void*>::type = 0) +{ + typename plain_matrix_type::type tmp(src); + call_assignment_no_alias(dst, tmp, func); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::value, void*>::type = 0) +{ + call_assignment_no_alias(dst, src, func); +} + +// by-pass "assume-aliasing" +// When there is no aliasing, we require that 'dst' has been properly resized +template class StorageBase, typename Src, typename Func> +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(NoAlias& dst, const Src& src, const Func& func) +{ + call_assignment_no_alias(dst.expression(), src, func); +} + + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) +{ + enum { + NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) + || (int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1) + ) && int(Dst::SizeAtCompileTime) != 1 + }; + + typedef typename internal::conditional, Dst>::type ActualDstTypeCleaned; + typedef typename internal::conditional, Dst&>::type ActualDstType; + ActualDstType actualDst(dst); + + // TODO check whether this is the right place to perform these checks: + EIGEN_STATIC_ASSERT_LVALUE(Dst) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src) + EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar); + + Assignment::run(actualDst, src, func); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_restricted_packet_assignment_no_alias(Dst& dst, const Src& src, const Func& func) +{ + typedef evaluator DstEvaluatorType; + typedef evaluator SrcEvaluatorType; + typedef restricted_packet_dense_assignment_kernel Kernel; + + EIGEN_STATIC_ASSERT_LVALUE(Dst) + EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename Dst::Scalar,typename Src::Scalar); + + SrcEvaluatorType srcEvaluator(src); + resize_if_allowed(dst, src, func); + + DstEvaluatorType dstEvaluator(dst); + Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); + + dense_assignment_loop::run(kernel); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias(Dst& dst, const Src& src) +{ + call_assignment_no_alias(dst, src, internal::assign_op()); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src, const Func& func) +{ + // TODO check whether this is the right place to perform these checks: + EIGEN_STATIC_ASSERT_LVALUE(Dst) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Dst,Src) + EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename Dst::Scalar,typename Src::Scalar); + + Assignment::run(dst, src, func); +} +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src) +{ + call_assignment_no_alias_no_transpose(dst, src, internal::assign_op()); +} + +// forward declaration +template void check_for_aliasing(const Dst &dst, const Src &src); + +// Generic Dense to Dense assignment +// Note that the last template argument "Weak" is needed to make it possible to perform +// both partial specialization+SFINAE without ambiguous specialization +template< typename DstXprType, typename SrcXprType, typename Functor, typename Weak> +struct Assignment +{ + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { +#ifndef EIGEN_NO_DEBUG + internal::check_for_aliasing(dst, src); +#endif + + call_dense_assignment_loop(dst, src, func); + } +}; + +// Generic assignment through evalTo. +// TODO: not sure we have to keep that one, but it helps porting current code to new evaluator mechanism. +// Note that the last template argument "Weak" is needed to make it possible to perform +// both partial specialization+SFINAE without ambiguous specialization +template< typename DstXprType, typename SrcXprType, typename Functor, typename Weak> +struct Assignment +{ + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + src.evalTo(dst); + } + + // NOTE The following two functions are templated to avoid their instantiation if not needed + // This is needed because some expressions supports evalTo only and/or have 'void' as scalar type. + template + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + src.addTo(dst); + } + + template + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + src.subTo(dst); + } +}; + +} // namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_EVALUATOR_H diff --git a/Vendor/eigen/Eigen/src/Core/Assign_MKL.h b/Vendor/eigen/Eigen/src/Core/Assign_MKL.h new file mode 100755 index 0000000..c6140d1 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Assign_MKL.h @@ -0,0 +1,178 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + Copyright (C) 2015 Gael Guennebaud + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Eigen bindings to Intel(R) MKL + * MKL VML support for coefficient-wise unary Eigen expressions like a=b.sin() + ******************************************************************************** +*/ + +#ifndef EIGEN_ASSIGN_VML_H +#define EIGEN_ASSIGN_VML_H + +namespace Eigen { + +namespace internal { + +template +class vml_assign_traits +{ + private: + enum { + DstHasDirectAccess = Dst::Flags & DirectAccessBit, + SrcHasDirectAccess = Src::Flags & DirectAccessBit, + StorageOrdersAgree = (int(Dst::IsRowMajor) == int(Src::IsRowMajor)), + InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) + : int(Dst::Flags)&RowMajorBit ? int(Dst::ColsAtCompileTime) + : int(Dst::RowsAtCompileTime), + InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) + : int(Dst::Flags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) + : int(Dst::MaxRowsAtCompileTime), + MaxSizeAtCompileTime = Dst::SizeAtCompileTime, + + MightEnableVml = StorageOrdersAgree && DstHasDirectAccess && SrcHasDirectAccess && Src::InnerStrideAtCompileTime==1 && Dst::InnerStrideAtCompileTime==1, + MightLinearize = MightEnableVml && (int(Dst::Flags) & int(Src::Flags) & LinearAccessBit), + VmlSize = MightLinearize ? MaxSizeAtCompileTime : InnerMaxSize, + LargeEnough = VmlSize==Dynamic || VmlSize>=EIGEN_MKL_VML_THRESHOLD + }; + public: + enum { + EnableVml = MightEnableVml && LargeEnough, + Traversal = MightLinearize ? LinearTraversal : DefaultTraversal + }; +}; + +#define EIGEN_PP_EXPAND(ARG) ARG +#if !defined (EIGEN_FAST_MATH) || (EIGEN_FAST_MATH != 1) +#define EIGEN_VMLMODE_EXPAND_xLA , VML_HA +#else +#define EIGEN_VMLMODE_EXPAND_xLA , VML_LA +#endif + +#define EIGEN_VMLMODE_EXPAND_x_ + +#define EIGEN_VMLMODE_PREFIX_xLA vm +#define EIGEN_VMLMODE_PREFIX_x_ v +#define EIGEN_VMLMODE_PREFIX(VMLMODE) EIGEN_CAT(EIGEN_VMLMODE_PREFIX_x,VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \ + template< typename DstXprType, typename SrcXprNested> \ + struct Assignment, SrcXprNested>, assign_op, \ + Dense2Dense, typename enable_if::EnableVml>::type> { \ + typedef CwiseUnaryOp, SrcXprNested> SrcXprType; \ + static void run(DstXprType &dst, const SrcXprType &src, const assign_op &func) { \ + resize_if_allowed(dst, src, func); \ + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \ + if(vml_assign_traits::Traversal==LinearTraversal) { \ + VMLOP(dst.size(), (const VMLTYPE*)src.nestedExpression().data(), \ + (VMLTYPE*)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_x##VMLMODE) ); \ + } else { \ + const Index outerSize = dst.outerSize(); \ + for(Index outer = 0; outer < outerSize; ++outer) { \ + const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : \ + &(src.nestedExpression().coeffRef(0, outer)); \ + EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); \ + VMLOP( dst.innerSize(), (const VMLTYPE*)src_ptr, \ + (VMLTYPE*)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_x##VMLMODE)); \ + } \ + } \ + } \ + }; \ + + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),s##VMLOP), float, float, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),d##VMLOP), double, double, VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),c##VMLOP), scomplex, MKL_Complex8, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),z##VMLOP), dcomplex, MKL_Complex16, VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) + + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sin, Sin, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(asin, Asin, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sinh, Sinh, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cos, Cos, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(acos, Acos, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cosh, Cosh, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tan, Tan, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(atan, Atan, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tanh, Tanh, LA) +// EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(exp, Exp, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log, Ln, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log10, Log10, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sqrt, Sqrt, _) + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(arg, Arg, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(round, Round, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(floor, Floor, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(ceil, Ceil, _) + +#define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \ + template< typename DstXprType, typename SrcXprNested, typename Plain> \ + struct Assignment, SrcXprNested, \ + const CwiseNullaryOp,Plain> >, assign_op, \ + Dense2Dense, typename enable_if::EnableVml>::type> { \ + typedef CwiseBinaryOp, SrcXprNested, \ + const CwiseNullaryOp,Plain> > SrcXprType; \ + static void run(DstXprType &dst, const SrcXprType &src, const assign_op &func) { \ + resize_if_allowed(dst, src, func); \ + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \ + VMLTYPE exponent = reinterpret_cast(src.rhs().functor().m_other); \ + if(vml_assign_traits::Traversal==LinearTraversal) \ + { \ + VMLOP( dst.size(), (const VMLTYPE*)src.lhs().data(), exponent, \ + (VMLTYPE*)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_x##VMLMODE) ); \ + } else { \ + const Index outerSize = dst.outerSize(); \ + for(Index outer = 0; outer < outerSize; ++outer) { \ + const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.lhs().coeffRef(outer,0)) : \ + &(src.lhs().coeffRef(0, outer)); \ + EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); \ + VMLOP( dst.innerSize(), (const VMLTYPE*)src_ptr, exponent, \ + (VMLTYPE*)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_x##VMLMODE)); \ + } \ + } \ + } \ + }; + +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmsPowx, float, float, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdPowx, double, double, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcPowx, scomplex, MKL_Complex8, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzPowx, dcomplex, MKL_Complex16, LA) + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_VML_H diff --git a/Vendor/eigen/Eigen/src/Core/BandMatrix.h b/Vendor/eigen/Eigen/src/Core/BandMatrix.h new file mode 100644 index 0000000..878c024 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/BandMatrix.h @@ -0,0 +1,353 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_BANDMATRIX_H +#define EIGEN_BANDMATRIX_H + +namespace Eigen { + +namespace internal { + +template +class BandMatrixBase : public EigenBase +{ + public: + + enum { + Flags = internal::traits::Flags, + CoeffReadCost = internal::traits::CoeffReadCost, + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + ColsAtCompileTime = internal::traits::ColsAtCompileTime, + MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, + Supers = internal::traits::Supers, + Subs = internal::traits::Subs, + Options = internal::traits::Options + }; + typedef typename internal::traits::Scalar Scalar; + typedef Matrix DenseMatrixType; + typedef typename DenseMatrixType::StorageIndex StorageIndex; + typedef typename internal::traits::CoefficientsType CoefficientsType; + typedef EigenBase Base; + + protected: + enum { + DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) + ? 1 + Supers + Subs + : Dynamic, + SizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime,ColsAtCompileTime) + }; + + public: + + using Base::derived; + using Base::rows; + using Base::cols; + + /** \returns the number of super diagonals */ + inline Index supers() const { return derived().supers(); } + + /** \returns the number of sub diagonals */ + inline Index subs() const { return derived().subs(); } + + /** \returns an expression of the underlying coefficient matrix */ + inline const CoefficientsType& coeffs() const { return derived().coeffs(); } + + /** \returns an expression of the underlying coefficient matrix */ + inline CoefficientsType& coeffs() { return derived().coeffs(); } + + /** \returns a vector expression of the \a i -th column, + * only the meaningful part is returned. + * \warning the internal storage must be column major. */ + inline Block col(Index i) + { + EIGEN_STATIC_ASSERT((int(Options) & int(RowMajor)) == 0, THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); + Index start = 0; + Index len = coeffs().rows(); + if (i<=supers()) + { + start = supers()-i; + len = (std::min)(rows(),std::max(0,coeffs().rows() - (supers()-i))); + } + else if (i>=rows()-subs()) + len = std::max(0,coeffs().rows() - (i + 1 - rows() + subs())); + return Block(coeffs(), start, i, len, 1); + } + + /** \returns a vector expression of the main diagonal */ + inline Block diagonal() + { return Block(coeffs(),supers(),0,1,(std::min)(rows(),cols())); } + + /** \returns a vector expression of the main diagonal (const version) */ + inline const Block diagonal() const + { return Block(coeffs(),supers(),0,1,(std::min)(rows(),cols())); } + + template struct DiagonalIntReturnType { + enum { + ReturnOpposite = (int(Options) & int(SelfAdjoint)) && (((Index) > 0 && Supers == 0) || ((Index) < 0 && Subs == 0)), + Conjugate = ReturnOpposite && NumTraits::IsComplex, + ActualIndex = ReturnOpposite ? -Index : Index, + DiagonalSize = (RowsAtCompileTime==Dynamic || ColsAtCompileTime==Dynamic) + ? Dynamic + : (ActualIndex<0 + ? EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime, RowsAtCompileTime + ActualIndex) + : EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime, ColsAtCompileTime - ActualIndex)) + }; + typedef Block BuildType; + typedef typename internal::conditional,BuildType >, + BuildType>::type Type; + }; + + /** \returns a vector expression of the \a N -th sub or super diagonal */ + template inline typename DiagonalIntReturnType::Type diagonal() + { + return typename DiagonalIntReturnType::BuildType(coeffs(), supers()-N, (std::max)(0,N), 1, diagonalLength(N)); + } + + /** \returns a vector expression of the \a N -th sub or super diagonal */ + template inline const typename DiagonalIntReturnType::Type diagonal() const + { + return typename DiagonalIntReturnType::BuildType(coeffs(), supers()-N, (std::max)(0,N), 1, diagonalLength(N)); + } + + /** \returns a vector expression of the \a i -th sub or super diagonal */ + inline Block diagonal(Index i) + { + eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers())); + return Block(coeffs(), supers()-i, std::max(0,i), 1, diagonalLength(i)); + } + + /** \returns a vector expression of the \a i -th sub or super diagonal */ + inline const Block diagonal(Index i) const + { + eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers())); + return Block(coeffs(), supers()-i, std::max(0,i), 1, diagonalLength(i)); + } + + template inline void evalTo(Dest& dst) const + { + dst.resize(rows(),cols()); + dst.setZero(); + dst.diagonal() = diagonal(); + for (Index i=1; i<=supers();++i) + dst.diagonal(i) = diagonal(i); + for (Index i=1; i<=subs();++i) + dst.diagonal(-i) = diagonal(-i); + } + + DenseMatrixType toDenseMatrix() const + { + DenseMatrixType res(rows(),cols()); + evalTo(res); + return res; + } + + protected: + + inline Index diagonalLength(Index i) const + { return i<0 ? (std::min)(cols(),rows()+i) : (std::min)(rows(),cols()-i); } +}; + +/** + * \class BandMatrix + * \ingroup Core_Module + * + * \brief Represents a rectangular matrix with a banded storage + * + * \tparam _Scalar Numeric type, i.e. float, double, int + * \tparam _Rows Number of rows, or \b Dynamic + * \tparam _Cols Number of columns, or \b Dynamic + * \tparam _Supers Number of super diagonal + * \tparam _Subs Number of sub diagonal + * \tparam _Options A combination of either \b #RowMajor or \b #ColMajor, and of \b #SelfAdjoint + * The former controls \ref TopicStorageOrders "storage order", and defaults to + * column-major. The latter controls whether the matrix represents a selfadjoint + * matrix in which case either Supers of Subs have to be null. + * + * \sa class TridiagonalMatrix + */ + +template +struct traits > +{ + typedef _Scalar Scalar; + typedef Dense StorageKind; + typedef Eigen::Index StorageIndex; + enum { + CoeffReadCost = NumTraits::ReadCost, + RowsAtCompileTime = _Rows, + ColsAtCompileTime = _Cols, + MaxRowsAtCompileTime = _Rows, + MaxColsAtCompileTime = _Cols, + Flags = LvalueBit, + Supers = _Supers, + Subs = _Subs, + Options = _Options, + DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic + }; + typedef Matrix CoefficientsType; +}; + +template +class BandMatrix : public BandMatrixBase > +{ + public: + + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::traits::StorageIndex StorageIndex; + typedef typename internal::traits::CoefficientsType CoefficientsType; + + explicit inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) + : m_coeffs(1+supers+subs,cols), + m_rows(rows), m_supers(supers), m_subs(subs) + { + } + + /** \returns the number of columns */ + inline EIGEN_CONSTEXPR Index rows() const { return m_rows.value(); } + + /** \returns the number of rows */ + inline EIGEN_CONSTEXPR Index cols() const { return m_coeffs.cols(); } + + /** \returns the number of super diagonals */ + inline EIGEN_CONSTEXPR Index supers() const { return m_supers.value(); } + + /** \returns the number of sub diagonals */ + inline EIGEN_CONSTEXPR Index subs() const { return m_subs.value(); } + + inline const CoefficientsType& coeffs() const { return m_coeffs; } + inline CoefficientsType& coeffs() { return m_coeffs; } + + protected: + + CoefficientsType m_coeffs; + internal::variable_if_dynamic m_rows; + internal::variable_if_dynamic m_supers; + internal::variable_if_dynamic m_subs; +}; + +template +class BandMatrixWrapper; + +template +struct traits > +{ + typedef typename _CoefficientsType::Scalar Scalar; + typedef typename _CoefficientsType::StorageKind StorageKind; + typedef typename _CoefficientsType::StorageIndex StorageIndex; + enum { + CoeffReadCost = internal::traits<_CoefficientsType>::CoeffReadCost, + RowsAtCompileTime = _Rows, + ColsAtCompileTime = _Cols, + MaxRowsAtCompileTime = _Rows, + MaxColsAtCompileTime = _Cols, + Flags = LvalueBit, + Supers = _Supers, + Subs = _Subs, + Options = _Options, + DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic + }; + typedef _CoefficientsType CoefficientsType; +}; + +template +class BandMatrixWrapper : public BandMatrixBase > +{ + public: + + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::traits::CoefficientsType CoefficientsType; + typedef typename internal::traits::StorageIndex StorageIndex; + + explicit inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) + : m_coeffs(coeffs), + m_rows(rows), m_supers(supers), m_subs(subs) + { + EIGEN_UNUSED_VARIABLE(cols); + //internal::assert(coeffs.cols()==cols() && (supers()+subs()+1)==coeffs.rows()); + } + + /** \returns the number of columns */ + inline EIGEN_CONSTEXPR Index rows() const { return m_rows.value(); } + + /** \returns the number of rows */ + inline EIGEN_CONSTEXPR Index cols() const { return m_coeffs.cols(); } + + /** \returns the number of super diagonals */ + inline EIGEN_CONSTEXPR Index supers() const { return m_supers.value(); } + + /** \returns the number of sub diagonals */ + inline EIGEN_CONSTEXPR Index subs() const { return m_subs.value(); } + + inline const CoefficientsType& coeffs() const { return m_coeffs; } + + protected: + + const CoefficientsType& m_coeffs; + internal::variable_if_dynamic m_rows; + internal::variable_if_dynamic m_supers; + internal::variable_if_dynamic m_subs; +}; + +/** + * \class TridiagonalMatrix + * \ingroup Core_Module + * + * \brief Represents a tridiagonal matrix with a compact banded storage + * + * \tparam Scalar Numeric type, i.e. float, double, int + * \tparam Size Number of rows and cols, or \b Dynamic + * \tparam Options Can be 0 or \b SelfAdjoint + * + * \sa class BandMatrix + */ +template +class TridiagonalMatrix : public BandMatrix +{ + typedef BandMatrix Base; + typedef typename Base::StorageIndex StorageIndex; + public: + explicit TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} + + inline typename Base::template DiagonalIntReturnType<1>::Type super() + { return Base::template diagonal<1>(); } + inline const typename Base::template DiagonalIntReturnType<1>::Type super() const + { return Base::template diagonal<1>(); } + inline typename Base::template DiagonalIntReturnType<-1>::Type sub() + { return Base::template diagonal<-1>(); } + inline const typename Base::template DiagonalIntReturnType<-1>::Type sub() const + { return Base::template diagonal<-1>(); } + protected: +}; + + +struct BandShape {}; + +template +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef BandShape Shape; +}; + +template +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef BandShape Shape; +}; + +template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_BANDMATRIX_H diff --git a/Vendor/eigen/Eigen/src/Core/Block.h b/Vendor/eigen/Eigen/src/Core/Block.h new file mode 100644 index 0000000..3206d66 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Block.h @@ -0,0 +1,448 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_BLOCK_H +#define EIGEN_BLOCK_H + +namespace Eigen { + +namespace internal { +template +struct traits > : traits +{ + typedef typename traits::Scalar Scalar; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::XprKind XprKind; + typedef typename ref_selector::type XprTypeNested; + typedef typename remove_reference::type _XprTypeNested; + enum{ + MatrixRows = traits::RowsAtCompileTime, + MatrixCols = traits::ColsAtCompileTime, + RowsAtCompileTime = MatrixRows == 0 ? 0 : BlockRows, + ColsAtCompileTime = MatrixCols == 0 ? 0 : BlockCols, + MaxRowsAtCompileTime = BlockRows==0 ? 0 + : RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) + : int(traits::MaxRowsAtCompileTime), + MaxColsAtCompileTime = BlockCols==0 ? 0 + : ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) + : int(traits::MaxColsAtCompileTime), + + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, + IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + : XprTypeIsRowMajor, + HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), + InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), + InnerStrideAtCompileTime = HasSameStorageOrderAsXprType + ? int(inner_stride_at_compile_time::ret) + : int(outer_stride_at_compile_time::ret), + OuterStrideAtCompileTime = HasSameStorageOrderAsXprType + ? int(outer_stride_at_compile_time::ret) + : int(inner_stride_at_compile_time::ret), + + // FIXME, this traits is rather specialized for dense object and it needs to be cleaned further + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, + Flags = (traits::Flags & (DirectAccessBit | (InnerPanel?CompressedAccessBit:0))) | FlagsLvalueBit | FlagsRowMajorBit, + // FIXME DirectAccessBit should not be handled by expressions + // + // Alignment is needed by MapBase's assertions + // We can sefely set it to false here. Internal alignment errors will be detected by an eigen_internal_assert in the respective evaluator + Alignment = 0 + }; +}; + +template::ret> class BlockImpl_dense; + +} // end namespace internal + +template class BlockImpl; + +/** \class Block + * \ingroup Core_Module + * + * \brief Expression of a fixed-size or dynamic-size block + * + * \tparam XprType the type of the expression in which we are taking a block + * \tparam BlockRows the number of rows of the block we are taking at compile time (optional) + * \tparam BlockCols the number of columns of the block we are taking at compile time (optional) + * \tparam InnerPanel is true, if the block maps to a set of rows of a row major matrix or + * to set of columns of a column major matrix (optional). The parameter allows to determine + * at compile time whether aligned access is possible on the block expression. + * + * This class represents an expression of either a fixed-size or dynamic-size block. It is the return + * type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block(Index,Index) and + * most of the time this is the only way it is used. + * + * However, if you want to directly maniputate block expressions, + * for instance if you want to write a function returning such an expression, you + * will need to use this class. + * + * Here is an example illustrating the dynamic case: + * \include class_Block.cpp + * Output: \verbinclude class_Block.out + * + * \note Even though this expression has dynamic size, in the case where \a XprType + * has fixed size, this expression inherits a fixed maximal size which means that evaluating + * it does not cause a dynamic memory allocation. + * + * Here is an example illustrating the fixed-size case: + * \include class_FixedBlock.cpp + * Output: \verbinclude class_FixedBlock.out + * + * \sa DenseBase::block(Index,Index,Index,Index), DenseBase::block(Index,Index), class VectorBlock + */ +template class Block + : public BlockImpl::StorageKind> +{ + typedef BlockImpl::StorageKind> Impl; + public: + //typedef typename Impl::Base Base; + typedef Impl Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(Block) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) + + typedef typename internal::remove_all::type NestedExpression; + + /** Column or Row constructor + */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Block(XprType& xpr, Index i) : Impl(xpr,i) + { + eigen_assert( (i>=0) && ( + ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && i= 0 && BlockRows >= 0 && startRow + BlockRows <= xpr.rows() + && startCol >= 0 && BlockCols >= 0 && startCol + BlockCols <= xpr.cols()); + } + + /** Dynamic-size constructor + */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Block(XprType& xpr, + Index startRow, Index startCol, + Index blockRows, Index blockCols) + : Impl(xpr, startRow, startCol, blockRows, blockCols) + { + eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) + && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); + eigen_assert(startRow >= 0 && blockRows >= 0 && startRow <= xpr.rows() - blockRows + && startCol >= 0 && blockCols >= 0 && startCol <= xpr.cols() - blockCols); + } +}; + +// The generic default implementation for dense block simplu forward to the internal::BlockImpl_dense +// that must be specialized for direct and non-direct access... +template +class BlockImpl + : public internal::BlockImpl_dense +{ + typedef internal::BlockImpl_dense Impl; + typedef typename XprType::StorageIndex StorageIndex; + public: + typedef Impl Base; + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE BlockImpl(XprType& xpr, Index startRow, Index startCol) : Impl(xpr, startRow, startCol) {} + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) + : Impl(xpr, startRow, startCol, blockRows, blockCols) {} +}; + +namespace internal { + +/** \internal Internal implementation of dense Blocks in the general case. */ +template class BlockImpl_dense + : public internal::dense_xpr_base >::type +{ + typedef Block BlockType; + typedef typename internal::ref_selector::non_const_type XprTypeNested; + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) + + // class InnerIterator; // FIXME apparently never used + + /** Column or Row constructor + */ + EIGEN_DEVICE_FUNC + inline BlockImpl_dense(XprType& xpr, Index i) + : m_xpr(xpr), + // It is a row if and only if BlockRows==1 and BlockCols==XprType::ColsAtCompileTime, + // and it is a column if and only if BlockRows==XprType::RowsAtCompileTime and BlockCols==1, + // all other cases are invalid. + // The case a 1x1 matrix seems ambiguous, but the result is the same anyway. + m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), + m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), + m_blockRows(BlockRows==1 ? 1 : xpr.rows()), + m_blockCols(BlockCols==1 ? 1 : xpr.cols()) + {} + + /** Fixed-size constructor + */ + EIGEN_DEVICE_FUNC + inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) + : m_xpr(xpr), m_startRow(startRow), m_startCol(startCol), + m_blockRows(BlockRows), m_blockCols(BlockCols) + {} + + /** Dynamic-size constructor + */ + EIGEN_DEVICE_FUNC + inline BlockImpl_dense(XprType& xpr, + Index startRow, Index startCol, + Index blockRows, Index blockCols) + : m_xpr(xpr), m_startRow(startRow), m_startCol(startCol), + m_blockRows(blockRows), m_blockCols(blockCols) + {} + + EIGEN_DEVICE_FUNC inline Index rows() const { return m_blockRows.value(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_blockCols.value(); } + + EIGEN_DEVICE_FUNC + inline Scalar& coeffRef(Index rowId, Index colId) + { + EIGEN_STATIC_ASSERT_LVALUE(XprType) + return m_xpr.coeffRef(rowId + m_startRow.value(), colId + m_startCol.value()); + } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return m_xpr.derived().coeffRef(rowId + m_startRow.value(), colId + m_startCol.value()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index rowId, Index colId) const + { + return m_xpr.coeff(rowId + m_startRow.value(), colId + m_startCol.value()); + } + + EIGEN_DEVICE_FUNC + inline Scalar& coeffRef(Index index) + { + EIGEN_STATIC_ASSERT_LVALUE(XprType) + return m_xpr.coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); + } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index index) const + { + return m_xpr.coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); + } + + EIGEN_DEVICE_FUNC + inline const CoeffReturnType coeff(Index index) const + { + return m_xpr.coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); + } + + template + inline PacketScalar packet(Index rowId, Index colId) const + { + return m_xpr.template packet(rowId + m_startRow.value(), colId + m_startCol.value()); + } + + template + inline void writePacket(Index rowId, Index colId, const PacketScalar& val) + { + m_xpr.template writePacket(rowId + m_startRow.value(), colId + m_startCol.value(), val); + } + + template + inline PacketScalar packet(Index index) const + { + return m_xpr.template packet + (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); + } + + template + inline void writePacket(Index index, const PacketScalar& val) + { + m_xpr.template writePacket + (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), + m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0), val); + } + + #ifdef EIGEN_PARSED_BY_DOXYGEN + /** \sa MapBase::data() */ + EIGEN_DEVICE_FUNC inline const Scalar* data() const; + EIGEN_DEVICE_FUNC inline Index innerStride() const; + EIGEN_DEVICE_FUNC inline Index outerStride() const; + #endif + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const typename internal::remove_all::type& nestedExpression() const + { + return m_xpr; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + XprType& nestedExpression() { return m_xpr; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + StorageIndex startRow() const EIGEN_NOEXCEPT + { + return m_startRow.value(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + StorageIndex startCol() const EIGEN_NOEXCEPT + { + return m_startCol.value(); + } + + protected: + + XprTypeNested m_xpr; + const internal::variable_if_dynamic m_startRow; + const internal::variable_if_dynamic m_startCol; + const internal::variable_if_dynamic m_blockRows; + const internal::variable_if_dynamic m_blockCols; +}; + +/** \internal Internal implementation of dense Blocks in the direct access case.*/ +template +class BlockImpl_dense + : public MapBase > +{ + typedef Block BlockType; + typedef typename internal::ref_selector::non_const_type XprTypeNested; + enum { + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0 + }; + public: + + typedef MapBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) + + /** Column or Row constructor + */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + BlockImpl_dense(XprType& xpr, Index i) + : Base(xpr.data() + i * ( ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && (!XprTypeIsRowMajor)) + || ((BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) && ( XprTypeIsRowMajor)) ? xpr.innerStride() : xpr.outerStride()), + BlockRows==1 ? 1 : xpr.rows(), + BlockCols==1 ? 1 : xpr.cols()), + m_xpr(xpr), + m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), + m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0) + { + init(); + } + + /** Fixed-size constructor + */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) + : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol)), + m_xpr(xpr), m_startRow(startRow), m_startCol(startCol) + { + init(); + } + + /** Dynamic-size constructor + */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + BlockImpl_dense(XprType& xpr, + Index startRow, Index startCol, + Index blockRows, Index blockCols) + : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol), blockRows, blockCols), + m_xpr(xpr), m_startRow(startRow), m_startCol(startCol) + { + init(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const typename internal::remove_all::type& nestedExpression() const EIGEN_NOEXCEPT + { + return m_xpr; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + XprType& nestedExpression() { return m_xpr; } + + /** \sa MapBase::innerStride() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index innerStride() const EIGEN_NOEXCEPT + { + return internal::traits::HasSameStorageOrderAsXprType + ? m_xpr.innerStride() + : m_xpr.outerStride(); + } + + /** \sa MapBase::outerStride() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index outerStride() const EIGEN_NOEXCEPT + { + return internal::traits::HasSameStorageOrderAsXprType + ? m_xpr.outerStride() + : m_xpr.innerStride(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + StorageIndex startRow() const EIGEN_NOEXCEPT { return m_startRow.value(); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + StorageIndex startCol() const EIGEN_NOEXCEPT { return m_startCol.value(); } + + #ifndef __SUNPRO_CC + // FIXME sunstudio is not friendly with the above friend... + // META-FIXME there is no 'friend' keyword around here. Is this obsolete? + protected: + #endif + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal used by allowAligned() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + BlockImpl_dense(XprType& xpr, const Scalar* data, Index blockRows, Index blockCols) + : Base(data, blockRows, blockCols), m_xpr(xpr) + { + init(); + } + #endif + + protected: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void init() + { + m_outerStride = internal::traits::HasSameStorageOrderAsXprType + ? m_xpr.outerStride() + : m_xpr.innerStride(); + } + + XprTypeNested m_xpr; + const internal::variable_if_dynamic m_startRow; + const internal::variable_if_dynamic m_startCol; + Index m_outerStride; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_BLOCK_H diff --git a/Vendor/eigen/Eigen/src/Core/BooleanRedux.h b/Vendor/eigen/Eigen/src/Core/BooleanRedux.h new file mode 100644 index 0000000..852de8b --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/BooleanRedux.h @@ -0,0 +1,162 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ALLANDANY_H +#define EIGEN_ALLANDANY_H + +namespace Eigen { + +namespace internal { + +template +struct all_unroller +{ + enum { + col = (UnrollCount-1) / Rows, + row = (UnrollCount-1) % Rows + }; + + EIGEN_DEVICE_FUNC static inline bool run(const Derived &mat) + { + return all_unroller::run(mat) && mat.coeff(row, col); + } +}; + +template +struct all_unroller +{ + EIGEN_DEVICE_FUNC static inline bool run(const Derived &/*mat*/) { return true; } +}; + +template +struct all_unroller +{ + EIGEN_DEVICE_FUNC static inline bool run(const Derived &) { return false; } +}; + +template +struct any_unroller +{ + enum { + col = (UnrollCount-1) / Rows, + row = (UnrollCount-1) % Rows + }; + + EIGEN_DEVICE_FUNC static inline bool run(const Derived &mat) + { + return any_unroller::run(mat) || mat.coeff(row, col); + } +}; + +template +struct any_unroller +{ + EIGEN_DEVICE_FUNC static inline bool run(const Derived & /*mat*/) { return false; } +}; + +template +struct any_unroller +{ + EIGEN_DEVICE_FUNC static inline bool run(const Derived &) { return false; } +}; + +} // end namespace internal + +/** \returns true if all coefficients are true + * + * Example: \include MatrixBase_all.cpp + * Output: \verbinclude MatrixBase_all.out + * + * \sa any(), Cwise::operator<() + */ +template +EIGEN_DEVICE_FUNC inline bool DenseBase::all() const +{ + typedef internal::evaluator Evaluator; + enum { + unroll = SizeAtCompileTime != Dynamic + && SizeAtCompileTime * (int(Evaluator::CoeffReadCost) + int(NumTraits::AddCost)) <= EIGEN_UNROLLING_LIMIT + }; + Evaluator evaluator(derived()); + if(unroll) + return internal::all_unroller::RowsAtCompileTime>::run(evaluator); + else + { + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if (!evaluator.coeff(i, j)) return false; + return true; + } +} + +/** \returns true if at least one coefficient is true + * + * \sa all() + */ +template +EIGEN_DEVICE_FUNC inline bool DenseBase::any() const +{ + typedef internal::evaluator Evaluator; + enum { + unroll = SizeAtCompileTime != Dynamic + && SizeAtCompileTime * (int(Evaluator::CoeffReadCost) + int(NumTraits::AddCost)) <= EIGEN_UNROLLING_LIMIT + }; + Evaluator evaluator(derived()); + if(unroll) + return internal::any_unroller::RowsAtCompileTime>::run(evaluator); + else + { + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if (evaluator.coeff(i, j)) return true; + return false; + } +} + +/** \returns the number of coefficients which evaluate to true + * + * \sa all(), any() + */ +template +EIGEN_DEVICE_FUNC inline Eigen::Index DenseBase::count() const +{ + return derived().template cast().template cast().sum(); +} + +/** \returns true is \c *this contains at least one Not A Number (NaN). + * + * \sa allFinite() + */ +template +inline bool DenseBase::hasNaN() const +{ +#if EIGEN_COMP_MSVC || (defined __FAST_MATH__) + return derived().array().isNaN().any(); +#else + return !((derived().array()==derived().array()).all()); +#endif +} + +/** \returns true if \c *this contains only finite numbers, i.e., no NaN and no +/-INF values. + * + * \sa hasNaN() + */ +template +inline bool DenseBase::allFinite() const +{ +#if EIGEN_COMP_MSVC || (defined __FAST_MATH__) + return derived().array().isFinite().all(); +#else + return !((derived()-derived()).hasNaN()); +#endif +} + +} // end namespace Eigen + +#endif // EIGEN_ALLANDANY_H diff --git a/Vendor/eigen/Eigen/src/Core/CommaInitializer.h b/Vendor/eigen/Eigen/src/Core/CommaInitializer.h new file mode 100644 index 0000000..c0e29c7 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/CommaInitializer.h @@ -0,0 +1,164 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_COMMAINITIALIZER_H +#define EIGEN_COMMAINITIALIZER_H + +namespace Eigen { + +/** \class CommaInitializer + * \ingroup Core_Module + * + * \brief Helper class used by the comma initializer operator + * + * This class is internally used to implement the comma initializer feature. It is + * the return type of MatrixBase::operator<<, and most of the time this is the only + * way it is used. + * + * \sa \blank \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished() + */ +template +struct CommaInitializer +{ + typedef typename XprType::Scalar Scalar; + + EIGEN_DEVICE_FUNC + inline CommaInitializer(XprType& xpr, const Scalar& s) + : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1) + { + eigen_assert(m_xpr.rows() > 0 && m_xpr.cols() > 0 + && "Cannot comma-initialize a 0x0 matrix (operator<<)"); + m_xpr.coeffRef(0,0) = s; + } + + template + EIGEN_DEVICE_FUNC + inline CommaInitializer(XprType& xpr, const DenseBase& other) + : m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows()) + { + eigen_assert(m_xpr.rows() >= other.rows() && m_xpr.cols() >= other.cols() + && "Cannot comma-initialize a 0x0 matrix (operator<<)"); + m_xpr.block(0, 0, other.rows(), other.cols()) = other; + } + + /* Copy/Move constructor which transfers ownership. This is crucial in + * absence of return value optimization to avoid assertions during destruction. */ + // FIXME in C++11 mode this could be replaced by a proper RValue constructor + EIGEN_DEVICE_FUNC + inline CommaInitializer(const CommaInitializer& o) + : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) { + // Mark original object as finished. In absence of R-value references we need to const_cast: + const_cast(o).m_row = m_xpr.rows(); + const_cast(o).m_col = m_xpr.cols(); + const_cast(o).m_currentBlockRows = 0; + } + + /* inserts a scalar value in the target matrix */ + EIGEN_DEVICE_FUNC + CommaInitializer& operator,(const Scalar& s) + { + if (m_col==m_xpr.cols()) + { + m_row+=m_currentBlockRows; + m_col = 0; + m_currentBlockRows = 1; + eigen_assert(m_row + EIGEN_DEVICE_FUNC + CommaInitializer& operator,(const DenseBase& other) + { + if (m_col==m_xpr.cols() && (other.cols()!=0 || other.rows()!=m_currentBlockRows)) + { + m_row+=m_currentBlockRows; + m_col = 0; + m_currentBlockRows = other.rows(); + eigen_assert(m_row+m_currentBlockRows<=m_xpr.rows() + && "Too many rows passed to comma initializer (operator<<)"); + } + eigen_assert((m_col + other.cols() <= m_xpr.cols()) + && "Too many coefficients passed to comma initializer (operator<<)"); + eigen_assert(m_currentBlockRows==other.rows()); + m_xpr.template block + (m_row, m_col, other.rows(), other.cols()) = other; + m_col += other.cols(); + return *this; + } + + EIGEN_DEVICE_FUNC + inline ~CommaInitializer() +#if defined VERIFY_RAISES_ASSERT && (!defined EIGEN_NO_ASSERTION_CHECKING) && defined EIGEN_EXCEPTIONS + EIGEN_EXCEPTION_SPEC(Eigen::eigen_assert_exception) +#endif + { + finished(); + } + + /** \returns the built matrix once all its coefficients have been set. + * Calling finished is 100% optional. Its purpose is to write expressions + * like this: + * \code + * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished()); + * \endcode + */ + EIGEN_DEVICE_FUNC + inline XprType& finished() { + eigen_assert(((m_row+m_currentBlockRows) == m_xpr.rows() || m_xpr.cols() == 0) + && m_col == m_xpr.cols() + && "Too few coefficients passed to comma initializer (operator<<)"); + return m_xpr; + } + + XprType& m_xpr; // target expression + Index m_row; // current row id + Index m_col; // current col id + Index m_currentBlockRows; // current block height +}; + +/** \anchor MatrixBaseCommaInitRef + * Convenient operator to set the coefficients of a matrix. + * + * The coefficients must be provided in a row major order and exactly match + * the size of the matrix. Otherwise an assertion is raised. + * + * Example: \include MatrixBase_set.cpp + * Output: \verbinclude MatrixBase_set.out + * + * \note According the c++ standard, the argument expressions of this comma initializer are evaluated in arbitrary order. + * + * \sa CommaInitializer::finished(), class CommaInitializer + */ +template +EIGEN_DEVICE_FUNC inline CommaInitializer DenseBase::operator<< (const Scalar& s) +{ + return CommaInitializer(*static_cast(this), s); +} + +/** \sa operator<<(const Scalar&) */ +template +template +EIGEN_DEVICE_FUNC inline CommaInitializer +DenseBase::operator<<(const DenseBase& other) +{ + return CommaInitializer(*static_cast(this), other); +} + +} // end namespace Eigen + +#endif // EIGEN_COMMAINITIALIZER_H diff --git a/Vendor/eigen/Eigen/src/Core/ConditionEstimator.h b/Vendor/eigen/Eigen/src/Core/ConditionEstimator.h new file mode 100644 index 0000000..51a2e5f --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/ConditionEstimator.h @@ -0,0 +1,175 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Rasmus Munk Larsen (rmlarsen@google.com) +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CONDITIONESTIMATOR_H +#define EIGEN_CONDITIONESTIMATOR_H + +namespace Eigen { + +namespace internal { + +template +struct rcond_compute_sign { + static inline Vector run(const Vector& v) { + const RealVector v_abs = v.cwiseAbs(); + return (v_abs.array() == static_cast(0)) + .select(Vector::Ones(v.size()), v.cwiseQuotient(v_abs)); + } +}; + +// Partial specialization to avoid elementwise division for real vectors. +template +struct rcond_compute_sign { + static inline Vector run(const Vector& v) { + return (v.array() < static_cast(0)) + .select(-Vector::Ones(v.size()), Vector::Ones(v.size())); + } +}; + +/** + * \returns an estimate of ||inv(matrix)||_1 given a decomposition of + * \a matrix that implements .solve() and .adjoint().solve() methods. + * + * This function implements Algorithms 4.1 and 5.1 from + * http://www.maths.manchester.ac.uk/~higham/narep/narep135.pdf + * which also forms the basis for the condition number estimators in + * LAPACK. Since at most 10 calls to the solve method of dec are + * performed, the total cost is O(dims^2), as opposed to O(dims^3) + * needed to compute the inverse matrix explicitly. + * + * The most common usage is in estimating the condition number + * ||matrix||_1 * ||inv(matrix)||_1. The first term ||matrix||_1 can be + * computed directly in O(n^2) operations. + * + * Supports the following decompositions: FullPivLU, PartialPivLU, LDLT, and + * LLT. + * + * \sa FullPivLU, PartialPivLU, LDLT, LLT. + */ +template +typename Decomposition::RealScalar rcond_invmatrix_L1_norm_estimate(const Decomposition& dec) +{ + typedef typename Decomposition::MatrixType MatrixType; + typedef typename Decomposition::Scalar Scalar; + typedef typename Decomposition::RealScalar RealScalar; + typedef typename internal::plain_col_type::type Vector; + typedef typename internal::plain_col_type::type RealVector; + const bool is_complex = (NumTraits::IsComplex != 0); + + eigen_assert(dec.rows() == dec.cols()); + const Index n = dec.rows(); + if (n == 0) + return 0; + + // Disable Index to float conversion warning +#ifdef __INTEL_COMPILER + #pragma warning push + #pragma warning ( disable : 2259 ) +#endif + Vector v = dec.solve(Vector::Ones(n) / Scalar(n)); +#ifdef __INTEL_COMPILER + #pragma warning pop +#endif + + // lower_bound is a lower bound on + // ||inv(matrix)||_1 = sup_v ||inv(matrix) v||_1 / ||v||_1 + // and is the objective maximized by the ("super-") gradient ascent + // algorithm below. + RealScalar lower_bound = v.template lpNorm<1>(); + if (n == 1) + return lower_bound; + + // Gradient ascent algorithm follows: We know that the optimum is achieved at + // one of the simplices v = e_i, so in each iteration we follow a + // super-gradient to move towards the optimal one. + RealScalar old_lower_bound = lower_bound; + Vector sign_vector(n); + Vector old_sign_vector; + Index v_max_abs_index = -1; + Index old_v_max_abs_index = v_max_abs_index; + for (int k = 0; k < 4; ++k) + { + sign_vector = internal::rcond_compute_sign::run(v); + if (k > 0 && !is_complex && sign_vector == old_sign_vector) { + // Break if the solution stagnated. + break; + } + // v_max_abs_index = argmax |real( inv(matrix)^T * sign_vector )| + v = dec.adjoint().solve(sign_vector); + v.real().cwiseAbs().maxCoeff(&v_max_abs_index); + if (v_max_abs_index == old_v_max_abs_index) { + // Break if the solution stagnated. + break; + } + // Move to the new simplex e_j, where j = v_max_abs_index. + v = dec.solve(Vector::Unit(n, v_max_abs_index)); // v = inv(matrix) * e_j. + lower_bound = v.template lpNorm<1>(); + if (lower_bound <= old_lower_bound) { + // Break if the gradient step did not increase the lower_bound. + break; + } + if (!is_complex) { + old_sign_vector = sign_vector; + } + old_v_max_abs_index = v_max_abs_index; + old_lower_bound = lower_bound; + } + // The following calculates an independent estimate of ||matrix||_1 by + // multiplying matrix by a vector with entries of slowly increasing + // magnitude and alternating sign: + // v_i = (-1)^{i} (1 + (i / (dim-1))), i = 0,...,dim-1. + // This improvement to Hager's algorithm above is due to Higham. It was + // added to make the algorithm more robust in certain corner cases where + // large elements in the matrix might otherwise escape detection due to + // exact cancellation (especially when op and op_adjoint correspond to a + // sequence of backsubstitutions and permutations), which could cause + // Hager's algorithm to vastly underestimate ||matrix||_1. + Scalar alternating_sign(RealScalar(1)); + for (Index i = 0; i < n; ++i) { + // The static_cast is needed when Scalar is a complex and RealScalar implements expression templates + v[i] = alternating_sign * static_cast(RealScalar(1) + (RealScalar(i) / (RealScalar(n - 1)))); + alternating_sign = -alternating_sign; + } + v = dec.solve(v); + const RealScalar alternate_lower_bound = (2 * v.template lpNorm<1>()) / (3 * RealScalar(n)); + return numext::maxi(lower_bound, alternate_lower_bound); +} + +/** \brief Reciprocal condition number estimator. + * + * Computing a decomposition of a dense matrix takes O(n^3) operations, while + * this method estimates the condition number quickly and reliably in O(n^2) + * operations. + * + * \returns an estimate of the reciprocal condition number + * (1 / (||matrix||_1 * ||inv(matrix)||_1)) of matrix, given ||matrix||_1 and + * its decomposition. Supports the following decompositions: FullPivLU, + * PartialPivLU, LDLT, and LLT. + * + * \sa FullPivLU, PartialPivLU, LDLT, LLT. + */ +template +typename Decomposition::RealScalar +rcond_estimate_helper(typename Decomposition::RealScalar matrix_norm, const Decomposition& dec) +{ + typedef typename Decomposition::RealScalar RealScalar; + eigen_assert(dec.rows() == dec.cols()); + if (dec.rows() == 0) return NumTraits::infinity(); + if (matrix_norm == RealScalar(0)) return RealScalar(0); + if (dec.rows() == 1) return RealScalar(1); + const RealScalar inverse_matrix_norm = rcond_invmatrix_L1_norm_estimate(dec); + return (inverse_matrix_norm == RealScalar(0) ? RealScalar(0) + : (RealScalar(1) / inverse_matrix_norm) / matrix_norm); +} + +} // namespace internal + +} // namespace Eigen + +#endif diff --git a/Vendor/eigen/Eigen/src/Core/CoreEvaluators.h b/Vendor/eigen/Eigen/src/Core/CoreEvaluators.h new file mode 100644 index 0000000..0ff8c8d --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/CoreEvaluators.h @@ -0,0 +1,1741 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Benoit Jacob +// Copyright (C) 2011-2014 Gael Guennebaud +// Copyright (C) 2011-2012 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +#ifndef EIGEN_COREEVALUATORS_H +#define EIGEN_COREEVALUATORS_H + +namespace Eigen { + +namespace internal { + +// This class returns the evaluator kind from the expression storage kind. +// Default assumes index based accessors +template +struct storage_kind_to_evaluator_kind { + typedef IndexBased Kind; +}; + +// This class returns the evaluator shape from the expression storage kind. +// It can be Dense, Sparse, Triangular, Diagonal, SelfAdjoint, Band, etc. +template struct storage_kind_to_shape; + +template<> struct storage_kind_to_shape { typedef DenseShape Shape; }; +template<> struct storage_kind_to_shape { typedef SolverShape Shape; }; +template<> struct storage_kind_to_shape { typedef PermutationShape Shape; }; +template<> struct storage_kind_to_shape { typedef TranspositionsShape Shape; }; + +// Evaluators have to be specialized with respect to various criteria such as: +// - storage/structure/shape +// - scalar type +// - etc. +// Therefore, we need specialization of evaluator providing additional template arguments for each kind of evaluators. +// We currently distinguish the following kind of evaluators: +// - unary_evaluator for expressions taking only one arguments (CwiseUnaryOp, CwiseUnaryView, Transpose, MatrixWrapper, ArrayWrapper, Reverse, Replicate) +// - binary_evaluator for expression taking two arguments (CwiseBinaryOp) +// - ternary_evaluator for expression taking three arguments (CwiseTernaryOp) +// - product_evaluator for linear algebra products (Product); special case of binary_evaluator because it requires additional tags for dispatching. +// - mapbase_evaluator for Map, Block, Ref +// - block_evaluator for Block (special dispatching to a mapbase_evaluator or unary_evaluator) + +template< typename T, + typename Arg1Kind = typename evaluator_traits::Kind, + typename Arg2Kind = typename evaluator_traits::Kind, + typename Arg3Kind = typename evaluator_traits::Kind, + typename Arg1Scalar = typename traits::Scalar, + typename Arg2Scalar = typename traits::Scalar, + typename Arg3Scalar = typename traits::Scalar> struct ternary_evaluator; + +template< typename T, + typename LhsKind = typename evaluator_traits::Kind, + typename RhsKind = typename evaluator_traits::Kind, + typename LhsScalar = typename traits::Scalar, + typename RhsScalar = typename traits::Scalar> struct binary_evaluator; + +template< typename T, + typename Kind = typename evaluator_traits::Kind, + typename Scalar = typename T::Scalar> struct unary_evaluator; + +// evaluator_traits contains traits for evaluator + +template +struct evaluator_traits_base +{ + // by default, get evaluator kind and shape from storage + typedef typename storage_kind_to_evaluator_kind::StorageKind>::Kind Kind; + typedef typename storage_kind_to_shape::StorageKind>::Shape Shape; +}; + +// Default evaluator traits +template +struct evaluator_traits : public evaluator_traits_base +{ +}; + +template::Shape > +struct evaluator_assume_aliasing { + static const bool value = false; +}; + +// By default, we assume a unary expression: +template +struct evaluator : public unary_evaluator +{ + typedef unary_evaluator Base; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator(const T& xpr) : Base(xpr) {} +}; + + +// TODO: Think about const-correctness +template +struct evaluator + : evaluator +{ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator(const T& xpr) : evaluator(xpr) {} +}; + +// ---------- base class for all evaluators ---------- + +template +struct evaluator_base +{ + // TODO that's not very nice to have to propagate all these traits. They are currently only needed to handle outer,inner indices. + typedef traits ExpressionTraits; + + enum { + Alignment = 0 + }; + // noncopyable: + // Don't make this class inherit noncopyable as this kills EBO (Empty Base Optimization) + // and make complex evaluator much larger than then should do. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE evaluator_base() {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ~evaluator_base() {} +private: + EIGEN_DEVICE_FUNC evaluator_base(const evaluator_base&); + EIGEN_DEVICE_FUNC const evaluator_base& operator=(const evaluator_base&); +}; + +// -------------------- Matrix and Array -------------------- +// +// evaluator is a common base class for the +// Matrix and Array evaluators. +// Here we directly specialize evaluator. This is not really a unary expression, and it is, by definition, dense, +// so no need for more sophisticated dispatching. + +// this helper permits to completely eliminate m_outerStride if it is known at compiletime. +template class plainobjectbase_evaluator_data { +public: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + plainobjectbase_evaluator_data(const Scalar* ptr, Index outerStride) : data(ptr) + { +#ifndef EIGEN_INTERNAL_DEBUGGING + EIGEN_UNUSED_VARIABLE(outerStride); +#endif + eigen_internal_assert(outerStride==OuterStride); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index outerStride() const EIGEN_NOEXCEPT { return OuterStride; } + const Scalar *data; +}; + +template class plainobjectbase_evaluator_data { +public: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + plainobjectbase_evaluator_data(const Scalar* ptr, Index outerStride) : data(ptr), m_outerStride(outerStride) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Index outerStride() const { return m_outerStride; } + const Scalar *data; +protected: + Index m_outerStride; +}; + +template +struct evaluator > + : evaluator_base +{ + typedef PlainObjectBase PlainObjectType; + typedef typename PlainObjectType::Scalar Scalar; + typedef typename PlainObjectType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = PlainObjectType::IsRowMajor, + IsVectorAtCompileTime = PlainObjectType::IsVectorAtCompileTime, + RowsAtCompileTime = PlainObjectType::RowsAtCompileTime, + ColsAtCompileTime = PlainObjectType::ColsAtCompileTime, + + CoeffReadCost = NumTraits::ReadCost, + Flags = traits::EvaluatorFlags, + Alignment = traits::Alignment + }; + enum { + // We do not need to know the outer stride for vectors + OuterStrideAtCompileTime = IsVectorAtCompileTime ? 0 + : int(IsRowMajor) ? ColsAtCompileTime + : RowsAtCompileTime + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + evaluator() + : m_d(0,OuterStrideAtCompileTime) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator(const PlainObjectType& m) + : m_d(m.data(),IsVectorAtCompileTime ? 0 : m.outerStride()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + if (IsRowMajor) + return m_d.data[row * m_d.outerStride() + col]; + else + return m_d.data[row + col * m_d.outerStride()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_d.data[index]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + if (IsRowMajor) + return const_cast(m_d.data)[row * m_d.outerStride() + col]; + else + return const_cast(m_d.data)[row + col * m_d.outerStride()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return const_cast(m_d.data)[index]; + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + if (IsRowMajor) + return ploadt(m_d.data + row * m_d.outerStride() + col); + else + return ploadt(m_d.data + row + col * m_d.outerStride()); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return ploadt(m_d.data + index); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + if (IsRowMajor) + return pstoret + (const_cast(m_d.data) + row * m_d.outerStride() + col, x); + else + return pstoret + (const_cast(m_d.data) + row + col * m_d.outerStride(), x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + return pstoret(const_cast(m_d.data) + index, x); + } + +protected: + + plainobjectbase_evaluator_data m_d; +}; + +template +struct evaluator > + : evaluator > > +{ + typedef Matrix XprType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + evaluator() {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator(const XprType& m) + : evaluator >(m) + { } +}; + +template +struct evaluator > + : evaluator > > +{ + typedef Array XprType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + evaluator() {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator(const XprType& m) + : evaluator >(m) + { } +}; + +// -------------------- Transpose -------------------- + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef Transpose XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = evaluator::Flags ^ RowMajorBit, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit unary_evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(col, row); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(col, row); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + typename XprType::Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(col, row); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_argImpl.template packet(index); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + m_argImpl.template writePacket(col, row, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + m_argImpl.template writePacket(index, x); + } + +protected: + evaluator m_argImpl; +}; + +// -------------------- CwiseNullaryOp -------------------- +// Like Matrix and Array, this is not really a unary expression, so we directly specialize evaluator. +// Likewise, there is not need to more sophisticated dispatching here. + +template::value, + bool has_unary = has_unary_operator::value, + bool has_binary = has_binary_operator::value> +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { return op(i,j); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { return op(i); } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { return op.template packetOp(i,j); } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { return op.template packetOp(i); } +}; + +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType=0, IndexType=0) const { return op(); } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType=0, IndexType=0) const { return op.template packetOp(); } +}; + +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j=0) const { return op(i,j); } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j=0) const { return op.template packetOp(i,j); } +}; + +// We need the following specialization for vector-only functors assigned to a runtime vector, +// for instance, using linspace and assigning a RowVectorXd to a MatrixXd or even a row of a MatrixXd. +// In this case, i==0 and j is used for the actual iteration. +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { + eigen_assert(i==0 || j==0); + return op(i+j); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { + eigen_assert(i==0 || j==0); + return op.template packetOp(i+j); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { return op(i); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { return op.template packetOp(i); } +}; + +template +struct nullary_wrapper {}; + +#if 0 && EIGEN_COMP_MSVC>0 +// Disable this ugly workaround. This is now handled in traits::match, +// but this piece of code might still become handly if some other weird compilation +// erros pop up again. + +// MSVC exhibits a weird compilation error when +// compiling: +// Eigen::MatrixXf A = MatrixXf::Random(3,3); +// Ref R = 2.f*A; +// and that has_*ary_operator> have not been instantiated yet. +// The "problem" is that evaluator<2.f*A> is instantiated by traits::match<2.f*A> +// and at that time has_*ary_operator returns true regardless of T. +// Then nullary_wrapper is badly instantiated as nullary_wrapper<.,.,true,true,true>. +// The trick is thus to defer the proper instantiation of nullary_wrapper when coeff(), +// and packet() are really instantiated as implemented below: + +// This is a simple wrapper around Index to enforce the re-instantiation of +// has_*ary_operator when needed. +template struct nullary_wrapper_workaround_msvc { + nullary_wrapper_workaround_msvc(const T&); + operator T()const; +}; + +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().operator()(op,i,j); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().operator()(op,i); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().template packetOp(op,i,j); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().template packetOp(op,i); + } +}; +#endif // MSVC workaround + +template +struct evaluator > + : evaluator_base > +{ + typedef CwiseNullaryOp XprType; + typedef typename internal::remove_all::type PlainObjectTypeCleaned; + + enum { + CoeffReadCost = internal::functor_traits::Cost, + + Flags = (evaluator::Flags + & ( HereditaryBits + | (functor_has_linear_access::ret ? LinearAccessBit : 0) + | (functor_traits::PacketAccess ? PacketAccessBit : 0))) + | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), + Alignment = AlignedMax + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& n) + : m_functor(n.functor()), m_wrapper() + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(IndexType row, IndexType col) const + { + return m_wrapper(m_functor, row, col); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(IndexType index) const + { + return m_wrapper(m_functor,index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(IndexType row, IndexType col) const + { + return m_wrapper.template packetOp(m_functor, row, col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(IndexType index) const + { + return m_wrapper.template packetOp(m_functor, index); + } + +protected: + const NullaryOp m_functor; + const internal::nullary_wrapper m_wrapper; +}; + +// -------------------- CwiseUnaryOp -------------------- + +template +struct unary_evaluator, IndexBased > + : evaluator_base > +{ + typedef CwiseUnaryOp XprType; + + enum { + CoeffReadCost = int(evaluator::CoeffReadCost) + int(functor_traits::Cost), + + Flags = evaluator::Flags + & (HereditaryBits | LinearAccessBit | (functor_traits::PacketAccess ? PacketAccessBit : 0)), + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit unary_evaluator(const XprType& op) : m_d(op) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_d.func()(m_d.argImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_d.func()(m_d.argImpl.coeff(index)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_d.func().packetOp(m_d.argImpl.template packet(row, col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_d.func().packetOp(m_d.argImpl.template packet(index)); + } + +protected: + + // this helper permits to completely eliminate the functor if it is empty + struct Data + { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Data(const XprType& xpr) : op(xpr.functor()), argImpl(xpr.nestedExpression()) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const UnaryOp& func() const { return op; } + UnaryOp op; + evaluator argImpl; + }; + + Data m_d; +}; + +// -------------------- CwiseTernaryOp -------------------- + +// this is a ternary expression +template +struct evaluator > + : public ternary_evaluator > +{ + typedef CwiseTernaryOp XprType; + typedef ternary_evaluator > Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +template +struct ternary_evaluator, IndexBased, IndexBased> + : evaluator_base > +{ + typedef CwiseTernaryOp XprType; + + enum { + CoeffReadCost = int(evaluator::CoeffReadCost) + int(evaluator::CoeffReadCost) + int(evaluator::CoeffReadCost) + int(functor_traits::Cost), + + Arg1Flags = evaluator::Flags, + Arg2Flags = evaluator::Flags, + Arg3Flags = evaluator::Flags, + SameType = is_same::value && is_same::value, + StorageOrdersAgree = (int(Arg1Flags)&RowMajorBit)==(int(Arg2Flags)&RowMajorBit) && (int(Arg1Flags)&RowMajorBit)==(int(Arg3Flags)&RowMajorBit), + Flags0 = (int(Arg1Flags) | int(Arg2Flags) | int(Arg3Flags)) & ( + HereditaryBits + | (int(Arg1Flags) & int(Arg2Flags) & int(Arg3Flags) & + ( (StorageOrdersAgree ? LinearAccessBit : 0) + | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) + ) + ) + ), + Flags = (Flags0 & ~RowMajorBit) | (Arg1Flags & RowMajorBit), + Alignment = EIGEN_PLAIN_ENUM_MIN( + EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, evaluator::Alignment), + evaluator::Alignment) + }; + + EIGEN_DEVICE_FUNC explicit ternary_evaluator(const XprType& xpr) : m_d(xpr) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_d.func()(m_d.arg1Impl.coeff(row, col), m_d.arg2Impl.coeff(row, col), m_d.arg3Impl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_d.func()(m_d.arg1Impl.coeff(index), m_d.arg2Impl.coeff(index), m_d.arg3Impl.coeff(index)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_d.func().packetOp(m_d.arg1Impl.template packet(row, col), + m_d.arg2Impl.template packet(row, col), + m_d.arg3Impl.template packet(row, col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_d.func().packetOp(m_d.arg1Impl.template packet(index), + m_d.arg2Impl.template packet(index), + m_d.arg3Impl.template packet(index)); + } + +protected: + // this helper permits to completely eliminate the functor if it is empty + struct Data + { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Data(const XprType& xpr) : op(xpr.functor()), arg1Impl(xpr.arg1()), arg2Impl(xpr.arg2()), arg3Impl(xpr.arg3()) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TernaryOp& func() const { return op; } + TernaryOp op; + evaluator arg1Impl; + evaluator arg2Impl; + evaluator arg3Impl; + }; + + Data m_d; +}; + +// -------------------- CwiseBinaryOp -------------------- + +// this is a binary expression +template +struct evaluator > + : public binary_evaluator > +{ + typedef CwiseBinaryOp XprType; + typedef binary_evaluator > Base; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +template +struct binary_evaluator, IndexBased, IndexBased> + : evaluator_base > +{ + typedef CwiseBinaryOp XprType; + + enum { + CoeffReadCost = int(evaluator::CoeffReadCost) + int(evaluator::CoeffReadCost) + int(functor_traits::Cost), + + LhsFlags = evaluator::Flags, + RhsFlags = evaluator::Flags, + SameType = is_same::value, + StorageOrdersAgree = (int(LhsFlags)&RowMajorBit)==(int(RhsFlags)&RowMajorBit), + Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( + HereditaryBits + | (int(LhsFlags) & int(RhsFlags) & + ( (StorageOrdersAgree ? LinearAccessBit : 0) + | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) + ) + ) + ), + Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment,evaluator::Alignment) + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit binary_evaluator(const XprType& xpr) : m_d(xpr) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_d.func()(m_d.lhsImpl.coeff(row, col), m_d.rhsImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_d.func()(m_d.lhsImpl.coeff(index), m_d.rhsImpl.coeff(index)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_d.func().packetOp(m_d.lhsImpl.template packet(row, col), + m_d.rhsImpl.template packet(row, col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_d.func().packetOp(m_d.lhsImpl.template packet(index), + m_d.rhsImpl.template packet(index)); + } + +protected: + + // this helper permits to completely eliminate the functor if it is empty + struct Data + { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Data(const XprType& xpr) : op(xpr.functor()), lhsImpl(xpr.lhs()), rhsImpl(xpr.rhs()) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const BinaryOp& func() const { return op; } + BinaryOp op; + evaluator lhsImpl; + evaluator rhsImpl; + }; + + Data m_d; +}; + +// -------------------- CwiseUnaryView -------------------- + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef CwiseUnaryView XprType; + + enum { + CoeffReadCost = int(evaluator::CoeffReadCost) + int(functor_traits::Cost), + + Flags = (evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit)), + + Alignment = 0 // FIXME it is not very clear why alignment is necessarily lost... + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op) : m_d(op) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_d.func()(m_d.argImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_d.func()(m_d.argImpl.coeff(index)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_d.func()(m_d.argImpl.coeffRef(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_d.func()(m_d.argImpl.coeffRef(index)); + } + +protected: + + // this helper permits to completely eliminate the functor if it is empty + struct Data + { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Data(const XprType& xpr) : op(xpr.functor()), argImpl(xpr.nestedExpression()) {} + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const UnaryOp& func() const { return op; } + UnaryOp op; + evaluator argImpl; + }; + + Data m_d; +}; + +// -------------------- Map -------------------- + +// FIXME perhaps the PlainObjectType could be provided by Derived::PlainObject ? +// but that might complicate template specialization +template +struct mapbase_evaluator; + +template +struct mapbase_evaluator : evaluator_base +{ + typedef Derived XprType; + typedef typename XprType::PointerType PointerType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = XprType::RowsAtCompileTime, + ColsAtCompileTime = XprType::ColsAtCompileTime, + CoeffReadCost = NumTraits::ReadCost + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit mapbase_evaluator(const XprType& map) + : m_data(const_cast(map.data())), + m_innerStride(map.innerStride()), + m_outerStride(map.outerStride()) + { + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(evaluator::Flags&PacketAccessBit, internal::inner_stride_at_compile_time::ret==1), + PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_data[col * colStride() + row * rowStride()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_data[index * m_innerStride.value()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_data[col * colStride() + row * rowStride()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_data[index * m_innerStride.value()]; + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + PointerType ptr = m_data + row * rowStride() + col * colStride(); + return internal::ploadt(ptr); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return internal::ploadt(m_data + index * m_innerStride.value()); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + PointerType ptr = m_data + row * rowStride() + col * colStride(); + return internal::pstoret(ptr, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + internal::pstoret(m_data + index * m_innerStride.value(), x); + } +protected: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index rowStride() const EIGEN_NOEXCEPT { + return XprType::IsRowMajor ? m_outerStride.value() : m_innerStride.value(); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index colStride() const EIGEN_NOEXCEPT { + return XprType::IsRowMajor ? m_innerStride.value() : m_outerStride.value(); + } + + PointerType m_data; + const internal::variable_if_dynamic m_innerStride; + const internal::variable_if_dynamic m_outerStride; +}; + +template +struct evaluator > + : public mapbase_evaluator, PlainObjectType> +{ + typedef Map XprType; + typedef typename XprType::Scalar Scalar; + // TODO: should check for smaller packet types once we can handle multi-sized packet types + typedef typename packet_traits::type PacketScalar; + + enum { + InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 + ? int(PlainObjectType::InnerStrideAtCompileTime) + : int(StrideType::InnerStrideAtCompileTime), + OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 + ? int(PlainObjectType::OuterStrideAtCompileTime) + : int(StrideType::OuterStrideAtCompileTime), + HasNoInnerStride = InnerStrideAtCompileTime == 1, + HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, + HasNoStride = HasNoInnerStride && HasNoOuterStride, + IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, + + PacketAccessMask = bool(HasNoInnerStride) ? ~int(0) : ~int(PacketAccessBit), + LinearAccessMask = bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime) ? ~int(0) : ~int(LinearAccessBit), + Flags = int( evaluator::Flags) & (LinearAccessMask&PacketAccessMask), + + Alignment = int(MapOptions)&int(AlignedMask) + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& map) + : mapbase_evaluator(map) + { } +}; + +// -------------------- Ref -------------------- + +template +struct evaluator > + : public mapbase_evaluator, PlainObjectType> +{ + typedef Ref XprType; + + enum { + Flags = evaluator >::Flags, + Alignment = evaluator >::Alignment + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator(const XprType& ref) + : mapbase_evaluator(ref) + { } +}; + +// -------------------- Block -------------------- + +template::ret> struct block_evaluator; + +template +struct evaluator > + : block_evaluator +{ + typedef Block XprType; + typedef typename XprType::Scalar Scalar; + // TODO: should check for smaller packet types once we can handle multi-sized packet types + typedef typename packet_traits::type PacketScalar; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime, + + ArgTypeIsRowMajor = (int(evaluator::Flags)&RowMajorBit) != 0, + IsRowMajor = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 + : ArgTypeIsRowMajor, + HasSameStorageOrderAsArgType = (IsRowMajor == ArgTypeIsRowMajor), + InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), + InnerStrideAtCompileTime = HasSameStorageOrderAsArgType + ? int(inner_stride_at_compile_time::ret) + : int(outer_stride_at_compile_time::ret), + OuterStrideAtCompileTime = HasSameStorageOrderAsArgType + ? int(outer_stride_at_compile_time::ret) + : int(inner_stride_at_compile_time::ret), + MaskPacketAccessBit = (InnerStrideAtCompileTime == 1 || HasSameStorageOrderAsArgType) ? PacketAccessBit : 0, + + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (evaluator::Flags&LinearAccessBit))) ? LinearAccessBit : 0, + FlagsRowMajorBit = XprType::Flags&RowMajorBit, + Flags0 = evaluator::Flags & ( (HereditaryBits & ~RowMajorBit) | + DirectAccessBit | + MaskPacketAccessBit), + Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit, + + PacketAlignment = unpacket_traits::alignment, + Alignment0 = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) + && (OuterStrideAtCompileTime!=0) + && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % int(PacketAlignment)) == 0)) ? int(PacketAlignment) : 0, + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, Alignment0) + }; + typedef block_evaluator block_evaluator_type; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator(const XprType& block) : block_evaluator_type(block) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } +}; + +// no direct-access => dispatch to a unary evaluator +template +struct block_evaluator + : unary_evaluator > +{ + typedef Block XprType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit block_evaluator(const XprType& block) + : unary_evaluator(block) + {} +}; + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef Block XprType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit unary_evaluator(const XprType& block) + : m_argImpl(block.nestedExpression()), + m_startRow(block.startRow()), + m_startCol(block.startCol()), + m_linear_offset(ForwardLinearAccess?(ArgType::IsRowMajor ? block.startRow()*block.nestedExpression().cols() + block.startCol() : block.startCol()*block.nestedExpression().rows() + block.startRow()):0) + { } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + RowsAtCompileTime = XprType::RowsAtCompileTime, + ForwardLinearAccess = (InnerPanel || int(XprType::IsRowMajor)==int(ArgType::IsRowMajor)) && bool(evaluator::Flags&LinearAccessBit) + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(m_startRow.value() + row, m_startCol.value() + col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return linear_coeff_impl(index, bool_constant()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(m_startRow.value() + row, m_startCol.value() + col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return linear_coeffRef_impl(index, bool_constant()); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(m_startRow.value() + row, m_startCol.value() + col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + if (ForwardLinearAccess) + return m_argImpl.template packet(m_linear_offset.value() + index); + else + return packet(RowsAtCompileTime == 1 ? 0 : index, + RowsAtCompileTime == 1 ? index : 0); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + return m_argImpl.template writePacket(m_startRow.value() + row, m_startCol.value() + col, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + if (ForwardLinearAccess) + return m_argImpl.template writePacket(m_linear_offset.value() + index, x); + else + return writePacket(RowsAtCompileTime == 1 ? 0 : index, + RowsAtCompileTime == 1 ? index : 0, + x); + } + +protected: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType linear_coeff_impl(Index index, internal::true_type /* ForwardLinearAccess */) const + { + return m_argImpl.coeff(m_linear_offset.value() + index); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType linear_coeff_impl(Index index, internal::false_type /* not ForwardLinearAccess */) const + { + return coeff(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& linear_coeffRef_impl(Index index, internal::true_type /* ForwardLinearAccess */) + { + return m_argImpl.coeffRef(m_linear_offset.value() + index); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& linear_coeffRef_impl(Index index, internal::false_type /* not ForwardLinearAccess */) + { + return coeffRef(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); + } + + evaluator m_argImpl; + const variable_if_dynamic m_startRow; + const variable_if_dynamic m_startCol; + const variable_if_dynamic m_linear_offset; +}; + +// TODO: This evaluator does not actually use the child evaluator; +// all action is via the data() as returned by the Block expression. + +template +struct block_evaluator + : mapbase_evaluator, + typename Block::PlainObject> +{ + typedef Block XprType; + typedef typename XprType::Scalar Scalar; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit block_evaluator(const XprType& block) + : mapbase_evaluator(block) + { + // TODO: for the 3.3 release, this should be turned to an internal assertion, but let's keep it as is for the beta lifetime + eigen_assert(((internal::UIntPtr(block.data()) % EIGEN_PLAIN_ENUM_MAX(1,evaluator::Alignment)) == 0) && "data is not aligned"); + } +}; + + +// -------------------- Select -------------------- +// NOTE shall we introduce a ternary_evaluator? + +// TODO enable vectorization for Select +template +struct evaluator > + : evaluator_base > +{ + typedef Select XprType; + enum { + CoeffReadCost = evaluator::CoeffReadCost + + EIGEN_PLAIN_ENUM_MAX(evaluator::CoeffReadCost, + evaluator::CoeffReadCost), + + Flags = (unsigned int)evaluator::Flags & evaluator::Flags & HereditaryBits, + + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, evaluator::Alignment) + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator(const XprType& select) + : m_conditionImpl(select.conditionMatrix()), + m_thenImpl(select.thenMatrix()), + m_elseImpl(select.elseMatrix()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + if (m_conditionImpl.coeff(row, col)) + return m_thenImpl.coeff(row, col); + else + return m_elseImpl.coeff(row, col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + if (m_conditionImpl.coeff(index)) + return m_thenImpl.coeff(index); + else + return m_elseImpl.coeff(index); + } + +protected: + evaluator m_conditionImpl; + evaluator m_thenImpl; + evaluator m_elseImpl; +}; + + +// -------------------- Replicate -------------------- + +template +struct unary_evaluator > + : evaluator_base > +{ + typedef Replicate XprType; + typedef typename XprType::CoeffReturnType CoeffReturnType; + enum { + Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor + }; + typedef typename internal::nested_eval::type ArgTypeNested; + typedef typename internal::remove_all::type ArgTypeNestedCleaned; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + LinearAccessMask = XprType::IsVectorAtCompileTime ? LinearAccessBit : 0, + Flags = (evaluator::Flags & (HereditaryBits|LinearAccessMask) & ~RowMajorBit) | (traits::Flags & RowMajorBit), + + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit unary_evaluator(const XprType& replicate) + : m_arg(replicate.nestedExpression()), + m_argImpl(m_arg), + m_rows(replicate.nestedExpression().rows()), + m_cols(replicate.nestedExpression().cols()) + {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + // try to avoid using modulo; this is a pure optimization strategy + const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? row + : row % m_rows.value(); + const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? col + : col % m_cols.value(); + + return m_argImpl.coeff(actual_row, actual_col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + // try to avoid using modulo; this is a pure optimization strategy + const Index actual_index = internal::traits::RowsAtCompileTime==1 + ? (ColFactor==1 ? index : index%m_cols.value()) + : (RowFactor==1 ? index : index%m_rows.value()); + + return m_argImpl.coeff(actual_index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? row + : row % m_rows.value(); + const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? col + : col % m_cols.value(); + + return m_argImpl.template packet(actual_row, actual_col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + const Index actual_index = internal::traits::RowsAtCompileTime==1 + ? (ColFactor==1 ? index : index%m_cols.value()) + : (RowFactor==1 ? index : index%m_rows.value()); + + return m_argImpl.template packet(actual_index); + } + +protected: + const ArgTypeNested m_arg; + evaluator m_argImpl; + const variable_if_dynamic m_rows; + const variable_if_dynamic m_cols; +}; + +// -------------------- MatrixWrapper and ArrayWrapper -------------------- +// +// evaluator_wrapper_base is a common base class for the +// MatrixWrapper and ArrayWrapper evaluators. + +template +struct evaluator_wrapper_base + : evaluator_base +{ + typedef typename remove_all::type ArgType; + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = evaluator::Flags, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} + + typedef typename ArgType::Scalar Scalar; + typedef typename ArgType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(row, col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(row, col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(row, col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_argImpl.template packet(index); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + m_argImpl.template writePacket(row, col, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + m_argImpl.template writePacket(index, x); + } + +protected: + evaluator m_argImpl; +}; + +template +struct unary_evaluator > + : evaluator_wrapper_base > +{ + typedef MatrixWrapper XprType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit unary_evaluator(const XprType& wrapper) + : evaluator_wrapper_base >(wrapper.nestedExpression()) + { } +}; + +template +struct unary_evaluator > + : evaluator_wrapper_base > +{ + typedef ArrayWrapper XprType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit unary_evaluator(const XprType& wrapper) + : evaluator_wrapper_base >(wrapper.nestedExpression()) + { } +}; + + +// -------------------- Reverse -------------------- + +// defined in Reverse.h: +template struct reverse_packet_cond; + +template +struct unary_evaluator > + : evaluator_base > +{ + typedef Reverse XprType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = XprType::IsRowMajor, + IsColMajor = !IsRowMajor, + ReverseRow = (Direction == Vertical) || (Direction == BothDirections), + ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), + ReversePacket = (Direction == BothDirections) + || ((Direction == Vertical) && IsColMajor) + || ((Direction == Horizontal) && IsRowMajor), + + CoeffReadCost = evaluator::CoeffReadCost, + + // let's enable LinearAccess only with vectorization because of the product overhead + // FIXME enable DirectAccess with negative strides? + Flags0 = evaluator::Flags, + LinearAccess = ( (Direction==BothDirections) && (int(Flags0)&PacketAccessBit) ) + || ((ReverseRow && XprType::ColsAtCompileTime==1) || (ReverseCol && XprType::RowsAtCompileTime==1)) + ? LinearAccessBit : 0, + + Flags = int(Flags0) & (HereditaryBits | PacketAccessBit | LinearAccess), + + Alignment = 0 // FIXME in some rare cases, Alignment could be preserved, like a Vector4f. + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit unary_evaluator(const XprType& reverse) + : m_argImpl(reverse.nestedExpression()), + m_rows(ReverseRow ? reverse.nestedExpression().rows() : 1), + m_cols(ReverseCol ? reverse.nestedExpression().cols() : 1) + { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(ReverseRow ? m_rows.value() - row - 1 : row, + ReverseCol ? m_cols.value() - col - 1 : col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(m_rows.value() * m_cols.value() - index - 1); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(ReverseRow ? m_rows.value() - row - 1 : row, + ReverseCol ? m_cols.value() - col - 1 : col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(m_rows.value() * m_cols.value() - index - 1); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + enum { + PacketSize = unpacket_traits::size, + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1 + }; + typedef internal::reverse_packet_cond reverse_packet; + return reverse_packet::run(m_argImpl.template packet( + ReverseRow ? m_rows.value() - row - OffsetRow : row, + ReverseCol ? m_cols.value() - col - OffsetCol : col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + enum { PacketSize = unpacket_traits::size }; + return preverse(m_argImpl.template packet(m_rows.value() * m_cols.value() - index - PacketSize)); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + // FIXME we could factorize some code with packet(i,j) + enum { + PacketSize = unpacket_traits::size, + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1 + }; + typedef internal::reverse_packet_cond reverse_packet; + m_argImpl.template writePacket( + ReverseRow ? m_rows.value() - row - OffsetRow : row, + ReverseCol ? m_cols.value() - col - OffsetCol : col, + reverse_packet::run(x)); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + enum { PacketSize = unpacket_traits::size }; + m_argImpl.template writePacket + (m_rows.value() * m_cols.value() - index - PacketSize, preverse(x)); + } + +protected: + evaluator m_argImpl; + + // If we do not reverse rows, then we do not need to know the number of rows; same for columns + // Nonetheless, in this case it is important to set to 1 such that the coeff(index) method works fine for vectors. + const variable_if_dynamic m_rows; + const variable_if_dynamic m_cols; +}; + + +// -------------------- Diagonal -------------------- + +template +struct evaluator > + : evaluator_base > +{ + typedef Diagonal XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + + Flags = (unsigned int)(evaluator::Flags & (HereditaryBits | DirectAccessBit) & ~RowMajorBit) | LinearAccessBit, + + Alignment = 0 + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit evaluator(const XprType& diagonal) + : m_argImpl(diagonal.nestedExpression()), + m_index(diagonal.index()) + { } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index) const + { + return m_argImpl.coeff(row + rowOffset(), row + colOffset()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index + rowOffset(), index + colOffset()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index) + { + return m_argImpl.coeffRef(row + rowOffset(), row + colOffset()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index + rowOffset(), index + colOffset()); + } + +protected: + evaluator m_argImpl; + const internal::variable_if_dynamicindex m_index; + +private: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index rowOffset() const { return m_index.value() > 0 ? 0 : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index colOffset() const { return m_index.value() > 0 ? m_index.value() : 0; } +}; + + +//---------------------------------------------------------------------- +// deprecated code +//---------------------------------------------------------------------- + +// -------------------- EvalToTemp -------------------- + +// expression class for evaluating nested expression to a temporary + +template class EvalToTemp; + +template +struct traits > + : public traits +{ }; + +template +class EvalToTemp + : public dense_xpr_base >::type +{ + public: + + typedef typename dense_xpr_base::type Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(EvalToTemp) + + explicit EvalToTemp(const ArgType& arg) + : m_arg(arg) + { } + + const ArgType& arg() const + { + return m_arg; + } + + EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT + { + return m_arg.rows(); + } + + EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT + { + return m_arg.cols(); + } + + private: + const ArgType& m_arg; +}; + +template +struct evaluator > + : public evaluator +{ + typedef EvalToTemp XprType; + typedef typename ArgType::PlainObject PlainObject; + typedef evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : m_result(xpr.arg()) + { + ::new (static_cast(this)) Base(m_result); + } + + // This constructor is used when nesting an EvalTo evaluator in another evaluator + EIGEN_DEVICE_FUNC evaluator(const ArgType& arg) + : m_result(arg) + { + ::new (static_cast(this)) Base(m_result); + } + +protected: + PlainObject m_result; +}; + +} // namespace internal + +} // end namespace Eigen + +#endif // EIGEN_COREEVALUATORS_H diff --git a/Vendor/eigen/Eigen/src/Core/CoreIterators.h b/Vendor/eigen/Eigen/src/Core/CoreIterators.h new file mode 100644 index 0000000..b967196 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/CoreIterators.h @@ -0,0 +1,132 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_COREITERATORS_H +#define EIGEN_COREITERATORS_H + +namespace Eigen { + +/* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core + */ + +namespace internal { + +template +class inner_iterator_selector; + +} + +/** \class InnerIterator + * \brief An InnerIterator allows to loop over the element of any matrix expression. + * + * \warning To be used with care because an evaluator is constructed every time an InnerIterator iterator is constructed. + * + * TODO: add a usage example + */ +template +class InnerIterator +{ +protected: + typedef internal::inner_iterator_selector::Kind> IteratorType; + typedef internal::evaluator EvaluatorType; + typedef typename internal::traits::Scalar Scalar; +public: + /** Construct an iterator over the \a outerId -th row or column of \a xpr */ + InnerIterator(const XprType &xpr, const Index &outerId) + : m_eval(xpr), m_iter(m_eval, outerId, xpr.innerSize()) + {} + + /// \returns the value of the current coefficient. + EIGEN_STRONG_INLINE Scalar value() const { return m_iter.value(); } + /** Increment the iterator \c *this to the next non-zero coefficient. + * Explicit zeros are not skipped over. To skip explicit zeros, see class SparseView + */ + EIGEN_STRONG_INLINE InnerIterator& operator++() { m_iter.operator++(); return *this; } + EIGEN_STRONG_INLINE InnerIterator& operator+=(Index i) { m_iter.operator+=(i); return *this; } + EIGEN_STRONG_INLINE InnerIterator operator+(Index i) + { InnerIterator result(*this); result+=i; return result; } + + + /// \returns the column or row index of the current coefficient. + EIGEN_STRONG_INLINE Index index() const { return m_iter.index(); } + /// \returns the row index of the current coefficient. + EIGEN_STRONG_INLINE Index row() const { return m_iter.row(); } + /// \returns the column index of the current coefficient. + EIGEN_STRONG_INLINE Index col() const { return m_iter.col(); } + /// \returns \c true if the iterator \c *this still references a valid coefficient. + EIGEN_STRONG_INLINE operator bool() const { return m_iter; } + +protected: + EvaluatorType m_eval; + IteratorType m_iter; +private: + // If you get here, then you're not using the right InnerIterator type, e.g.: + // SparseMatrix A; + // SparseMatrix::InnerIterator it(A,0); + template InnerIterator(const EigenBase&,Index outer); +}; + +namespace internal { + +// Generic inner iterator implementation for dense objects +template +class inner_iterator_selector +{ +protected: + typedef evaluator EvaluatorType; + typedef typename traits::Scalar Scalar; + enum { IsRowMajor = (XprType::Flags&RowMajorBit)==RowMajorBit }; + +public: + EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &innerSize) + : m_eval(eval), m_inner(0), m_outer(outerId), m_end(innerSize) + {} + + EIGEN_STRONG_INLINE Scalar value() const + { + return (IsRowMajor) ? m_eval.coeff(m_outer, m_inner) + : m_eval.coeff(m_inner, m_outer); + } + + EIGEN_STRONG_INLINE inner_iterator_selector& operator++() { m_inner++; return *this; } + + EIGEN_STRONG_INLINE Index index() const { return m_inner; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } + +protected: + const EvaluatorType& m_eval; + Index m_inner; + const Index m_outer; + const Index m_end; +}; + +// For iterator-based evaluator, inner-iterator is already implemented as +// evaluator<>::InnerIterator +template +class inner_iterator_selector + : public evaluator::InnerIterator +{ +protected: + typedef typename evaluator::InnerIterator Base; + typedef evaluator EvaluatorType; + +public: + EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &/*innerSize*/) + : Base(eval, outerId) + {} +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_COREITERATORS_H diff --git a/Vendor/eigen/Eigen/src/Core/CwiseBinaryOp.h b/Vendor/eigen/Eigen/src/Core/CwiseBinaryOp.h new file mode 100644 index 0000000..2202b1c --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/CwiseBinaryOp.h @@ -0,0 +1,183 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2014 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CWISE_BINARY_OP_H +#define EIGEN_CWISE_BINARY_OP_H + +namespace Eigen { + +namespace internal { +template +struct traits > +{ + // we must not inherit from traits since it has + // the potential to cause problems with MSVC + typedef typename remove_all::type Ancestor; + typedef typename traits::XprKind XprKind; + enum { + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime + }; + + // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor), + // we still want to handle the case when the result type is different. + typedef typename result_of< + BinaryOp( + const typename Lhs::Scalar&, + const typename Rhs::Scalar& + ) + >::type Scalar; + typedef typename cwise_promote_storage_type::StorageKind, + typename traits::StorageKind, + BinaryOp>::ret StorageKind; + typedef typename promote_index_type::StorageIndex, + typename traits::StorageIndex>::type StorageIndex; + typedef typename Lhs::Nested LhsNested; + typedef typename Rhs::Nested RhsNested; + typedef typename remove_reference::type _LhsNested; + typedef typename remove_reference::type _RhsNested; + enum { + Flags = cwise_promote_storage_order::StorageKind,typename traits::StorageKind,_LhsNested::Flags & RowMajorBit,_RhsNested::Flags & RowMajorBit>::value + }; +}; +} // end namespace internal + +template +class CwiseBinaryOpImpl; + +/** \class CwiseBinaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions + * + * \tparam BinaryOp template functor implementing the operator + * \tparam LhsType the type of the left-hand side + * \tparam RhsType the type of the right-hand side + * + * This class represents an expression where a coefficient-wise binary operator is applied to two expressions. + * It is the return type of binary operators, by which we mean only those binary operators where + * both the left-hand side and the right-hand side are Eigen expressions. + * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp. + * + * Most of the time, this is the only way that it is used, so you typically don't have to name + * CwiseBinaryOp types explicitly. + * + * \sa MatrixBase::binaryExpr(const MatrixBase &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp + */ +template +class CwiseBinaryOp : + public CwiseBinaryOpImpl< + BinaryOp, LhsType, RhsType, + typename internal::cwise_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + BinaryOp>::ret>, + internal::no_assignment_operator +{ + public: + + typedef typename internal::remove_all::type Functor; + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; + + typedef typename CwiseBinaryOpImpl< + BinaryOp, LhsType, RhsType, + typename internal::cwise_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + BinaryOp>::ret>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) + + typedef typename internal::ref_selector::type LhsNested; + typedef typename internal::ref_selector::type RhsNested; + typedef typename internal::remove_reference::type _LhsNested; + typedef typename internal::remove_reference::type _RhsNested; + +#if EIGEN_COMP_MSVC && EIGEN_HAS_CXX11 + //Required for Visual Studio or the Copy constructor will probably not get inlined! + EIGEN_STRONG_INLINE + CwiseBinaryOp(const CwiseBinaryOp&) = default; +#endif + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CwiseBinaryOp(const Lhs& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp()) + : m_lhs(aLhs), m_rhs(aRhs), m_functor(func) + { + EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar); + // require the sizes to match + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs, Rhs) + eigen_assert(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index rows() const EIGEN_NOEXCEPT { + // return the fixed size type if available to enable compile time optimizations + return internal::traits::type>::RowsAtCompileTime==Dynamic ? m_rhs.rows() : m_lhs.rows(); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index cols() const EIGEN_NOEXCEPT { + // return the fixed size type if available to enable compile time optimizations + return internal::traits::type>::ColsAtCompileTime==Dynamic ? m_rhs.cols() : m_lhs.cols(); + } + + /** \returns the left hand side nested expression */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const _LhsNested& lhs() const { return m_lhs; } + /** \returns the right hand side nested expression */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const _RhsNested& rhs() const { return m_rhs; } + /** \returns the functor representing the binary operation */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const BinaryOp& functor() const { return m_functor; } + + protected: + LhsNested m_lhs; + RhsNested m_rhs; + const BinaryOp m_functor; +}; + +// Generic API dispatcher +template +class CwiseBinaryOpImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; + +/** replaces \c *this by \c *this - \a other. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & +MatrixBase::operator-=(const MatrixBase &other) +{ + call_assignment(derived(), other.derived(), internal::sub_assign_op()); + return derived(); +} + +/** replaces \c *this by \c *this + \a other. + * + * \returns a reference to \c *this + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived & +MatrixBase::operator+=(const MatrixBase& other) +{ + call_assignment(derived(), other.derived(), internal::add_assign_op()); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_CWISE_BINARY_OP_H diff --git a/Vendor/eigen/Eigen/src/Core/CwiseNullaryOp.h b/Vendor/eigen/Eigen/src/Core/CwiseNullaryOp.h new file mode 100644 index 0000000..289ec51 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/CwiseNullaryOp.h @@ -0,0 +1,1001 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CWISE_NULLARY_OP_H +#define EIGEN_CWISE_NULLARY_OP_H + +namespace Eigen { + +namespace internal { +template +struct traits > : traits +{ + enum { + Flags = traits::Flags & RowMajorBit + }; +}; + +} // namespace internal + +/** \class CwiseNullaryOp + * \ingroup Core_Module + * + * \brief Generic expression of a matrix where all coefficients are defined by a functor + * + * \tparam NullaryOp template functor implementing the operator + * \tparam PlainObjectType the underlying plain matrix/array type + * + * This class represents an expression of a generic nullary operator. + * It is the return type of the Ones(), Zero(), Constant(), Identity() and Random() methods, + * and most of the time this is the only way it is used. + * + * However, if you want to write a function returning such an expression, you + * will need to use this class. + * + * The functor NullaryOp must expose one of the following method: + + + + +
\c operator()() if the procedural generation does not depend on the coefficient entries (e.g., random numbers)
\c operator()(Index i)if the procedural generation makes sense for vectors only and that it depends on the coefficient index \c i (e.g., linspace)
\c operator()(Index i,Index j)if the procedural generation depends on the matrix coordinates \c i, \c j (e.g., to generate a checkerboard with 0 and 1)
+ * It is also possible to expose the last two operators if the generation makes sense for matrices but can be optimized for vectors. + * + * See DenseBase::NullaryExpr(Index,const CustomNullaryOp&) for an example binding + * C++11 random number generators. + * + * A nullary expression can also be used to implement custom sophisticated matrix manipulations + * that cannot be covered by the existing set of natively supported matrix manipulations. + * See this \ref TopicCustomizing_NullaryExpr "page" for some examples and additional explanations + * on the behavior of CwiseNullaryOp. + * + * \sa class CwiseUnaryOp, class CwiseBinaryOp, DenseBase::NullaryExpr + */ +template +class CwiseNullaryOp : public internal::dense_xpr_base< CwiseNullaryOp >::type, internal::no_assignment_operator +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp) + + EIGEN_DEVICE_FUNC + CwiseNullaryOp(Index rows, Index cols, const NullaryOp& func = NullaryOp()) + : m_rows(rows), m_cols(cols), m_functor(func) + { + eigen_assert(rows >= 0 + && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) + && cols >= 0 + && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index rows() const { return m_rows.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index cols() const { return m_cols.value(); } + + /** \returns the functor representing the nullary operation */ + EIGEN_DEVICE_FUNC + const NullaryOp& functor() const { return m_functor; } + + protected: + const internal::variable_if_dynamic m_rows; + const internal::variable_if_dynamic m_cols; + const NullaryOp m_functor; +}; + + +/** \returns an expression of a matrix defined by a custom functor \a func + * + * The parameters \a rows and \a cols are the number of rows and of columns of + * the returned matrix. Must be compatible with this MatrixBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used + * instead. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +#ifndef EIGEN_PARSED_BY_DOXYGEN +const CwiseNullaryOp::PlainObject> +#else +const CwiseNullaryOp +#endif +DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func) +{ + return CwiseNullaryOp(rows, cols, func); +} + +/** \returns an expression of a matrix defined by a custom functor \a func + * + * The parameter \a size is the size of the returned vector. + * Must be compatible with this MatrixBase type. + * + * \only_for_vectors + * + * This variant is meant to be used for dynamic-size vector types. For fixed-size types, + * it is redundant to pass \a size as argument, so Zero() should be used + * instead. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * Here is an example with C++11 random generators: \include random_cpp11.cpp + * Output: \verbinclude random_cpp11.out + * + * \sa class CwiseNullaryOp + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +#ifndef EIGEN_PARSED_BY_DOXYGEN +const CwiseNullaryOp::PlainObject> +#else +const CwiseNullaryOp +#endif +DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); + else return CwiseNullaryOp(size, 1, func); +} + +/** \returns an expression of a matrix defined by a custom functor \a func + * + * This variant is only for fixed-size DenseBase types. For dynamic-size types, you + * need to use the variants taking size arguments. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +#ifndef EIGEN_PARSED_BY_DOXYGEN +const CwiseNullaryOp::PlainObject> +#else +const CwiseNullaryOp +#endif +DenseBase::NullaryExpr(const CustomNullaryOp& func) +{ + return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); +} + +/** \returns an expression of a constant matrix of value \a value + * + * The parameters \a rows and \a cols are the number of rows and of columns of + * the returned matrix. Must be compatible with this DenseBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used + * instead. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Constant(Index rows, Index cols, const Scalar& value) +{ + return DenseBase::NullaryExpr(rows, cols, internal::scalar_constant_op(value)); +} + +/** \returns an expression of a constant matrix of value \a value + * + * The parameter \a size is the size of the returned vector. + * Must be compatible with this DenseBase type. + * + * \only_for_vectors + * + * This variant is meant to be used for dynamic-size vector types. For fixed-size types, + * it is redundant to pass \a size as argument, so Zero() should be used + * instead. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Constant(Index size, const Scalar& value) +{ + return DenseBase::NullaryExpr(size, internal::scalar_constant_op(value)); +} + +/** \returns an expression of a constant matrix of value \a value + * + * This variant is only for fixed-size DenseBase types. For dynamic-size types, you + * need to use the variants taking size arguments. + * + * The template parameter \a CustomNullaryOp is the type of the functor. + * + * \sa class CwiseNullaryOp + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Constant(const Scalar& value) +{ + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + return DenseBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_constant_op(value)); +} + +/** \deprecated because of accuracy loss. In Eigen 3.3, it is an alias for LinSpaced(Index,const Scalar&,const Scalar&) + * + * \only_for_vectors + * + * Example: \include DenseBase_LinSpaced_seq_deprecated.cpp + * Output: \verbinclude DenseBase_LinSpaced_seq_deprecated.out + * + * \sa LinSpaced(Index,const Scalar&, const Scalar&), setLinSpaced(Index,const Scalar&,const Scalar&) + */ +template +EIGEN_DEPRECATED EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType +DenseBase::LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); +} + +/** \deprecated because of accuracy loss. In Eigen 3.3, it is an alias for LinSpaced(const Scalar&,const Scalar&) + * + * \sa LinSpaced(const Scalar&, const Scalar&) + */ +template +EIGEN_DEPRECATED EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType +DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); +} + +/** + * \brief Sets a linearly spaced vector. + * + * The function generates 'size' equally spaced values in the closed interval [low,high]. + * When size is set to 1, a vector of length 1 containing 'high' is returned. + * + * \only_for_vectors + * + * Example: \include DenseBase_LinSpaced.cpp + * Output: \verbinclude DenseBase_LinSpaced.out + * + * For integer scalar types, an even spacing is possible if and only if the length of the range, + * i.e., \c high-low is a scalar multiple of \c size-1, or if \c size is a scalar multiple of the + * number of values \c high-low+1 (meaning each value can be repeated the same number of time). + * If one of these two considions is not satisfied, then \c high is lowered to the largest value + * satisfying one of this constraint. + * Here are some examples: + * + * Example: \include DenseBase_LinSpacedInt.cpp + * Output: \verbinclude DenseBase_LinSpacedInt.out + * + * \sa setLinSpaced(Index,const Scalar&,const Scalar&), CwiseNullaryOp + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType +DenseBase::LinSpaced(Index size, const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); +} + +/** + * \copydoc DenseBase::LinSpaced(Index, const Scalar&, const Scalar&) + * Special version for fixed size types which does not require the size parameter. + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType +DenseBase::LinSpaced(const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); +} + +/** \returns true if all coefficients in this matrix are approximately equal to \a val, to within precision \a prec */ +template +EIGEN_DEVICE_FUNC bool DenseBase::isApproxToConstant +(const Scalar& val, const RealScalar& prec) const +{ + typename internal::nested_eval::type self(derived()); + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if(!internal::isApprox(self.coeff(i, j), val, prec)) + return false; + return true; +} + +/** This is just an alias for isApproxToConstant(). + * + * \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */ +template +EIGEN_DEVICE_FUNC bool DenseBase::isConstant +(const Scalar& val, const RealScalar& prec) const +{ + return isApproxToConstant(val, prec); +} + +/** Alias for setConstant(): sets all coefficients in this expression to \a val. + * + * \sa setConstant(), Constant(), class CwiseNullaryOp + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void DenseBase::fill(const Scalar& val) +{ + setConstant(val); +} + +/** Sets all coefficients in this expression to value \a val. + * + * \sa fill(), setConstant(Index,const Scalar&), setConstant(Index,Index,const Scalar&), setZero(), setOnes(), Constant(), class CwiseNullaryOp, setZero(), setOnes() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setConstant(const Scalar& val) +{ + return derived() = Constant(rows(), cols(), val); +} + +/** Resizes to the given \a size, and sets all coefficients in this expression to the given value \a val. + * + * \only_for_vectors + * + * Example: \include Matrix_setConstant_int.cpp + * Output: \verbinclude Matrix_setConstant_int.out + * + * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setConstant(Index size, const Scalar& val) +{ + resize(size); + return setConstant(val); +} + +/** Resizes to the given size, and sets all coefficients in this expression to the given value \a val. + * + * \param rows the new number of rows + * \param cols the new number of columns + * \param val the value to which all coefficients are set + * + * Example: \include Matrix_setConstant_int_int.cpp + * Output: \verbinclude Matrix_setConstant_int_int.out + * + * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setConstant(Index rows, Index cols, const Scalar& val) +{ + resize(rows, cols); + return setConstant(val); +} + +/** Resizes to the given size, changing only the number of columns, and sets all + * coefficients in this expression to the given value \a val. For the parameter + * of type NoChange_t, just pass the special value \c NoChange. + * + * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setConstant(NoChange_t, Index cols, const Scalar& val) +{ + return setConstant(rows(), cols, val); +} + +/** Resizes to the given size, changing only the number of rows, and sets all + * coefficients in this expression to the given value \a val. For the parameter + * of type NoChange_t, just pass the special value \c NoChange. + * + * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setConstant(Index rows, NoChange_t, const Scalar& val) +{ + return setConstant(rows, cols(), val); +} + + +/** + * \brief Sets a linearly spaced vector. + * + * The function generates 'size' equally spaced values in the closed interval [low,high]. + * When size is set to 1, a vector of length 1 containing 'high' is returned. + * + * \only_for_vectors + * + * Example: \include DenseBase_setLinSpaced.cpp + * Output: \verbinclude DenseBase_setLinSpaced.out + * + * For integer scalar types, do not miss the explanations on the definition + * of \link LinSpaced(Index,const Scalar&,const Scalar&) even spacing \endlink. + * + * \sa LinSpaced(Index,const Scalar&,const Scalar&), CwiseNullaryOp + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Index newSize, const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op(low,high,newSize)); +} + +/** + * \brief Sets a linearly spaced vector. + * + * The function fills \c *this with equally spaced values in the closed interval [low,high]. + * When size is set to 1, a vector of length 1 containing 'high' is returned. + * + * \only_for_vectors + * + * For integer scalar types, do not miss the explanations on the definition + * of \link LinSpaced(Index,const Scalar&,const Scalar&) even spacing \endlink. + * + * \sa LinSpaced(Index,const Scalar&,const Scalar&), setLinSpaced(Index, const Scalar&, const Scalar&), CwiseNullaryOp + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, const Scalar& high) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return setLinSpaced(size(), low, high); +} + +// zero: + +/** \returns an expression of a zero matrix. + * + * The parameters \a rows and \a cols are the number of rows and of columns of + * the returned matrix. Must be compatible with this MatrixBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used + * instead. + * + * Example: \include MatrixBase_zero_int_int.cpp + * Output: \verbinclude MatrixBase_zero_int_int.out + * + * \sa Zero(), Zero(Index) + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Zero(Index rows, Index cols) +{ + return Constant(rows, cols, Scalar(0)); +} + +/** \returns an expression of a zero vector. + * + * The parameter \a size is the size of the returned vector. + * Must be compatible with this MatrixBase type. + * + * \only_for_vectors + * + * This variant is meant to be used for dynamic-size vector types. For fixed-size types, + * it is redundant to pass \a size as argument, so Zero() should be used + * instead. + * + * Example: \include MatrixBase_zero_int.cpp + * Output: \verbinclude MatrixBase_zero_int.out + * + * \sa Zero(), Zero(Index,Index) + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Zero(Index size) +{ + return Constant(size, Scalar(0)); +} + +/** \returns an expression of a fixed-size zero matrix or vector. + * + * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you + * need to use the variants taking size arguments. + * + * Example: \include MatrixBase_zero.cpp + * Output: \verbinclude MatrixBase_zero.out + * + * \sa Zero(Index), Zero(Index,Index) + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Zero() +{ + return Constant(Scalar(0)); +} + +/** \returns true if *this is approximately equal to the zero matrix, + * within the precision given by \a prec. + * + * Example: \include MatrixBase_isZero.cpp + * Output: \verbinclude MatrixBase_isZero.out + * + * \sa class CwiseNullaryOp, Zero() + */ +template +EIGEN_DEVICE_FUNC bool DenseBase::isZero(const RealScalar& prec) const +{ + typename internal::nested_eval::type self(derived()); + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < rows(); ++i) + if(!internal::isMuchSmallerThan(self.coeff(i, j), static_cast(1), prec)) + return false; + return true; +} + +/** Sets all coefficients in this expression to zero. + * + * Example: \include MatrixBase_setZero.cpp + * Output: \verbinclude MatrixBase_setZero.out + * + * \sa class CwiseNullaryOp, Zero() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setZero() +{ + return setConstant(Scalar(0)); +} + +/** Resizes to the given \a size, and sets all coefficients in this expression to zero. + * + * \only_for_vectors + * + * Example: \include Matrix_setZero_int.cpp + * Output: \verbinclude Matrix_setZero_int.out + * + * \sa DenseBase::setZero(), setZero(Index,Index), class CwiseNullaryOp, DenseBase::Zero() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setZero(Index newSize) +{ + resize(newSize); + return setConstant(Scalar(0)); +} + +/** Resizes to the given size, and sets all coefficients in this expression to zero. + * + * \param rows the new number of rows + * \param cols the new number of columns + * + * Example: \include Matrix_setZero_int_int.cpp + * Output: \verbinclude Matrix_setZero_int_int.out + * + * \sa DenseBase::setZero(), setZero(Index), class CwiseNullaryOp, DenseBase::Zero() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setZero(Index rows, Index cols) +{ + resize(rows, cols); + return setConstant(Scalar(0)); +} + +/** Resizes to the given size, changing only the number of columns, and sets all + * coefficients in this expression to zero. For the parameter of type NoChange_t, + * just pass the special value \c NoChange. + * + * \sa DenseBase::setZero(), setZero(Index), setZero(Index, Index), setZero(Index, NoChange_t), class CwiseNullaryOp, DenseBase::Zero() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setZero(NoChange_t, Index cols) +{ + return setZero(rows(), cols); +} + +/** Resizes to the given size, changing only the number of rows, and sets all + * coefficients in this expression to zero. For the parameter of type NoChange_t, + * just pass the special value \c NoChange. + * + * \sa DenseBase::setZero(), setZero(Index), setZero(Index, Index), setZero(NoChange_t, Index), class CwiseNullaryOp, DenseBase::Zero() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setZero(Index rows, NoChange_t) +{ + return setZero(rows, cols()); +} + +// ones: + +/** \returns an expression of a matrix where all coefficients equal one. + * + * The parameters \a rows and \a cols are the number of rows and of columns of + * the returned matrix. Must be compatible with this MatrixBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Ones() should be used + * instead. + * + * Example: \include MatrixBase_ones_int_int.cpp + * Output: \verbinclude MatrixBase_ones_int_int.out + * + * \sa Ones(), Ones(Index), isOnes(), class Ones + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Ones(Index rows, Index cols) +{ + return Constant(rows, cols, Scalar(1)); +} + +/** \returns an expression of a vector where all coefficients equal one. + * + * The parameter \a newSize is the size of the returned vector. + * Must be compatible with this MatrixBase type. + * + * \only_for_vectors + * + * This variant is meant to be used for dynamic-size vector types. For fixed-size types, + * it is redundant to pass \a size as argument, so Ones() should be used + * instead. + * + * Example: \include MatrixBase_ones_int.cpp + * Output: \verbinclude MatrixBase_ones_int.out + * + * \sa Ones(), Ones(Index,Index), isOnes(), class Ones + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Ones(Index newSize) +{ + return Constant(newSize, Scalar(1)); +} + +/** \returns an expression of a fixed-size matrix or vector where all coefficients equal one. + * + * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you + * need to use the variants taking size arguments. + * + * Example: \include MatrixBase_ones.cpp + * Output: \verbinclude MatrixBase_ones.out + * + * \sa Ones(Index), Ones(Index,Index), isOnes(), class Ones + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType +DenseBase::Ones() +{ + return Constant(Scalar(1)); +} + +/** \returns true if *this is approximately equal to the matrix where all coefficients + * are equal to 1, within the precision given by \a prec. + * + * Example: \include MatrixBase_isOnes.cpp + * Output: \verbinclude MatrixBase_isOnes.out + * + * \sa class CwiseNullaryOp, Ones() + */ +template +EIGEN_DEVICE_FUNC bool DenseBase::isOnes +(const RealScalar& prec) const +{ + return isApproxToConstant(Scalar(1), prec); +} + +/** Sets all coefficients in this expression to one. + * + * Example: \include MatrixBase_setOnes.cpp + * Output: \verbinclude MatrixBase_setOnes.out + * + * \sa class CwiseNullaryOp, Ones() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::setOnes() +{ + return setConstant(Scalar(1)); +} + +/** Resizes to the given \a newSize, and sets all coefficients in this expression to one. + * + * \only_for_vectors + * + * Example: \include Matrix_setOnes_int.cpp + * Output: \verbinclude Matrix_setOnes_int.out + * + * \sa MatrixBase::setOnes(), setOnes(Index,Index), class CwiseNullaryOp, MatrixBase::Ones() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setOnes(Index newSize) +{ + resize(newSize); + return setConstant(Scalar(1)); +} + +/** Resizes to the given size, and sets all coefficients in this expression to one. + * + * \param rows the new number of rows + * \param cols the new number of columns + * + * Example: \include Matrix_setOnes_int_int.cpp + * Output: \verbinclude Matrix_setOnes_int_int.out + * + * \sa MatrixBase::setOnes(), setOnes(Index), class CwiseNullaryOp, MatrixBase::Ones() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setOnes(Index rows, Index cols) +{ + resize(rows, cols); + return setConstant(Scalar(1)); +} + +/** Resizes to the given size, changing only the number of rows, and sets all + * coefficients in this expression to one. For the parameter of type NoChange_t, + * just pass the special value \c NoChange. + * + * \sa MatrixBase::setOnes(), setOnes(Index), setOnes(Index, Index), setOnes(NoChange_t, Index), class CwiseNullaryOp, MatrixBase::Ones() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setOnes(Index rows, NoChange_t) +{ + return setOnes(rows, cols()); +} + +/** Resizes to the given size, changing only the number of columns, and sets all + * coefficients in this expression to one. For the parameter of type NoChange_t, + * just pass the special value \c NoChange. + * + * \sa MatrixBase::setOnes(), setOnes(Index), setOnes(Index, Index), setOnes(Index, NoChange_t) class CwiseNullaryOp, MatrixBase::Ones() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setOnes(NoChange_t, Index cols) +{ + return setOnes(rows(), cols); +} + +// Identity: + +/** \returns an expression of the identity matrix (not necessarily square). + * + * The parameters \a rows and \a cols are the number of rows and of columns of + * the returned matrix. Must be compatible with this MatrixBase type. + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Identity() should be used + * instead. + * + * Example: \include MatrixBase_identity_int_int.cpp + * Output: \verbinclude MatrixBase_identity_int_int.out + * + * \sa Identity(), setIdentity(), isIdentity() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType +MatrixBase::Identity(Index rows, Index cols) +{ + return DenseBase::NullaryExpr(rows, cols, internal::scalar_identity_op()); +} + +/** \returns an expression of the identity matrix (not necessarily square). + * + * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you + * need to use the variant taking size arguments. + * + * Example: \include MatrixBase_identity.cpp + * Output: \verbinclude MatrixBase_identity.out + * + * \sa Identity(Index,Index), setIdentity(), isIdentity() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType +MatrixBase::Identity() +{ + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + return MatrixBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_identity_op()); +} + +/** \returns true if *this is approximately equal to the identity matrix + * (not necessarily square), + * within the precision given by \a prec. + * + * Example: \include MatrixBase_isIdentity.cpp + * Output: \verbinclude MatrixBase_isIdentity.out + * + * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), setIdentity() + */ +template +bool MatrixBase::isIdentity +(const RealScalar& prec) const +{ + typename internal::nested_eval::type self(derived()); + for(Index j = 0; j < cols(); ++j) + { + for(Index i = 0; i < rows(); ++i) + { + if(i == j) + { + if(!internal::isApprox(self.coeff(i, j), static_cast(1), prec)) + return false; + } + else + { + if(!internal::isMuchSmallerThan(self.coeff(i, j), static_cast(1), prec)) + return false; + } + } + } + return true; +} + +namespace internal { + +template=16)> +struct setIdentity_impl +{ + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE Derived& run(Derived& m) + { + return m = Derived::Identity(m.rows(), m.cols()); + } +}; + +template +struct setIdentity_impl +{ + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE Derived& run(Derived& m) + { + m.setZero(); + const Index size = numext::mini(m.rows(), m.cols()); + for(Index i = 0; i < size; ++i) m.coeffRef(i,i) = typename Derived::Scalar(1); + return m; + } +}; + +} // end namespace internal + +/** Writes the identity expression (not necessarily square) into *this. + * + * Example: \include MatrixBase_setIdentity.cpp + * Output: \verbinclude MatrixBase_setIdentity.out + * + * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), isIdentity() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() +{ + return internal::setIdentity_impl::run(derived()); +} + +/** \brief Resizes to the given size, and writes the identity expression (not necessarily square) into *this. + * + * \param rows the new number of rows + * \param cols the new number of columns + * + * Example: \include Matrix_setIdentity_int_int.cpp + * Output: \verbinclude Matrix_setIdentity_int_int.out + * + * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Identity() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index rows, Index cols) +{ + derived().resize(rows, cols); + return setIdentity(); +} + +/** \returns an expression of the i-th unit (basis) vector. + * + * \only_for_vectors + * + * \sa MatrixBase::Unit(Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index newSize, Index i) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return BasisReturnType(SquareMatrixType::Identity(newSize,newSize), i); +} + +/** \returns an expression of the i-th unit (basis) vector. + * + * \only_for_vectors + * + * This variant is for fixed-size vector only. + * + * \sa MatrixBase::Unit(Index,Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index i) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + return BasisReturnType(SquareMatrixType::Identity(),i); +} + +/** \returns an expression of the X axis unit vector (1{,0}^*) + * + * \only_for_vectors + * + * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitX() +{ return Derived::Unit(0); } + +/** \returns an expression of the Y axis unit vector (0,1{,0}^*) + * + * \only_for_vectors + * + * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitY() +{ return Derived::Unit(1); } + +/** \returns an expression of the Z axis unit vector (0,0,1{,0}^*) + * + * \only_for_vectors + * + * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitZ() +{ return Derived::Unit(2); } + +/** \returns an expression of the W axis unit vector (0,0,0,1) + * + * \only_for_vectors + * + * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitW() +{ return Derived::Unit(3); } + +/** \brief Set the coefficients of \c *this to the i-th unit (basis) vector + * + * \param i index of the unique coefficient to be set to 1 + * + * \only_for_vectors + * + * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Unit(Index,Index) + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::setUnit(Index i) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived); + eigen_assert(i +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::setUnit(Index newSize, Index i) +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived); + eigen_assert(i +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2016 Eugene Brevdo +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CWISE_TERNARY_OP_H +#define EIGEN_CWISE_TERNARY_OP_H + +namespace Eigen { + +namespace internal { +template +struct traits > { + // we must not inherit from traits since it has + // the potential to cause problems with MSVC + typedef typename remove_all::type Ancestor; + typedef typename traits::XprKind XprKind; + enum { + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime + }; + + // even though we require Arg1, Arg2, and Arg3 to have the same scalar type + // (see CwiseTernaryOp constructor), + // we still want to handle the case when the result type is different. + typedef typename result_of::type Scalar; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::StorageIndex StorageIndex; + + typedef typename Arg1::Nested Arg1Nested; + typedef typename Arg2::Nested Arg2Nested; + typedef typename Arg3::Nested Arg3Nested; + typedef typename remove_reference::type _Arg1Nested; + typedef typename remove_reference::type _Arg2Nested; + typedef typename remove_reference::type _Arg3Nested; + enum { Flags = _Arg1Nested::Flags & RowMajorBit }; +}; +} // end namespace internal + +template +class CwiseTernaryOpImpl; + +/** \class CwiseTernaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise ternary operator is + * applied to two expressions + * + * \tparam TernaryOp template functor implementing the operator + * \tparam Arg1Type the type of the first argument + * \tparam Arg2Type the type of the second argument + * \tparam Arg3Type the type of the third argument + * + * This class represents an expression where a coefficient-wise ternary + * operator is applied to three expressions. + * It is the return type of ternary operators, by which we mean only those + * ternary operators where + * all three arguments are Eigen expressions. + * For example, the return type of betainc(matrix1, matrix2, matrix3) is a + * CwiseTernaryOp. + * + * Most of the time, this is the only way that it is used, so you typically + * don't have to name + * CwiseTernaryOp types explicitly. + * + * \sa MatrixBase::ternaryExpr(const MatrixBase &, const + * MatrixBase &, const CustomTernaryOp &) const, class CwiseBinaryOp, + * class CwiseUnaryOp, class CwiseNullaryOp + */ +template +class CwiseTernaryOp : public CwiseTernaryOpImpl< + TernaryOp, Arg1Type, Arg2Type, Arg3Type, + typename internal::traits::StorageKind>, + internal::no_assignment_operator +{ + public: + typedef typename internal::remove_all::type Arg1; + typedef typename internal::remove_all::type Arg2; + typedef typename internal::remove_all::type Arg3; + + typedef typename CwiseTernaryOpImpl< + TernaryOp, Arg1Type, Arg2Type, Arg3Type, + typename internal::traits::StorageKind>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseTernaryOp) + + typedef typename internal::ref_selector::type Arg1Nested; + typedef typename internal::ref_selector::type Arg2Nested; + typedef typename internal::ref_selector::type Arg3Nested; + typedef typename internal::remove_reference::type _Arg1Nested; + typedef typename internal::remove_reference::type _Arg2Nested; + typedef typename internal::remove_reference::type _Arg3Nested; + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CwiseTernaryOp(const Arg1& a1, const Arg2& a2, + const Arg3& a3, + const TernaryOp& func = TernaryOp()) + : m_arg1(a1), m_arg2(a2), m_arg3(a3), m_functor(func) { + // require the sizes to match + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Arg1, Arg2) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Arg1, Arg3) + + // The index types should match + EIGEN_STATIC_ASSERT((internal::is_same< + typename internal::traits::StorageKind, + typename internal::traits::StorageKind>::value), + STORAGE_KIND_MUST_MATCH) + EIGEN_STATIC_ASSERT((internal::is_same< + typename internal::traits::StorageKind, + typename internal::traits::StorageKind>::value), + STORAGE_KIND_MUST_MATCH) + + eigen_assert(a1.rows() == a2.rows() && a1.cols() == a2.cols() && + a1.rows() == a3.rows() && a1.cols() == a3.cols()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index rows() const { + // return the fixed size type if available to enable compile time + // optimizations + if (internal::traits::type>:: + RowsAtCompileTime == Dynamic && + internal::traits::type>:: + RowsAtCompileTime == Dynamic) + return m_arg3.rows(); + else if (internal::traits::type>:: + RowsAtCompileTime == Dynamic && + internal::traits::type>:: + RowsAtCompileTime == Dynamic) + return m_arg2.rows(); + else + return m_arg1.rows(); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index cols() const { + // return the fixed size type if available to enable compile time + // optimizations + if (internal::traits::type>:: + ColsAtCompileTime == Dynamic && + internal::traits::type>:: + ColsAtCompileTime == Dynamic) + return m_arg3.cols(); + else if (internal::traits::type>:: + ColsAtCompileTime == Dynamic && + internal::traits::type>:: + ColsAtCompileTime == Dynamic) + return m_arg2.cols(); + else + return m_arg1.cols(); + } + + /** \returns the first argument nested expression */ + EIGEN_DEVICE_FUNC + const _Arg1Nested& arg1() const { return m_arg1; } + /** \returns the first argument nested expression */ + EIGEN_DEVICE_FUNC + const _Arg2Nested& arg2() const { return m_arg2; } + /** \returns the third argument nested expression */ + EIGEN_DEVICE_FUNC + const _Arg3Nested& arg3() const { return m_arg3; } + /** \returns the functor representing the ternary operation */ + EIGEN_DEVICE_FUNC + const TernaryOp& functor() const { return m_functor; } + + protected: + Arg1Nested m_arg1; + Arg2Nested m_arg2; + Arg3Nested m_arg3; + const TernaryOp m_functor; +}; + +// Generic API dispatcher +template +class CwiseTernaryOpImpl + : public internal::generic_xpr_base< + CwiseTernaryOp >::type { + public: + typedef typename internal::generic_xpr_base< + CwiseTernaryOp >::type Base; +}; + +} // end namespace Eigen + +#endif // EIGEN_CWISE_TERNARY_OP_H diff --git a/Vendor/eigen/Eigen/src/Core/CwiseUnaryOp.h b/Vendor/eigen/Eigen/src/Core/CwiseUnaryOp.h new file mode 100644 index 0000000..e68c4f7 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/CwiseUnaryOp.h @@ -0,0 +1,103 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2014 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CWISE_UNARY_OP_H +#define EIGEN_CWISE_UNARY_OP_H + +namespace Eigen { + +namespace internal { +template +struct traits > + : traits +{ + typedef typename result_of< + UnaryOp(const typename XprType::Scalar&) + >::type Scalar; + typedef typename XprType::Nested XprTypeNested; + typedef typename remove_reference::type _XprTypeNested; + enum { + Flags = _XprTypeNested::Flags & RowMajorBit + }; +}; +} + +template +class CwiseUnaryOpImpl; + +/** \class CwiseUnaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise unary operator is applied to an expression + * + * \tparam UnaryOp template functor implementing the operator + * \tparam XprType the type of the expression to which we are applying the unary operator + * + * This class represents an expression where a unary operator is applied to an expression. + * It is the return type of all operations taking exactly 1 input expression, regardless of the + * presence of other inputs such as scalars. For example, the operator* in the expression 3*matrix + * is considered unary, because only the right-hand side is an expression, and its + * return type is a specialization of CwiseUnaryOp. + * + * Most of the time, this is the only way that it is used, so you typically don't have to name + * CwiseUnaryOp types explicitly. + * + * \sa MatrixBase::unaryExpr(const CustomUnaryOp &) const, class CwiseBinaryOp, class CwiseNullaryOp + */ +template +class CwiseUnaryOp : public CwiseUnaryOpImpl::StorageKind>, internal::no_assignment_operator +{ + public: + + typedef typename CwiseUnaryOpImpl::StorageKind>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) + typedef typename internal::ref_selector::type XprTypeNested; + typedef typename internal::remove_all::type NestedExpression; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) + : m_xpr(xpr), m_functor(func) {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index rows() const EIGEN_NOEXCEPT { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index cols() const EIGEN_NOEXCEPT { return m_xpr.cols(); } + + /** \returns the functor representing the unary operation */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const UnaryOp& functor() const { return m_functor; } + + /** \returns the nested expression */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const typename internal::remove_all::type& + nestedExpression() const { return m_xpr; } + + /** \returns the nested expression */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + typename internal::remove_all::type& + nestedExpression() { return m_xpr; } + + protected: + XprTypeNested m_xpr; + const UnaryOp m_functor; +}; + +// Generic API dispatcher +template +class CwiseUnaryOpImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; + +} // end namespace Eigen + +#endif // EIGEN_CWISE_UNARY_OP_H diff --git a/Vendor/eigen/Eigen/src/Core/CwiseUnaryView.h b/Vendor/eigen/Eigen/src/Core/CwiseUnaryView.h new file mode 100644 index 0000000..a06d762 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/CwiseUnaryView.h @@ -0,0 +1,132 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CWISE_UNARY_VIEW_H +#define EIGEN_CWISE_UNARY_VIEW_H + +namespace Eigen { + +namespace internal { +template +struct traits > + : traits +{ + typedef typename result_of< + ViewOp(const typename traits::Scalar&) + >::type Scalar; + typedef typename MatrixType::Nested MatrixTypeNested; + typedef typename remove_all::type _MatrixTypeNested; + enum { + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = traits<_MatrixTypeNested>::Flags & (RowMajorBit | FlagsLvalueBit | DirectAccessBit), // FIXME DirectAccessBit should not be handled by expressions + MatrixTypeInnerStride = inner_stride_at_compile_time::ret, + // need to cast the sizeof's from size_t to int explicitly, otherwise: + // "error: no integral type can represent all of the enumerator values + InnerStrideAtCompileTime = MatrixTypeInnerStride == Dynamic + ? int(Dynamic) + : int(MatrixTypeInnerStride) * int(sizeof(typename traits::Scalar) / sizeof(Scalar)), + OuterStrideAtCompileTime = outer_stride_at_compile_time::ret == Dynamic + ? int(Dynamic) + : outer_stride_at_compile_time::ret * int(sizeof(typename traits::Scalar) / sizeof(Scalar)) + }; +}; +} + +template +class CwiseUnaryViewImpl; + +/** \class CwiseUnaryView + * \ingroup Core_Module + * + * \brief Generic lvalue expression of a coefficient-wise unary operator of a matrix or a vector + * + * \tparam ViewOp template functor implementing the view + * \tparam MatrixType the type of the matrix we are applying the unary operator + * + * This class represents a lvalue expression of a generic unary view operator of a matrix or a vector. + * It is the return type of real() and imag(), and most of the time this is the only way it is used. + * + * \sa MatrixBase::unaryViewExpr(const CustomUnaryOp &) const, class CwiseUnaryOp + */ +template +class CwiseUnaryView : public CwiseUnaryViewImpl::StorageKind> +{ + public: + + typedef typename CwiseUnaryViewImpl::StorageKind>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) + typedef typename internal::ref_selector::non_const_type MatrixTypeNested; + typedef typename internal::remove_all::type NestedExpression; + + explicit EIGEN_DEVICE_FUNC inline CwiseUnaryView(MatrixType& mat, const ViewOp& func = ViewOp()) + : m_matrix(mat), m_functor(func) {} + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView) + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index rows() const EIGEN_NOEXCEPT { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index cols() const EIGEN_NOEXCEPT { return m_matrix.cols(); } + + /** \returns the functor representing unary operation */ + EIGEN_DEVICE_FUNC const ViewOp& functor() const { return m_functor; } + + /** \returns the nested expression */ + EIGEN_DEVICE_FUNC const typename internal::remove_all::type& + nestedExpression() const { return m_matrix; } + + /** \returns the nested expression */ + EIGEN_DEVICE_FUNC typename internal::remove_reference::type& + nestedExpression() { return m_matrix; } + + protected: + MatrixTypeNested m_matrix; + ViewOp m_functor; +}; + +// Generic API dispatcher +template +class CwiseUnaryViewImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; + +template +class CwiseUnaryViewImpl + : public internal::dense_xpr_base< CwiseUnaryView >::type +{ + public: + + typedef CwiseUnaryView Derived; + typedef typename internal::dense_xpr_base< CwiseUnaryView >::type Base; + + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryViewImpl) + + EIGEN_DEVICE_FUNC inline Scalar* data() { return &(this->coeffRef(0)); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return &(this->coeff(0)); } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR inline Index innerStride() const + { + return derived().nestedExpression().innerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR inline Index outerStride() const + { + return derived().nestedExpression().outerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); + } + protected: + EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(CwiseUnaryViewImpl) +}; + +} // end namespace Eigen + +#endif // EIGEN_CWISE_UNARY_VIEW_H diff --git a/Vendor/eigen/Eigen/src/Core/DenseBase.h b/Vendor/eigen/Eigen/src/Core/DenseBase.h new file mode 100644 index 0000000..9b16db6 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/DenseBase.h @@ -0,0 +1,701 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007-2010 Benoit Jacob +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DENSEBASE_H +#define EIGEN_DENSEBASE_H + +namespace Eigen { + +namespace internal { + +// The index type defined by EIGEN_DEFAULT_DENSE_INDEX_TYPE must be a signed type. +// This dummy function simply aims at checking that at compile time. +static inline void check_DenseIndex_is_signed() { + EIGEN_STATIC_ASSERT(NumTraits::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE) +} + +} // end namespace internal + +/** \class DenseBase + * \ingroup Core_Module + * + * \brief Base class for all dense matrices, vectors, and arrays + * + * This class is the base that is inherited by all dense objects (matrix, vector, arrays, + * and related expression types). The common Eigen API for dense objects is contained in this class. + * + * \tparam Derived is the derived type, e.g., a matrix type or an expression. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_DENSEBASE_PLUGIN. + * + * \sa \blank \ref TopicClassHierarchy + */ +template class DenseBase +#ifndef EIGEN_PARSED_BY_DOXYGEN + : public DenseCoeffsBase::value> +#else + : public DenseCoeffsBase +#endif // not EIGEN_PARSED_BY_DOXYGEN +{ + public: + + /** Inner iterator type to iterate over the coefficients of a row or column. + * \sa class InnerIterator + */ + typedef Eigen::InnerIterator InnerIterator; + + typedef typename internal::traits::StorageKind StorageKind; + + /** + * \brief The type used to store indices + * \details This typedef is relevant for types that store multiple indices such as + * PermutationMatrix or Transpositions, otherwise it defaults to Eigen::Index + * \sa \blank \ref TopicPreprocessorDirectives, Eigen::Index, SparseMatrixBase. + */ + typedef typename internal::traits::StorageIndex StorageIndex; + + /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. */ + typedef typename internal::traits::Scalar Scalar; + + /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. + * + * It is an alias for the Scalar type */ + typedef Scalar value_type; + + typedef typename NumTraits::Real RealScalar; + typedef DenseCoeffsBase::value> Base; + + using Base::derived; + using Base::const_cast_derived; + using Base::rows; + using Base::cols; + using Base::size; + using Base::rowIndexByOuterInner; + using Base::colIndexByOuterInner; + using Base::coeff; + using Base::coeffByOuterInner; + using Base::operator(); + using Base::operator[]; + using Base::x; + using Base::y; + using Base::z; + using Base::w; + using Base::stride; + using Base::innerStride; + using Base::outerStride; + using Base::rowStride; + using Base::colStride; + typedef typename Base::CoeffReturnType CoeffReturnType; + + enum { + + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + /**< The number of rows at compile-time. This is just a copy of the value provided + * by the \a Derived type. If a value is not known at compile-time, + * it is set to the \a Dynamic constant. + * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */ + + ColsAtCompileTime = internal::traits::ColsAtCompileTime, + /**< The number of columns at compile-time. This is just a copy of the value provided + * by the \a Derived type. If a value is not known at compile-time, + * it is set to the \a Dynamic constant. + * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */ + + + SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, + internal::traits::ColsAtCompileTime>::ret), + /**< This is equal to the number of coefficients, i.e. the number of + * rows times the number of columns, or to \a Dynamic if this is not + * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ + + MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, + /**< This value is equal to the maximum possible number of rows that this expression + * might have. If this expression might have an arbitrarily high number of rows, + * this value is set to \a Dynamic. + * + * This value is useful to know when evaluating an expression, in order to determine + * whether it is possible to avoid doing a dynamic memory allocation. + * + * \sa RowsAtCompileTime, MaxColsAtCompileTime, MaxSizeAtCompileTime + */ + + MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, + /**< This value is equal to the maximum possible number of columns that this expression + * might have. If this expression might have an arbitrarily high number of columns, + * this value is set to \a Dynamic. + * + * This value is useful to know when evaluating an expression, in order to determine + * whether it is possible to avoid doing a dynamic memory allocation. + * + * \sa ColsAtCompileTime, MaxRowsAtCompileTime, MaxSizeAtCompileTime + */ + + MaxSizeAtCompileTime = (internal::size_at_compile_time::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime>::ret), + /**< This value is equal to the maximum possible number of coefficients that this expression + * might have. If this expression might have an arbitrarily high number of coefficients, + * this value is set to \a Dynamic. + * + * This value is useful to know when evaluating an expression, in order to determine + * whether it is possible to avoid doing a dynamic memory allocation. + * + * \sa SizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime + */ + + IsVectorAtCompileTime = internal::traits::RowsAtCompileTime == 1 + || internal::traits::ColsAtCompileTime == 1, + /**< This is set to true if either the number of rows or the number of + * columns is known at compile-time to be equal to 1. Indeed, in that case, + * we are dealing with a column-vector (if there is only one column) or with + * a row-vector (if there is only one row). */ + + NumDimensions = int(MaxSizeAtCompileTime) == 1 ? 0 : bool(IsVectorAtCompileTime) ? 1 : 2, + /**< This value is equal to Tensor::NumDimensions, i.e. 0 for scalars, 1 for vectors, + * and 2 for matrices. + */ + + Flags = internal::traits::Flags, + /**< This stores expression \ref flags flags which may or may not be inherited by new expressions + * constructed from this one. See the \ref flags "list of flags". + */ + + IsRowMajor = int(Flags) & RowMajorBit, /**< True if this expression has row-major storage order. */ + + InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) + : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), + + InnerStrideAtCompileTime = internal::inner_stride_at_compile_time::ret, + OuterStrideAtCompileTime = internal::outer_stride_at_compile_time::ret + }; + + typedef typename internal::find_best_packet::type PacketScalar; + + enum { IsPlainObjectBase = 0 }; + + /** The plain matrix type corresponding to this expression. + * \sa PlainObject */ + typedef Matrix::Scalar, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime, + AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), + internal::traits::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime + > PlainMatrix; + + /** The plain array type corresponding to this expression. + * \sa PlainObject */ + typedef Array::Scalar, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime, + AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), + internal::traits::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime + > PlainArray; + + /** \brief The plain matrix or array type corresponding to this expression. + * + * This is not necessarily exactly the return type of eval(). In the case of plain matrices, + * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed + * that the return type of eval() is either PlainObject or const PlainObject&. + */ + typedef typename internal::conditional::XprKind,MatrixXpr >::value, + PlainMatrix, PlainArray>::type PlainObject; + + /** \returns the number of nonzero coefficients which is in practice the number + * of stored coefficients. */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index nonZeros() const { return size(); } + + /** \returns the outer size. + * + * \note For a vector, this returns just 1. For a matrix (non-vector), this is the major dimension + * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of columns for a + * column-major matrix, and the number of rows for a row-major matrix. */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + Index outerSize() const + { + return IsVectorAtCompileTime ? 1 + : int(IsRowMajor) ? this->rows() : this->cols(); + } + + /** \returns the inner size. + * + * \note For a vector, this is just the size. For a matrix (non-vector), this is the minor dimension + * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of rows for a + * column-major matrix, and the number of columns for a row-major matrix. */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + Index innerSize() const + { + return IsVectorAtCompileTime ? this->size() + : int(IsRowMajor) ? this->cols() : this->rows(); + } + + /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are + * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does + * nothing else. + */ + EIGEN_DEVICE_FUNC + void resize(Index newSize) + { + EIGEN_ONLY_USED_FOR_DEBUG(newSize); + eigen_assert(newSize == this->size() + && "DenseBase::resize() does not actually allow to resize."); + } + /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are + * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does + * nothing else. + */ + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) + { + EIGEN_ONLY_USED_FOR_DEBUG(rows); + EIGEN_ONLY_USED_FOR_DEBUG(cols); + eigen_assert(rows == this->rows() && cols == this->cols() + && "DenseBase::resize() does not actually allow to resize."); + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal Represents a matrix with all coefficients equal to one another*/ + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; + /** \internal \deprecated Represents a vector with linearly spaced coefficients that allows sequential access only. */ + EIGEN_DEPRECATED typedef CwiseNullaryOp,PlainObject> SequentialLinSpacedReturnType; + /** \internal Represents a vector with linearly spaced coefficients that allows random access. */ + typedef CwiseNullaryOp,PlainObject> RandomAccessLinSpacedReturnType; + /** \internal the return type of MatrixBase::eigenvalues() */ + typedef Matrix::Scalar>::Real, internal::traits::ColsAtCompileTime, 1> EigenvaluesReturnType; + +#endif // not EIGEN_PARSED_BY_DOXYGEN + + /** Copies \a other into *this. \returns a reference to *this. */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator=(const DenseBase& other); + + /** Special case of the template operator=, in order to prevent the compiler + * from generating a default operator= (issue hit with g++ 4.1) + */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator=(const DenseBase& other); + + template + EIGEN_DEVICE_FUNC + Derived& operator=(const EigenBase &other); + + template + EIGEN_DEVICE_FUNC + Derived& operator+=(const EigenBase &other); + + template + EIGEN_DEVICE_FUNC + Derived& operator-=(const EigenBase &other); + + template + EIGEN_DEVICE_FUNC + Derived& operator=(const ReturnByValue& func); + + /** \internal + * Copies \a other into *this without evaluating other. \returns a reference to *this. */ + template + /** \deprecated */ + EIGEN_DEPRECATED EIGEN_DEVICE_FUNC + Derived& lazyAssign(const DenseBase& other); + + EIGEN_DEVICE_FUNC + CommaInitializer operator<< (const Scalar& s); + + template + /** \deprecated it now returns \c *this */ + EIGEN_DEPRECATED + const Derived& flagged() const + { return derived(); } + + template + EIGEN_DEVICE_FUNC + CommaInitializer operator<< (const DenseBase& other); + + typedef Transpose TransposeReturnType; + EIGEN_DEVICE_FUNC + TransposeReturnType transpose(); + typedef typename internal::add_const >::type ConstTransposeReturnType; + EIGEN_DEVICE_FUNC + ConstTransposeReturnType transpose() const; + EIGEN_DEVICE_FUNC + void transposeInPlace(); + + EIGEN_DEVICE_FUNC static const ConstantReturnType + Constant(Index rows, Index cols, const Scalar& value); + EIGEN_DEVICE_FUNC static const ConstantReturnType + Constant(Index size, const Scalar& value); + EIGEN_DEVICE_FUNC static const ConstantReturnType + Constant(const Scalar& value); + + EIGEN_DEPRECATED EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType + LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high); + EIGEN_DEPRECATED EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType + LinSpaced(Sequential_t, const Scalar& low, const Scalar& high); + + EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType + LinSpaced(Index size, const Scalar& low, const Scalar& high); + EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType + LinSpaced(const Scalar& low, const Scalar& high); + + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp + NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func); + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp + NullaryExpr(Index size, const CustomNullaryOp& func); + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp + NullaryExpr(const CustomNullaryOp& func); + + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(Index size); + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(Index size); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(); + + EIGEN_DEVICE_FUNC void fill(const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setConstant(const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); + EIGEN_DEVICE_FUNC Derived& setLinSpaced(const Scalar& low, const Scalar& high); + EIGEN_DEVICE_FUNC Derived& setZero(); + EIGEN_DEVICE_FUNC Derived& setOnes(); + EIGEN_DEVICE_FUNC Derived& setRandom(); + + template EIGEN_DEVICE_FUNC + bool isApprox(const DenseBase& other, + const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC + bool isMuchSmallerThan(const RealScalar& other, + const RealScalar& prec = NumTraits::dummy_precision()) const; + template EIGEN_DEVICE_FUNC + bool isMuchSmallerThan(const DenseBase& other, + const RealScalar& prec = NumTraits::dummy_precision()) const; + + EIGEN_DEVICE_FUNC bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isZero(const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isOnes(const RealScalar& prec = NumTraits::dummy_precision()) const; + + inline bool hasNaN() const; + inline bool allFinite() const; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator*=(const Scalar& other); + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator/=(const Scalar& other); + + typedef typename internal::add_const_on_value_type::type>::type EvalReturnType; + /** \returns the matrix or vector obtained by evaluating this expression. + * + * Notice that in the case of a plain matrix or vector (not an expression) this function just returns + * a const reference, in order to avoid a useless copy. + * + * \warning Be careful with eval() and the auto C++ keyword, as detailed in this \link TopicPitfalls_auto_keyword page \endlink. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE EvalReturnType eval() const + { + // Even though MSVC does not honor strong inlining when the return type + // is a dynamic matrix, we desperately need strong inlining for fixed + // size types on MSVC. + return typename internal::eval::type(derived()); + } + + /** swaps *this with the expression \a other. + * + */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void swap(const DenseBase& other) + { + EIGEN_STATIC_ASSERT(!OtherDerived::IsPlainObjectBase,THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + eigen_assert(rows()==other.rows() && cols()==other.cols()); + call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); + } + + /** swaps *this with the matrix or array \a other. + * + */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void swap(PlainObjectBase& other) + { + eigen_assert(rows()==other.rows() && cols()==other.cols()); + call_assignment(derived(), other.derived(), internal::swap_assign_op()); + } + + EIGEN_DEVICE_FUNC inline const NestByValue nestByValue() const; + EIGEN_DEVICE_FUNC inline const ForceAlignedAccess forceAlignedAccess() const; + EIGEN_DEVICE_FUNC inline ForceAlignedAccess forceAlignedAccess(); + template EIGEN_DEVICE_FUNC + inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; + template EIGEN_DEVICE_FUNC + inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); + + EIGEN_DEVICE_FUNC Scalar sum() const; + EIGEN_DEVICE_FUNC Scalar mean() const; + EIGEN_DEVICE_FUNC Scalar trace() const; + + EIGEN_DEVICE_FUNC Scalar prod() const; + + template + EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff() const; + template + EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff() const; + + + // By default, the fastest version with undefined NaN propagation semantics is + // used. + // TODO(rmlarsen): Replace with default template argument when we move to + // c++11 or beyond. + EIGEN_DEVICE_FUNC inline typename internal::traits::Scalar minCoeff() const { + return minCoeff(); + } + EIGEN_DEVICE_FUNC inline typename internal::traits::Scalar maxCoeff() const { + return maxCoeff(); + } + + template + EIGEN_DEVICE_FUNC + typename internal::traits::Scalar minCoeff(IndexType* row, IndexType* col) const; + template + EIGEN_DEVICE_FUNC + typename internal::traits::Scalar maxCoeff(IndexType* row, IndexType* col) const; + template + EIGEN_DEVICE_FUNC + typename internal::traits::Scalar minCoeff(IndexType* index) const; + template + EIGEN_DEVICE_FUNC + typename internal::traits::Scalar maxCoeff(IndexType* index) const; + + // TODO(rmlarsen): Replace these methods with a default template argument. + template + EIGEN_DEVICE_FUNC inline + typename internal::traits::Scalar minCoeff(IndexType* row, IndexType* col) const { + return minCoeff(row, col); + } + template + EIGEN_DEVICE_FUNC inline + typename internal::traits::Scalar maxCoeff(IndexType* row, IndexType* col) const { + return maxCoeff(row, col); + } + template + EIGEN_DEVICE_FUNC inline + typename internal::traits::Scalar minCoeff(IndexType* index) const { + return minCoeff(index); + } + template + EIGEN_DEVICE_FUNC inline + typename internal::traits::Scalar maxCoeff(IndexType* index) const { + return maxCoeff(index); + } + + template + EIGEN_DEVICE_FUNC + Scalar redux(const BinaryOp& func) const; + + template + EIGEN_DEVICE_FUNC + void visit(Visitor& func) const; + + /** \returns a WithFormat proxy object allowing to print a matrix the with given + * format \a fmt. + * + * See class IOFormat for some examples. + * + * \sa class IOFormat, class WithFormat + */ + inline const WithFormat format(const IOFormat& fmt) const + { + return WithFormat(derived(), fmt); + } + + /** \returns the unique coefficient of a 1x1 expression */ + EIGEN_DEVICE_FUNC + CoeffReturnType value() const + { + EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) + eigen_assert(this->rows() == 1 && this->cols() == 1); + return derived().coeff(0,0); + } + + EIGEN_DEVICE_FUNC bool all() const; + EIGEN_DEVICE_FUNC bool any() const; + EIGEN_DEVICE_FUNC Index count() const; + + typedef VectorwiseOp RowwiseReturnType; + typedef const VectorwiseOp ConstRowwiseReturnType; + typedef VectorwiseOp ColwiseReturnType; + typedef const VectorwiseOp ConstColwiseReturnType; + + /** \returns a VectorwiseOp wrapper of *this for broadcasting and partial reductions + * + * Example: \include MatrixBase_rowwise.cpp + * Output: \verbinclude MatrixBase_rowwise.out + * + * \sa colwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting + */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC inline ConstRowwiseReturnType rowwise() const { + return ConstRowwiseReturnType(derived()); + } + EIGEN_DEVICE_FUNC RowwiseReturnType rowwise(); + + /** \returns a VectorwiseOp wrapper of *this broadcasting and partial reductions + * + * Example: \include MatrixBase_colwise.cpp + * Output: \verbinclude MatrixBase_colwise.out + * + * \sa rowwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting + */ + EIGEN_DEVICE_FUNC inline ConstColwiseReturnType colwise() const { + return ConstColwiseReturnType(derived()); + } + EIGEN_DEVICE_FUNC ColwiseReturnType colwise(); + + typedef CwiseNullaryOp,PlainObject> RandomReturnType; + static const RandomReturnType Random(Index rows, Index cols); + static const RandomReturnType Random(Index size); + static const RandomReturnType Random(); + + template + inline EIGEN_DEVICE_FUNC const Select + select(const DenseBase& thenMatrix, + const DenseBase& elseMatrix) const; + + template + inline EIGEN_DEVICE_FUNC const Select + select(const DenseBase& thenMatrix, const typename ThenDerived::Scalar& elseScalar) const; + + template + inline EIGEN_DEVICE_FUNC const Select + select(const typename ElseDerived::Scalar& thenScalar, const DenseBase& elseMatrix) const; + + template RealScalar lpNorm() const; + + template + EIGEN_DEVICE_FUNC + const Replicate replicate() const; + /** + * \return an expression of the replication of \c *this + * + * Example: \include MatrixBase_replicate_int_int.cpp + * Output: \verbinclude MatrixBase_replicate_int_int.out + * + * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate + */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC + const Replicate replicate(Index rowFactor, Index colFactor) const + { + return Replicate(derived(), rowFactor, colFactor); + } + + typedef Reverse ReverseReturnType; + typedef const Reverse ConstReverseReturnType; + EIGEN_DEVICE_FUNC ReverseReturnType reverse(); + /** This is the const version of reverse(). */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC ConstReverseReturnType reverse() const + { + return ConstReverseReturnType(derived()); + } + EIGEN_DEVICE_FUNC void reverseInPlace(); + + #ifdef EIGEN_PARSED_BY_DOXYGEN + /** STL-like RandomAccessIterator + * iterator type as returned by the begin() and end() methods. + */ + typedef random_access_iterator_type iterator; + /** This is the const version of iterator (aka read-only) */ + typedef random_access_iterator_type const_iterator; + #else + typedef typename internal::conditional< (Flags&DirectAccessBit)==DirectAccessBit, + internal::pointer_based_stl_iterator, + internal::generic_randaccess_stl_iterator + >::type iterator_type; + + typedef typename internal::conditional< (Flags&DirectAccessBit)==DirectAccessBit, + internal::pointer_based_stl_iterator, + internal::generic_randaccess_stl_iterator + >::type const_iterator_type; + + // Stl-style iterators are supported only for vectors. + + typedef typename internal::conditional< IsVectorAtCompileTime, + iterator_type, + void + >::type iterator; + + typedef typename internal::conditional< IsVectorAtCompileTime, + const_iterator_type, + void + >::type const_iterator; + #endif + + inline iterator begin(); + inline const_iterator begin() const; + inline const_iterator cbegin() const; + inline iterator end(); + inline const_iterator end() const; + inline const_iterator cend() const; + +#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase +#define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +#define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) +#define EIGEN_DOC_UNARY_ADDONS(X,Y) +# include "../plugins/CommonCwiseUnaryOps.h" +# include "../plugins/BlockMethods.h" +# include "../plugins/IndexedViewMethods.h" +# include "../plugins/ReshapedMethods.h" +# ifdef EIGEN_DENSEBASE_PLUGIN +# include EIGEN_DENSEBASE_PLUGIN +# endif +#undef EIGEN_CURRENT_STORAGE_BASE_CLASS +#undef EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +#undef EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF +#undef EIGEN_DOC_UNARY_ADDONS + + // disable the use of evalTo for dense objects with a nice compilation error + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& ) const + { + EIGEN_STATIC_ASSERT((internal::is_same::value),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS); + } + + protected: + EIGEN_DEFAULT_COPY_CONSTRUCTOR(DenseBase) + /** Default constructor. Do nothing. */ + EIGEN_DEVICE_FUNC DenseBase() + { + /* Just checks for self-consistency of the flags. + * Only do it when debugging Eigen, as this borders on paranoia and could slow compilation down + */ +#ifdef EIGEN_INTERNAL_DEBUGGING + EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, int(IsRowMajor)) + && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, int(!IsRowMajor))), + INVALID_STORAGE_ORDER_FOR_THIS_VECTOR_EXPRESSION) +#endif + } + + private: + EIGEN_DEVICE_FUNC explicit DenseBase(int); + EIGEN_DEVICE_FUNC DenseBase(int,int); + template EIGEN_DEVICE_FUNC explicit DenseBase(const DenseBase&); +}; + +} // end namespace Eigen + +#endif // EIGEN_DENSEBASE_H diff --git a/Vendor/eigen/Eigen/src/Core/DenseCoeffsBase.h b/Vendor/eigen/Eigen/src/Core/DenseCoeffsBase.h new file mode 100644 index 0000000..37fcdb5 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/DenseCoeffsBase.h @@ -0,0 +1,685 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DENSECOEFFSBASE_H +#define EIGEN_DENSECOEFFSBASE_H + +namespace Eigen { + +namespace internal { +template struct add_const_on_value_type_if_arithmetic +{ + typedef typename conditional::value, T, typename add_const_on_value_type::type>::type type; +}; +} + +/** \brief Base class providing read-only coefficient access to matrices and arrays. + * \ingroup Core_Module + * \tparam Derived Type of the derived class + * + * \note #ReadOnlyAccessors Constant indicating read-only access + * + * This class defines the \c operator() \c const function and friends, which can be used to read specific + * entries of a matrix or array. + * + * \sa DenseCoeffsBase, DenseCoeffsBase, + * \ref TopicClassHierarchy + */ +template +class DenseCoeffsBase : public EigenBase +{ + public: + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + + // Explanation for this CoeffReturnType typedef. + // - This is the return type of the coeff() method. + // - The LvalueBit means exactly that we can offer a coeffRef() method, which means exactly that we can get references + // to coeffs, which means exactly that we can have coeff() return a const reference (as opposed to returning a value). + // - The is_artihmetic check is required since "const int", "const double", etc. will cause warnings on some systems + // while the declaration of "const T", where T is a non arithmetic type does not. Always returning "const Scalar&" is + // not possible, since the underlying expressions might not offer a valid address the reference could be referring to. + typedef typename internal::conditional::Flags&LvalueBit), + const Scalar&, + typename internal::conditional::value, Scalar, const Scalar>::type + >::type CoeffReturnType; + + typedef typename internal::add_const_on_value_type_if_arithmetic< + typename internal::packet_traits::type + >::type PacketReturnType; + + typedef EigenBase Base; + using Base::rows; + using Base::cols; + using Base::size; + using Base::derived; + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const + { + return int(Derived::RowsAtCompileTime) == 1 ? 0 + : int(Derived::ColsAtCompileTime) == 1 ? inner + : int(Derived::Flags)&RowMajorBit ? outer + : inner; + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) const + { + return int(Derived::ColsAtCompileTime) == 1 ? 0 + : int(Derived::RowsAtCompileTime) == 1 ? inner + : int(Derived::Flags)&RowMajorBit ? inner + : outer; + } + + /** Short version: don't use this function, use + * \link operator()(Index,Index) const \endlink instead. + * + * Long version: this function is similar to + * \link operator()(Index,Index) const \endlink, but without the assertion. + * Use this for limiting the performance cost of debugging code when doing + * repeated coefficient access. Only use this when it is guaranteed that the + * parameters \a row and \a col are in range. + * + * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this + * function equivalent to \link operator()(Index,Index) const \endlink. + * + * \sa operator()(Index,Index) const, coeffRef(Index,Index), coeff(Index) const + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const + { + eigen_internal_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + return internal::evaluator(derived()).coeff(row,col); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CoeffReturnType coeffByOuterInner(Index outer, Index inner) const + { + return coeff(rowIndexByOuterInner(outer, inner), + colIndexByOuterInner(outer, inner)); + } + + /** \returns the coefficient at given the given row and column. + * + * \sa operator()(Index,Index), operator[](Index) + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CoeffReturnType operator()(Index row, Index col) const + { + eigen_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + return coeff(row, col); + } + + /** Short version: don't use this function, use + * \link operator[](Index) const \endlink instead. + * + * Long version: this function is similar to + * \link operator[](Index) const \endlink, but without the assertion. + * Use this for limiting the performance cost of debugging code when doing + * repeated coefficient access. Only use this when it is guaranteed that the + * parameter \a index is in range. + * + * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this + * function equivalent to \link operator[](Index) const \endlink. + * + * \sa operator[](Index) const, coeffRef(Index), coeff(Index,Index) const + */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CoeffReturnType + coeff(Index index) const + { + EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) + eigen_internal_assert(index >= 0 && index < size()); + return internal::evaluator(derived()).coeff(index); + } + + + /** \returns the coefficient at given index. + * + * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. + * + * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const, + * z() const, w() const + */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CoeffReturnType + operator[](Index index) const + { + EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, + THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) + eigen_assert(index >= 0 && index < size()); + return coeff(index); + } + + /** \returns the coefficient at given index. + * + * This is synonymous to operator[](Index) const. + * + * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. + * + * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const, + * z() const, w() const + */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CoeffReturnType + operator()(Index index) const + { + eigen_assert(index >= 0 && index < size()); + return coeff(index); + } + + /** equivalent to operator[](0). */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CoeffReturnType + x() const { return (*this)[0]; } + + /** equivalent to operator[](1). */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CoeffReturnType + y() const + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=2, OUT_OF_RANGE_ACCESS); + return (*this)[1]; + } + + /** equivalent to operator[](2). */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CoeffReturnType + z() const + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=3, OUT_OF_RANGE_ACCESS); + return (*this)[2]; + } + + /** equivalent to operator[](3). */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CoeffReturnType + w() const + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=4, OUT_OF_RANGE_ACCESS); + return (*this)[3]; + } + + /** \internal + * \returns the packet of coefficients starting at the given row and column. It is your responsibility + * to ensure that a packet really starts there. This method is only available on expressions having the + * PacketAccessBit. + * + * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select + * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets + * starting at an address which is a multiple of the packet size. + */ + + template + EIGEN_STRONG_INLINE PacketReturnType packet(Index row, Index col) const + { + typedef typename internal::packet_traits::type DefaultPacketType; + eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); + return internal::evaluator(derived()).template packet(row,col); + } + + + /** \internal */ + template + EIGEN_STRONG_INLINE PacketReturnType packetByOuterInner(Index outer, Index inner) const + { + return packet(rowIndexByOuterInner(outer, inner), + colIndexByOuterInner(outer, inner)); + } + + /** \internal + * \returns the packet of coefficients starting at the given index. It is your responsibility + * to ensure that a packet really starts there. This method is only available on expressions having the + * PacketAccessBit and the LinearAccessBit. + * + * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select + * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets + * starting at an address which is a multiple of the packet size. + */ + + template + EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) + typedef typename internal::packet_traits::type DefaultPacketType; + eigen_internal_assert(index >= 0 && index < size()); + return internal::evaluator(derived()).template packet(index); + } + + protected: + // explanation: DenseBase is doing "using ..." on the methods from DenseCoeffsBase. + // But some methods are only available in the DirectAccess case. + // So we add dummy methods here with these names, so that "using... " doesn't fail. + // It's not private so that the child class DenseBase can access them, and it's not public + // either since it's an implementation detail, so has to be protected. + void coeffRef(); + void coeffRefByOuterInner(); + void writePacket(); + void writePacketByOuterInner(); + void copyCoeff(); + void copyCoeffByOuterInner(); + void copyPacket(); + void copyPacketByOuterInner(); + void stride(); + void innerStride(); + void outerStride(); + void rowStride(); + void colStride(); +}; + +/** \brief Base class providing read/write coefficient access to matrices and arrays. + * \ingroup Core_Module + * \tparam Derived Type of the derived class + * + * \note #WriteAccessors Constant indicating read/write access + * + * This class defines the non-const \c operator() function and friends, which can be used to write specific + * entries of a matrix or array. This class inherits DenseCoeffsBase which + * defines the const variant for reading specific entries. + * + * \sa DenseCoeffsBase, \ref TopicClassHierarchy + */ +template +class DenseCoeffsBase : public DenseCoeffsBase +{ + public: + + typedef DenseCoeffsBase Base; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + + using Base::coeff; + using Base::rows; + using Base::cols; + using Base::size; + using Base::derived; + using Base::rowIndexByOuterInner; + using Base::colIndexByOuterInner; + using Base::operator[]; + using Base::operator(); + using Base::x; + using Base::y; + using Base::z; + using Base::w; + + /** Short version: don't use this function, use + * \link operator()(Index,Index) \endlink instead. + * + * Long version: this function is similar to + * \link operator()(Index,Index) \endlink, but without the assertion. + * Use this for limiting the performance cost of debugging code when doing + * repeated coefficient access. Only use this when it is guaranteed that the + * parameters \a row and \a col are in range. + * + * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this + * function equivalent to \link operator()(Index,Index) \endlink. + * + * \sa operator()(Index,Index), coeff(Index, Index) const, coeffRef(Index) + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) + { + eigen_internal_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + return internal::evaluator(derived()).coeffRef(row,col); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + coeffRefByOuterInner(Index outer, Index inner) + { + return coeffRef(rowIndexByOuterInner(outer, inner), + colIndexByOuterInner(outer, inner)); + } + + /** \returns a reference to the coefficient at given the given row and column. + * + * \sa operator[](Index) + */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + operator()(Index row, Index col) + { + eigen_assert(row >= 0 && row < rows() + && col >= 0 && col < cols()); + return coeffRef(row, col); + } + + + /** Short version: don't use this function, use + * \link operator[](Index) \endlink instead. + * + * Long version: this function is similar to + * \link operator[](Index) \endlink, but without the assertion. + * Use this for limiting the performance cost of debugging code when doing + * repeated coefficient access. Only use this when it is guaranteed that the + * parameters \a row and \a col are in range. + * + * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this + * function equivalent to \link operator[](Index) \endlink. + * + * \sa operator[](Index), coeff(Index) const, coeffRef(Index,Index) + */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + coeffRef(Index index) + { + EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) + eigen_internal_assert(index >= 0 && index < size()); + return internal::evaluator(derived()).coeffRef(index); + } + + /** \returns a reference to the coefficient at given index. + * + * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. + * + * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w() + */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + operator[](Index index) + { + EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, + THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) + eigen_assert(index >= 0 && index < size()); + return coeffRef(index); + } + + /** \returns a reference to the coefficient at given index. + * + * This is synonymous to operator[](Index). + * + * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. + * + * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w() + */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + operator()(Index index) + { + eigen_assert(index >= 0 && index < size()); + return coeffRef(index); + } + + /** equivalent to operator[](0). */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + x() { return (*this)[0]; } + + /** equivalent to operator[](1). */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + y() + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=2, OUT_OF_RANGE_ACCESS); + return (*this)[1]; + } + + /** equivalent to operator[](2). */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + z() + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=3, OUT_OF_RANGE_ACCESS); + return (*this)[2]; + } + + /** equivalent to operator[](3). */ + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + w() + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=4, OUT_OF_RANGE_ACCESS); + return (*this)[3]; + } +}; + +/** \brief Base class providing direct read-only coefficient access to matrices and arrays. + * \ingroup Core_Module + * \tparam Derived Type of the derived class + * + * \note #DirectAccessors Constant indicating direct access + * + * This class defines functions to work with strides which can be used to access entries directly. This class + * inherits DenseCoeffsBase which defines functions to access entries read-only using + * \c operator() . + * + * \sa \blank \ref TopicClassHierarchy + */ +template +class DenseCoeffsBase : public DenseCoeffsBase +{ + public: + + typedef DenseCoeffsBase Base; + typedef typename internal::traits::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + + using Base::rows; + using Base::cols; + using Base::size; + using Base::derived; + + /** \returns the pointer increment between two consecutive elements within a slice in the inner direction. + * + * \sa outerStride(), rowStride(), colStride() + */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index innerStride() const + { + return derived().innerStride(); + } + + /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns + * in a column-major matrix). + * + * \sa innerStride(), rowStride(), colStride() + */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index outerStride() const + { + return derived().outerStride(); + } + + // FIXME shall we remove it ? + EIGEN_CONSTEXPR inline Index stride() const + { + return Derived::IsVectorAtCompileTime ? innerStride() : outerStride(); + } + + /** \returns the pointer increment between two consecutive rows. + * + * \sa innerStride(), outerStride(), colStride() + */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index rowStride() const + { + return Derived::IsRowMajor ? outerStride() : innerStride(); + } + + /** \returns the pointer increment between two consecutive columns. + * + * \sa innerStride(), outerStride(), rowStride() + */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index colStride() const + { + return Derived::IsRowMajor ? innerStride() : outerStride(); + } +}; + +/** \brief Base class providing direct read/write coefficient access to matrices and arrays. + * \ingroup Core_Module + * \tparam Derived Type of the derived class + * + * \note #DirectWriteAccessors Constant indicating direct access + * + * This class defines functions to work with strides which can be used to access entries directly. This class + * inherits DenseCoeffsBase which defines functions to access entries read/write using + * \c operator(). + * + * \sa \blank \ref TopicClassHierarchy + */ +template +class DenseCoeffsBase + : public DenseCoeffsBase +{ + public: + + typedef DenseCoeffsBase Base; + typedef typename internal::traits::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + + using Base::rows; + using Base::cols; + using Base::size; + using Base::derived; + + /** \returns the pointer increment between two consecutive elements within a slice in the inner direction. + * + * \sa outerStride(), rowStride(), colStride() + */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index innerStride() const EIGEN_NOEXCEPT + { + return derived().innerStride(); + } + + /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns + * in a column-major matrix). + * + * \sa innerStride(), rowStride(), colStride() + */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index outerStride() const EIGEN_NOEXCEPT + { + return derived().outerStride(); + } + + // FIXME shall we remove it ? + EIGEN_CONSTEXPR inline Index stride() const EIGEN_NOEXCEPT + { + return Derived::IsVectorAtCompileTime ? innerStride() : outerStride(); + } + + /** \returns the pointer increment between two consecutive rows. + * + * \sa innerStride(), outerStride(), colStride() + */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index rowStride() const EIGEN_NOEXCEPT + { + return Derived::IsRowMajor ? outerStride() : innerStride(); + } + + /** \returns the pointer increment between two consecutive columns. + * + * \sa innerStride(), outerStride(), rowStride() + */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index colStride() const EIGEN_NOEXCEPT + { + return Derived::IsRowMajor ? innerStride() : outerStride(); + } +}; + +namespace internal { + +template +struct first_aligned_impl +{ + static EIGEN_CONSTEXPR inline Index run(const Derived&) EIGEN_NOEXCEPT + { return 0; } +}; + +template +struct first_aligned_impl +{ + static inline Index run(const Derived& m) + { + return internal::first_aligned(m.data(), m.size()); + } +}; + +/** \internal \returns the index of the first element of the array stored by \a m that is properly aligned with respect to \a Alignment for vectorization. + * + * \tparam Alignment requested alignment in Bytes. + * + * There is also the variant first_aligned(const Scalar*, Integer) defined in Memory.h. See it for more + * documentation. + */ +template +static inline Index first_aligned(const DenseBase& m) +{ + enum { ReturnZero = (int(evaluator::Alignment) >= Alignment) || !(Derived::Flags & DirectAccessBit) }; + return first_aligned_impl::run(m.derived()); +} + +template +static inline Index first_default_aligned(const DenseBase& m) +{ + typedef typename Derived::Scalar Scalar; + typedef typename packet_traits::type DefaultPacketType; + return internal::first_aligned::alignment),Derived>(m); +} + +template::ret> +struct inner_stride_at_compile_time +{ + enum { ret = traits::InnerStrideAtCompileTime }; +}; + +template +struct inner_stride_at_compile_time +{ + enum { ret = 0 }; +}; + +template::ret> +struct outer_stride_at_compile_time +{ + enum { ret = traits::OuterStrideAtCompileTime }; +}; + +template +struct outer_stride_at_compile_time +{ + enum { ret = 0 }; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_DENSECOEFFSBASE_H diff --git a/Vendor/eigen/Eigen/src/Core/DenseStorage.h b/Vendor/eigen/Eigen/src/Core/DenseStorage.h new file mode 100644 index 0000000..08ef6c5 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/DenseStorage.h @@ -0,0 +1,652 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2009 Benoit Jacob +// Copyright (C) 2010-2013 Hauke Heibel +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATRIXSTORAGE_H +#define EIGEN_MATRIXSTORAGE_H + +#ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(X) X; EIGEN_DENSE_STORAGE_CTOR_PLUGIN; +#else + #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(X) +#endif + +namespace Eigen { + +namespace internal { + +struct constructor_without_unaligned_array_assert {}; + +template +EIGEN_DEVICE_FUNC +void check_static_allocation_size() +{ + // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit + #if EIGEN_STACK_ALLOCATION_LIMIT + EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + #endif +} + +/** \internal + * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned: + * to 16 bytes boundary if the total size is a multiple of 16 bytes. + */ +template ::value > +struct plain_array +{ + T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +#if defined(EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT) + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) +#elif EIGEN_GNUC_AT_LEAST(4,7) + // GCC 4.7 is too aggressive in its optimizations and remove the alignment test based on the fact the array is declared to be aligned. + // See this bug report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53900 + // Hiding the origin of the array pointer behind a function argument seems to do the trick even if the function is inlined: + template + EIGEN_ALWAYS_INLINE PtrType eigen_unaligned_array_assert_workaround_gcc47(PtrType array) { return array; } + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ + eigen_assert((internal::UIntPtr(eigen_unaligned_array_assert_workaround_gcc47(array)) & (sizemask)) == 0 \ + && "this assertion is explained here: " \ + "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ + " **** READ THIS WEB PAGE !!! ****"); +#else + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ + eigen_assert((internal::UIntPtr(array) & (sizemask)) == 0 \ + && "this assertion is explained here: " \ + "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ + " **** READ THIS WEB PAGE !!! ****"); +#endif + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(8) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(7); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(16) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(15); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(32) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(31); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(64) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(63); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + T array[1]; + EIGEN_DEVICE_FUNC plain_array() {} + EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) {} +}; + +struct plain_array_helper { + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + static void copy(const plain_array& src, const Eigen::Index size, + plain_array& dst) { + smart_copy(src.array, src.array + size, dst.array); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + static void swap(plain_array& a, const Eigen::Index a_size, + plain_array& b, const Eigen::Index b_size) { + if (a_size < b_size) { + std::swap_ranges(b.array, b.array + a_size, a.array); + smart_move(b.array + a_size, b.array + b_size, a.array + a_size); + } else if (a_size > b_size) { + std::swap_ranges(a.array, a.array + b_size, b.array); + smart_move(a.array + b_size, a.array + a_size, b.array + b_size); + } else { + std::swap_ranges(a.array, a.array + a_size, b.array); + } + } +}; + +} // end namespace internal + +/** \internal + * + * \class DenseStorage + * \ingroup Core_Module + * + * \brief Stores the data of a matrix + * + * This class stores the data of fixed-size, dynamic-size or mixed matrices + * in a way as compact as possible. + * + * \sa Matrix + */ +template class DenseStorage; + +// purely fixed-size matrix +template class DenseStorage +{ + internal::plain_array m_data; + public: + EIGEN_DEVICE_FUNC DenseStorage() { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = Size) + } + EIGEN_DEVICE_FUNC + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()) {} +#if !EIGEN_HAS_CXX11 || defined(EIGEN_DENSE_STORAGE_CTOR_PLUGIN) + EIGEN_DEVICE_FUNC + DenseStorage(const DenseStorage& other) : m_data(other.m_data) { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = Size) + } +#else + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage&) = default; +#endif +#if !EIGEN_HAS_CXX11 + EIGEN_DEVICE_FUNC + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) m_data = other.m_data; + return *this; + } +#else + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage&) = default; +#endif +#if EIGEN_HAS_RVALUE_REFERENCES +#if !EIGEN_HAS_CXX11 + EIGEN_DEVICE_FUNC DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT + : m_data(std::move(other.m_data)) + { + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT + { + if (this != &other) + m_data = std::move(other.m_data); + return *this; + } +#else + EIGEN_DEVICE_FUNC DenseStorage(DenseStorage&&) = default; + EIGEN_DEVICE_FUNC DenseStorage& operator=(DenseStorage&&) = default; +#endif +#endif + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows==_Rows && cols==_Cols); + EIGEN_UNUSED_VARIABLE(size); + EIGEN_UNUSED_VARIABLE(rows); + EIGEN_UNUSED_VARIABLE(cols); + } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { + numext::swap(m_data, other.m_data); + } + EIGEN_DEVICE_FUNC static EIGEN_CONSTEXPR Index rows(void) EIGEN_NOEXCEPT {return _Rows;} + EIGEN_DEVICE_FUNC static EIGEN_CONSTEXPR Index cols(void) EIGEN_NOEXCEPT {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void resize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } +}; + +// null matrix +template class DenseStorage +{ + public: + EIGEN_DEVICE_FUNC DenseStorage() {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) {} + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage&) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage&) { return *this; } + EIGEN_DEVICE_FUNC DenseStorage(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& ) {} + EIGEN_DEVICE_FUNC static EIGEN_CONSTEXPR Index rows(void) EIGEN_NOEXCEPT {return _Rows;} + EIGEN_DEVICE_FUNC static EIGEN_CONSTEXPR Index cols(void) EIGEN_NOEXCEPT {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void resize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC const T *data() const { return 0; } + EIGEN_DEVICE_FUNC T *data() { return 0; } +}; + +// more specializations for null matrices; these are necessary to resolve ambiguities +template class DenseStorage +: public DenseStorage { }; + +template class DenseStorage +: public DenseStorage { }; + +template class DenseStorage +: public DenseStorage { }; + +// dynamic-size matrix with fixed-size storage +template class DenseStorage +{ + internal::plain_array m_data; + Index m_rows; + Index m_cols; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(other.m_rows), m_cols(other.m_cols) + { + internal::plain_array_helper::copy(other.m_data, m_rows * m_cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_rows = other.m_rows; + m_cols = other.m_cols; + internal::plain_array_helper::copy(other.m_data, m_rows * m_cols, m_data); + } + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index, Index rows, Index cols) : m_rows(rows), m_cols(cols) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) + { + internal::plain_array_helper::swap(m_data, m_rows * m_cols, other.m_data, other.m_rows * other.m_cols); + numext::swap(m_rows,other.m_rows); + numext::swap(m_cols,other.m_cols); + } + EIGEN_DEVICE_FUNC Index rows() const {return m_rows;} + EIGEN_DEVICE_FUNC Index cols() const {return m_cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index, Index rows, Index cols) { m_rows = rows; m_cols = cols; } + EIGEN_DEVICE_FUNC void resize(Index, Index rows, Index cols) { m_rows = rows; m_cols = cols; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } +}; + +// dynamic-size matrix with fixed-size storage and fixed width +template class DenseStorage +{ + internal::plain_array m_data; + Index m_rows; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_rows(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(other.m_rows) + { + internal::plain_array_helper::copy(other.m_data, m_rows * _Cols, m_data); + } + + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_rows = other.m_rows; + internal::plain_array_helper::copy(other.m_data, m_rows * _Cols, m_data); + } + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index, Index rows, Index) : m_rows(rows) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) + { + internal::plain_array_helper::swap(m_data, m_rows * _Cols, other.m_data, other.m_rows * _Cols); + numext::swap(m_rows, other.m_rows); + } + EIGEN_DEVICE_FUNC Index rows(void) const EIGEN_NOEXCEPT {return m_rows;} + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index cols(void) const EIGEN_NOEXCEPT {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index, Index rows, Index) { m_rows = rows; } + EIGEN_DEVICE_FUNC void resize(Index, Index rows, Index) { m_rows = rows; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } +}; + +// dynamic-size matrix with fixed-size storage and fixed height +template class DenseStorage +{ + internal::plain_array m_data; + Index m_cols; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(other.m_cols) + { + internal::plain_array_helper::copy(other.m_data, _Rows * m_cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_cols = other.m_cols; + internal::plain_array_helper::copy(other.m_data, _Rows * m_cols, m_data); + } + return *this; + } + EIGEN_DEVICE_FUNC DenseStorage(Index, Index, Index cols) : m_cols(cols) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { + internal::plain_array_helper::swap(m_data, _Rows * m_cols, other.m_data, _Rows * other.m_cols); + numext::swap(m_cols, other.m_cols); + } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index rows(void) const EIGEN_NOEXCEPT {return _Rows;} + EIGEN_DEVICE_FUNC Index cols(void) const EIGEN_NOEXCEPT {return m_cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index, Index, Index cols) { m_cols = cols; } + EIGEN_DEVICE_FUNC void resize(Index, Index, Index cols) { m_cols = cols; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } +}; + +// purely dynamic matrix. +template class DenseStorage +{ + T *m_data; + Index m_rows; + Index m_cols; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) + : m_data(0), m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) + : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows), m_cols(cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows>=0 && cols >=0); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(other.m_rows*other.m_cols)) + , m_rows(other.m_rows) + , m_cols(other.m_cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_rows*m_cols) + internal::smart_copy(other.m_data, other.m_data+other.m_rows*other.m_cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT + : m_data(std::move(other.m_data)) + , m_rows(std::move(other.m_rows)) + , m_cols(std::move(other.m_cols)) + { + other.m_data = nullptr; + other.m_rows = 0; + other.m_cols = 0; + } + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT + { + numext::swap(m_data, other.m_data); + numext::swap(m_rows, other.m_rows); + numext::swap(m_cols, other.m_cols); + return *this; + } +#endif + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) + { + numext::swap(m_data,other.m_data); + numext::swap(m_rows,other.m_rows); + numext::swap(m_cols,other.m_cols); + } + EIGEN_DEVICE_FUNC Index rows(void) const EIGEN_NOEXCEPT {return m_rows;} + EIGEN_DEVICE_FUNC Index cols(void) const EIGEN_NOEXCEPT {return m_cols;} + void conservativeResize(Index size, Index rows, Index cols) + { + m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*m_cols); + m_rows = rows; + m_cols = cols; + } + EIGEN_DEVICE_FUNC void resize(Index size, Index rows, Index cols) + { + if(size != m_rows*m_cols) + { + internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); + if (size>0) // >0 and not simply !=0 to let the compiler knows that size cannot be negative + m_data = internal::conditional_aligned_new_auto(size); + else + m_data = 0; + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + } + m_rows = rows; + m_cols = cols; + } + EIGEN_DEVICE_FUNC const T *data() const { return m_data; } + EIGEN_DEVICE_FUNC T *data() { return m_data; } +}; + +// matrix with dynamic width and fixed height (so that matrix has dynamic size). +template class DenseStorage +{ + T *m_data; + Index m_cols; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_cols(0) {} + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows==_Rows && cols >=0); + EIGEN_UNUSED_VARIABLE(rows); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(_Rows*other.m_cols)) + , m_cols(other.m_cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_cols*_Rows) + internal::smart_copy(other.m_data, other.m_data+_Rows*m_cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT + : m_data(std::move(other.m_data)) + , m_cols(std::move(other.m_cols)) + { + other.m_data = nullptr; + other.m_cols = 0; + } + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT + { + numext::swap(m_data, other.m_data); + numext::swap(m_cols, other.m_cols); + return *this; + } +#endif + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { + numext::swap(m_data,other.m_data); + numext::swap(m_cols,other.m_cols); + } + EIGEN_DEVICE_FUNC static EIGEN_CONSTEXPR Index rows(void) EIGEN_NOEXCEPT {return _Rows;} + EIGEN_DEVICE_FUNC Index cols(void) const EIGEN_NOEXCEPT {return m_cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index size, Index, Index cols) + { + m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, _Rows*m_cols); + m_cols = cols; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index size, Index, Index cols) + { + if(size != _Rows*m_cols) + { + internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); + if (size>0) // >0 and not simply !=0 to let the compiler knows that size cannot be negative + m_data = internal::conditional_aligned_new_auto(size); + else + m_data = 0; + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + } + m_cols = cols; + } + EIGEN_DEVICE_FUNC const T *data() const { return m_data; } + EIGEN_DEVICE_FUNC T *data() { return m_data; } +}; + +// matrix with dynamic height and fixed width (so that matrix has dynamic size). +template class DenseStorage +{ + T *m_data; + Index m_rows; + public: + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_rows(0) {} + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows>=0 && cols == _Cols); + EIGEN_UNUSED_VARIABLE(cols); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(other.m_rows*_Cols)) + , m_rows(other.m_rows) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_rows*_Cols) + internal::smart_copy(other.m_data, other.m_data+other.m_rows*_Cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT + : m_data(std::move(other.m_data)) + , m_rows(std::move(other.m_rows)) + { + other.m_data = nullptr; + other.m_rows = 0; + } + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT + { + numext::swap(m_data, other.m_data); + numext::swap(m_rows, other.m_rows); + return *this; + } +#endif + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { + numext::swap(m_data,other.m_data); + numext::swap(m_rows,other.m_rows); + } + EIGEN_DEVICE_FUNC Index rows(void) const EIGEN_NOEXCEPT {return m_rows;} + EIGEN_DEVICE_FUNC static EIGEN_CONSTEXPR Index cols(void) {return _Cols;} + void conservativeResize(Index size, Index rows, Index) + { + m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*_Cols); + m_rows = rows; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index size, Index rows, Index) + { + if(size != m_rows*_Cols) + { + internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); + if (size>0) // >0 and not simply !=0 to let the compiler knows that size cannot be negative + m_data = internal::conditional_aligned_new_auto(size); + else + m_data = 0; + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + } + m_rows = rows; + } + EIGEN_DEVICE_FUNC const T *data() const { return m_data; } + EIGEN_DEVICE_FUNC T *data() { return m_data; } +}; + +} // end namespace Eigen + +#endif // EIGEN_MATRIX_H diff --git a/Vendor/eigen/Eigen/src/Core/Diagonal.h b/Vendor/eigen/Eigen/src/Core/Diagonal.h new file mode 100644 index 0000000..3112d2c --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Diagonal.h @@ -0,0 +1,258 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007-2009 Benoit Jacob +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DIAGONAL_H +#define EIGEN_DIAGONAL_H + +namespace Eigen { + +/** \class Diagonal + * \ingroup Core_Module + * + * \brief Expression of a diagonal/subdiagonal/superdiagonal in a matrix + * + * \param MatrixType the type of the object in which we are taking a sub/main/super diagonal + * \param DiagIndex the index of the sub/super diagonal. The default is 0 and it means the main diagonal. + * A positive value means a superdiagonal, a negative value means a subdiagonal. + * You can also use DynamicIndex so the index can be set at runtime. + * + * The matrix is not required to be square. + * + * This class represents an expression of the main diagonal, or any sub/super diagonal + * of a square matrix. It is the return type of MatrixBase::diagonal() and MatrixBase::diagonal(Index) and most of the + * time this is the only way it is used. + * + * \sa MatrixBase::diagonal(), MatrixBase::diagonal(Index) + */ + +namespace internal { +template +struct traits > + : traits +{ + typedef typename ref_selector::type MatrixTypeNested; + typedef typename remove_reference::type _MatrixTypeNested; + typedef typename MatrixType::StorageKind StorageKind; + enum { + RowsAtCompileTime = (int(DiagIndex) == DynamicIndex || int(MatrixType::SizeAtCompileTime) == Dynamic) ? Dynamic + : (EIGEN_PLAIN_ENUM_MIN(MatrixType::RowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), + MatrixType::ColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), + ColsAtCompileTime = 1, + MaxRowsAtCompileTime = int(MatrixType::MaxSizeAtCompileTime) == Dynamic ? Dynamic + : DiagIndex == DynamicIndex ? EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::MaxRowsAtCompileTime, + MatrixType::MaxColsAtCompileTime) + : (EIGEN_PLAIN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), + MatrixType::MaxColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), + MaxColsAtCompileTime = 1, + MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = (unsigned int)_MatrixTypeNested::Flags & (RowMajorBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, // FIXME DirectAccessBit should not be handled by expressions + MatrixTypeOuterStride = outer_stride_at_compile_time::ret, + InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, + OuterStrideAtCompileTime = 0 + }; +}; +} + +template class Diagonal + : public internal::dense_xpr_base< Diagonal >::type +{ + public: + + enum { DiagIndex = _DiagIndex }; + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) + + EIGEN_DEVICE_FUNC + explicit inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) + { + eigen_assert( a_index <= m_matrix.cols() && -a_index <= m_matrix.rows() ); + } + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal) + + EIGEN_DEVICE_FUNC + inline Index rows() const + { + return m_index.value()<0 ? numext::mini(m_matrix.cols(),m_matrix.rows()+m_index.value()) + : numext::mini(m_matrix.rows(),m_matrix.cols()-m_index.value()); + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index cols() const EIGEN_NOEXCEPT { return 1; } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index innerStride() const EIGEN_NOEXCEPT { + return m_matrix.outerStride() + 1; + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index outerStride() const EIGEN_NOEXCEPT { return 0; } + + typedef typename internal::conditional< + internal::is_lvalue::value, + Scalar, + const Scalar + >::type ScalarWithConstIfNotLvalue; + + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue* data() { return &(m_matrix.coeffRef(rowOffset(), colOffset())); } + EIGEN_DEVICE_FUNC + inline const Scalar* data() const { return &(m_matrix.coeffRef(rowOffset(), colOffset())); } + + EIGEN_DEVICE_FUNC + inline Scalar& coeffRef(Index row, Index) + { + EIGEN_STATIC_ASSERT_LVALUE(MatrixType) + return m_matrix.coeffRef(row+rowOffset(), row+colOffset()); + } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index row, Index) const + { + return m_matrix.coeffRef(row+rowOffset(), row+colOffset()); + } + + EIGEN_DEVICE_FUNC + inline CoeffReturnType coeff(Index row, Index) const + { + return m_matrix.coeff(row+rowOffset(), row+colOffset()); + } + + EIGEN_DEVICE_FUNC + inline Scalar& coeffRef(Index idx) + { + EIGEN_STATIC_ASSERT_LVALUE(MatrixType) + return m_matrix.coeffRef(idx+rowOffset(), idx+colOffset()); + } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index idx) const + { + return m_matrix.coeffRef(idx+rowOffset(), idx+colOffset()); + } + + EIGEN_DEVICE_FUNC + inline CoeffReturnType coeff(Index idx) const + { + return m_matrix.coeff(idx+rowOffset(), idx+colOffset()); + } + + EIGEN_DEVICE_FUNC + inline const typename internal::remove_all::type& + nestedExpression() const + { + return m_matrix; + } + + EIGEN_DEVICE_FUNC + inline Index index() const + { + return m_index.value(); + } + + protected: + typename internal::ref_selector::non_const_type m_matrix; + const internal::variable_if_dynamicindex m_index; + + private: + // some compilers may fail to optimize std::max etc in case of compile-time constants... + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index absDiagIndex() const EIGEN_NOEXCEPT { return m_index.value()>0 ? m_index.value() : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index rowOffset() const EIGEN_NOEXCEPT { return m_index.value()>0 ? 0 : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index colOffset() const EIGEN_NOEXCEPT { return m_index.value()>0 ? m_index.value() : 0; } + // trigger a compile-time error if someone try to call packet + template typename MatrixType::PacketReturnType packet(Index) const; + template typename MatrixType::PacketReturnType packet(Index,Index) const; +}; + +/** \returns an expression of the main diagonal of the matrix \c *this + * + * \c *this is not required to be square. + * + * Example: \include MatrixBase_diagonal.cpp + * Output: \verbinclude MatrixBase_diagonal.out + * + * \sa class Diagonal */ +template +EIGEN_DEVICE_FUNC inline typename MatrixBase::DiagonalReturnType +MatrixBase::diagonal() +{ + return DiagonalReturnType(derived()); +} + +/** This is the const version of diagonal(). */ +template +EIGEN_DEVICE_FUNC inline typename MatrixBase::ConstDiagonalReturnType +MatrixBase::diagonal() const +{ + return ConstDiagonalReturnType(derived()); +} + +/** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this + * + * \c *this is not required to be square. + * + * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0 + * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal. + * + * Example: \include MatrixBase_diagonal_int.cpp + * Output: \verbinclude MatrixBase_diagonal_int.out + * + * \sa MatrixBase::diagonal(), class Diagonal */ +template +EIGEN_DEVICE_FUNC inline typename MatrixBase::DiagonalDynamicIndexReturnType +MatrixBase::diagonal(Index index) +{ + return DiagonalDynamicIndexReturnType(derived(), index); +} + +/** This is the const version of diagonal(Index). */ +template +EIGEN_DEVICE_FUNC inline typename MatrixBase::ConstDiagonalDynamicIndexReturnType +MatrixBase::diagonal(Index index) const +{ + return ConstDiagonalDynamicIndexReturnType(derived(), index); +} + +/** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this + * + * \c *this is not required to be square. + * + * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0 + * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal. + * + * Example: \include MatrixBase_diagonal_template_int.cpp + * Output: \verbinclude MatrixBase_diagonal_template_int.out + * + * \sa MatrixBase::diagonal(), class Diagonal */ +template +template +EIGEN_DEVICE_FUNC +inline typename MatrixBase::template DiagonalIndexReturnType::Type +MatrixBase::diagonal() +{ + return typename DiagonalIndexReturnType::Type(derived()); +} + +/** This is the const version of diagonal(). */ +template +template +EIGEN_DEVICE_FUNC +inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type +MatrixBase::diagonal() const +{ + return typename ConstDiagonalIndexReturnType::Type(derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_DIAGONAL_H diff --git a/Vendor/eigen/Eigen/src/Core/DiagonalMatrix.h b/Vendor/eigen/Eigen/src/Core/DiagonalMatrix.h new file mode 100644 index 0000000..542685c --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/DiagonalMatrix.h @@ -0,0 +1,391 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2007-2009 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DIAGONALMATRIX_H +#define EIGEN_DIAGONALMATRIX_H + +namespace Eigen { + +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +class DiagonalBase : public EigenBase +{ + public: + typedef typename internal::traits::DiagonalVectorType DiagonalVectorType; + typedef typename DiagonalVectorType::Scalar Scalar; + typedef typename DiagonalVectorType::RealScalar RealScalar; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::StorageIndex StorageIndex; + + enum { + RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + IsVectorAtCompileTime = 0, + Flags = NoPreferredStorageOrderBit + }; + + typedef Matrix DenseMatrixType; + typedef DenseMatrixType DenseType; + typedef DiagonalMatrix PlainObject; + + EIGEN_DEVICE_FUNC + inline const Derived& derived() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC + inline Derived& derived() { return *static_cast(this); } + + EIGEN_DEVICE_FUNC + DenseMatrixType toDenseMatrix() const { return derived(); } + + EIGEN_DEVICE_FUNC + inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); } + EIGEN_DEVICE_FUNC + inline DiagonalVectorType& diagonal() { return derived().diagonal(); } + + EIGEN_DEVICE_FUNC + inline Index rows() const { return diagonal().size(); } + EIGEN_DEVICE_FUNC + inline Index cols() const { return diagonal().size(); } + + template + EIGEN_DEVICE_FUNC + const Product + operator*(const MatrixBase &matrix) const + { + return Product(derived(),matrix.derived()); + } + + typedef DiagonalWrapper, const DiagonalVectorType> > InverseReturnType; + EIGEN_DEVICE_FUNC + inline const InverseReturnType + inverse() const + { + return InverseReturnType(diagonal().cwiseInverse()); + } + + EIGEN_DEVICE_FUNC + inline const DiagonalWrapper + operator*(const Scalar& scalar) const + { + return DiagonalWrapper(diagonal() * scalar); + } + EIGEN_DEVICE_FUNC + friend inline const DiagonalWrapper + operator*(const Scalar& scalar, const DiagonalBase& other) + { + return DiagonalWrapper(scalar * other.diagonal()); + } + + template + EIGEN_DEVICE_FUNC + #ifdef EIGEN_PARSED_BY_DOXYGEN + inline unspecified_expression_type + #else + inline const DiagonalWrapper + #endif + operator+(const DiagonalBase& other) const + { + return (diagonal() + other.diagonal()).asDiagonal(); + } + + template + EIGEN_DEVICE_FUNC + #ifdef EIGEN_PARSED_BY_DOXYGEN + inline unspecified_expression_type + #else + inline const DiagonalWrapper + #endif + operator-(const DiagonalBase& other) const + { + return (diagonal() - other.diagonal()).asDiagonal(); + } +}; + +#endif + +/** \class DiagonalMatrix + * \ingroup Core_Module + * + * \brief Represents a diagonal matrix with its storage + * + * \param _Scalar the type of coefficients + * \param SizeAtCompileTime the dimension of the matrix, or Dynamic + * \param MaxSizeAtCompileTime the dimension of the matrix, or Dynamic. This parameter is optional and defaults + * to SizeAtCompileTime. Most of the time, you do not need to specify it. + * + * \sa class DiagonalWrapper + */ + +namespace internal { +template +struct traits > + : traits > +{ + typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; + typedef DiagonalShape StorageKind; + enum { + Flags = LvalueBit | NoPreferredStorageOrderBit + }; +}; +} +template +class DiagonalMatrix + : public DiagonalBase > +{ + public: + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename internal::traits::DiagonalVectorType DiagonalVectorType; + typedef const DiagonalMatrix& Nested; + typedef _Scalar Scalar; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::StorageIndex StorageIndex; + #endif + + protected: + + DiagonalVectorType m_diagonal; + + public: + + /** const version of diagonal(). */ + EIGEN_DEVICE_FUNC + inline const DiagonalVectorType& diagonal() const { return m_diagonal; } + /** \returns a reference to the stored vector of diagonal coefficients. */ + EIGEN_DEVICE_FUNC + inline DiagonalVectorType& diagonal() { return m_diagonal; } + + /** Default constructor without initialization */ + EIGEN_DEVICE_FUNC + inline DiagonalMatrix() {} + + /** Constructs a diagonal matrix with given dimension */ + EIGEN_DEVICE_FUNC + explicit inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} + + /** 2D constructor. */ + EIGEN_DEVICE_FUNC + inline DiagonalMatrix(const Scalar& x, const Scalar& y) : m_diagonal(x,y) {} + + /** 3D constructor. */ + EIGEN_DEVICE_FUNC + inline DiagonalMatrix(const Scalar& x, const Scalar& y, const Scalar& z) : m_diagonal(x,y,z) {} + + #if EIGEN_HAS_CXX11 + /** \brief Construct a diagonal matrix with fixed size from an arbitrary number of coefficients. \cpp11 + * + * There exists C++98 anologue constructors for fixed-size diagonal matrices having 2 or 3 coefficients. + * + * \warning To construct a diagonal matrix of fixed size, the number of values passed to this + * constructor must match the fixed dimension of \c *this. + * + * \sa DiagonalMatrix(const Scalar&, const Scalar&) + * \sa DiagonalMatrix(const Scalar&, const Scalar&, const Scalar&) + */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + DiagonalMatrix(const Scalar& a0, const Scalar& a1, const Scalar& a2, const ArgTypes&... args) + : m_diagonal(a0, a1, a2, args...) {} + + /** \brief Constructs a DiagonalMatrix and initializes it by elements given by an initializer list of initializer + * lists \cpp11 + */ + EIGEN_DEVICE_FUNC + explicit EIGEN_STRONG_INLINE DiagonalMatrix(const std::initializer_list>& list) + : m_diagonal(list) {} + #endif // EIGEN_HAS_CXX11 + + /** Copy constructor. */ + template + EIGEN_DEVICE_FUNC + inline DiagonalMatrix(const DiagonalBase& other) : m_diagonal(other.diagonal()) {} + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** copy constructor. prevent a default copy constructor from hiding the other templated constructor */ + inline DiagonalMatrix(const DiagonalMatrix& other) : m_diagonal(other.diagonal()) {} + #endif + + /** generic constructor from expression of the diagonal coefficients */ + template + EIGEN_DEVICE_FUNC + explicit inline DiagonalMatrix(const MatrixBase& other) : m_diagonal(other) + {} + + /** Copy operator. */ + template + EIGEN_DEVICE_FUNC + DiagonalMatrix& operator=(const DiagonalBase& other) + { + m_diagonal = other.diagonal(); + return *this; + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + EIGEN_DEVICE_FUNC + DiagonalMatrix& operator=(const DiagonalMatrix& other) + { + m_diagonal = other.diagonal(); + return *this; + } + #endif + + /** Resizes to given size. */ + EIGEN_DEVICE_FUNC + inline void resize(Index size) { m_diagonal.resize(size); } + /** Sets all coefficients to zero. */ + EIGEN_DEVICE_FUNC + inline void setZero() { m_diagonal.setZero(); } + /** Resizes and sets all coefficients to zero. */ + EIGEN_DEVICE_FUNC + inline void setZero(Index size) { m_diagonal.setZero(size); } + /** Sets this matrix to be the identity matrix of the current size. */ + EIGEN_DEVICE_FUNC + inline void setIdentity() { m_diagonal.setOnes(); } + /** Sets this matrix to be the identity matrix of the given size. */ + EIGEN_DEVICE_FUNC + inline void setIdentity(Index size) { m_diagonal.setOnes(size); } +}; + +/** \class DiagonalWrapper + * \ingroup Core_Module + * + * \brief Expression of a diagonal matrix + * + * \param _DiagonalVectorType the type of the vector of diagonal coefficients + * + * This class is an expression of a diagonal matrix, but not storing its own vector of diagonal coefficients, + * instead wrapping an existing vector expression. It is the return type of MatrixBase::asDiagonal() + * and most of the time this is the only way that it is used. + * + * \sa class DiagonalMatrix, class DiagonalBase, MatrixBase::asDiagonal() + */ + +namespace internal { +template +struct traits > +{ + typedef _DiagonalVectorType DiagonalVectorType; + typedef typename DiagonalVectorType::Scalar Scalar; + typedef typename DiagonalVectorType::StorageIndex StorageIndex; + typedef DiagonalShape StorageKind; + typedef typename traits::XprKind XprKind; + enum { + RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, + MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + Flags = (traits::Flags & LvalueBit) | NoPreferredStorageOrderBit + }; +}; +} + +template +class DiagonalWrapper + : public DiagonalBase >, internal::no_assignment_operator +{ + public: + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef _DiagonalVectorType DiagonalVectorType; + typedef DiagonalWrapper Nested; + #endif + + /** Constructor from expression of diagonal coefficients to wrap. */ + EIGEN_DEVICE_FUNC + explicit inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} + + /** \returns a const reference to the wrapped expression of diagonal coefficients. */ + EIGEN_DEVICE_FUNC + const DiagonalVectorType& diagonal() const { return m_diagonal; } + + protected: + typename DiagonalVectorType::Nested m_diagonal; +}; + +/** \returns a pseudo-expression of a diagonal matrix with *this as vector of diagonal coefficients + * + * \only_for_vectors + * + * Example: \include MatrixBase_asDiagonal.cpp + * Output: \verbinclude MatrixBase_asDiagonal.out + * + * \sa class DiagonalWrapper, class DiagonalMatrix, diagonal(), isDiagonal() + **/ +template +EIGEN_DEVICE_FUNC inline const DiagonalWrapper +MatrixBase::asDiagonal() const +{ + return DiagonalWrapper(derived()); +} + +/** \returns true if *this is approximately equal to a diagonal matrix, + * within the precision given by \a prec. + * + * Example: \include MatrixBase_isDiagonal.cpp + * Output: \verbinclude MatrixBase_isDiagonal.out + * + * \sa asDiagonal() + */ +template +bool MatrixBase::isDiagonal(const RealScalar& prec) const +{ + if(cols() != rows()) return false; + RealScalar maxAbsOnDiagonal = static_cast(-1); + for(Index j = 0; j < cols(); ++j) + { + RealScalar absOnDiagonal = numext::abs(coeff(j,j)); + if(absOnDiagonal > maxAbsOnDiagonal) maxAbsOnDiagonal = absOnDiagonal; + } + for(Index j = 0; j < cols(); ++j) + for(Index i = 0; i < j; ++i) + { + if(!internal::isMuchSmallerThan(coeff(i, j), maxAbsOnDiagonal, prec)) return false; + if(!internal::isMuchSmallerThan(coeff(j, i), maxAbsOnDiagonal, prec)) return false; + } + return true; +} + +namespace internal { + +template<> struct storage_kind_to_shape { typedef DiagonalShape Shape; }; + +struct Diagonal2Dense {}; + +template<> struct AssignmentKind { typedef Diagonal2Dense Kind; }; + +// Diagonal matrix to Dense assignment +template< typename DstXprType, typename SrcXprType, typename Functor> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + dst.setZero(); + dst.diagonal() = src.diagonal(); + } + + static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &/*func*/) + { dst.diagonal() += src.diagonal(); } + + static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &/*func*/) + { dst.diagonal() -= src.diagonal(); } +}; + +} // namespace internal + +} // end namespace Eigen + +#endif // EIGEN_DIAGONALMATRIX_H diff --git a/Vendor/eigen/Eigen/src/Core/DiagonalProduct.h b/Vendor/eigen/Eigen/src/Core/DiagonalProduct.h new file mode 100644 index 0000000..7911d1c --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/DiagonalProduct.h @@ -0,0 +1,28 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2007-2009 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DIAGONALPRODUCT_H +#define EIGEN_DIAGONALPRODUCT_H + +namespace Eigen { + +/** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. + */ +template +template +EIGEN_DEVICE_FUNC inline const Product +MatrixBase::operator*(const DiagonalBase &a_diagonal) const +{ + return Product(derived(),a_diagonal.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_DIAGONALPRODUCT_H diff --git a/Vendor/eigen/Eigen/src/Core/Dot.h b/Vendor/eigen/Eigen/src/Core/Dot.h new file mode 100644 index 0000000..5c3441b --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Dot.h @@ -0,0 +1,318 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008, 2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DOT_H +#define EIGEN_DOT_H + +namespace Eigen { + +namespace internal { + +// helper function for dot(). The problem is that if we put that in the body of dot(), then upon calling dot +// with mismatched types, the compiler emits errors about failing to instantiate cwiseProduct BEFORE +// looking at the static assertions. Thus this is a trick to get better compile errors. +template +struct dot_nocheck +{ + typedef scalar_conj_product_op::Scalar,typename traits::Scalar> conj_prod; + typedef typename conj_prod::result_type ResScalar; + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE + static ResScalar run(const MatrixBase& a, const MatrixBase& b) + { + return a.template binaryExpr(b).sum(); + } +}; + +template +struct dot_nocheck +{ + typedef scalar_conj_product_op::Scalar,typename traits::Scalar> conj_prod; + typedef typename conj_prod::result_type ResScalar; + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE + static ResScalar run(const MatrixBase& a, const MatrixBase& b) + { + return a.transpose().template binaryExpr(b).sum(); + } +}; + +} // end namespace internal + +/** \fn MatrixBase::dot + * \returns the dot product of *this with other. + * + * \only_for_vectors + * + * \note If the scalar type is complex numbers, then this function returns the hermitian + * (sesquilinear) dot product, conjugate-linear in the first variable and linear in the + * second variable. + * + * \sa squaredNorm(), norm() + */ +template +template +EIGEN_DEVICE_FUNC +EIGEN_STRONG_INLINE +typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType +MatrixBase::dot(const MatrixBase& other) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) + EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) +#if !(defined(EIGEN_NO_STATIC_ASSERT) && defined(EIGEN_NO_DEBUG)) + typedef internal::scalar_conj_product_op func; + EIGEN_CHECK_BINARY_COMPATIBILIY(func,Scalar,typename OtherDerived::Scalar); +#endif + + eigen_assert(size() == other.size()); + + return internal::dot_nocheck::run(*this, other); +} + +//---------- implementation of L2 norm and related functions ---------- + +/** \returns, for vectors, the squared \em l2 norm of \c *this, and for matrices the squared Frobenius norm. + * In both cases, it consists in the sum of the square of all the matrix entries. + * For vectors, this is also equals to the dot product of \c *this with itself. + * + * \sa dot(), norm(), lpNorm() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::squaredNorm() const +{ + return numext::real((*this).cwiseAbs2().sum()); +} + +/** \returns, for vectors, the \em l2 norm of \c *this, and for matrices the Frobenius norm. + * In both cases, it consists in the square root of the sum of the square of all the matrix entries. + * For vectors, this is also equals to the square root of the dot product of \c *this with itself. + * + * \sa lpNorm(), dot(), squaredNorm() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::norm() const +{ + return numext::sqrt(squaredNorm()); +} + +/** \returns an expression of the quotient of \c *this by its own norm. + * + * \warning If the input vector is too small (i.e., this->norm()==0), + * then this function returns a copy of the input. + * + * \only_for_vectors + * + * \sa norm(), normalize() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::PlainObject +MatrixBase::normalized() const +{ + typedef typename internal::nested_eval::type _Nested; + _Nested n(derived()); + RealScalar z = n.squaredNorm(); + // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU + if(z>RealScalar(0)) + return n / numext::sqrt(z); + else + return n; +} + +/** Normalizes the vector, i.e. divides it by its own norm. + * + * \only_for_vectors + * + * \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged. + * + * \sa norm(), normalized() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void MatrixBase::normalize() +{ + RealScalar z = squaredNorm(); + // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU + if(z>RealScalar(0)) + derived() /= numext::sqrt(z); +} + +/** \returns an expression of the quotient of \c *this by its own norm while avoiding underflow and overflow. + * + * \only_for_vectors + * + * This method is analogue to the normalized() method, but it reduces the risk of + * underflow and overflow when computing the norm. + * + * \warning If the input vector is too small (i.e., this->norm()==0), + * then this function returns a copy of the input. + * + * \sa stableNorm(), stableNormalize(), normalized() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename MatrixBase::PlainObject +MatrixBase::stableNormalized() const +{ + typedef typename internal::nested_eval::type _Nested; + _Nested n(derived()); + RealScalar w = n.cwiseAbs().maxCoeff(); + RealScalar z = (n/w).squaredNorm(); + if(z>RealScalar(0)) + return n / (numext::sqrt(z)*w); + else + return n; +} + +/** Normalizes the vector while avoid underflow and overflow + * + * \only_for_vectors + * + * This method is analogue to the normalize() method, but it reduces the risk of + * underflow and overflow when computing the norm. + * + * \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged. + * + * \sa stableNorm(), stableNormalized(), normalize() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void MatrixBase::stableNormalize() +{ + RealScalar w = cwiseAbs().maxCoeff(); + RealScalar z = (derived()/w).squaredNorm(); + if(z>RealScalar(0)) + derived() /= numext::sqrt(z)*w; +} + +//---------- implementation of other norms ---------- + +namespace internal { + +template +struct lpNorm_selector +{ + typedef typename NumTraits::Scalar>::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const MatrixBase& m) + { + EIGEN_USING_STD(pow) + return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p); + } +}; + +template +struct lpNorm_selector +{ + EIGEN_DEVICE_FUNC + static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) + { + return m.cwiseAbs().sum(); + } +}; + +template +struct lpNorm_selector +{ + EIGEN_DEVICE_FUNC + static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) + { + return m.norm(); + } +}; + +template +struct lpNorm_selector +{ + typedef typename NumTraits::Scalar>::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const MatrixBase& m) + { + if(Derived::SizeAtCompileTime==0 || (Derived::SizeAtCompileTime==Dynamic && m.size()==0)) + return RealScalar(0); + return m.cwiseAbs().maxCoeff(); + } +}; + +} // end namespace internal + +/** \returns the \b coefficient-wise \f$ \ell^p \f$ norm of \c *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values + * of the coefficients of \c *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ + * norm, that is the maximum of the absolute values of the coefficients of \c *this. + * + * In all cases, if \c *this is empty, then the value 0 is returned. + * + * \note For matrices, this function does not compute the operator-norm. That is, if \c *this is a matrix, then its coefficients are interpreted as a 1D vector. Nonetheless, you can easily compute the 1-norm and \f$\infty\f$-norm matrix operator norms using \link TutorialReductionsVisitorsBroadcastingReductionsNorm partial reductions \endlink. + * + * \sa norm() + */ +template +template +#ifndef EIGEN_PARSED_BY_DOXYGEN +EIGEN_DEVICE_FUNC inline typename NumTraits::Scalar>::Real +#else +EIGEN_DEVICE_FUNC MatrixBase::RealScalar +#endif +MatrixBase::lpNorm() const +{ + return internal::lpNorm_selector::run(*this); +} + +//---------- implementation of isOrthogonal / isUnitary ---------- + +/** \returns true if *this is approximately orthogonal to \a other, + * within the precision given by \a prec. + * + * Example: \include MatrixBase_isOrthogonal.cpp + * Output: \verbinclude MatrixBase_isOrthogonal.out + */ +template +template +bool MatrixBase::isOrthogonal +(const MatrixBase& other, const RealScalar& prec) const +{ + typename internal::nested_eval::type nested(derived()); + typename internal::nested_eval::type otherNested(other.derived()); + return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm(); +} + +/** \returns true if *this is approximately an unitary matrix, + * within the precision given by \a prec. In the case where the \a Scalar + * type is real numbers, a unitary matrix is an orthogonal matrix, whence the name. + * + * \note This can be used to check whether a family of vectors forms an orthonormal basis. + * Indeed, \c m.isUnitary() returns true if and only if the columns (equivalently, the rows) of m form an + * orthonormal basis. + * + * Example: \include MatrixBase_isUnitary.cpp + * Output: \verbinclude MatrixBase_isUnitary.out + */ +template +bool MatrixBase::isUnitary(const RealScalar& prec) const +{ + typename internal::nested_eval::type self(derived()); + for(Index i = 0; i < cols(); ++i) + { + if(!internal::isApprox(self.col(i).squaredNorm(), static_cast(1), prec)) + return false; + for(Index j = 0; j < i; ++j) + if(!internal::isMuchSmallerThan(self.col(i).dot(self.col(j)), static_cast(1), prec)) + return false; + } + return true; +} + +} // end namespace Eigen + +#endif // EIGEN_DOT_H diff --git a/Vendor/eigen/Eigen/src/Core/EigenBase.h b/Vendor/eigen/Eigen/src/Core/EigenBase.h new file mode 100644 index 0000000..6b3c7d3 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/EigenBase.h @@ -0,0 +1,160 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Benoit Jacob +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_EIGENBASE_H +#define EIGEN_EIGENBASE_H + +namespace Eigen { + +/** \class EigenBase + * \ingroup Core_Module + * + * Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). + * + * In other words, an EigenBase object is an object that can be copied into a MatrixBase. + * + * Besides MatrixBase-derived classes, this also includes special matrix classes such as diagonal matrices, etc. + * + * Notice that this class is trivial, it is only used to disambiguate overloaded functions. + * + * \sa \blank \ref TopicClassHierarchy + */ +template struct EigenBase +{ +// typedef typename internal::plain_matrix_type::type PlainObject; + + /** \brief The interface type of indices + * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. + * \sa StorageIndex, \ref TopicPreprocessorDirectives. + * DEPRECATED: Since Eigen 3.3, its usage is deprecated. Use Eigen::Index instead. + * Deprecation is not marked with a doxygen comment because there are too many existing usages to add the deprecation attribute. + */ + typedef Eigen::Index Index; + + // FIXME is it needed? + typedef typename internal::traits::StorageKind StorageKind; + + /** \returns a reference to the derived object */ + EIGEN_DEVICE_FUNC + Derived& derived() { return *static_cast(this); } + /** \returns a const reference to the derived object */ + EIGEN_DEVICE_FUNC + const Derived& derived() const { return *static_cast(this); } + + EIGEN_DEVICE_FUNC + inline Derived& const_cast_derived() const + { return *static_cast(const_cast(this)); } + EIGEN_DEVICE_FUNC + inline const Derived& const_derived() const + { return *static_cast(this); } + + /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index rows() const EIGEN_NOEXCEPT { return derived().rows(); } + /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index cols() const EIGEN_NOEXCEPT { return derived().cols(); } + /** \returns the number of coefficients, which is rows()*cols(). + * \sa rows(), cols(), SizeAtCompileTime. */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index size() const EIGEN_NOEXCEPT { return rows() * cols(); } + + /** \internal Don't use it, but do the equivalent: \code dst = *this; \endcode */ + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& dst) const + { derived().evalTo(dst); } + + /** \internal Don't use it, but do the equivalent: \code dst += *this; \endcode */ + template + EIGEN_DEVICE_FUNC + inline void addTo(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + typename Dest::PlainObject res(rows(),cols()); + evalTo(res); + dst += res; + } + + /** \internal Don't use it, but do the equivalent: \code dst -= *this; \endcode */ + template + EIGEN_DEVICE_FUNC + inline void subTo(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + typename Dest::PlainObject res(rows(),cols()); + evalTo(res); + dst -= res; + } + + /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheRight(*this); \endcode */ + template + EIGEN_DEVICE_FUNC inline void applyThisOnTheRight(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + dst = dst * this->derived(); + } + + /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheLeft(*this); \endcode */ + template + EIGEN_DEVICE_FUNC inline void applyThisOnTheLeft(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + dst = this->derived() * dst; + } + +}; + +/*************************************************************************** +* Implementation of matrix base methods +***************************************************************************/ + +/** \brief Copies the generic expression \a other into *this. + * + * \details The expression must provide a (templated) evalTo(Derived& dst) const + * function which does the actual job. In practice, this allows any user to write + * its own special matrix without having to modify MatrixBase + * + * \returns a reference to *this. + */ +template +template +EIGEN_DEVICE_FUNC +Derived& DenseBase::operator=(const EigenBase &other) +{ + call_assignment(derived(), other.derived()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +Derived& DenseBase::operator+=(const EigenBase &other) +{ + call_assignment(derived(), other.derived(), internal::add_assign_op()); + return derived(); +} + +template +template +EIGEN_DEVICE_FUNC +Derived& DenseBase::operator-=(const EigenBase &other) +{ + call_assignment(derived(), other.derived(), internal::sub_assign_op()); + return derived(); +} + +} // end namespace Eigen + +#endif // EIGEN_EIGENBASE_H diff --git a/Vendor/eigen/Eigen/src/Core/ForceAlignedAccess.h b/Vendor/eigen/Eigen/src/Core/ForceAlignedAccess.h new file mode 100644 index 0000000..817a43a --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/ForceAlignedAccess.h @@ -0,0 +1,150 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_FORCEALIGNEDACCESS_H +#define EIGEN_FORCEALIGNEDACCESS_H + +namespace Eigen { + +/** \class ForceAlignedAccess + * \ingroup Core_Module + * + * \brief Enforce aligned packet loads and stores regardless of what is requested + * + * \param ExpressionType the type of the object of which we are forcing aligned packet access + * + * This class is the return type of MatrixBase::forceAlignedAccess() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::forceAlignedAccess() + */ + +namespace internal { +template +struct traits > : public traits +{}; +} + +template class ForceAlignedAccess + : public internal::dense_xpr_base< ForceAlignedAccess >::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) + + EIGEN_DEVICE_FUNC explicit inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index rows() const EIGEN_NOEXCEPT { return m_expression.rows(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index cols() const EIGEN_NOEXCEPT { return m_expression.cols(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index outerStride() const EIGEN_NOEXCEPT { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index innerStride() const EIGEN_NOEXCEPT { return m_expression.innerStride(); } + + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const + { + return m_expression.coeff(row, col); + } + + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) + { + return m_expression.const_cast_derived().coeffRef(row, col); + } + + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const + { + return m_expression.coeff(index); + } + + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) + { + return m_expression.const_cast_derived().coeffRef(index); + } + + template + inline const PacketScalar packet(Index row, Index col) const + { + return m_expression.template packet(row, col); + } + + template + inline void writePacket(Index row, Index col, const PacketScalar& x) + { + m_expression.const_cast_derived().template writePacket(row, col, x); + } + + template + inline const PacketScalar packet(Index index) const + { + return m_expression.template packet(index); + } + + template + inline void writePacket(Index index, const PacketScalar& x) + { + m_expression.const_cast_derived().template writePacket(index, x); + } + + EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } + + protected: + const ExpressionType& m_expression; + + private: + ForceAlignedAccess& operator=(const ForceAlignedAccess&); +}; + +/** \returns an expression of *this with forced aligned access + * \sa forceAlignedAccessIf(),class ForceAlignedAccess + */ +template +inline const ForceAlignedAccess +MatrixBase::forceAlignedAccess() const +{ + return ForceAlignedAccess(derived()); +} + +/** \returns an expression of *this with forced aligned access + * \sa forceAlignedAccessIf(), class ForceAlignedAccess + */ +template +inline ForceAlignedAccess +MatrixBase::forceAlignedAccess() +{ + return ForceAlignedAccess(derived()); +} + +/** \returns an expression of *this with forced aligned access if \a Enable is true. + * \sa forceAlignedAccess(), class ForceAlignedAccess + */ +template +template +inline typename internal::add_const_on_value_type,Derived&>::type>::type +MatrixBase::forceAlignedAccessIf() const +{ + return derived(); // FIXME This should not work but apparently is never used +} + +/** \returns an expression of *this with forced aligned access if \a Enable is true. + * \sa forceAlignedAccess(), class ForceAlignedAccess + */ +template +template +inline typename internal::conditional,Derived&>::type +MatrixBase::forceAlignedAccessIf() +{ + return derived(); // FIXME This should not work but apparently is never used +} + +} // end namespace Eigen + +#endif // EIGEN_FORCEALIGNEDACCESS_H diff --git a/Vendor/eigen/Eigen/src/Core/Fuzzy.h b/Vendor/eigen/Eigen/src/Core/Fuzzy.h new file mode 100644 index 0000000..43aa49b --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Fuzzy.h @@ -0,0 +1,155 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_FUZZY_H +#define EIGEN_FUZZY_H + +namespace Eigen { + +namespace internal +{ + +template::IsInteger> +struct isApprox_selector +{ + EIGEN_DEVICE_FUNC + static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) + { + typename internal::nested_eval::type nested(x); + typename internal::nested_eval::type otherNested(y); + return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * numext::mini(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); + } +}; + +template +struct isApprox_selector +{ + EIGEN_DEVICE_FUNC + static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar&) + { + return x.matrix() == y.matrix(); + } +}; + +template::IsInteger> +struct isMuchSmallerThan_object_selector +{ + EIGEN_DEVICE_FUNC + static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) + { + return x.cwiseAbs2().sum() <= numext::abs2(prec) * y.cwiseAbs2().sum(); + } +}; + +template +struct isMuchSmallerThan_object_selector +{ + EIGEN_DEVICE_FUNC + static bool run(const Derived& x, const OtherDerived&, const typename Derived::RealScalar&) + { + return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); + } +}; + +template::IsInteger> +struct isMuchSmallerThan_scalar_selector +{ + EIGEN_DEVICE_FUNC + static bool run(const Derived& x, const typename Derived::RealScalar& y, const typename Derived::RealScalar& prec) + { + return x.cwiseAbs2().sum() <= numext::abs2(prec * y); + } +}; + +template +struct isMuchSmallerThan_scalar_selector +{ + EIGEN_DEVICE_FUNC + static bool run(const Derived& x, const typename Derived::RealScalar&, const typename Derived::RealScalar&) + { + return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); + } +}; + +} // end namespace internal + + +/** \returns \c true if \c *this is approximately equal to \a other, within the precision + * determined by \a prec. + * + * \note The fuzzy compares are done multiplicatively. Two vectors \f$ v \f$ and \f$ w \f$ + * are considered to be approximately equal within precision \f$ p \f$ if + * \f[ \Vert v - w \Vert \leqslant p\,\min(\Vert v\Vert, \Vert w\Vert). \f] + * For matrices, the comparison is done using the Hilbert-Schmidt norm (aka Frobenius norm + * L2 norm). + * + * \note Because of the multiplicativeness of this comparison, one can't use this function + * to check whether \c *this is approximately equal to the zero matrix or vector. + * Indeed, \c isApprox(zero) returns false unless \c *this itself is exactly the zero matrix + * or vector. If you want to test whether \c *this is zero, use internal::isMuchSmallerThan(const + * RealScalar&, RealScalar) instead. + * + * \sa internal::isMuchSmallerThan(const RealScalar&, RealScalar) const + */ +template +template +EIGEN_DEVICE_FUNC bool DenseBase::isApprox( + const DenseBase& other, + const RealScalar& prec +) const +{ + return internal::isApprox_selector::run(derived(), other.derived(), prec); +} + +/** \returns \c true if the norm of \c *this is much smaller than \a other, + * within the precision determined by \a prec. + * + * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is + * considered to be much smaller than \f$ x \f$ within precision \f$ p \f$ if + * \f[ \Vert v \Vert \leqslant p\,\vert x\vert. \f] + * + * For matrices, the comparison is done using the Hilbert-Schmidt norm. For this reason, + * the value of the reference scalar \a other should come from the Hilbert-Schmidt norm + * of a reference matrix of same dimensions. + * + * \sa isApprox(), isMuchSmallerThan(const DenseBase&, RealScalar) const + */ +template +EIGEN_DEVICE_FUNC bool DenseBase::isMuchSmallerThan( + const typename NumTraits::Real& other, + const RealScalar& prec +) const +{ + return internal::isMuchSmallerThan_scalar_selector::run(derived(), other, prec); +} + +/** \returns \c true if the norm of \c *this is much smaller than the norm of \a other, + * within the precision determined by \a prec. + * + * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is + * considered to be much smaller than a vector \f$ w \f$ within precision \f$ p \f$ if + * \f[ \Vert v \Vert \leqslant p\,\Vert w\Vert. \f] + * For matrices, the comparison is done using the Hilbert-Schmidt norm. + * + * \sa isApprox(), isMuchSmallerThan(const RealScalar&, RealScalar) const + */ +template +template +EIGEN_DEVICE_FUNC bool DenseBase::isMuchSmallerThan( + const DenseBase& other, + const RealScalar& prec +) const +{ + return internal::isMuchSmallerThan_object_selector::run(derived(), other.derived(), prec); +} + +} // end namespace Eigen + +#endif // EIGEN_FUZZY_H diff --git a/Vendor/eigen/Eigen/src/Core/GeneralProduct.h b/Vendor/eigen/Eigen/src/Core/GeneralProduct.h new file mode 100644 index 0000000..6906aa7 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/GeneralProduct.h @@ -0,0 +1,465 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_GENERAL_PRODUCT_H +#define EIGEN_GENERAL_PRODUCT_H + +namespace Eigen { + +enum { + Large = 2, + Small = 3 +}; + +// Define the threshold value to fallback from the generic matrix-matrix product +// implementation (heavy) to the lightweight coeff-based product one. +// See generic_product_impl +// in products/GeneralMatrixMatrix.h for more details. +// TODO This threshold should also be used in the compile-time selector below. +#ifndef EIGEN_GEMM_TO_COEFFBASED_THRESHOLD +// This default value has been obtained on a Haswell architecture. +#define EIGEN_GEMM_TO_COEFFBASED_THRESHOLD 20 +#endif + +namespace internal { + +template struct product_type_selector; + +template struct product_size_category +{ + enum { + #ifndef EIGEN_GPU_COMPILE_PHASE + is_large = MaxSize == Dynamic || + Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD || + (Size==Dynamic && MaxSize>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD), + #else + is_large = 0, + #endif + value = is_large ? Large + : Size == 1 ? 1 + : Small + }; +}; + +template struct product_type +{ + typedef typename remove_all::type _Lhs; + typedef typename remove_all::type _Rhs; + enum { + MaxRows = traits<_Lhs>::MaxRowsAtCompileTime, + Rows = traits<_Lhs>::RowsAtCompileTime, + MaxCols = traits<_Rhs>::MaxColsAtCompileTime, + Cols = traits<_Rhs>::ColsAtCompileTime, + MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::MaxColsAtCompileTime, + traits<_Rhs>::MaxRowsAtCompileTime), + Depth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::ColsAtCompileTime, + traits<_Rhs>::RowsAtCompileTime) + }; + + // the splitting into different lines of code here, introducing the _select enums and the typedef below, + // is to work around an internal compiler error with gcc 4.1 and 4.2. +private: + enum { + rows_select = product_size_category::value, + cols_select = product_size_category::value, + depth_select = product_size_category::value + }; + typedef product_type_selector selector; + +public: + enum { + value = selector::ret, + ret = selector::ret + }; +#ifdef EIGEN_DEBUG_PRODUCT + static void debug() + { + EIGEN_DEBUG_VAR(Rows); + EIGEN_DEBUG_VAR(Cols); + EIGEN_DEBUG_VAR(Depth); + EIGEN_DEBUG_VAR(rows_select); + EIGEN_DEBUG_VAR(cols_select); + EIGEN_DEBUG_VAR(depth_select); + EIGEN_DEBUG_VAR(value); + } +#endif +}; + +/* The following allows to select the kind of product at compile time + * based on the three dimensions of the product. + * This is a compile time mapping from {1,Small,Large}^3 -> {product types} */ +// FIXME I'm not sure the current mapping is the ideal one. +template struct product_type_selector { enum { ret = OuterProduct }; }; +template struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template struct product_type_selector<1, N, 1> { enum { ret = LazyCoeffBasedProductMode }; }; +template struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; +template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template<> struct product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; +template<> struct product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = GemvProduct }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = GemmProduct }; }; + +} // end namespace internal + +/*********************************************************************** +* Implementation of Inner Vector Vector Product +***********************************************************************/ + +// FIXME : maybe the "inner product" could return a Scalar +// instead of a 1x1 matrix ?? +// Pro: more natural for the user +// Cons: this could be a problem if in a meta unrolled algorithm a matrix-matrix +// product ends up to a row-vector times col-vector product... To tackle this use +// case, we could have a specialization for Block with: operator=(Scalar x); + +/*********************************************************************** +* Implementation of Outer Vector Vector Product +***********************************************************************/ + +/*********************************************************************** +* Implementation of General Matrix Vector Product +***********************************************************************/ + +/* According to the shape/flags of the matrix we have to distinghish 3 different cases: + * 1 - the matrix is col-major, BLAS compatible and M is large => call fast BLAS-like colmajor routine + * 2 - the matrix is row-major, BLAS compatible and N is large => call fast BLAS-like rowmajor routine + * 3 - all other cases are handled using a simple loop along the outer-storage direction. + * Therefore we need a lower level meta selector. + * Furthermore, if the matrix is the rhs, then the product has to be transposed. + */ +namespace internal { + +template +struct gemv_dense_selector; + +} // end namespace internal + +namespace internal { + +template struct gemv_static_vector_if; + +template +struct gemv_static_vector_if +{ + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Scalar* data() { eigen_internal_assert(false && "should never be called"); return 0; } +}; + +template +struct gemv_static_vector_if +{ + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Scalar* data() { return 0; } +}; + +template +struct gemv_static_vector_if +{ + enum { + ForceAlignment = internal::packet_traits::Vectorizable, + PacketSize = internal::packet_traits::size + }; + #if EIGEN_MAX_STATIC_ALIGN_BYTES!=0 + internal::plain_array m_data; + EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; } + #else + // Some architectures cannot align on the stack, + // => let's manually enforce alignment by allocating more data and return the address of the first aligned element. + internal::plain_array m_data; + EIGEN_STRONG_INLINE Scalar* data() { + return ForceAlignment + ? reinterpret_cast((internal::UIntPtr(m_data.array) & ~(std::size_t(EIGEN_MAX_ALIGN_BYTES-1))) + EIGEN_MAX_ALIGN_BYTES) + : m_data.array; + } + #endif +}; + +// The vector is on the left => transposition +template +struct gemv_dense_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + Transpose destT(dest); + enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; + gemv_dense_selector + ::run(rhs.transpose(), lhs.transpose(), destT, alpha); + } +}; + +template<> struct gemv_dense_selector +{ + template + static inline void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + typedef typename Dest::RealScalar RealScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + + typedef Map, EIGEN_PLAIN_ENUM_MIN(AlignedMax,internal::packet_traits::size)> MappedDest; + + ActualLhsType actualLhs = LhsBlasTraits::extract(lhs); + ActualRhsType actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = combine_scalar_factors(alpha, lhs, rhs); + + // make sure Dest is a compile-time vector type (bug 1166) + typedef typename conditional::type ActualDest; + + enum { + // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 + // on, the other hand it is good for the cache to pack the vector anyways... + EvalToDestAtCompileTime = (ActualDest::InnerStrideAtCompileTime==1), + ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), + MightCannotUseDest = ((!EvalToDestAtCompileTime) || ComplexByReal) && (ActualDest::MaxSizeAtCompileTime!=0) + }; + + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + RhsScalar compatibleAlpha = get_factor::run(actualAlpha); + + if(!MightCannotUseDest) + { + // shortcut if we are sure to be able to use dest directly, + // this ease the compiler to generate cleaner and more optimzized code for most common cases + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhs.data(), actualRhs.innerStride()), + dest.data(), 1, + compatibleAlpha); + } + else + { + gemv_static_vector_if static_dest; + + const bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); + const bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; + + ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), + evalToDest ? dest.data() : static_dest.data()); + + if(!evalToDest) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + Index size = dest.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + if(!alphaIsCompatible) + { + MappedDest(actualDestPtr, dest.size()).setZero(); + compatibleAlpha = RhsScalar(1); + } + else + MappedDest(actualDestPtr, dest.size()) = dest; + } + + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhs.data(), actualRhs.innerStride()), + actualDestPtr, 1, + compatibleAlpha); + + if (!evalToDest) + { + if(!alphaIsCompatible) + dest.matrix() += actualAlpha * MappedDest(actualDestPtr, dest.size()); + else + dest = MappedDest(actualDestPtr, dest.size()); + } + } + } +}; + +template<> struct gemv_dense_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + typename add_const::type actualLhs = LhsBlasTraits::extract(lhs); + typename add_const::type actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = combine_scalar_factors(alpha, lhs, rhs); + + enum { + // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 + // on, the other hand it is good for the cache to pack the vector anyways... + DirectlyUseRhs = ActualRhsTypeCleaned::InnerStrideAtCompileTime==1 || ActualRhsTypeCleaned::MaxSizeAtCompileTime==0 + }; + + gemv_static_vector_if static_rhs; + + ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), + DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); + + if(!DirectlyUseRhs) + { + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + Index size = actualRhs.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + Map(actualRhsPtr, actualRhs.size()) = actualRhs; + } + + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhsPtr, 1), + dest.data(), dest.col(0).innerStride(), //NOTE if dest is not a vector at compile-time, then dest.innerStride() might be wrong. (bug 1166) + actualAlpha); + } +}; + +template<> struct gemv_dense_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + EIGEN_STATIC_ASSERT((!nested_eval::Evaluate),EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE); + // TODO if rhs is large enough it might be beneficial to make sure that dest is sequentially stored in memory, otherwise use a temp + typename nested_eval::type actual_rhs(rhs); + const Index size = rhs.rows(); + for(Index k=0; k struct gemv_dense_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + EIGEN_STATIC_ASSERT((!nested_eval::Evaluate),EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE); + typename nested_eval::type actual_rhs(rhs); + const Index rows = dest.rows(); + for(Index i=0; i +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +const Product +MatrixBase::operator*(const MatrixBase &other) const +{ + // A note regarding the function declaration: In MSVC, this function will sometimes + // not be inlined since DenseStorage is an unwindable object for dynamic + // matrices and product types are holding a member to store the result. + // Thus it does not help tagging this function with EIGEN_STRONG_INLINE. + enum { + ProductIsValid = Derived::ColsAtCompileTime==Dynamic + || OtherDerived::RowsAtCompileTime==Dynamic + || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), + AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, + SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) + }; + // note to the lost user: + // * for a dot product use: v1.dot(v2) + // * for a coeff-wise product use: v1.cwiseProduct(v2) + EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), + INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) + EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), + INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) + EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) +#ifdef EIGEN_DEBUG_PRODUCT + internal::product_type::debug(); +#endif + + return Product(derived(), other.derived()); +} + +/** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. + * + * The returned product will behave like any other expressions: the coefficients of the product will be + * computed once at a time as requested. This might be useful in some extremely rare cases when only + * a small and no coherent fraction of the result's coefficients have to be computed. + * + * \warning This version of the matrix product can be much much slower. So use it only if you know + * what you are doing and that you measured a true speed improvement. + * + * \sa operator*(const MatrixBase&) + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +const Product +MatrixBase::lazyProduct(const MatrixBase &other) const +{ + enum { + ProductIsValid = Derived::ColsAtCompileTime==Dynamic + || OtherDerived::RowsAtCompileTime==Dynamic + || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), + AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, + SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) + }; + // note to the lost user: + // * for a dot product use: v1.dot(v2) + // * for a coeff-wise product use: v1.cwiseProduct(v2) + EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), + INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) + EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), + INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) + EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) + + return Product(derived(), other.derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_H diff --git a/Vendor/eigen/Eigen/src/Core/GenericPacketMath.h b/Vendor/eigen/Eigen/src/Core/GenericPacketMath.h new file mode 100644 index 0000000..cf677a1 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/GenericPacketMath.h @@ -0,0 +1,1040 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_GENERIC_PACKET_MATH_H +#define EIGEN_GENERIC_PACKET_MATH_H + +namespace Eigen { + +namespace internal { + +/** \internal + * \file GenericPacketMath.h + * + * Default implementation for types not supported by the vectorization. + * In practice these functions are provided to make easier the writing + * of generic vectorized code. + */ + +#ifndef EIGEN_DEBUG_ALIGNED_LOAD +#define EIGEN_DEBUG_ALIGNED_LOAD +#endif + +#ifndef EIGEN_DEBUG_UNALIGNED_LOAD +#define EIGEN_DEBUG_UNALIGNED_LOAD +#endif + +#ifndef EIGEN_DEBUG_ALIGNED_STORE +#define EIGEN_DEBUG_ALIGNED_STORE +#endif + +#ifndef EIGEN_DEBUG_UNALIGNED_STORE +#define EIGEN_DEBUG_UNALIGNED_STORE +#endif + +struct default_packet_traits +{ + enum { + HasHalfPacket = 0, + + HasAdd = 1, + HasSub = 1, + HasShift = 1, + HasMul = 1, + HasNegate = 1, + HasAbs = 1, + HasArg = 0, + HasAbs2 = 1, + HasAbsDiff = 0, + HasMin = 1, + HasMax = 1, + HasConj = 1, + HasSetLinear = 1, + HasBlend = 0, + // This flag is used to indicate whether packet comparison is supported. + // pcmp_eq, pcmp_lt and pcmp_le should be defined for it to be true. + HasCmp = 0, + + HasDiv = 0, + HasSqrt = 0, + HasRsqrt = 0, + HasExp = 0, + HasExpm1 = 0, + HasLog = 0, + HasLog1p = 0, + HasLog10 = 0, + HasPow = 0, + + HasSin = 0, + HasCos = 0, + HasTan = 0, + HasASin = 0, + HasACos = 0, + HasATan = 0, + HasSinh = 0, + HasCosh = 0, + HasTanh = 0, + HasLGamma = 0, + HasDiGamma = 0, + HasZeta = 0, + HasPolygamma = 0, + HasErf = 0, + HasErfc = 0, + HasNdtri = 0, + HasBessel = 0, + HasIGamma = 0, + HasIGammaDerA = 0, + HasGammaSampleDerAlpha = 0, + HasIGammac = 0, + HasBetaInc = 0, + + HasRound = 0, + HasRint = 0, + HasFloor = 0, + HasCeil = 0, + HasSign = 0 + }; +}; + +template struct packet_traits : default_packet_traits +{ + typedef T type; + typedef T half; + enum { + Vectorizable = 0, + size = 1, + AlignedOnScalar = 0, + HasHalfPacket = 0 + }; + enum { + HasAdd = 0, + HasSub = 0, + HasMul = 0, + HasNegate = 0, + HasAbs = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasConj = 0, + HasSetLinear = 0 + }; +}; + +template struct packet_traits : packet_traits { }; + +template struct unpacket_traits +{ + typedef T type; + typedef T half; + enum + { + size = 1, + alignment = 1, + vectorizable = false, + masked_load_available=false, + masked_store_available=false + }; +}; + +template struct unpacket_traits : unpacket_traits { }; + +template struct type_casting_traits { + enum { + VectorizedCast = 0, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + +/** \internal Wrapper to ensure that multiple packet types can map to the same + same underlying vector type. */ +template +struct eigen_packet_wrapper +{ + EIGEN_ALWAYS_INLINE operator T&() { return m_val; } + EIGEN_ALWAYS_INLINE operator const T&() const { return m_val; } + EIGEN_ALWAYS_INLINE eigen_packet_wrapper() {} + EIGEN_ALWAYS_INLINE eigen_packet_wrapper(const T &v) : m_val(v) {} + EIGEN_ALWAYS_INLINE eigen_packet_wrapper& operator=(const T &v) { + m_val = v; + return *this; + } + + T m_val; +}; + + +/** \internal A convenience utility for determining if the type is a scalar. + * This is used to enable some generic packet implementations. + */ +template +struct is_scalar { + typedef typename unpacket_traits::type Scalar; + enum { + value = internal::is_same::value + }; +}; + +/** \internal \returns static_cast(a) (coeff-wise) */ +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a) { + return static_cast(a); +} +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a, const SrcPacket& /*b*/) { + return static_cast(a); +} +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a, const SrcPacket& /*b*/, const SrcPacket& /*c*/, const SrcPacket& /*d*/) { + return static_cast(a); +} +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a, const SrcPacket& /*b*/, const SrcPacket& /*c*/, const SrcPacket& /*d*/, + const SrcPacket& /*e*/, const SrcPacket& /*f*/, const SrcPacket& /*g*/, const SrcPacket& /*h*/) { + return static_cast(a); +} + +/** \internal \returns reinterpret_cast(a) */ +template +EIGEN_DEVICE_FUNC inline Target +preinterpret(const Packet& a); /* { return reinterpret_cast(a); } */ + +/** \internal \returns a + b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +padd(const Packet& a, const Packet& b) { return a+b; } +// Avoid compiler warning for boolean algebra. +template<> EIGEN_DEVICE_FUNC inline bool +padd(const bool& a, const bool& b) { return a || b; } + +/** \internal \returns a - b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +psub(const Packet& a, const Packet& b) { return a-b; } + +/** \internal \returns -a (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pnegate(const Packet& a) { return -a; } + +template<> EIGEN_DEVICE_FUNC inline bool +pnegate(const bool& a) { return !a; } + +/** \internal \returns conj(a) (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pconj(const Packet& a) { return numext::conj(a); } + +/** \internal \returns a * b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pmul(const Packet& a, const Packet& b) { return a*b; } +// Avoid compiler warning for boolean algebra. +template<> EIGEN_DEVICE_FUNC inline bool +pmul(const bool& a, const bool& b) { return a && b; } + +/** \internal \returns a / b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pdiv(const Packet& a, const Packet& b) { return a/b; } + +// In the generic case, memset to all one bits. +template +struct ptrue_impl { + static EIGEN_DEVICE_FUNC inline Packet run(const Packet& /*a*/){ + Packet b; + memset(static_cast(&b), 0xff, sizeof(Packet)); + return b; + } +}; + +// For non-trivial scalars, set to Scalar(1) (i.e. a non-zero value). +// Although this is technically not a valid bitmask, the scalar path for pselect +// uses a comparison to zero, so this should still work in most cases. We don't +// have another option, since the scalar type requires initialization. +template +struct ptrue_impl::value && NumTraits::RequireInitialization>::type > { + static EIGEN_DEVICE_FUNC inline T run(const T& /*a*/){ + return T(1); + } +}; + +/** \internal \returns one bits. */ +template EIGEN_DEVICE_FUNC inline Packet +ptrue(const Packet& a) { + return ptrue_impl::run(a); +} + +// In the general case, memset to zero. +template +struct pzero_impl { + static EIGEN_DEVICE_FUNC inline Packet run(const Packet& /*a*/) { + Packet b; + memset(static_cast(&b), 0x00, sizeof(Packet)); + return b; + } +}; + +// For scalars, explicitly set to Scalar(0), since the underlying representation +// for zero may not consist of all-zero bits. +template +struct pzero_impl::value>::type> { + static EIGEN_DEVICE_FUNC inline T run(const T& /*a*/) { + return T(0); + } +}; + +/** \internal \returns packet of zeros */ +template EIGEN_DEVICE_FUNC inline Packet +pzero(const Packet& a) { + return pzero_impl::run(a); +} + +/** \internal \returns a <= b as a bit mask */ +template EIGEN_DEVICE_FUNC inline Packet +pcmp_le(const Packet& a, const Packet& b) { return a<=b ? ptrue(a) : pzero(a); } + +/** \internal \returns a < b as a bit mask */ +template EIGEN_DEVICE_FUNC inline Packet +pcmp_lt(const Packet& a, const Packet& b) { return a EIGEN_DEVICE_FUNC inline Packet +pcmp_eq(const Packet& a, const Packet& b) { return a==b ? ptrue(a) : pzero(a); } + +/** \internal \returns a < b or a==NaN or b==NaN as a bit mask */ +template EIGEN_DEVICE_FUNC inline Packet +pcmp_lt_or_nan(const Packet& a, const Packet& b) { return a>=b ? pzero(a) : ptrue(a); } + +template +struct bit_and { + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR EIGEN_ALWAYS_INLINE T operator()(const T& a, const T& b) const { + return a & b; + } +}; + +template +struct bit_or { + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR EIGEN_ALWAYS_INLINE T operator()(const T& a, const T& b) const { + return a | b; + } +}; + +template +struct bit_xor { + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR EIGEN_ALWAYS_INLINE T operator()(const T& a, const T& b) const { + return a ^ b; + } +}; + +template +struct bit_not { + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR EIGEN_ALWAYS_INLINE T operator()(const T& a) const { + return ~a; + } +}; + +// Use operators &, |, ^, ~. +template +struct operator_bitwise_helper { + EIGEN_DEVICE_FUNC static inline T bitwise_and(const T& a, const T& b) { return bit_and()(a, b); } + EIGEN_DEVICE_FUNC static inline T bitwise_or(const T& a, const T& b) { return bit_or()(a, b); } + EIGEN_DEVICE_FUNC static inline T bitwise_xor(const T& a, const T& b) { return bit_xor()(a, b); } + EIGEN_DEVICE_FUNC static inline T bitwise_not(const T& a) { return bit_not()(a); } +}; + +// Apply binary operations byte-by-byte +template +struct bytewise_bitwise_helper { + EIGEN_DEVICE_FUNC static inline T bitwise_and(const T& a, const T& b) { + return binary(a, b, bit_and()); + } + EIGEN_DEVICE_FUNC static inline T bitwise_or(const T& a, const T& b) { + return binary(a, b, bit_or()); + } + EIGEN_DEVICE_FUNC static inline T bitwise_xor(const T& a, const T& b) { + return binary(a, b, bit_xor()); + } + EIGEN_DEVICE_FUNC static inline T bitwise_not(const T& a) { + return unary(a,bit_not()); + } + + private: + template + EIGEN_DEVICE_FUNC static inline T unary(const T& a, Op op) { + const unsigned char* a_ptr = reinterpret_cast(&a); + T c; + unsigned char* c_ptr = reinterpret_cast(&c); + for (size_t i = 0; i < sizeof(T); ++i) { + *c_ptr++ = op(*a_ptr++); + } + return c; + } + + template + EIGEN_DEVICE_FUNC static inline T binary(const T& a, const T& b, Op op) { + const unsigned char* a_ptr = reinterpret_cast(&a); + const unsigned char* b_ptr = reinterpret_cast(&b); + T c; + unsigned char* c_ptr = reinterpret_cast(&c); + for (size_t i = 0; i < sizeof(T); ++i) { + *c_ptr++ = op(*a_ptr++, *b_ptr++); + } + return c; + } +}; + +// In the general case, use byte-by-byte manipulation. +template +struct bitwise_helper : public bytewise_bitwise_helper {}; + +// For integers or non-trivial scalars, use binary operators. +template +struct bitwise_helper::value && (NumTraits::IsInteger || NumTraits::RequireInitialization)>::type + > : public operator_bitwise_helper {}; + +/** \internal \returns the bitwise and of \a a and \a b */ +template EIGEN_DEVICE_FUNC inline Packet +pand(const Packet& a, const Packet& b) { + return bitwise_helper::bitwise_and(a, b); +} + +/** \internal \returns the bitwise or of \a a and \a b */ +template EIGEN_DEVICE_FUNC inline Packet +por(const Packet& a, const Packet& b) { + return bitwise_helper::bitwise_or(a, b); +} + +/** \internal \returns the bitwise xor of \a a and \a b */ +template EIGEN_DEVICE_FUNC inline Packet +pxor(const Packet& a, const Packet& b) { + return bitwise_helper::bitwise_xor(a, b); +} + +/** \internal \returns the bitwise not of \a a */ +template EIGEN_DEVICE_FUNC inline Packet +pnot(const Packet& a) { + return bitwise_helper::bitwise_not(a); +} + +/** \internal \returns the bitwise and of \a a and not \a b */ +template EIGEN_DEVICE_FUNC inline Packet +pandnot(const Packet& a, const Packet& b) { return pand(a, pnot(b)); } + +// In the general case, use bitwise select. +template +struct pselect_impl { + static EIGEN_DEVICE_FUNC inline Packet run(const Packet& mask, const Packet& a, const Packet& b) { + return por(pand(a,mask),pandnot(b,mask)); + } +}; + +// For scalars, use ternary select. +template +struct pselect_impl::value>::type > { + static EIGEN_DEVICE_FUNC inline Packet run(const Packet& mask, const Packet& a, const Packet& b) { + return numext::equal_strict(mask, Packet(0)) ? b : a; + } +}; + +/** \internal \returns \a or \b for each field in packet according to \mask */ +template EIGEN_DEVICE_FUNC inline Packet +pselect(const Packet& mask, const Packet& a, const Packet& b) { + return pselect_impl::run(mask, a, b); +} + +template<> EIGEN_DEVICE_FUNC inline bool pselect( + const bool& cond, const bool& a, const bool& b) { + return cond ? a : b; +} + +/** \internal \returns the min or of \a a and \a b (coeff-wise) + If either \a a or \a b are NaN, the result is implementation defined. */ +template +struct pminmax_impl { + template + static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a, const Packet& b, Op op) { + return op(a,b); + } +}; + +/** \internal \returns the min or max of \a a and \a b (coeff-wise) + If either \a a or \a b are NaN, NaN is returned. */ +template<> +struct pminmax_impl { + template + static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a, const Packet& b, Op op) { + Packet not_nan_mask_a = pcmp_eq(a, a); + Packet not_nan_mask_b = pcmp_eq(b, b); + return pselect(not_nan_mask_a, + pselect(not_nan_mask_b, op(a, b), b), + a); + } +}; + +/** \internal \returns the min or max of \a a and \a b (coeff-wise) + If both \a a and \a b are NaN, NaN is returned. + Equivalent to std::fmin(a, b). */ +template<> +struct pminmax_impl { + template + static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a, const Packet& b, Op op) { + Packet not_nan_mask_a = pcmp_eq(a, a); + Packet not_nan_mask_b = pcmp_eq(b, b); + return pselect(not_nan_mask_a, + pselect(not_nan_mask_b, op(a, b), a), + b); + } +}; + + +#ifndef SYCL_DEVICE_ONLY +#define EIGEN_BINARY_OP_NAN_PROPAGATION(Type, Func) Func +#else +#define EIGEN_BINARY_OP_NAN_PROPAGATION(Type, Func) \ +[](const Type& a, const Type& b) { \ + return Func(a, b);} +#endif + +/** \internal \returns the min of \a a and \a b (coeff-wise). + If \a a or \b b is NaN, the return value is implementation defined. */ +template EIGEN_DEVICE_FUNC inline Packet +pmin(const Packet& a, const Packet& b) { return numext::mini(a,b); } + +/** \internal \returns the min of \a a and \a b (coeff-wise). + NaNPropagation determines the NaN propagation semantics. */ +template +EIGEN_DEVICE_FUNC inline Packet pmin(const Packet& a, const Packet& b) { + return pminmax_impl::run(a, b, EIGEN_BINARY_OP_NAN_PROPAGATION(Packet, (pmin))); +} + +/** \internal \returns the max of \a a and \a b (coeff-wise) + If \a a or \b b is NaN, the return value is implementation defined. */ +template EIGEN_DEVICE_FUNC inline Packet +pmax(const Packet& a, const Packet& b) { return numext::maxi(a, b); } + +/** \internal \returns the max of \a a and \a b (coeff-wise). + NaNPropagation determines the NaN propagation semantics. */ +template +EIGEN_DEVICE_FUNC inline Packet pmax(const Packet& a, const Packet& b) { + return pminmax_impl::run(a, b, EIGEN_BINARY_OP_NAN_PROPAGATION(Packet,(pmax))); +} + +/** \internal \returns the absolute value of \a a */ +template EIGEN_DEVICE_FUNC inline Packet +pabs(const Packet& a) { return numext::abs(a); } +template<> EIGEN_DEVICE_FUNC inline unsigned int +pabs(const unsigned int& a) { return a; } +template<> EIGEN_DEVICE_FUNC inline unsigned long +pabs(const unsigned long& a) { return a; } +template<> EIGEN_DEVICE_FUNC inline unsigned long long +pabs(const unsigned long long& a) { return a; } + +/** \internal \returns the addsub value of \a a,b */ +template EIGEN_DEVICE_FUNC inline Packet +paddsub(const Packet& a, const Packet& b) { + return pselect(peven_mask(a), padd(a, b), psub(a, b)); + } + +/** \internal \returns the phase angle of \a a */ +template EIGEN_DEVICE_FUNC inline Packet +parg(const Packet& a) { using numext::arg; return arg(a); } + + +/** \internal \returns \a a logically shifted by N bits to the right */ +template EIGEN_DEVICE_FUNC inline int +parithmetic_shift_right(const int& a) { return a >> N; } +template EIGEN_DEVICE_FUNC inline long int +parithmetic_shift_right(const long int& a) { return a >> N; } + +/** \internal \returns \a a arithmetically shifted by N bits to the right */ +template EIGEN_DEVICE_FUNC inline int +plogical_shift_right(const int& a) { return static_cast(static_cast(a) >> N); } +template EIGEN_DEVICE_FUNC inline long int +plogical_shift_right(const long int& a) { return static_cast(static_cast(a) >> N); } + +/** \internal \returns \a a shifted by N bits to the left */ +template EIGEN_DEVICE_FUNC inline int +plogical_shift_left(const int& a) { return a << N; } +template EIGEN_DEVICE_FUNC inline long int +plogical_shift_left(const long int& a) { return a << N; } + +/** \internal \returns the significant and exponent of the underlying floating point numbers + * See https://en.cppreference.com/w/cpp/numeric/math/frexp + */ +template +EIGEN_DEVICE_FUNC inline Packet pfrexp(const Packet& a, Packet& exponent) { + int exp; + EIGEN_USING_STD(frexp); + Packet result = static_cast(frexp(a, &exp)); + exponent = static_cast(exp); + return result; +} + +/** \internal \returns a * 2^((int)exponent) + * See https://en.cppreference.com/w/cpp/numeric/math/ldexp + */ +template EIGEN_DEVICE_FUNC inline Packet +pldexp(const Packet &a, const Packet &exponent) { + EIGEN_USING_STD(ldexp) + return static_cast(ldexp(a, static_cast(exponent))); +} + +/** \internal \returns the min of \a a and \a b (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pabsdiff(const Packet& a, const Packet& b) { return pselect(pcmp_lt(a, b), psub(b, a), psub(a, b)); } + +/** \internal \returns a packet version of \a *from, from must be 16 bytes aligned */ +template EIGEN_DEVICE_FUNC inline Packet +pload(const typename unpacket_traits::type* from) { return *from; } + +/** \internal \returns a packet version of \a *from, (un-aligned load) */ +template EIGEN_DEVICE_FUNC inline Packet +ploadu(const typename unpacket_traits::type* from) { return *from; } + +/** \internal \returns a packet version of \a *from, (un-aligned masked load) + * There is no generic implementation. We only have implementations for specialized + * cases. Generic case should not be called. + */ +template EIGEN_DEVICE_FUNC inline +typename enable_if::masked_load_available, Packet>::type +ploadu(const typename unpacket_traits::type* from, typename unpacket_traits::mask_t umask); + +/** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ +template EIGEN_DEVICE_FUNC inline Packet +pset1(const typename unpacket_traits::type& a) { return a; } + +/** \internal \returns a packet with constant coefficients set from bits */ +template EIGEN_DEVICE_FUNC inline Packet +pset1frombits(BitsType a); + +/** \internal \returns a packet with constant coefficients \a a[0], e.g.: (a[0],a[0],a[0],a[0]) */ +template EIGEN_DEVICE_FUNC inline Packet +pload1(const typename unpacket_traits::type *a) { return pset1(*a); } + +/** \internal \returns a packet with elements of \a *from duplicated. + * For instance, for a packet of 8 elements, 4 scalars will be read from \a *from and + * duplicated to form: {from[0],from[0],from[1],from[1],from[2],from[2],from[3],from[3]} + * Currently, this function is only used for scalar * complex products. + */ +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet +ploaddup(const typename unpacket_traits::type* from) { return *from; } + +/** \internal \returns a packet with elements of \a *from quadrupled. + * For instance, for a packet of 8 elements, 2 scalars will be read from \a *from and + * replicated to form: {from[0],from[0],from[0],from[0],from[1],from[1],from[1],from[1]} + * Currently, this function is only used in matrix products. + * For packet-size smaller or equal to 4, this function is equivalent to pload1 + */ +template EIGEN_DEVICE_FUNC inline Packet +ploadquad(const typename unpacket_traits::type* from) +{ return pload1(from); } + +/** \internal equivalent to + * \code + * a0 = pload1(a+0); + * a1 = pload1(a+1); + * a2 = pload1(a+2); + * a3 = pload1(a+3); + * \endcode + * \sa pset1, pload1, ploaddup, pbroadcast2 + */ +template EIGEN_DEVICE_FUNC +inline void pbroadcast4(const typename unpacket_traits::type *a, + Packet& a0, Packet& a1, Packet& a2, Packet& a3) +{ + a0 = pload1(a+0); + a1 = pload1(a+1); + a2 = pload1(a+2); + a3 = pload1(a+3); +} + +/** \internal equivalent to + * \code + * a0 = pload1(a+0); + * a1 = pload1(a+1); + * \endcode + * \sa pset1, pload1, ploaddup, pbroadcast4 + */ +template EIGEN_DEVICE_FUNC +inline void pbroadcast2(const typename unpacket_traits::type *a, + Packet& a0, Packet& a1) +{ + a0 = pload1(a+0); + a1 = pload1(a+1); +} + +/** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */ +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet +plset(const typename unpacket_traits::type& a) { return a; } + +/** \internal \returns a packet with constant coefficients \a a, e.g.: (x, 0, x, 0), + where x is the value of all 1-bits. */ +template EIGEN_DEVICE_FUNC inline Packet +peven_mask(const Packet& /*a*/) { + typedef typename unpacket_traits::type Scalar; + const size_t n = unpacket_traits::size; + EIGEN_ALIGN_TO_BOUNDARY(sizeof(Packet)) Scalar elements[n]; + for(size_t i = 0; i < n; ++i) { + memset(elements+i, ((i & 1) == 0 ? 0xff : 0), sizeof(Scalar)); + } + return ploadu(elements); +} + + +/** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */ +template EIGEN_DEVICE_FUNC inline void pstore(Scalar* to, const Packet& from) +{ (*to) = from; } + +/** \internal copy the packet \a from to \a *to, (un-aligned store) */ +template EIGEN_DEVICE_FUNC inline void pstoreu(Scalar* to, const Packet& from) +{ (*to) = from; } + +/** \internal copy the packet \a from to \a *to, (un-aligned store with a mask) + * There is no generic implementation. We only have implementations for specialized + * cases. Generic case should not be called. + */ +template +EIGEN_DEVICE_FUNC inline +typename enable_if::masked_store_available, void>::type +pstoreu(Scalar* to, const Packet& from, typename unpacket_traits::mask_t umask); + + template EIGEN_DEVICE_FUNC inline Packet pgather(const Scalar* from, Index /*stride*/) + { return ploadu(from); } + + template EIGEN_DEVICE_FUNC inline void pscatter(Scalar* to, const Packet& from, Index /*stride*/) + { pstore(to, from); } + +/** \internal tries to do cache prefetching of \a addr */ +template EIGEN_DEVICE_FUNC inline void prefetch(const Scalar* addr) +{ +#if defined(EIGEN_HIP_DEVICE_COMPILE) + // do nothing +#elif defined(EIGEN_CUDA_ARCH) +#if defined(__LP64__) || EIGEN_OS_WIN64 + // 64-bit pointer operand constraint for inlined asm + asm(" prefetch.L1 [ %1 ];" : "=l"(addr) : "l"(addr)); +#else + // 32-bit pointer operand constraint for inlined asm + asm(" prefetch.L1 [ %1 ];" : "=r"(addr) : "r"(addr)); +#endif +#elif (!EIGEN_COMP_MSVC) && (EIGEN_COMP_GNUC || EIGEN_COMP_CLANG || EIGEN_COMP_ICC) + __builtin_prefetch(addr); +#endif +} + +/** \internal \returns the reversed elements of \a a*/ +template EIGEN_DEVICE_FUNC inline Packet preverse(const Packet& a) +{ return a; } + +/** \internal \returns \a a with real and imaginary part flipped (for complex type only) */ +template EIGEN_DEVICE_FUNC inline Packet pcplxflip(const Packet& a) +{ + return Packet(numext::imag(a),numext::real(a)); +} + +/************************** +* Special math functions +***************************/ + +/** \internal \returns the sine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psin(const Packet& a) { EIGEN_USING_STD(sin); return sin(a); } + +/** \internal \returns the cosine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pcos(const Packet& a) { EIGEN_USING_STD(cos); return cos(a); } + +/** \internal \returns the tan of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet ptan(const Packet& a) { EIGEN_USING_STD(tan); return tan(a); } + +/** \internal \returns the arc sine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pasin(const Packet& a) { EIGEN_USING_STD(asin); return asin(a); } + +/** \internal \returns the arc cosine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pacos(const Packet& a) { EIGEN_USING_STD(acos); return acos(a); } + +/** \internal \returns the arc tangent of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet patan(const Packet& a) { EIGEN_USING_STD(atan); return atan(a); } + +/** \internal \returns the hyperbolic sine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psinh(const Packet& a) { EIGEN_USING_STD(sinh); return sinh(a); } + +/** \internal \returns the hyperbolic cosine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pcosh(const Packet& a) { EIGEN_USING_STD(cosh); return cosh(a); } + +/** \internal \returns the hyperbolic tan of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet ptanh(const Packet& a) { EIGEN_USING_STD(tanh); return tanh(a); } + +/** \internal \returns the exp of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pexp(const Packet& a) { EIGEN_USING_STD(exp); return exp(a); } + +/** \internal \returns the expm1 of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pexpm1(const Packet& a) { return numext::expm1(a); } + +/** \internal \returns the log of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog(const Packet& a) { EIGEN_USING_STD(log); return log(a); } + +/** \internal \returns the log1p of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog1p(const Packet& a) { return numext::log1p(a); } + +/** \internal \returns the log10 of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog10(const Packet& a) { EIGEN_USING_STD(log10); return log10(a); } + +/** \internal \returns the log10 of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog2(const Packet& a) { + typedef typename internal::unpacket_traits::type Scalar; + return pmul(pset1(Scalar(EIGEN_LOG2E)), plog(a)); +} + +/** \internal \returns the square-root of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psqrt(const Packet& a) { return numext::sqrt(a); } + +/** \internal \returns the reciprocal square-root of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet prsqrt(const Packet& a) { + typedef typename internal::unpacket_traits::type Scalar; + return pdiv(pset1(Scalar(1)), psqrt(a)); +} + +/** \internal \returns the rounded value of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pround(const Packet& a) { using numext::round; return round(a); } + +/** \internal \returns the floor of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pfloor(const Packet& a) { using numext::floor; return floor(a); } + +/** \internal \returns the rounded value of \a a (coeff-wise) with current + * rounding mode */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet print(const Packet& a) { using numext::rint; return rint(a); } + +/** \internal \returns the ceil of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pceil(const Packet& a) { using numext::ceil; return ceil(a); } + +/** \internal \returns the first element of a packet */ +template +EIGEN_DEVICE_FUNC inline typename unpacket_traits::type +pfirst(const Packet& a) +{ return a; } + +/** \internal \returns the sum of the elements of upper and lower half of \a a if \a a is larger than 4. + * For a packet {a0, a1, a2, a3, a4, a5, a6, a7}, it returns a half packet {a0+a4, a1+a5, a2+a6, a3+a7} + * For packet-size smaller or equal to 4, this boils down to a noop. + */ +template +EIGEN_DEVICE_FUNC inline typename conditional<(unpacket_traits::size%8)==0,typename unpacket_traits::half,Packet>::type +predux_half_dowto4(const Packet& a) +{ return a; } + +// Slow generic implementation of Packet reduction. +template +EIGEN_DEVICE_FUNC inline typename unpacket_traits::type +predux_helper(const Packet& a, Op op) { + typedef typename unpacket_traits::type Scalar; + const size_t n = unpacket_traits::size; + EIGEN_ALIGN_TO_BOUNDARY(sizeof(Packet)) Scalar elements[n]; + pstoreu(elements, a); + for(size_t k = n / 2; k > 0; k /= 2) { + for(size_t i = 0; i < k; ++i) { + elements[i] = op(elements[i], elements[i + k]); + } + } + return elements[0]; +} + +/** \internal \returns the sum of the elements of \a a*/ +template +EIGEN_DEVICE_FUNC inline typename unpacket_traits::type +predux(const Packet& a) +{ + return a; +} + +/** \internal \returns the product of the elements of \a a */ +template +EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_mul( + const Packet& a) { + typedef typename unpacket_traits::type Scalar; + return predux_helper(a, EIGEN_BINARY_OP_NAN_PROPAGATION(Scalar, (pmul))); +} + +/** \internal \returns the min of the elements of \a a */ +template +EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_min( + const Packet &a) { + typedef typename unpacket_traits::type Scalar; + return predux_helper(a, EIGEN_BINARY_OP_NAN_PROPAGATION(Scalar, (pmin))); +} + +template +EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_min( + const Packet& a) { + typedef typename unpacket_traits::type Scalar; + return predux_helper(a, EIGEN_BINARY_OP_NAN_PROPAGATION(Scalar, (pmin))); +} + +/** \internal \returns the min of the elements of \a a */ +template +EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_max( + const Packet &a) { + typedef typename unpacket_traits::type Scalar; + return predux_helper(a, EIGEN_BINARY_OP_NAN_PROPAGATION(Scalar, (pmax))); +} + +template +EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_max( + const Packet& a) { + typedef typename unpacket_traits::type Scalar; + return predux_helper(a, EIGEN_BINARY_OP_NAN_PROPAGATION(Scalar, (pmax))); +} + +#undef EIGEN_BINARY_OP_NAN_PROPAGATION + +/** \internal \returns true if all coeffs of \a a means "true" + * It is supposed to be called on values returned by pcmp_*. + */ +// not needed yet +// template EIGEN_DEVICE_FUNC inline bool predux_all(const Packet& a) +// { return bool(a); } + +/** \internal \returns true if any coeffs of \a a means "true" + * It is supposed to be called on values returned by pcmp_*. + */ +template EIGEN_DEVICE_FUNC inline bool predux_any(const Packet& a) +{ + // Dirty but generic implementation where "true" is assumed to be non 0 and all the sames. + // It is expected that "true" is either: + // - Scalar(1) + // - bits full of ones (NaN for floats), + // - or first bit equals to 1 (1 for ints, smallest denormal for floats). + // For all these cases, taking the sum is just fine, and this boils down to a no-op for scalars. + typedef typename unpacket_traits::type Scalar; + return numext::not_equal_strict(predux(a), Scalar(0)); +} + +/*************************************************************************** +* The following functions might not have to be overwritten for vectorized types +***************************************************************************/ + +/** \internal copy a packet with constant coefficient \a a (e.g., [a,a,a,a]) to \a *to. \a to must be 16 bytes aligned */ +// NOTE: this function must really be templated on the packet type (think about different packet types for the same scalar type) +template +inline void pstore1(typename unpacket_traits::type* to, const typename unpacket_traits::type& a) +{ + pstore(to, pset1(a)); +} + +/** \internal \returns a * b + c (coeff-wise) */ +template EIGEN_DEVICE_FUNC inline Packet +pmadd(const Packet& a, + const Packet& b, + const Packet& c) +{ return padd(pmul(a, b),c); } + +/** \internal \returns a packet version of \a *from. + * The pointer \a from must be aligned on a \a Alignment bytes boundary. */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet ploadt(const typename unpacket_traits::type* from) +{ + if(Alignment >= unpacket_traits::alignment) + return pload(from); + else + return ploadu(from); +} + +/** \internal copy the packet \a from to \a *to. + * The pointer \a from must be aligned on a \a Alignment bytes boundary. */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void pstoret(Scalar* to, const Packet& from) +{ + if(Alignment >= unpacket_traits::alignment) + pstore(to, from); + else + pstoreu(to, from); +} + +/** \internal \returns a packet version of \a *from. + * Unlike ploadt, ploadt_ro takes advantage of the read-only memory path on the + * hardware if available to speedup the loading of data that won't be modified + * by the current computation. + */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet ploadt_ro(const typename unpacket_traits::type* from) +{ + return ploadt(from); +} + +/*************************************************************************** +* Fast complex products (GCC generates a function call which is very slow) +***************************************************************************/ + +// Eigen+CUDA does not support complexes. +#if !defined(EIGEN_GPUCC) + +template<> inline std::complex pmul(const std::complex& a, const std::complex& b) +{ return std::complex(a.real()*b.real() - a.imag()*b.imag(), a.imag()*b.real() + a.real()*b.imag()); } + +template<> inline std::complex pmul(const std::complex& a, const std::complex& b) +{ return std::complex(a.real()*b.real() - a.imag()*b.imag(), a.imag()*b.real() + a.real()*b.imag()); } + +#endif + + +/*************************************************************************** + * PacketBlock, that is a collection of N packets where the number of words + * in the packet is a multiple of N. +***************************************************************************/ +template ::size> struct PacketBlock { + Packet packet[N]; +}; + +template EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& /*kernel*/) { + // Nothing to do in the scalar case, i.e. a 1x1 matrix. +} + +/*************************************************************************** + * Selector, i.e. vector of N boolean values used to select (i.e. blend) + * words from 2 packets. +***************************************************************************/ +template struct Selector { + bool select[N]; +}; + +template EIGEN_DEVICE_FUNC inline Packet +pblend(const Selector::size>& ifPacket, const Packet& thenPacket, const Packet& elsePacket) { + return ifPacket.select[0] ? thenPacket : elsePacket; +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_GENERIC_PACKET_MATH_H diff --git a/Vendor/eigen/Eigen/src/Core/GlobalFunctions.h b/Vendor/eigen/Eigen/src/Core/GlobalFunctions.h new file mode 100644 index 0000000..629af94 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/GlobalFunctions.h @@ -0,0 +1,194 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010-2016 Gael Guennebaud +// Copyright (C) 2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_GLOBAL_FUNCTIONS_H +#define EIGEN_GLOBAL_FUNCTIONS_H + +#ifdef EIGEN_PARSED_BY_DOXYGEN + +#define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR,DOC_OP,DOC_DETAILS) \ + /** \returns an expression of the coefficient-wise DOC_OP of \a x + + DOC_DETAILS + + \sa Math functions, class CwiseUnaryOp + */ \ + template \ + inline const Eigen::CwiseUnaryOp, const Derived> \ + NAME(const Eigen::ArrayBase& x); + +#else + +#define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR,DOC_OP,DOC_DETAILS) \ + template \ + inline const Eigen::CwiseUnaryOp, const Derived> \ + (NAME)(const Eigen::ArrayBase& x) { \ + return Eigen::CwiseUnaryOp, const Derived>(x.derived()); \ + } + +#endif // EIGEN_PARSED_BY_DOXYGEN + +#define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ + \ + template \ + struct NAME##_retval > \ + { \ + typedef const Eigen::CwiseUnaryOp, const Derived> type; \ + }; \ + template \ + struct NAME##_impl > \ + { \ + static inline typename NAME##_retval >::type run(const Eigen::ArrayBase& x) \ + { \ + return typename NAME##_retval >::type(x.derived()); \ + } \ + }; + +namespace Eigen +{ + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op,real part,\sa ArrayBase::real) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op,imaginary part,\sa ArrayBase::imag) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op,complex conjugate,\sa ArrayBase::conjugate) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(inverse,scalar_inverse_op,inverse,\sa ArrayBase::inverse) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op,sine,\sa ArrayBase::sin) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op,cosine,\sa ArrayBase::cos) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op,tangent,\sa ArrayBase::tan) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(atan,scalar_atan_op,arc-tangent,\sa ArrayBase::atan) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op,arc-sine,\sa ArrayBase::asin) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op,arc-consine,\sa ArrayBase::acos) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sinh,scalar_sinh_op,hyperbolic sine,\sa ArrayBase::sinh) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cosh,scalar_cosh_op,hyperbolic cosine,\sa ArrayBase::cosh) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tanh,scalar_tanh_op,hyperbolic tangent,\sa ArrayBase::tanh) +#if EIGEN_HAS_CXX11_MATH + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asinh,scalar_asinh_op,inverse hyperbolic sine,\sa ArrayBase::asinh) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acosh,scalar_acosh_op,inverse hyperbolic cosine,\sa ArrayBase::acosh) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(atanh,scalar_atanh_op,inverse hyperbolic tangent,\sa ArrayBase::atanh) +#endif + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(logistic,scalar_logistic_op,logistic function,\sa ArrayBase::logistic) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(lgamma,scalar_lgamma_op,natural logarithm of the gamma function,\sa ArrayBase::lgamma) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(digamma,scalar_digamma_op,derivative of lgamma,\sa ArrayBase::digamma) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erf,scalar_erf_op,error function,\sa ArrayBase::erf) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erfc,scalar_erfc_op,complement error function,\sa ArrayBase::erfc) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(ndtri,scalar_ndtri_op,inverse normal distribution function,\sa ArrayBase::ndtri) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op,exponential,\sa ArrayBase::exp) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(expm1,scalar_expm1_op,exponential of a value minus 1,\sa ArrayBase::expm1) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op,natural logarithm,\sa Eigen::log10 DOXCOMMA ArrayBase::log) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log1p,scalar_log1p_op,natural logarithm of 1 plus the value,\sa ArrayBase::log1p) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log10,scalar_log10_op,base 10 logarithm,\sa Eigen::log DOXCOMMA ArrayBase::log10) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log2,scalar_log2_op,base 2 logarithm,\sa Eigen::log DOXCOMMA ArrayBase::log2) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op,absolute value,\sa ArrayBase::abs DOXCOMMA MatrixBase::cwiseAbs) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs2,scalar_abs2_op,squared absolute value,\sa ArrayBase::abs2 DOXCOMMA MatrixBase::cwiseAbs2) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(arg,scalar_arg_op,complex argument,\sa ArrayBase::arg DOXCOMMA MatrixBase::cwiseArg) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op,square root,\sa ArrayBase::sqrt DOXCOMMA MatrixBase::cwiseSqrt) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(rsqrt,scalar_rsqrt_op,reciprocal square root,\sa ArrayBase::rsqrt) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(square,scalar_square_op,square (power 2),\sa Eigen::abs2 DOXCOMMA Eigen::pow DOXCOMMA ArrayBase::square) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cube,scalar_cube_op,cube (power 3),\sa Eigen::pow DOXCOMMA ArrayBase::cube) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(rint,scalar_rint_op,nearest integer,\sa Eigen::floor DOXCOMMA Eigen::ceil DOXCOMMA ArrayBase::round) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(round,scalar_round_op,nearest integer,\sa Eigen::floor DOXCOMMA Eigen::ceil DOXCOMMA ArrayBase::round) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(floor,scalar_floor_op,nearest integer not greater than the giben value,\sa Eigen::ceil DOXCOMMA ArrayBase::floor) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(ceil,scalar_ceil_op,nearest integer not less than the giben value,\sa Eigen::floor DOXCOMMA ArrayBase::ceil) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isnan,scalar_isnan_op,not-a-number test,\sa Eigen::isinf DOXCOMMA Eigen::isfinite DOXCOMMA ArrayBase::isnan) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isinf,scalar_isinf_op,infinite value test,\sa Eigen::isnan DOXCOMMA Eigen::isfinite DOXCOMMA ArrayBase::isinf) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isfinite,scalar_isfinite_op,finite value test,\sa Eigen::isinf DOXCOMMA Eigen::isnan DOXCOMMA ArrayBase::isfinite) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sign,scalar_sign_op,sign (or 0),\sa ArrayBase::sign) + + /** \returns an expression of the coefficient-wise power of \a x to the given constant \a exponent. + * + * \tparam ScalarExponent is the scalar type of \a exponent. It must be compatible with the scalar type of the given expression (\c Derived::Scalar). + * + * \sa ArrayBase::pow() + * + * \relates ArrayBase + */ +#ifdef EIGEN_PARSED_BY_DOXYGEN + template + inline const CwiseBinaryOp,Derived,Constant > + pow(const Eigen::ArrayBase& x, const ScalarExponent& exponent); +#else + template + EIGEN_DEVICE_FUNC inline + EIGEN_MSVC10_WORKAROUND_BINARYOP_RETURN_TYPE( + const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,typename internal::promote_scalar_arg::type,pow)) + pow(const Eigen::ArrayBase& x, const ScalarExponent& exponent) + { + typedef typename internal::promote_scalar_arg::type PromotedExponent; + return EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,PromotedExponent,pow)(x.derived(), + typename internal::plain_constant_type::type(x.derived().rows(), x.derived().cols(), internal::scalar_constant_op(exponent))); + } +#endif + + /** \returns an expression of the coefficient-wise power of \a x to the given array of \a exponents. + * + * This function computes the coefficient-wise power. + * + * Example: \include Cwise_array_power_array.cpp + * Output: \verbinclude Cwise_array_power_array.out + * + * \sa ArrayBase::pow() + * + * \relates ArrayBase + */ + template + inline const Eigen::CwiseBinaryOp, const Derived, const ExponentDerived> + pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) + { + return Eigen::CwiseBinaryOp, const Derived, const ExponentDerived>( + x.derived(), + exponents.derived() + ); + } + + /** \returns an expression of the coefficient-wise power of the scalar \a x to the given array of \a exponents. + * + * This function computes the coefficient-wise power between a scalar and an array of exponents. + * + * \tparam Scalar is the scalar type of \a x. It must be compatible with the scalar type of the given array expression (\c Derived::Scalar). + * + * Example: \include Cwise_scalar_power_array.cpp + * Output: \verbinclude Cwise_scalar_power_array.out + * + * \sa ArrayBase::pow() + * + * \relates ArrayBase + */ +#ifdef EIGEN_PARSED_BY_DOXYGEN + template + inline const CwiseBinaryOp,Constant,Derived> + pow(const Scalar& x,const Eigen::ArrayBase& x); +#else + template + EIGEN_DEVICE_FUNC inline + EIGEN_MSVC10_WORKAROUND_BINARYOP_RETURN_TYPE( + const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename internal::promote_scalar_arg::type,Derived,pow)) + pow(const Scalar& x, const Eigen::ArrayBase& exponents) { + typedef typename internal::promote_scalar_arg::type PromotedScalar; + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(PromotedScalar,Derived,pow)( + typename internal::plain_constant_type::type(exponents.derived().rows(), exponents.derived().cols(), internal::scalar_constant_op(x)), exponents.derived()); + } +#endif + + + namespace internal + { + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(real,scalar_real_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(imag,scalar_imag_op) + EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(abs2,scalar_abs2_op) + } +} + +// TODO: cleanly disable those functions that are not supported on Array (numext::real_ref, internal::random, internal::isApprox...) + +#endif // EIGEN_GLOBAL_FUNCTIONS_H diff --git a/Vendor/eigen/Eigen/src/Core/IO.h b/Vendor/eigen/Eigen/src/Core/IO.h new file mode 100644 index 0000000..e81c315 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/IO.h @@ -0,0 +1,258 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_IO_H +#define EIGEN_IO_H + +namespace Eigen { + +enum { DontAlignCols = 1 }; +enum { StreamPrecision = -1, + FullPrecision = -2 }; + +namespace internal { +template +std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt); +} + +/** \class IOFormat + * \ingroup Core_Module + * + * \brief Stores a set of parameters controlling the way matrices are printed + * + * List of available parameters: + * - \b precision number of digits for floating point values, or one of the special constants \c StreamPrecision and \c FullPrecision. + * The default is the special value \c StreamPrecision which means to use the + * stream's own precision setting, as set for instance using \c cout.precision(3). The other special value + * \c FullPrecision means that the number of digits will be computed to match the full precision of each floating-point + * type. + * - \b flags an OR-ed combination of flags, the default value is 0, the only currently available flag is \c DontAlignCols which + * allows to disable the alignment of columns, resulting in faster code. + * - \b coeffSeparator string printed between two coefficients of the same row + * - \b rowSeparator string printed between two rows + * - \b rowPrefix string printed at the beginning of each row + * - \b rowSuffix string printed at the end of each row + * - \b matPrefix string printed at the beginning of the matrix + * - \b matSuffix string printed at the end of the matrix + * - \b fill character printed to fill the empty space in aligned columns + * + * Example: \include IOFormat.cpp + * Output: \verbinclude IOFormat.out + * + * \sa DenseBase::format(), class WithFormat + */ +struct IOFormat +{ + /** Default constructor, see class IOFormat for the meaning of the parameters */ + IOFormat(int _precision = StreamPrecision, int _flags = 0, + const std::string& _coeffSeparator = " ", + const std::string& _rowSeparator = "\n", const std::string& _rowPrefix="", const std::string& _rowSuffix="", + const std::string& _matPrefix="", const std::string& _matSuffix="", const char _fill=' ') + : matPrefix(_matPrefix), matSuffix(_matSuffix), rowPrefix(_rowPrefix), rowSuffix(_rowSuffix), rowSeparator(_rowSeparator), + rowSpacer(""), coeffSeparator(_coeffSeparator), fill(_fill), precision(_precision), flags(_flags) + { + // TODO check if rowPrefix, rowSuffix or rowSeparator contains a newline + // don't add rowSpacer if columns are not to be aligned + if((flags & DontAlignCols)) + return; + int i = int(matSuffix.length())-1; + while (i>=0 && matSuffix[i]!='\n') + { + rowSpacer += ' '; + i--; + } + } + std::string matPrefix, matSuffix; + std::string rowPrefix, rowSuffix, rowSeparator, rowSpacer; + std::string coeffSeparator; + char fill; + int precision; + int flags; +}; + +/** \class WithFormat + * \ingroup Core_Module + * + * \brief Pseudo expression providing matrix output with given format + * + * \tparam ExpressionType the type of the object on which IO stream operations are performed + * + * This class represents an expression with stream operators controlled by a given IOFormat. + * It is the return type of DenseBase::format() + * and most of the time this is the only way it is used. + * + * See class IOFormat for some examples. + * + * \sa DenseBase::format(), class IOFormat + */ +template +class WithFormat +{ + public: + + WithFormat(const ExpressionType& matrix, const IOFormat& format) + : m_matrix(matrix), m_format(format) + {} + + friend std::ostream & operator << (std::ostream & s, const WithFormat& wf) + { + return internal::print_matrix(s, wf.m_matrix.eval(), wf.m_format); + } + + protected: + typename ExpressionType::Nested m_matrix; + IOFormat m_format; +}; + +namespace internal { + +// NOTE: This helper is kept for backward compatibility with previous code specializing +// this internal::significant_decimals_impl structure. In the future we should directly +// call digits10() which has been introduced in July 2016 in 3.3. +template +struct significant_decimals_impl +{ + static inline int run() + { + return NumTraits::digits10(); + } +}; + +/** \internal + * print the matrix \a _m to the output stream \a s using the output format \a fmt */ +template +std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt) +{ + using internal::is_same; + using internal::conditional; + + if(_m.size() == 0) + { + s << fmt.matPrefix << fmt.matSuffix; + return s; + } + + typename Derived::Nested m = _m; + typedef typename Derived::Scalar Scalar; + typedef typename + conditional< + is_same::value || + is_same::value || + is_same::value || + is_same::value, + int, + typename conditional< + is_same >::value || + is_same >::value || + is_same >::value || + is_same >::value, + std::complex, + const Scalar& + >::type + >::type PrintType; + + Index width = 0; + + std::streamsize explicit_precision; + if(fmt.precision == StreamPrecision) + { + explicit_precision = 0; + } + else if(fmt.precision == FullPrecision) + { + if (NumTraits::IsInteger) + { + explicit_precision = 0; + } + else + { + explicit_precision = significant_decimals_impl::run(); + } + } + else + { + explicit_precision = fmt.precision; + } + + std::streamsize old_precision = 0; + if(explicit_precision) old_precision = s.precision(explicit_precision); + + bool align_cols = !(fmt.flags & DontAlignCols); + if(align_cols) + { + // compute the largest width + for(Index j = 0; j < m.cols(); ++j) + for(Index i = 0; i < m.rows(); ++i) + { + std::stringstream sstr; + sstr.copyfmt(s); + sstr << static_cast(m.coeff(i,j)); + width = std::max(width, Index(sstr.str().length())); + } + } + std::streamsize old_width = s.width(); + char old_fill_character = s.fill(); + s << fmt.matPrefix; + for(Index i = 0; i < m.rows(); ++i) + { + if (i) + s << fmt.rowSpacer; + s << fmt.rowPrefix; + if(width) { + s.fill(fmt.fill); + s.width(width); + } + s << static_cast(m.coeff(i, 0)); + for(Index j = 1; j < m.cols(); ++j) + { + s << fmt.coeffSeparator; + if(width) { + s.fill(fmt.fill); + s.width(width); + } + s << static_cast(m.coeff(i, j)); + } + s << fmt.rowSuffix; + if( i < m.rows() - 1) + s << fmt.rowSeparator; + } + s << fmt.matSuffix; + if(explicit_precision) s.precision(old_precision); + if(width) { + s.fill(old_fill_character); + s.width(old_width); + } + return s; +} + +} // end namespace internal + +/** \relates DenseBase + * + * Outputs the matrix, to the given stream. + * + * If you wish to print the matrix with a format different than the default, use DenseBase::format(). + * + * It is also possible to change the default format by defining EIGEN_DEFAULT_IO_FORMAT before including Eigen headers. + * If not defined, this will automatically be defined to Eigen::IOFormat(), that is the Eigen::IOFormat with default parameters. + * + * \sa DenseBase::format() + */ +template +std::ostream & operator << +(std::ostream & s, + const DenseBase & m) +{ + return internal::print_matrix(s, m.eval(), EIGEN_DEFAULT_IO_FORMAT); +} + +} // end namespace Eigen + +#endif // EIGEN_IO_H diff --git a/Vendor/eigen/Eigen/src/Core/IndexedView.h b/Vendor/eigen/Eigen/src/Core/IndexedView.h new file mode 100644 index 0000000..0847625 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/IndexedView.h @@ -0,0 +1,237 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_INDEXED_VIEW_H +#define EIGEN_INDEXED_VIEW_H + +namespace Eigen { + +namespace internal { + +template +struct traits > + : traits +{ + enum { + RowsAtCompileTime = int(array_size::value), + ColsAtCompileTime = int(array_size::value), + MaxRowsAtCompileTime = RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) : Dynamic, + MaxColsAtCompileTime = ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : Dynamic, + + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, + IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + : XprTypeIsRowMajor, + + RowIncr = int(get_compile_time_incr::value), + ColIncr = int(get_compile_time_incr::value), + InnerIncr = IsRowMajor ? ColIncr : RowIncr, + OuterIncr = IsRowMajor ? RowIncr : ColIncr, + + HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), + XprInnerStride = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time::ret) : int(outer_stride_at_compile_time::ret), + XprOuterstride = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time::ret) : int(inner_stride_at_compile_time::ret), + + InnerSize = XprTypeIsRowMajor ? ColsAtCompileTime : RowsAtCompileTime, + IsBlockAlike = InnerIncr==1 && OuterIncr==1, + IsInnerPannel = HasSameStorageOrderAsXprType && is_same,typename conditional::type>::value, + + InnerStrideAtCompileTime = InnerIncr<0 || InnerIncr==DynamicIndex || XprInnerStride==Dynamic ? Dynamic : XprInnerStride * InnerIncr, + OuterStrideAtCompileTime = OuterIncr<0 || OuterIncr==DynamicIndex || XprOuterstride==Dynamic ? Dynamic : XprOuterstride * OuterIncr, + + ReturnAsScalar = is_same::value && is_same::value, + ReturnAsBlock = (!ReturnAsScalar) && IsBlockAlike, + ReturnAsIndexedView = (!ReturnAsScalar) && (!ReturnAsBlock), + + // FIXME we deal with compile-time strides if and only if we have DirectAccessBit flag, + // but this is too strict regarding negative strides... + DirectAccessMask = (int(InnerIncr)!=UndefinedIncr && int(OuterIncr)!=UndefinedIncr && InnerIncr>=0 && OuterIncr>=0) ? DirectAccessBit : 0, + FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, + Flags = (traits::Flags & (HereditaryBits | DirectAccessMask )) | FlagsLvalueBit | FlagsRowMajorBit | FlagsLinearAccessBit + }; + + typedef Block BlockType; +}; + +} + +template +class IndexedViewImpl; + + +/** \class IndexedView + * \ingroup Core_Module + * + * \brief Expression of a non-sequential sub-matrix defined by arbitrary sequences of row and column indices + * + * \tparam XprType the type of the expression in which we are taking the intersections of sub-rows and sub-columns + * \tparam RowIndices the type of the object defining the sequence of row indices + * \tparam ColIndices the type of the object defining the sequence of column indices + * + * This class represents an expression of a sub-matrix (or sub-vector) defined as the intersection + * of sub-sets of rows and columns, that are themself defined by generic sequences of row indices \f$ \{r_0,r_1,..r_{m-1}\} \f$ + * and column indices \f$ \{c_0,c_1,..c_{n-1} \}\f$. Let \f$ A \f$ be the nested matrix, then the resulting matrix \f$ B \f$ has \c m + * rows and \c n columns, and its entries are given by: \f$ B(i,j) = A(r_i,c_j) \f$. + * + * The \c RowIndices and \c ColIndices types must be compatible with the following API: + * \code + * operator[](Index) const; + * Index size() const; + * \endcode + * + * Typical supported types thus include: + * - std::vector + * - std::valarray + * - std::array + * - Plain C arrays: int[N] + * - Eigen::ArrayXi + * - decltype(ArrayXi::LinSpaced(...)) + * - Any view/expressions of the previous types + * - Eigen::ArithmeticSequence + * - Eigen::internal::AllRange (helper for Eigen::all) + * - Eigen::internal::SingleRange (helper for single index) + * - etc. + * + * In typical usages of %Eigen, this class should never be used directly. It is the return type of + * DenseBase::operator()(const RowIndices&, const ColIndices&). + * + * \sa class Block + */ +template +class IndexedView : public IndexedViewImpl::StorageKind> +{ +public: + typedef typename IndexedViewImpl::StorageKind>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(IndexedView) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(IndexedView) + + typedef typename internal::ref_selector::non_const_type MatrixTypeNested; + typedef typename internal::remove_all::type NestedExpression; + + template + IndexedView(XprType& xpr, const T0& rowIndices, const T1& colIndices) + : m_xpr(xpr), m_rowIndices(rowIndices), m_colIndices(colIndices) + {} + + /** \returns number of rows */ + Index rows() const { return internal::size(m_rowIndices); } + + /** \returns number of columns */ + Index cols() const { return internal::size(m_colIndices); } + + /** \returns the nested expression */ + const typename internal::remove_all::type& + nestedExpression() const { return m_xpr; } + + /** \returns the nested expression */ + typename internal::remove_reference::type& + nestedExpression() { return m_xpr; } + + /** \returns a const reference to the object storing/generating the row indices */ + const RowIndices& rowIndices() const { return m_rowIndices; } + + /** \returns a const reference to the object storing/generating the column indices */ + const ColIndices& colIndices() const { return m_colIndices; } + +protected: + MatrixTypeNested m_xpr; + RowIndices m_rowIndices; + ColIndices m_colIndices; +}; + + +// Generic API dispatcher +template +class IndexedViewImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; + +namespace internal { + + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef IndexedView XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost /* TODO + cost of row/col index */, + + FlagsLinearAccessBit = (traits::RowsAtCompileTime == 1 || traits::ColsAtCompileTime == 1) ? LinearAccessBit : 0, + + FlagsRowMajorBit = traits::FlagsRowMajorBit, + + Flags = (evaluator::Flags & (HereditaryBits & ~RowMajorBit /*| LinearAccessBit | DirectAccessBit*/)) | FlagsLinearAccessBit | FlagsRowMajorBit, + + Alignment = 0 + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_xpr(xpr) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(m_xpr.rowIndices()[row], m_xpr.colIndices()[col]); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(m_xpr.rowIndices()[row], m_xpr.colIndices()[col]); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + EIGEN_STATIC_ASSERT_LVALUE(XprType) + Index row = XprType::RowsAtCompileTime == 1 ? 0 : index; + Index col = XprType::RowsAtCompileTime == 1 ? index : 0; + return m_argImpl.coeffRef( m_xpr.rowIndices()[row], m_xpr.colIndices()[col]); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Scalar& coeffRef(Index index) const + { + Index row = XprType::RowsAtCompileTime == 1 ? 0 : index; + Index col = XprType::RowsAtCompileTime == 1 ? index : 0; + return m_argImpl.coeffRef( m_xpr.rowIndices()[row], m_xpr.colIndices()[col]); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const CoeffReturnType coeff(Index index) const + { + Index row = XprType::RowsAtCompileTime == 1 ? 0 : index; + Index col = XprType::RowsAtCompileTime == 1 ? index : 0; + return m_argImpl.coeff( m_xpr.rowIndices()[row], m_xpr.colIndices()[col]); + } + +protected: + + evaluator m_argImpl; + const XprType& m_xpr; + +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_INDEXED_VIEW_H diff --git a/Vendor/eigen/Eigen/src/Core/Inverse.h b/Vendor/eigen/Eigen/src/Core/Inverse.h new file mode 100644 index 0000000..c514438 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Inverse.h @@ -0,0 +1,117 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014-2019 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_INVERSE_H +#define EIGEN_INVERSE_H + +namespace Eigen { + +template class InverseImpl; + +namespace internal { + +template +struct traits > + : traits +{ + typedef typename XprType::PlainObject PlainObject; + typedef traits BaseTraits; + enum { + Flags = BaseTraits::Flags & RowMajorBit + }; +}; + +} // end namespace internal + +/** \class Inverse + * + * \brief Expression of the inverse of another expression + * + * \tparam XprType the type of the expression we are taking the inverse + * + * This class represents an abstract expression of A.inverse() + * and most of the time this is the only way it is used. + * + */ +template +class Inverse : public InverseImpl::StorageKind> +{ +public: + typedef typename XprType::StorageIndex StorageIndex; + typedef typename XprType::Scalar Scalar; + typedef typename internal::ref_selector::type XprTypeNested; + typedef typename internal::remove_all::type XprTypeNestedCleaned; + typedef typename internal::ref_selector::type Nested; + typedef typename internal::remove_all::type NestedExpression; + + explicit EIGEN_DEVICE_FUNC Inverse(const XprType &xpr) + : m_xpr(xpr) + {} + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT { return m_xpr.cols(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT { return m_xpr.rows(); } + + EIGEN_DEVICE_FUNC const XprTypeNestedCleaned& nestedExpression() const { return m_xpr; } + +protected: + XprTypeNested m_xpr; +}; + +// Generic API dispatcher +template +class InverseImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; + typedef typename XprType::Scalar Scalar; +private: + + Scalar coeff(Index row, Index col) const; + Scalar coeff(Index i) const; +}; + +namespace internal { + +/** \internal + * \brief Default evaluator for Inverse expression. + * + * This default evaluator for Inverse expression simply evaluate the inverse into a temporary + * by a call to internal::call_assignment_no_alias. + * Therefore, inverse implementers only have to specialize Assignment, ...> for + * there own nested expression. + * + * \sa class Inverse + */ +template +struct unary_evaluator > + : public evaluator::PlainObject> +{ + typedef Inverse InverseType; + typedef typename InverseType::PlainObject PlainObject; + typedef evaluator Base; + + enum { Flags = Base::Flags | EvalBeforeNestingBit }; + + unary_evaluator(const InverseType& inv_xpr) + : m_result(inv_xpr.rows(), inv_xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + internal::call_assignment_no_alias(m_result, inv_xpr); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_INVERSE_H diff --git a/Vendor/eigen/Eigen/src/Core/Map.h b/Vendor/eigen/Eigen/src/Core/Map.h new file mode 100644 index 0000000..218cc15 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Map.h @@ -0,0 +1,171 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007-2010 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MAP_H +#define EIGEN_MAP_H + +namespace Eigen { + +namespace internal { +template +struct traits > + : public traits +{ + typedef traits TraitsBase; + enum { + PlainObjectTypeInnerSize = ((traits::Flags&RowMajorBit)==RowMajorBit) + ? PlainObjectType::ColsAtCompileTime + : PlainObjectType::RowsAtCompileTime, + + InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 + ? int(PlainObjectType::InnerStrideAtCompileTime) + : int(StrideType::InnerStrideAtCompileTime), + OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 + ? (InnerStrideAtCompileTime==Dynamic || PlainObjectTypeInnerSize==Dynamic + ? Dynamic + : int(InnerStrideAtCompileTime) * int(PlainObjectTypeInnerSize)) + : int(StrideType::OuterStrideAtCompileTime), + Alignment = int(MapOptions)&int(AlignedMask), + Flags0 = TraitsBase::Flags & (~NestByRefBit), + Flags = is_lvalue::value ? int(Flags0) : (int(Flags0) & ~LvalueBit) + }; +private: + enum { Options }; // Expressions don't have Options +}; +} + +/** \class Map + * \ingroup Core_Module + * + * \brief A matrix or vector expression mapping an existing array of data. + * + * \tparam PlainObjectType the equivalent matrix type of the mapped data + * \tparam MapOptions specifies the pointer alignment in bytes. It can be: \c #Aligned128, \c #Aligned64, \c #Aligned32, \c #Aligned16, \c #Aligned8 or \c #Unaligned. + * The default is \c #Unaligned. + * \tparam StrideType optionally specifies strides. By default, Map assumes the memory layout + * of an ordinary, contiguous array. This can be overridden by specifying strides. + * The type passed here must be a specialization of the Stride template, see examples below. + * + * This class represents a matrix or vector expression mapping an existing array of data. + * It can be used to let Eigen interface without any overhead with non-Eigen data structures, + * such as plain C arrays or structures from other libraries. By default, it assumes that the + * data is laid out contiguously in memory. You can however override this by explicitly specifying + * inner and outer strides. + * + * Here's an example of simply mapping a contiguous array as a \ref TopicStorageOrders "column-major" matrix: + * \include Map_simple.cpp + * Output: \verbinclude Map_simple.out + * + * If you need to map non-contiguous arrays, you can do so by specifying strides: + * + * Here's an example of mapping an array as a vector, specifying an inner stride, that is, the pointer + * increment between two consecutive coefficients. Here, we're specifying the inner stride as a compile-time + * fixed value. + * \include Map_inner_stride.cpp + * Output: \verbinclude Map_inner_stride.out + * + * Here's an example of mapping an array while specifying an outer stride. Here, since we're mapping + * as a column-major matrix, 'outer stride' means the pointer increment between two consecutive columns. + * Here, we're specifying the outer stride as a runtime parameter. Note that here \c OuterStride<> is + * a short version of \c OuterStride because the default template parameter of OuterStride + * is \c Dynamic + * \include Map_outer_stride.cpp + * Output: \verbinclude Map_outer_stride.out + * + * For more details and for an example of specifying both an inner and an outer stride, see class Stride. + * + * \b Tip: to change the array of data mapped by a Map object, you can use the C++ + * placement new syntax: + * + * Example: \include Map_placement_new.cpp + * Output: \verbinclude Map_placement_new.out + * + * This class is the return type of PlainObjectBase::Map() but can also be used directly. + * + * \sa PlainObjectBase::Map(), \ref TopicStorageOrders + */ +template class Map + : public MapBase > +{ + public: + + typedef MapBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Map) + + typedef typename Base::PointerType PointerType; + typedef PointerType PointerArgType; + EIGEN_DEVICE_FUNC + inline PointerType cast_to_pointer_type(PointerArgType ptr) { return ptr; } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index innerStride() const + { + return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index outerStride() const + { + return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() + : internal::traits::OuterStrideAtCompileTime != Dynamic ? Index(internal::traits::OuterStrideAtCompileTime) + : IsVectorAtCompileTime ? (this->size() * innerStride()) + : int(Flags)&RowMajorBit ? (this->cols() * innerStride()) + : (this->rows() * innerStride()); + } + + /** Constructor in the fixed-size case. + * + * \param dataPtr pointer to the array to map + * \param stride optional Stride object, passing the strides. + */ + EIGEN_DEVICE_FUNC + explicit inline Map(PointerArgType dataPtr, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr)), m_stride(stride) + { + PlainObjectType::Base::_check_template_params(); + } + + /** Constructor in the dynamic-size vector case. + * + * \param dataPtr pointer to the array to map + * \param size the size of the vector expression + * \param stride optional Stride object, passing the strides. + */ + EIGEN_DEVICE_FUNC + inline Map(PointerArgType dataPtr, Index size, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), size), m_stride(stride) + { + PlainObjectType::Base::_check_template_params(); + } + + /** Constructor in the dynamic-size matrix case. + * + * \param dataPtr pointer to the array to map + * \param rows the number of rows of the matrix expression + * \param cols the number of columns of the matrix expression + * \param stride optional Stride object, passing the strides. + */ + EIGEN_DEVICE_FUNC + inline Map(PointerArgType dataPtr, Index rows, Index cols, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), rows, cols), m_stride(stride) + { + PlainObjectType::Base::_check_template_params(); + } + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map) + + protected: + StrideType m_stride; +}; + + +} // end namespace Eigen + +#endif // EIGEN_MAP_H diff --git a/Vendor/eigen/Eigen/src/Core/MapBase.h b/Vendor/eigen/Eigen/src/Core/MapBase.h new file mode 100644 index 0000000..d856447 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/MapBase.h @@ -0,0 +1,310 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2007-2010 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MAPBASE_H +#define EIGEN_MAPBASE_H + +#define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ + EIGEN_STATIC_ASSERT((int(internal::evaluator::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ + YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) + +namespace Eigen { + +/** \ingroup Core_Module + * + * \brief Base class for dense Map and Block expression with direct access + * + * This base class provides the const low-level accessors (e.g. coeff, coeffRef) of dense + * Map and Block objects with direct access. + * Typical users do not have to directly deal with this class. + * + * This class can be extended by through the macro plugin \c EIGEN_MAPBASE_PLUGIN. + * See \link TopicCustomizing_Plugins customizing Eigen \endlink for details. + * + * The \c Derived class has to provide the following two methods describing the memory layout: + * \code Index innerStride() const; \endcode + * \code Index outerStride() const; \endcode + * + * \sa class Map, class Block + */ +template class MapBase + : public internal::dense_xpr_base::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + enum { + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + ColsAtCompileTime = internal::traits::ColsAtCompileTime, + InnerStrideAtCompileTime = internal::traits::InnerStrideAtCompileTime, + SizeAtCompileTime = Base::SizeAtCompileTime + }; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + typedef typename internal::conditional< + bool(internal::is_lvalue::value), + Scalar *, + const Scalar *>::type + PointerType; + + using Base::derived; +// using Base::RowsAtCompileTime; +// using Base::ColsAtCompileTime; +// using Base::SizeAtCompileTime; + using Base::MaxRowsAtCompileTime; + using Base::MaxColsAtCompileTime; + using Base::MaxSizeAtCompileTime; + using Base::IsVectorAtCompileTime; + using Base::Flags; + using Base::IsRowMajor; + + using Base::rows; + using Base::cols; + using Base::size; + using Base::coeff; + using Base::coeffRef; + using Base::lazyAssign; + using Base::eval; + + using Base::innerStride; + using Base::outerStride; + using Base::rowStride; + using Base::colStride; + + // bug 217 - compile error on ICC 11.1 + using Base::operator=; + + typedef typename Base::CoeffReturnType CoeffReturnType; + + /** \copydoc DenseBase::rows() */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index rows() const EIGEN_NOEXCEPT { return m_rows.value(); } + /** \copydoc DenseBase::cols() */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index cols() const EIGEN_NOEXCEPT { return m_cols.value(); } + + /** Returns a pointer to the first coefficient of the matrix or vector. + * + * \note When addressing this data, make sure to honor the strides returned by innerStride() and outerStride(). + * + * \sa innerStride(), outerStride() + */ + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_data; } + + /** \copydoc PlainObjectBase::coeff(Index,Index) const */ + EIGEN_DEVICE_FUNC + inline const Scalar& coeff(Index rowId, Index colId) const + { + return m_data[colId * colStride() + rowId * rowStride()]; + } + + /** \copydoc PlainObjectBase::coeff(Index) const */ + EIGEN_DEVICE_FUNC + inline const Scalar& coeff(Index index) const + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + return m_data[index * innerStride()]; + } + + /** \copydoc PlainObjectBase::coeffRef(Index,Index) const */ + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + return this->m_data[colId * colStride() + rowId * rowStride()]; + } + + /** \copydoc PlainObjectBase::coeffRef(Index) const */ + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index index) const + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + return this->m_data[index * innerStride()]; + } + + /** \internal */ + template + inline PacketScalar packet(Index rowId, Index colId) const + { + return internal::ploadt + (m_data + (colId * colStride() + rowId * rowStride())); + } + + /** \internal */ + template + inline PacketScalar packet(Index index) const + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + return internal::ploadt(m_data + index * innerStride()); + } + + /** \internal Constructor for fixed size matrices or vectors */ + EIGEN_DEVICE_FUNC + explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) + { + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + checkSanity(); + } + + /** \internal Constructor for dynamically sized vectors */ + EIGEN_DEVICE_FUNC + inline MapBase(PointerType dataPtr, Index vecSize) + : m_data(dataPtr), + m_rows(RowsAtCompileTime == Dynamic ? vecSize : Index(RowsAtCompileTime)), + m_cols(ColsAtCompileTime == Dynamic ? vecSize : Index(ColsAtCompileTime)) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + eigen_assert(vecSize >= 0); + eigen_assert(dataPtr == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == vecSize); + checkSanity(); + } + + /** \internal Constructor for dynamically sized matrices */ + EIGEN_DEVICE_FUNC + inline MapBase(PointerType dataPtr, Index rows, Index cols) + : m_data(dataPtr), m_rows(rows), m_cols(cols) + { + eigen_assert( (dataPtr == 0) + || ( rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) + && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); + checkSanity(); + } + + #ifdef EIGEN_MAPBASE_PLUGIN + #include EIGEN_MAPBASE_PLUGIN + #endif + + protected: + EIGEN_DEFAULT_COPY_CONSTRUCTOR(MapBase) + EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(MapBase) + + template + EIGEN_DEVICE_FUNC + void checkSanity(typename internal::enable_if<(internal::traits::Alignment>0),void*>::type = 0) const + { +#if EIGEN_MAX_ALIGN_BYTES>0 + // innerStride() is not set yet when this function is called, so we optimistically assume the lowest plausible value: + const Index minInnerStride = InnerStrideAtCompileTime == Dynamic ? 1 : Index(InnerStrideAtCompileTime); + EIGEN_ONLY_USED_FOR_DEBUG(minInnerStride); + eigen_assert(( ((internal::UIntPtr(m_data) % internal::traits::Alignment) == 0) + || (cols() * rows() * minInnerStride * sizeof(Scalar)) < internal::traits::Alignment ) && "data is not aligned"); +#endif + } + + template + EIGEN_DEVICE_FUNC + void checkSanity(typename internal::enable_if::Alignment==0,void*>::type = 0) const + {} + + PointerType m_data; + const internal::variable_if_dynamic m_rows; + const internal::variable_if_dynamic m_cols; +}; + +/** \ingroup Core_Module + * + * \brief Base class for non-const dense Map and Block expression with direct access + * + * This base class provides the non-const low-level accessors (e.g. coeff and coeffRef) of + * dense Map and Block objects with direct access. + * It inherits MapBase which defines the const variant for reading specific entries. + * + * \sa class Map, class Block + */ +template class MapBase + : public MapBase +{ + typedef MapBase ReadOnlyMapBase; + public: + + typedef MapBase Base; + + typedef typename Base::Scalar Scalar; + typedef typename Base::PacketScalar PacketScalar; + typedef typename Base::StorageIndex StorageIndex; + typedef typename Base::PointerType PointerType; + + using Base::derived; + using Base::rows; + using Base::cols; + using Base::size; + using Base::coeff; + using Base::coeffRef; + + using Base::innerStride; + using Base::outerStride; + using Base::rowStride; + using Base::colStride; + + typedef typename internal::conditional< + internal::is_lvalue::value, + Scalar, + const Scalar + >::type ScalarWithConstIfNotLvalue; + + EIGEN_DEVICE_FUNC + inline const Scalar* data() const { return this->m_data; } + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue* data() { return this->m_data; } // no const-cast here so non-const-correct code will give a compile error + + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue& coeffRef(Index row, Index col) + { + return this->m_data[col * colStride() + row * rowStride()]; + } + + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue& coeffRef(Index index) + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + return this->m_data[index * innerStride()]; + } + + template + inline void writePacket(Index row, Index col, const PacketScalar& val) + { + internal::pstoret + (this->m_data + (col * colStride() + row * rowStride()), val); + } + + template + inline void writePacket(Index index, const PacketScalar& val) + { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + internal::pstoret + (this->m_data + index * innerStride(), val); + } + + EIGEN_DEVICE_FUNC explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index rows, Index cols) : Base(dataPtr, rows, cols) {} + + EIGEN_DEVICE_FUNC + Derived& operator=(const MapBase& other) + { + ReadOnlyMapBase::Base::operator=(other); + return derived(); + } + + // In theory we could simply refer to Base:Base::operator=, but MSVC does not like Base::Base, + // see bugs 821 and 920. + using ReadOnlyMapBase::Base::operator=; + protected: + EIGEN_DEFAULT_COPY_CONSTRUCTOR(MapBase) + EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(MapBase) +}; + +#undef EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS + +} // end namespace Eigen + +#endif // EIGEN_MAPBASE_H diff --git a/Vendor/eigen/Eigen/src/Core/MathFunctions.h b/Vendor/eigen/Eigen/src/Core/MathFunctions.h new file mode 100644 index 0000000..61b78f4 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/MathFunctions.h @@ -0,0 +1,2057 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2010 Benoit Jacob +// Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATHFUNCTIONS_H +#define EIGEN_MATHFUNCTIONS_H + +// TODO this should better be moved to NumTraits +// Source: WolframAlpha +#define EIGEN_PI 3.141592653589793238462643383279502884197169399375105820974944592307816406L +#define EIGEN_LOG2E 1.442695040888963407359924681001892137426645954152985934135449406931109219L +#define EIGEN_LN2 0.693147180559945309417232121458176568075500134360255254120680009493393621L + +namespace Eigen { + +// On WINCE, std::abs is defined for int only, so let's defined our own overloads: +// This issue has been confirmed with MSVC 2008 only, but the issue might exist for more recent versions too. +#if EIGEN_OS_WINCE && EIGEN_COMP_MSVC && EIGEN_COMP_MSVC<=1500 +long abs(long x) { return (labs(x)); } +double abs(double x) { return (fabs(x)); } +float abs(float x) { return (fabsf(x)); } +long double abs(long double x) { return (fabsl(x)); } +#endif + +namespace internal { + +/** \internal \class global_math_functions_filtering_base + * + * What it does: + * Defines a typedef 'type' as follows: + * - if type T has a member typedef Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl, then + * global_math_functions_filtering_base::type is a typedef for it. + * - otherwise, global_math_functions_filtering_base::type is a typedef for T. + * + * How it's used: + * To allow to defined the global math functions (like sin...) in certain cases, like the Array expressions. + * When you do sin(array1+array2), the object array1+array2 has a complicated expression type, all what you want to know + * is that it inherits ArrayBase. So we implement a partial specialization of sin_impl for ArrayBase. + * So we must make sure to use sin_impl > and not sin_impl, otherwise our partial specialization + * won't be used. How does sin know that? That's exactly what global_math_functions_filtering_base tells it. + * + * How it's implemented: + * SFINAE in the style of enable_if. Highly susceptible of breaking compilers. With GCC, it sure does work, but if you replace + * the typename dummy by an integer template parameter, it doesn't work anymore! + */ + +template +struct global_math_functions_filtering_base +{ + typedef T type; +}; + +template struct always_void { typedef void type; }; + +template +struct global_math_functions_filtering_base + ::type + > +{ + typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type; +}; + +#define EIGEN_MATHFUNC_IMPL(func, scalar) Eigen::internal::func##_impl::type> +#define EIGEN_MATHFUNC_RETVAL(func, scalar) typename Eigen::internal::func##_retval::type>::type + +/**************************************************************************** +* Implementation of real * +****************************************************************************/ + +template::IsComplex> +struct real_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return x; + } +}; + +template +struct real_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + using std::real; + return real(x); + } +}; + +template struct real_impl : real_default_impl {}; + +#if defined(EIGEN_GPU_COMPILE_PHASE) +template +struct real_impl > +{ + typedef T RealScalar; + EIGEN_DEVICE_FUNC + static inline T run(const std::complex& x) + { + return x.real(); + } +}; +#endif + +template +struct real_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of imag * +****************************************************************************/ + +template::IsComplex> +struct imag_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar&) + { + return RealScalar(0); + } +}; + +template +struct imag_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + using std::imag; + return imag(x); + } +}; + +template struct imag_impl : imag_default_impl {}; + +#if defined(EIGEN_GPU_COMPILE_PHASE) +template +struct imag_impl > +{ + typedef T RealScalar; + EIGEN_DEVICE_FUNC + static inline T run(const std::complex& x) + { + return x.imag(); + } +}; +#endif + +template +struct imag_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of real_ref * +****************************************************************************/ + +template +struct real_ref_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar& run(Scalar& x) + { + return reinterpret_cast(&x)[0]; + } + EIGEN_DEVICE_FUNC + static inline const RealScalar& run(const Scalar& x) + { + return reinterpret_cast(&x)[0]; + } +}; + +template +struct real_ref_retval +{ + typedef typename NumTraits::Real & type; +}; + +/**************************************************************************** +* Implementation of imag_ref * +****************************************************************************/ + +template +struct imag_ref_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar& run(Scalar& x) + { + return reinterpret_cast(&x)[1]; + } + EIGEN_DEVICE_FUNC + static inline const RealScalar& run(const Scalar& x) + { + return reinterpret_cast(&x)[1]; + } +}; + +template +struct imag_ref_default_impl +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline Scalar run(Scalar&) + { + return Scalar(0); + } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline const Scalar run(const Scalar&) + { + return Scalar(0); + } +}; + +template +struct imag_ref_impl : imag_ref_default_impl::IsComplex> {}; + +template +struct imag_ref_retval +{ + typedef typename NumTraits::Real & type; +}; + +/**************************************************************************** +* Implementation of conj * +****************************************************************************/ + +template::IsComplex> +struct conj_default_impl +{ + EIGEN_DEVICE_FUNC + static inline Scalar run(const Scalar& x) + { + return x; + } +}; + +template +struct conj_default_impl +{ + EIGEN_DEVICE_FUNC + static inline Scalar run(const Scalar& x) + { + using std::conj; + return conj(x); + } +}; + +template::IsComplex> +struct conj_impl : conj_default_impl {}; + +template +struct conj_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of abs2 * +****************************************************************************/ + +template +struct abs2_impl_default +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return x*x; + } +}; + +template +struct abs2_impl_default // IsComplex +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return x.real()*x.real() + x.imag()*x.imag(); + } +}; + +template +struct abs2_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return abs2_impl_default::IsComplex>::run(x); + } +}; + +template +struct abs2_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of sqrt/rsqrt * +****************************************************************************/ + +template +struct sqrt_impl +{ + EIGEN_DEVICE_FUNC + static EIGEN_ALWAYS_INLINE Scalar run(const Scalar& x) + { + EIGEN_USING_STD(sqrt); + return sqrt(x); + } +}; + +// Complex sqrt defined in MathFunctionsImpl.h. +template EIGEN_DEVICE_FUNC std::complex complex_sqrt(const std::complex& a_x); + +// Custom implementation is faster than `std::sqrt`, works on +// GPU, and correctly handles special cases (unlike MSVC). +template +struct sqrt_impl > +{ + EIGEN_DEVICE_FUNC + static EIGEN_ALWAYS_INLINE std::complex run(const std::complex& x) + { + return complex_sqrt(x); + } +}; + +template +struct sqrt_retval +{ + typedef Scalar type; +}; + +// Default implementation relies on numext::sqrt, at bottom of file. +template +struct rsqrt_impl; + +// Complex rsqrt defined in MathFunctionsImpl.h. +template EIGEN_DEVICE_FUNC std::complex complex_rsqrt(const std::complex& a_x); + +template +struct rsqrt_impl > +{ + EIGEN_DEVICE_FUNC + static EIGEN_ALWAYS_INLINE std::complex run(const std::complex& x) + { + return complex_rsqrt(x); + } +}; + +template +struct rsqrt_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of norm1 * +****************************************************************************/ + +template +struct norm1_default_impl; + +template +struct norm1_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + EIGEN_USING_STD(abs); + return abs(x.real()) + abs(x.imag()); + } +}; + +template +struct norm1_default_impl +{ + EIGEN_DEVICE_FUNC + static inline Scalar run(const Scalar& x) + { + EIGEN_USING_STD(abs); + return abs(x); + } +}; + +template +struct norm1_impl : norm1_default_impl::IsComplex> {}; + +template +struct norm1_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of hypot * +****************************************************************************/ + +template struct hypot_impl; + +template +struct hypot_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of cast * +****************************************************************************/ + +template +struct cast_impl +{ + EIGEN_DEVICE_FUNC + static inline NewType run(const OldType& x) + { + return static_cast(x); + } +}; + +// Casting from S -> Complex leads to an implicit conversion from S to T, +// generating warnings on clang. Here we explicitly cast the real component. +template +struct cast_impl::IsComplex && NumTraits::IsComplex + >::type> +{ + EIGEN_DEVICE_FUNC + static inline NewType run(const OldType& x) + { + typedef typename NumTraits::Real NewReal; + return static_cast(static_cast(x)); + } +}; + +// here, for once, we're plainly returning NewType: we don't want cast to do weird things. + +template +EIGEN_DEVICE_FUNC +inline NewType cast(const OldType& x) +{ + return cast_impl::run(x); +} + +/**************************************************************************** +* Implementation of round * +****************************************************************************/ + +template +struct round_impl +{ + EIGEN_DEVICE_FUNC + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) +#if EIGEN_HAS_CXX11_MATH + EIGEN_USING_STD(round); +#endif + return Scalar(round(x)); + } +}; + +#if !EIGEN_HAS_CXX11_MATH +#if EIGEN_HAS_C99_MATH +// Use ::roundf for float. +template<> +struct round_impl { + EIGEN_DEVICE_FUNC + static inline float run(const float& x) + { + return ::roundf(x); + } +}; +#else +template +struct round_using_floor_ceil_impl +{ + EIGEN_DEVICE_FUNC + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) + // Without C99 round/roundf, resort to floor/ceil. + EIGEN_USING_STD(floor); + EIGEN_USING_STD(ceil); + // If not enough precision to resolve a decimal at all, return the input. + // Otherwise, adding 0.5 can trigger an increment by 1. + const Scalar limit = Scalar(1ull << (NumTraits::digits() - 1)); + if (x >= limit || x <= -limit) { + return x; + } + return (x > Scalar(0)) ? Scalar(floor(x + Scalar(0.5))) : Scalar(ceil(x - Scalar(0.5))); + } +}; + +template<> +struct round_impl : round_using_floor_ceil_impl {}; + +template<> +struct round_impl : round_using_floor_ceil_impl {}; +#endif // EIGEN_HAS_C99_MATH +#endif // !EIGEN_HAS_CXX11_MATH + +template +struct round_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of rint * +****************************************************************************/ + +template +struct rint_impl { + EIGEN_DEVICE_FUNC + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) +#if EIGEN_HAS_CXX11_MATH + EIGEN_USING_STD(rint); +#endif + return rint(x); + } +}; + +#if !EIGEN_HAS_CXX11_MATH +template<> +struct rint_impl { + EIGEN_DEVICE_FUNC + static inline double run(const double& x) + { + return ::rint(x); + } +}; +template<> +struct rint_impl { + EIGEN_DEVICE_FUNC + static inline float run(const float& x) + { + return ::rintf(x); + } +}; +#endif + +template +struct rint_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of arg * +****************************************************************************/ + +// Visual Studio 2017 has a bug where arg(float) returns 0 for negative inputs. +// This seems to be fixed in VS 2019. +#if EIGEN_HAS_CXX11_MATH && (!EIGEN_COMP_MSVC || EIGEN_COMP_MSVC >= 1920) +// std::arg is only defined for types of std::complex, or integer types or float/double/long double +template::IsComplex || is_integral::value + || is_same::value || is_same::value + || is_same::value > +struct arg_default_impl; + +template +struct arg_default_impl { + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + #if defined(EIGEN_HIP_DEVICE_COMPILE) + // HIP does not seem to have a native device side implementation for the math routine "arg" + using std::arg; + #else + EIGEN_USING_STD(arg); + #endif + return static_cast(arg(x)); + } +}; + +// Must be non-complex floating-point type (e.g. half/bfloat16). +template +struct arg_default_impl { + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return (x < Scalar(0)) ? RealScalar(EIGEN_PI) : RealScalar(0); + } +}; +#else +template::IsComplex> +struct arg_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return (x < RealScalar(0)) ? RealScalar(EIGEN_PI) : RealScalar(0); + } +}; + +template +struct arg_default_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + EIGEN_USING_STD(arg); + return arg(x); + } +}; +#endif +template struct arg_impl : arg_default_impl {}; + +template +struct arg_retval +{ + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of expm1 * +****************************************************************************/ + +// This implementation is based on GSL Math's expm1. +namespace std_fallback { + // fallback expm1 implementation in case there is no expm1(Scalar) function in namespace of Scalar, + // or that there is no suitable std::expm1 function available. Implementation + // attributed to Kahan. See: http://www.plunk.org/~hatch/rightway.php. + template + EIGEN_DEVICE_FUNC inline Scalar expm1(const Scalar& x) { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + typedef typename NumTraits::Real RealScalar; + + EIGEN_USING_STD(exp); + Scalar u = exp(x); + if (numext::equal_strict(u, Scalar(1))) { + return x; + } + Scalar um1 = u - RealScalar(1); + if (numext::equal_strict(um1, Scalar(-1))) { + return RealScalar(-1); + } + + EIGEN_USING_STD(log); + Scalar logu = log(u); + return numext::equal_strict(u, logu) ? u : (u - RealScalar(1)) * x / logu; + } +} + +template +struct expm1_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + #if EIGEN_HAS_CXX11_MATH + using std::expm1; + #else + using std_fallback::expm1; + #endif + return expm1(x); + } +}; + +template +struct expm1_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of log * +****************************************************************************/ + +// Complex log defined in MathFunctionsImpl.h. +template EIGEN_DEVICE_FUNC std::complex complex_log(const std::complex& z); + +template +struct log_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) + { + EIGEN_USING_STD(log); + return static_cast(log(x)); + } +}; + +template +struct log_impl > { + EIGEN_DEVICE_FUNC static inline std::complex run(const std::complex& z) + { + return complex_log(z); + } +}; + +/**************************************************************************** +* Implementation of log1p * +****************************************************************************/ + +namespace std_fallback { + // fallback log1p implementation in case there is no log1p(Scalar) function in namespace of Scalar, + // or that there is no suitable std::log1p function available + template + EIGEN_DEVICE_FUNC inline Scalar log1p(const Scalar& x) { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + typedef typename NumTraits::Real RealScalar; + EIGEN_USING_STD(log); + Scalar x1p = RealScalar(1) + x; + Scalar log_1p = log_impl::run(x1p); + const bool is_small = numext::equal_strict(x1p, Scalar(1)); + const bool is_inf = numext::equal_strict(x1p, log_1p); + return (is_small || is_inf) ? x : x * (log_1p / (x1p - RealScalar(1))); + } +} + +template +struct log1p_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + #if EIGEN_HAS_CXX11_MATH + using std::log1p; + #else + using std_fallback::log1p; + #endif + return log1p(x); + } +}; + +// Specialization for complex types that are not supported by std::log1p. +template +struct log1p_impl > { + EIGEN_DEVICE_FUNC static inline std::complex run( + const std::complex& x) { + EIGEN_STATIC_ASSERT_NON_INTEGER(RealScalar) + return std_fallback::log1p(x); + } +}; + +template +struct log1p_retval +{ + typedef Scalar type; +}; + +/**************************************************************************** +* Implementation of pow * +****************************************************************************/ + +template::IsInteger&&NumTraits::IsInteger> +struct pow_impl +{ + //typedef Scalar retval; + typedef typename ScalarBinaryOpTraits >::ReturnType result_type; + static EIGEN_DEVICE_FUNC inline result_type run(const ScalarX& x, const ScalarY& y) + { + EIGEN_USING_STD(pow); + return pow(x, y); + } +}; + +template +struct pow_impl +{ + typedef ScalarX result_type; + static EIGEN_DEVICE_FUNC inline ScalarX run(ScalarX x, ScalarY y) + { + ScalarX res(1); + eigen_assert(!NumTraits::IsSigned || y >= 0); + if(y & 1) res *= x; + y >>= 1; + while(y) + { + x *= x; + if(y&1) res *= x; + y >>= 1; + } + return res; + } +}; + +/**************************************************************************** +* Implementation of random * +****************************************************************************/ + +template +struct random_default_impl {}; + +template +struct random_impl : random_default_impl::IsComplex, NumTraits::IsInteger> {}; + +template +struct random_retval +{ + typedef Scalar type; +}; + +template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y); +template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(); + +template +struct random_default_impl +{ + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return x + (y-x) * Scalar(std::rand()) / Scalar(RAND_MAX); + } + static inline Scalar run() + { + return run(Scalar(NumTraits::IsSigned ? -1 : 0), Scalar(1)); + } +}; + +enum { + meta_floor_log2_terminate, + meta_floor_log2_move_up, + meta_floor_log2_move_down, + meta_floor_log2_bogus +}; + +template struct meta_floor_log2_selector +{ + enum { middle = (lower + upper) / 2, + value = (upper <= lower + 1) ? int(meta_floor_log2_terminate) + : (n < (1 << middle)) ? int(meta_floor_log2_move_down) + : (n==0) ? int(meta_floor_log2_bogus) + : int(meta_floor_log2_move_up) + }; +}; + +template::value> +struct meta_floor_log2 {}; + +template +struct meta_floor_log2 +{ + enum { value = meta_floor_log2::middle>::value }; +}; + +template +struct meta_floor_log2 +{ + enum { value = meta_floor_log2::middle, upper>::value }; +}; + +template +struct meta_floor_log2 +{ + enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower }; +}; + +template +struct meta_floor_log2 +{ + // no value, error at compile time +}; + +template +struct random_default_impl +{ + static inline Scalar run(const Scalar& x, const Scalar& y) + { + if (y <= x) + return x; + // ScalarU is the unsigned counterpart of Scalar, possibly Scalar itself. + typedef typename make_unsigned::type ScalarU; + // ScalarX is the widest of ScalarU and unsigned int. + // We'll deal only with ScalarX and unsigned int below thus avoiding signed + // types and arithmetic and signed overflows (which are undefined behavior). + typedef typename conditional<(ScalarU(-1) > unsigned(-1)), ScalarU, unsigned>::type ScalarX; + // The following difference doesn't overflow, provided our integer types are two's + // complement and have the same number of padding bits in signed and unsigned variants. + // This is the case in most modern implementations of C++. + ScalarX range = ScalarX(y) - ScalarX(x); + ScalarX offset = 0; + ScalarX divisor = 1; + ScalarX multiplier = 1; + const unsigned rand_max = RAND_MAX; + if (range <= rand_max) divisor = (rand_max + 1) / (range + 1); + else multiplier = 1 + range / (rand_max + 1); + // Rejection sampling. + do { + offset = (unsigned(std::rand()) * multiplier) / divisor; + } while (offset > range); + return Scalar(ScalarX(x) + offset); + } + + static inline Scalar run() + { +#ifdef EIGEN_MAKING_DOCS + return run(Scalar(NumTraits::IsSigned ? -10 : 0), Scalar(10)); +#else + enum { rand_bits = meta_floor_log2<(unsigned int)(RAND_MAX)+1>::value, + scalar_bits = sizeof(Scalar) * CHAR_BIT, + shift = EIGEN_PLAIN_ENUM_MAX(0, int(rand_bits) - int(scalar_bits)), + offset = NumTraits::IsSigned ? (1 << (EIGEN_PLAIN_ENUM_MIN(rand_bits,scalar_bits)-1)) : 0 + }; + return Scalar((std::rand() >> shift) - offset); +#endif + } +}; + +template +struct random_default_impl +{ + static inline Scalar run(const Scalar& x, const Scalar& y) + { + return Scalar(random(x.real(), y.real()), + random(x.imag(), y.imag())); + } + static inline Scalar run() + { + typedef typename NumTraits::Real RealScalar; + return Scalar(random(), random()); + } +}; + +template +inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y); +} + +template +inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() +{ + return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); +} + +// Implementation of is* functions + +// std::is* do not work with fast-math and gcc, std::is* are available on MSVC 2013 and newer, as well as in clang. +#if (EIGEN_HAS_CXX11_MATH && !(EIGEN_COMP_GNUC_STRICT && __FINITE_MATH_ONLY__)) || (EIGEN_COMP_MSVC>=1800) || (EIGEN_COMP_CLANG) +#define EIGEN_USE_STD_FPCLASSIFY 1 +#else +#define EIGEN_USE_STD_FPCLASSIFY 0 +#endif + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isnan_impl(const T&) { return false; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isinf_impl(const T&) { return false; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isfinite_impl(const T&) { return true; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isfinite_impl(const T& x) +{ + #if defined(EIGEN_GPU_COMPILE_PHASE) + return (::isfinite)(x); + #elif EIGEN_USE_STD_FPCLASSIFY + using std::isfinite; + return isfinite EIGEN_NOT_A_MACRO (x); + #else + return x<=NumTraits::highest() && x>=NumTraits::lowest(); + #endif +} + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isinf_impl(const T& x) +{ + #if defined(EIGEN_GPU_COMPILE_PHASE) + return (::isinf)(x); + #elif EIGEN_USE_STD_FPCLASSIFY + using std::isinf; + return isinf EIGEN_NOT_A_MACRO (x); + #else + return x>NumTraits::highest() || x::lowest(); + #endif +} + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isnan_impl(const T& x) +{ + #if defined(EIGEN_GPU_COMPILE_PHASE) + return (::isnan)(x); + #elif EIGEN_USE_STD_FPCLASSIFY + using std::isnan; + return isnan EIGEN_NOT_A_MACRO (x); + #else + return x != x; + #endif +} + +#if (!EIGEN_USE_STD_FPCLASSIFY) + +#if EIGEN_COMP_MSVC + +template EIGEN_DEVICE_FUNC bool isinf_msvc_helper(T x) +{ + return _fpclass(x)==_FPCLASS_NINF || _fpclass(x)==_FPCLASS_PINF; +} + +//MSVC defines a _isnan builtin function, but for double only +EIGEN_DEVICE_FUNC inline bool isnan_impl(const long double& x) { return _isnan(x)!=0; } +EIGEN_DEVICE_FUNC inline bool isnan_impl(const double& x) { return _isnan(x)!=0; } +EIGEN_DEVICE_FUNC inline bool isnan_impl(const float& x) { return _isnan(x)!=0; } + +EIGEN_DEVICE_FUNC inline bool isinf_impl(const long double& x) { return isinf_msvc_helper(x); } +EIGEN_DEVICE_FUNC inline bool isinf_impl(const double& x) { return isinf_msvc_helper(x); } +EIGEN_DEVICE_FUNC inline bool isinf_impl(const float& x) { return isinf_msvc_helper(x); } + +#elif (defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ && EIGEN_COMP_GNUC) + +#if EIGEN_GNUC_AT_LEAST(5,0) + #define EIGEN_TMP_NOOPT_ATTRIB EIGEN_DEVICE_FUNC inline __attribute__((optimize("no-finite-math-only"))) +#else + // NOTE the inline qualifier and noinline attribute are both needed: the former is to avoid linking issue (duplicate symbol), + // while the second prevent too aggressive optimizations in fast-math mode: + #define EIGEN_TMP_NOOPT_ATTRIB EIGEN_DEVICE_FUNC inline __attribute__((noinline,optimize("no-finite-math-only"))) +#endif + +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const long double& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const double& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const float& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const double& x) { return __builtin_isinf(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const float& x) { return __builtin_isinf(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const long double& x) { return __builtin_isinf(x); } + +#undef EIGEN_TMP_NOOPT_ATTRIB + +#endif + +#endif + +// The following overload are defined at the end of this file +template EIGEN_DEVICE_FUNC bool isfinite_impl(const std::complex& x); +template EIGEN_DEVICE_FUNC bool isnan_impl(const std::complex& x); +template EIGEN_DEVICE_FUNC bool isinf_impl(const std::complex& x); + +template T generic_fast_tanh_float(const T& a_x); +} // end namespace internal + +/**************************************************************************** +* Generic math functions * +****************************************************************************/ + +namespace numext { + +#if (!defined(EIGEN_GPUCC) || defined(EIGEN_CONSTEXPR_ARE_DEVICE_FUNC)) +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T mini(const T& x, const T& y) +{ + EIGEN_USING_STD(min) + return min EIGEN_NOT_A_MACRO (x,y); +} + +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T maxi(const T& x, const T& y) +{ + EIGEN_USING_STD(max) + return max EIGEN_NOT_A_MACRO (x,y); +} +#else +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T mini(const T& x, const T& y) +{ + return y < x ? y : x; +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE float mini(const float& x, const float& y) +{ + return fminf(x, y); +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE double mini(const double& x, const double& y) +{ + return fmin(x, y); +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE long double mini(const long double& x, const long double& y) +{ +#if defined(EIGEN_HIPCC) + // no "fminl" on HIP yet + return (x < y) ? x : y; +#else + return fminl(x, y); +#endif +} + +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T maxi(const T& x, const T& y) +{ + return x < y ? y : x; +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE float maxi(const float& x, const float& y) +{ + return fmaxf(x, y); +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE double maxi(const double& x, const double& y) +{ + return fmax(x, y); +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE long double maxi(const long double& x, const long double& y) +{ +#if defined(EIGEN_HIPCC) + // no "fmaxl" on HIP yet + return (x > y) ? x : y; +#else + return fmaxl(x, y); +#endif +} +#endif + +#if defined(SYCL_DEVICE_ONLY) + + +#define SYCL_SPECIALIZE_SIGNED_INTEGER_TYPES_BINARY(NAME, FUNC) \ + SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC, cl::sycl::cl_char) \ + SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC, cl::sycl::cl_short) \ + SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC, cl::sycl::cl_int) \ + SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC, cl::sycl::cl_long) +#define SYCL_SPECIALIZE_SIGNED_INTEGER_TYPES_UNARY(NAME, FUNC) \ + SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC, cl::sycl::cl_char) \ + SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC, cl::sycl::cl_short) \ + SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC, cl::sycl::cl_int) \ + SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC, cl::sycl::cl_long) +#define SYCL_SPECIALIZE_UNSIGNED_INTEGER_TYPES_BINARY(NAME, FUNC) \ + SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC, cl::sycl::cl_uchar) \ + SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC, cl::sycl::cl_ushort) \ + SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC, cl::sycl::cl_uint) \ + SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC, cl::sycl::cl_ulong) +#define SYCL_SPECIALIZE_UNSIGNED_INTEGER_TYPES_UNARY(NAME, FUNC) \ + SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC, cl::sycl::cl_uchar) \ + SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC, cl::sycl::cl_ushort) \ + SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC, cl::sycl::cl_uint) \ + SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC, cl::sycl::cl_ulong) +#define SYCL_SPECIALIZE_INTEGER_TYPES_BINARY(NAME, FUNC) \ + SYCL_SPECIALIZE_SIGNED_INTEGER_TYPES_BINARY(NAME, FUNC) \ + SYCL_SPECIALIZE_UNSIGNED_INTEGER_TYPES_BINARY(NAME, FUNC) +#define SYCL_SPECIALIZE_INTEGER_TYPES_UNARY(NAME, FUNC) \ + SYCL_SPECIALIZE_SIGNED_INTEGER_TYPES_UNARY(NAME, FUNC) \ + SYCL_SPECIALIZE_UNSIGNED_INTEGER_TYPES_UNARY(NAME, FUNC) +#define SYCL_SPECIALIZE_FLOATING_TYPES_BINARY(NAME, FUNC) \ + SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC, cl::sycl::cl_float) \ + SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC,cl::sycl::cl_double) +#define SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(NAME, FUNC) \ + SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC, cl::sycl::cl_float) \ + SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC,cl::sycl::cl_double) +#define SYCL_SPECIALIZE_FLOATING_TYPES_UNARY_FUNC_RET_TYPE(NAME, FUNC, RET_TYPE) \ + SYCL_SPECIALIZE_GEN_UNARY_FUNC(NAME, FUNC, RET_TYPE, cl::sycl::cl_float) \ + SYCL_SPECIALIZE_GEN_UNARY_FUNC(NAME, FUNC, RET_TYPE, cl::sycl::cl_double) + +#define SYCL_SPECIALIZE_GEN_UNARY_FUNC(NAME, FUNC, RET_TYPE, ARG_TYPE) \ +template<> \ + EIGEN_DEVICE_FUNC \ + EIGEN_ALWAYS_INLINE RET_TYPE NAME(const ARG_TYPE& x) { \ + return cl::sycl::FUNC(x); \ + } + +#define SYCL_SPECIALIZE_UNARY_FUNC(NAME, FUNC, TYPE) \ + SYCL_SPECIALIZE_GEN_UNARY_FUNC(NAME, FUNC, TYPE, TYPE) + +#define SYCL_SPECIALIZE_GEN1_BINARY_FUNC(NAME, FUNC, RET_TYPE, ARG_TYPE1, ARG_TYPE2) \ + template<> \ + EIGEN_DEVICE_FUNC \ + EIGEN_ALWAYS_INLINE RET_TYPE NAME(const ARG_TYPE1& x, const ARG_TYPE2& y) { \ + return cl::sycl::FUNC(x, y); \ + } + +#define SYCL_SPECIALIZE_GEN2_BINARY_FUNC(NAME, FUNC, RET_TYPE, ARG_TYPE) \ + SYCL_SPECIALIZE_GEN1_BINARY_FUNC(NAME, FUNC, RET_TYPE, ARG_TYPE, ARG_TYPE) + +#define SYCL_SPECIALIZE_BINARY_FUNC(NAME, FUNC, TYPE) \ + SYCL_SPECIALIZE_GEN2_BINARY_FUNC(NAME, FUNC, TYPE, TYPE) + +SYCL_SPECIALIZE_INTEGER_TYPES_BINARY(mini, min) +SYCL_SPECIALIZE_FLOATING_TYPES_BINARY(mini, fmin) +SYCL_SPECIALIZE_INTEGER_TYPES_BINARY(maxi, max) +SYCL_SPECIALIZE_FLOATING_TYPES_BINARY(maxi, fmax) + +#endif + + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x) +{ + return internal::real_ref_impl::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) real_ref(Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(arg, Scalar) arg(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(arg, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) +{ + return internal::imag_ref_impl::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) imag_ref(Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); +} + +EIGEN_DEVICE_FUNC +inline bool abs2(bool x) { return x; } + +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T absdiff(const T& x, const T& y) +{ + return x > y ? x - y : y - x; +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE float absdiff(const float& x, const float& y) +{ + return fabsf(x - y); +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE double absdiff(const double& x, const double& y) +{ + return fabs(x - y); +} + +#if !defined(EIGEN_GPUCC) +// HIP and CUDA do not support long double. +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE long double absdiff(const long double& x, const long double& y) { + return fabsl(x - y); +} +#endif + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) hypot(const Scalar& x, const Scalar& y) +{ + return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); +} + +#if defined(SYCL_DEVICE_ONLY) + SYCL_SPECIALIZE_FLOATING_TYPES_BINARY(hypot, hypot) +#endif + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(log1p, Scalar) log1p(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(log1p, Scalar)::run(x); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(log1p, log1p) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float log1p(const float &x) { return ::log1pf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double log1p(const double &x) { return ::log1p(x); } +#endif + +template +EIGEN_DEVICE_FUNC +inline typename internal::pow_impl::result_type pow(const ScalarX& x, const ScalarY& y) +{ + return internal::pow_impl::run(x, y); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_BINARY(pow, pow) +#endif + +template EIGEN_DEVICE_FUNC bool (isnan) (const T &x) { return internal::isnan_impl(x); } +template EIGEN_DEVICE_FUNC bool (isinf) (const T &x) { return internal::isinf_impl(x); } +template EIGEN_DEVICE_FUNC bool (isfinite)(const T &x) { return internal::isfinite_impl(x); } + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY_FUNC_RET_TYPE(isnan, isnan, bool) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY_FUNC_RET_TYPE(isinf, isinf, bool) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY_FUNC_RET_TYPE(isfinite, isfinite, bool) +#endif + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(rint, Scalar) rint(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(rint, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(round, Scalar) round(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(round, Scalar)::run(x); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(round, round) +#endif + +template +EIGEN_DEVICE_FUNC +T (floor)(const T& x) +{ + EIGEN_USING_STD(floor) + return floor(x); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(floor, floor) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float floor(const float &x) { return ::floorf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double floor(const double &x) { return ::floor(x); } +#endif + +template +EIGEN_DEVICE_FUNC +T (ceil)(const T& x) +{ + EIGEN_USING_STD(ceil); + return ceil(x); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(ceil, ceil) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float ceil(const float &x) { return ::ceilf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double ceil(const double &x) { return ::ceil(x); } +#endif + + +/** Log base 2 for 32 bits positive integers. + * Conveniently returns 0 for x==0. */ +inline int log2(int x) +{ + eigen_assert(x>=0); + unsigned int v(x); + static const int table[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return table[(v * 0x07C4ACDDU) >> 27]; +} + +/** \returns the square root of \a x. + * + * It is essentially equivalent to + * \code using std::sqrt; return sqrt(x); \endcode + * but slightly faster for float/double and some compilers (e.g., gcc), thanks to + * specializations when SSE is enabled. + * + * It's usage is justified in performance critical functions, like norm/normalize. + */ +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE EIGEN_MATHFUNC_RETVAL(sqrt, Scalar) sqrt(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(sqrt, Scalar)::run(x); +} + +// Boolean specialization, avoids implicit float to bool conversion (-Wimplicit-conversion-floating-point-to-bool). +template<> +EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_DEVICE_FUNC +bool sqrt(const bool &x) { return x; } + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(sqrt, sqrt) +#endif + +/** \returns the reciprocal square root of \a x. **/ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T rsqrt(const T& x) +{ + return internal::rsqrt_impl::run(x); +} + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T log(const T &x) { + return internal::log_impl::run(x); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(log, log) +#endif + + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float log(const float &x) { return ::logf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double log(const double &x) { return ::log(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +typename internal::enable_if::IsSigned || NumTraits::IsComplex,typename NumTraits::Real>::type +abs(const T &x) { + EIGEN_USING_STD(abs); + return abs(x); +} + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +typename internal::enable_if::IsSigned || NumTraits::IsComplex),typename NumTraits::Real>::type +abs(const T &x) { + return x; +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_INTEGER_TYPES_UNARY(abs, abs) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(abs, fabs) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float abs(const float &x) { return ::fabsf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double abs(const double &x) { return ::fabs(x); } + +template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float abs(const std::complex& x) { + return ::hypotf(x.real(), x.imag()); +} + +template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double abs(const std::complex& x) { + return ::hypot(x.real(), x.imag()); +} +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T exp(const T &x) { + EIGEN_USING_STD(exp); + return exp(x); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(exp, exp) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float exp(const float &x) { return ::expf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double exp(const double &x) { return ::exp(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +std::complex exp(const std::complex& x) { + float com = ::expf(x.real()); + float res_real = com * ::cosf(x.imag()); + float res_imag = com * ::sinf(x.imag()); + return std::complex(res_real, res_imag); +} + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +std::complex exp(const std::complex& x) { + double com = ::exp(x.real()); + double res_real = com * ::cos(x.imag()); + double res_imag = com * ::sin(x.imag()); + return std::complex(res_real, res_imag); +} +#endif + +template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(expm1, Scalar) expm1(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(expm1, Scalar)::run(x); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(expm1, expm1) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float expm1(const float &x) { return ::expm1f(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double expm1(const double &x) { return ::expm1(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T cos(const T &x) { + EIGEN_USING_STD(cos); + return cos(x); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(cos,cos) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float cos(const float &x) { return ::cosf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double cos(const double &x) { return ::cos(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T sin(const T &x) { + EIGEN_USING_STD(sin); + return sin(x); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(sin, sin) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float sin(const float &x) { return ::sinf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double sin(const double &x) { return ::sin(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T tan(const T &x) { + EIGEN_USING_STD(tan); + return tan(x); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(tan, tan) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float tan(const float &x) { return ::tanf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double tan(const double &x) { return ::tan(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T acos(const T &x) { + EIGEN_USING_STD(acos); + return acos(x); +} + +#if EIGEN_HAS_CXX11_MATH +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T acosh(const T &x) { + EIGEN_USING_STD(acosh); + return static_cast(acosh(x)); +} +#endif + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(acos, acos) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(acosh, acosh) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float acos(const float &x) { return ::acosf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double acos(const double &x) { return ::acos(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T asin(const T &x) { + EIGEN_USING_STD(asin); + return asin(x); +} + +#if EIGEN_HAS_CXX11_MATH +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T asinh(const T &x) { + EIGEN_USING_STD(asinh); + return static_cast(asinh(x)); +} +#endif + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(asin, asin) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(asinh, asinh) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float asin(const float &x) { return ::asinf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double asin(const double &x) { return ::asin(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T atan(const T &x) { + EIGEN_USING_STD(atan); + return static_cast(atan(x)); +} + +#if EIGEN_HAS_CXX11_MATH +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T atanh(const T &x) { + EIGEN_USING_STD(atanh); + return static_cast(atanh(x)); +} +#endif + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(atan, atan) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(atanh, atanh) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float atan(const float &x) { return ::atanf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double atan(const double &x) { return ::atan(x); } +#endif + + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T cosh(const T &x) { + EIGEN_USING_STD(cosh); + return static_cast(cosh(x)); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(cosh, cosh) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float cosh(const float &x) { return ::coshf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double cosh(const double &x) { return ::cosh(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T sinh(const T &x) { + EIGEN_USING_STD(sinh); + return static_cast(sinh(x)); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(sinh, sinh) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float sinh(const float &x) { return ::sinhf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double sinh(const double &x) { return ::sinh(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T tanh(const T &x) { + EIGEN_USING_STD(tanh); + return tanh(x); +} + +#if (!defined(EIGEN_GPUCC)) && EIGEN_FAST_MATH && !defined(SYCL_DEVICE_ONLY) +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float tanh(float x) { return internal::generic_fast_tanh_float(x); } +#endif + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_UNARY(tanh, tanh) +#endif + +#if defined(EIGEN_GPUCC) +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float tanh(const float &x) { return ::tanhf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double tanh(const double &x) { return ::tanh(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T fmod(const T& a, const T& b) { + EIGEN_USING_STD(fmod); + return fmod(a, b); +} + +#if defined(SYCL_DEVICE_ONLY) +SYCL_SPECIALIZE_FLOATING_TYPES_BINARY(fmod, fmod) +#endif + +#if defined(EIGEN_GPUCC) +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float fmod(const float& a, const float& b) { + return ::fmodf(a, b); +} + +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double fmod(const double& a, const double& b) { + return ::fmod(a, b); +} +#endif + +#if defined(SYCL_DEVICE_ONLY) +#undef SYCL_SPECIALIZE_SIGNED_INTEGER_TYPES_BINARY +#undef SYCL_SPECIALIZE_SIGNED_INTEGER_TYPES_UNARY +#undef SYCL_SPECIALIZE_UNSIGNED_INTEGER_TYPES_BINARY +#undef SYCL_SPECIALIZE_UNSIGNED_INTEGER_TYPES_UNARY +#undef SYCL_SPECIALIZE_INTEGER_TYPES_BINARY +#undef SYCL_SPECIALIZE_UNSIGNED_INTEGER_TYPES_UNARY +#undef SYCL_SPECIALIZE_FLOATING_TYPES_BINARY +#undef SYCL_SPECIALIZE_FLOATING_TYPES_UNARY +#undef SYCL_SPECIALIZE_FLOATING_TYPES_UNARY_FUNC_RET_TYPE +#undef SYCL_SPECIALIZE_GEN_UNARY_FUNC +#undef SYCL_SPECIALIZE_UNARY_FUNC +#undef SYCL_SPECIALIZE_GEN1_BINARY_FUNC +#undef SYCL_SPECIALIZE_GEN2_BINARY_FUNC +#undef SYCL_SPECIALIZE_BINARY_FUNC +#endif + +} // end namespace numext + +namespace internal { + +template +EIGEN_DEVICE_FUNC bool isfinite_impl(const std::complex& x) +{ + return (numext::isfinite)(numext::real(x)) && (numext::isfinite)(numext::imag(x)); +} + +template +EIGEN_DEVICE_FUNC bool isnan_impl(const std::complex& x) +{ + return (numext::isnan)(numext::real(x)) || (numext::isnan)(numext::imag(x)); +} + +template +EIGEN_DEVICE_FUNC bool isinf_impl(const std::complex& x) +{ + return ((numext::isinf)(numext::real(x)) || (numext::isinf)(numext::imag(x))) && (!(numext::isnan)(x)); +} + +/**************************************************************************** +* Implementation of fuzzy comparisons * +****************************************************************************/ + +template +struct scalar_fuzzy_default_impl {}; + +template +struct scalar_fuzzy_default_impl +{ + typedef typename NumTraits::Real RealScalar; + template EIGEN_DEVICE_FUNC + static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) + { + return numext::abs(x) <= numext::abs(y) * prec; + } + EIGEN_DEVICE_FUNC + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + return numext::abs(x - y) <= numext::mini(numext::abs(x), numext::abs(y)) * prec; + } + EIGEN_DEVICE_FUNC + static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + return x <= y || isApprox(x, y, prec); + } +}; + +template +struct scalar_fuzzy_default_impl +{ + typedef typename NumTraits::Real RealScalar; + template EIGEN_DEVICE_FUNC + static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) + { + return x == Scalar(0); + } + EIGEN_DEVICE_FUNC + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) + { + return x == y; + } + EIGEN_DEVICE_FUNC + static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) + { + return x <= y; + } +}; + +template +struct scalar_fuzzy_default_impl +{ + typedef typename NumTraits::Real RealScalar; + template EIGEN_DEVICE_FUNC + static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) + { + return numext::abs2(x) <= numext::abs2(y) * prec * prec; + } + EIGEN_DEVICE_FUNC + static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) + { + return numext::abs2(x - y) <= numext::mini(numext::abs2(x), numext::abs2(y)) * prec * prec; + } +}; + +template +struct scalar_fuzzy_impl : scalar_fuzzy_default_impl::IsComplex, NumTraits::IsInteger> {}; + +template EIGEN_DEVICE_FUNC +inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, + const typename NumTraits::Real &precision = NumTraits::dummy_precision()) +{ + return scalar_fuzzy_impl::template isMuchSmallerThan(x, y, precision); +} + +template EIGEN_DEVICE_FUNC +inline bool isApprox(const Scalar& x, const Scalar& y, + const typename NumTraits::Real &precision = NumTraits::dummy_precision()) +{ + return scalar_fuzzy_impl::isApprox(x, y, precision); +} + +template EIGEN_DEVICE_FUNC +inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, + const typename NumTraits::Real &precision = NumTraits::dummy_precision()) +{ + return scalar_fuzzy_impl::isApproxOrLessThan(x, y, precision); +} + +/****************************************** +*** The special case of the bool type *** +******************************************/ + +template<> struct random_impl +{ + static inline bool run() + { + return random(0,1)==0 ? false : true; + } + + static inline bool run(const bool& a, const bool& b) + { + return random(a, b)==0 ? false : true; + } +}; + +template<> struct scalar_fuzzy_impl +{ + typedef bool RealScalar; + + template EIGEN_DEVICE_FUNC + static inline bool isMuchSmallerThan(const bool& x, const bool&, const bool&) + { + return !x; + } + + EIGEN_DEVICE_FUNC + static inline bool isApprox(bool x, bool y, bool) + { + return x == y; + } + + EIGEN_DEVICE_FUNC + static inline bool isApproxOrLessThan(const bool& x, const bool& y, const bool&) + { + return (!x) || y; + } + +}; + +} // end namespace internal + +// Default implementations that rely on other numext implementations +namespace internal { + +// Specialization for complex types that are not supported by std::expm1. +template +struct expm1_impl > { + EIGEN_DEVICE_FUNC static inline std::complex run( + const std::complex& x) { + EIGEN_STATIC_ASSERT_NON_INTEGER(RealScalar) + RealScalar xr = x.real(); + RealScalar xi = x.imag(); + // expm1(z) = exp(z) - 1 + // = exp(x + i * y) - 1 + // = exp(x) * (cos(y) + i * sin(y)) - 1 + // = exp(x) * cos(y) - 1 + i * exp(x) * sin(y) + // Imag(expm1(z)) = exp(x) * sin(y) + // Real(expm1(z)) = exp(x) * cos(y) - 1 + // = exp(x) * cos(y) - 1. + // = expm1(x) + exp(x) * (cos(y) - 1) + // = expm1(x) + exp(x) * (2 * sin(y / 2) ** 2) + RealScalar erm1 = numext::expm1(xr); + RealScalar er = erm1 + RealScalar(1.); + RealScalar sin2 = numext::sin(xi / RealScalar(2.)); + sin2 = sin2 * sin2; + RealScalar s = numext::sin(xi); + RealScalar real_part = erm1 - RealScalar(2.) * er * sin2; + return std::complex(real_part, er * s); + } +}; + +template +struct rsqrt_impl { + EIGEN_DEVICE_FUNC + static EIGEN_ALWAYS_INLINE T run(const T& x) { + return T(1)/numext::sqrt(x); + } +}; + +#if defined(EIGEN_GPU_COMPILE_PHASE) +template +struct conj_impl, true> +{ + EIGEN_DEVICE_FUNC + static inline std::complex run(const std::complex& x) + { + return std::complex(numext::real(x), -numext::imag(x)); + } +}; +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATHFUNCTIONS_H diff --git a/Vendor/eigen/Eigen/src/Core/MathFunctionsImpl.h b/Vendor/eigen/Eigen/src/Core/MathFunctionsImpl.h new file mode 100644 index 0000000..4eaaaa7 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/MathFunctionsImpl.h @@ -0,0 +1,200 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Pedro Gonnet (pedro.gonnet@gmail.com) +// Copyright (C) 2016 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATHFUNCTIONSIMPL_H +#define EIGEN_MATHFUNCTIONSIMPL_H + +namespace Eigen { + +namespace internal { + +/** \internal \returns the hyperbolic tan of \a a (coeff-wise) + Doesn't do anything fancy, just a 13/6-degree rational interpolant which + is accurate up to a couple of ulps in the (approximate) range [-8, 8], + outside of which tanh(x) = +/-1 in single precision. The input is clamped + to the range [-c, c]. The value c is chosen as the smallest value where + the approximation evaluates to exactly 1. In the reange [-0.0004, 0.0004] + the approxmation tanh(x) ~= x is used for better accuracy as x tends to zero. + + This implementation works on both scalars and packets. +*/ +template +T generic_fast_tanh_float(const T& a_x) +{ + // Clamp the inputs to the range [-c, c] +#ifdef EIGEN_VECTORIZE_FMA + const T plus_clamp = pset1(7.99881172180175781f); + const T minus_clamp = pset1(-7.99881172180175781f); +#else + const T plus_clamp = pset1(7.90531110763549805f); + const T minus_clamp = pset1(-7.90531110763549805f); +#endif + const T tiny = pset1(0.0004f); + const T x = pmax(pmin(a_x, plus_clamp), minus_clamp); + const T tiny_mask = pcmp_lt(pabs(a_x), tiny); + // The monomial coefficients of the numerator polynomial (odd). + const T alpha_1 = pset1(4.89352455891786e-03f); + const T alpha_3 = pset1(6.37261928875436e-04f); + const T alpha_5 = pset1(1.48572235717979e-05f); + const T alpha_7 = pset1(5.12229709037114e-08f); + const T alpha_9 = pset1(-8.60467152213735e-11f); + const T alpha_11 = pset1(2.00018790482477e-13f); + const T alpha_13 = pset1(-2.76076847742355e-16f); + + // The monomial coefficients of the denominator polynomial (even). + const T beta_0 = pset1(4.89352518554385e-03f); + const T beta_2 = pset1(2.26843463243900e-03f); + const T beta_4 = pset1(1.18534705686654e-04f); + const T beta_6 = pset1(1.19825839466702e-06f); + + // Since the polynomials are odd/even, we need x^2. + const T x2 = pmul(x, x); + + // Evaluate the numerator polynomial p. + T p = pmadd(x2, alpha_13, alpha_11); + p = pmadd(x2, p, alpha_9); + p = pmadd(x2, p, alpha_7); + p = pmadd(x2, p, alpha_5); + p = pmadd(x2, p, alpha_3); + p = pmadd(x2, p, alpha_1); + p = pmul(x, p); + + // Evaluate the denominator polynomial q. + T q = pmadd(x2, beta_6, beta_4); + q = pmadd(x2, q, beta_2); + q = pmadd(x2, q, beta_0); + + // Divide the numerator by the denominator. + return pselect(tiny_mask, x, pdiv(p, q)); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +RealScalar positive_real_hypot(const RealScalar& x, const RealScalar& y) +{ + // IEEE IEC 6059 special cases. + if ((numext::isinf)(x) || (numext::isinf)(y)) + return NumTraits::infinity(); + if ((numext::isnan)(x) || (numext::isnan)(y)) + return NumTraits::quiet_NaN(); + + EIGEN_USING_STD(sqrt); + RealScalar p, qp; + p = numext::maxi(x,y); + if(p==RealScalar(0)) return RealScalar(0); + qp = numext::mini(y,x) / p; + return p * sqrt(RealScalar(1) + qp*qp); +} + +template +struct hypot_impl +{ + typedef typename NumTraits::Real RealScalar; + static EIGEN_DEVICE_FUNC + inline RealScalar run(const Scalar& x, const Scalar& y) + { + EIGEN_USING_STD(abs); + return positive_real_hypot(abs(x), abs(y)); + } +}; + +// Generic complex sqrt implementation that correctly handles corner cases +// according to https://en.cppreference.com/w/cpp/numeric/complex/sqrt +template +EIGEN_DEVICE_FUNC std::complex complex_sqrt(const std::complex& z) { + // Computes the principal sqrt of the input. + // + // For a complex square root of the number x + i*y. We want to find real + // numbers u and v such that + // (u + i*v)^2 = x + i*y <=> + // u^2 - v^2 + i*2*u*v = x + i*v. + // By equating the real and imaginary parts we get: + // u^2 - v^2 = x + // 2*u*v = y. + // + // For x >= 0, this has the numerically stable solution + // u = sqrt(0.5 * (x + sqrt(x^2 + y^2))) + // v = y / (2 * u) + // and for x < 0, + // v = sign(y) * sqrt(0.5 * (-x + sqrt(x^2 + y^2))) + // u = y / (2 * v) + // + // Letting w = sqrt(0.5 * (|x| + |z|)), + // if x == 0: u = w, v = sign(y) * w + // if x > 0: u = w, v = y / (2 * w) + // if x < 0: u = |y| / (2 * w), v = sign(y) * w + + const T x = numext::real(z); + const T y = numext::imag(z); + const T zero = T(0); + const T w = numext::sqrt(T(0.5) * (numext::abs(x) + numext::hypot(x, y))); + + return + (numext::isinf)(y) ? std::complex(NumTraits::infinity(), y) + : x == zero ? std::complex(w, y < zero ? -w : w) + : x > zero ? std::complex(w, y / (2 * w)) + : std::complex(numext::abs(y) / (2 * w), y < zero ? -w : w ); +} + +// Generic complex rsqrt implementation. +template +EIGEN_DEVICE_FUNC std::complex complex_rsqrt(const std::complex& z) { + // Computes the principal reciprocal sqrt of the input. + // + // For a complex reciprocal square root of the number z = x + i*y. We want to + // find real numbers u and v such that + // (u + i*v)^2 = 1 / (x + i*y) <=> + // u^2 - v^2 + i*2*u*v = x/|z|^2 - i*v/|z|^2. + // By equating the real and imaginary parts we get: + // u^2 - v^2 = x/|z|^2 + // 2*u*v = y/|z|^2. + // + // For x >= 0, this has the numerically stable solution + // u = sqrt(0.5 * (x + |z|)) / |z| + // v = -y / (2 * u * |z|) + // and for x < 0, + // v = -sign(y) * sqrt(0.5 * (-x + |z|)) / |z| + // u = -y / (2 * v * |z|) + // + // Letting w = sqrt(0.5 * (|x| + |z|)), + // if x == 0: u = w / |z|, v = -sign(y) * w / |z| + // if x > 0: u = w / |z|, v = -y / (2 * w * |z|) + // if x < 0: u = |y| / (2 * w * |z|), v = -sign(y) * w / |z| + + const T x = numext::real(z); + const T y = numext::imag(z); + const T zero = T(0); + + const T abs_z = numext::hypot(x, y); + const T w = numext::sqrt(T(0.5) * (numext::abs(x) + abs_z)); + const T woz = w / abs_z; + // Corner cases consistent with 1/sqrt(z) on gcc/clang. + return + abs_z == zero ? std::complex(NumTraits::infinity(), NumTraits::quiet_NaN()) + : ((numext::isinf)(x) || (numext::isinf)(y)) ? std::complex(zero, zero) + : x == zero ? std::complex(woz, y < zero ? woz : -woz) + : x > zero ? std::complex(woz, -y / (2 * w * abs_z)) + : std::complex(numext::abs(y) / (2 * w * abs_z), y < zero ? woz : -woz ); +} + +template +EIGEN_DEVICE_FUNC std::complex complex_log(const std::complex& z) { + // Computes complex log. + T a = numext::abs(z); + EIGEN_USING_STD(atan2); + T b = atan2(z.imag(), z.real()); + return std::complex(numext::log(a), b); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATHFUNCTIONSIMPL_H diff --git a/Vendor/eigen/Eigen/src/Core/Matrix.h b/Vendor/eigen/Eigen/src/Core/Matrix.h new file mode 100644 index 0000000..f0e59a9 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Matrix.h @@ -0,0 +1,565 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2010 Benoit Jacob +// Copyright (C) 2008-2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATRIX_H +#define EIGEN_MATRIX_H + +namespace Eigen { + +namespace internal { +template +struct traits > +{ +private: + enum { size = internal::size_at_compile_time<_Rows,_Cols>::ret }; + typedef typename find_best_packet<_Scalar,size>::type PacketScalar; + enum { + row_major_bit = _Options&RowMajor ? RowMajorBit : 0, + is_dynamic_size_storage = _MaxRows==Dynamic || _MaxCols==Dynamic, + max_size = is_dynamic_size_storage ? Dynamic : _MaxRows*_MaxCols, + default_alignment = compute_default_alignment<_Scalar,max_size>::value, + actual_alignment = ((_Options&DontAlign)==0) ? default_alignment : 0, + required_alignment = unpacket_traits::alignment, + packet_access_bit = (packet_traits<_Scalar>::Vectorizable && (EIGEN_UNALIGNED_VECTORIZE || (actual_alignment>=required_alignment))) ? PacketAccessBit : 0 + }; + +public: + typedef _Scalar Scalar; + typedef Dense StorageKind; + typedef Eigen::Index StorageIndex; + typedef MatrixXpr XprKind; + enum { + RowsAtCompileTime = _Rows, + ColsAtCompileTime = _Cols, + MaxRowsAtCompileTime = _MaxRows, + MaxColsAtCompileTime = _MaxCols, + Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, + Options = _Options, + InnerStrideAtCompileTime = 1, + OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime, + + // FIXME, the following flag in only used to define NeedsToAlign in PlainObjectBase + EvaluatorFlags = LinearAccessBit | DirectAccessBit | packet_access_bit | row_major_bit, + Alignment = actual_alignment + }; +}; +} + +/** \class Matrix + * \ingroup Core_Module + * + * \brief The matrix class, also used for vectors and row-vectors + * + * The %Matrix class is the work-horse for all \em dense (\ref dense "note") matrices and vectors within Eigen. + * Vectors are matrices with one column, and row-vectors are matrices with one row. + * + * The %Matrix class encompasses \em both fixed-size and dynamic-size objects (\ref fixedsize "note"). + * + * The first three template parameters are required: + * \tparam _Scalar Numeric type, e.g. float, double, int or std::complex. + * User defined scalar types are supported as well (see \ref user_defined_scalars "here"). + * \tparam _Rows Number of rows, or \b Dynamic + * \tparam _Cols Number of columns, or \b Dynamic + * + * The remaining template parameters are optional -- in most cases you don't have to worry about them. + * \tparam _Options A combination of either \b #RowMajor or \b #ColMajor, and of either + * \b #AutoAlign or \b #DontAlign. + * The former controls \ref TopicStorageOrders "storage order", and defaults to column-major. The latter controls alignment, which is required + * for vectorization. It defaults to aligning matrices except for fixed sizes that aren't a multiple of the packet size. + * \tparam _MaxRows Maximum number of rows. Defaults to \a _Rows (\ref maxrows "note"). + * \tparam _MaxCols Maximum number of columns. Defaults to \a _Cols (\ref maxrows "note"). + * + * Eigen provides a number of typedefs covering the usual cases. Here are some examples: + * + * \li \c Matrix2d is a 2x2 square matrix of doubles (\c Matrix) + * \li \c Vector4f is a vector of 4 floats (\c Matrix) + * \li \c RowVector3i is a row-vector of 3 ints (\c Matrix) + * + * \li \c MatrixXf is a dynamic-size matrix of floats (\c Matrix) + * \li \c VectorXf is a dynamic-size vector of floats (\c Matrix) + * + * \li \c Matrix2Xf is a partially fixed-size (dynamic-size) matrix of floats (\c Matrix) + * \li \c MatrixX3d is a partially dynamic-size (fixed-size) matrix of double (\c Matrix) + * + * See \link matrixtypedefs this page \endlink for a complete list of predefined \em %Matrix and \em Vector typedefs. + * + * You can access elements of vectors and matrices using normal subscripting: + * + * \code + * Eigen::VectorXd v(10); + * v[0] = 0.1; + * v[1] = 0.2; + * v(0) = 0.3; + * v(1) = 0.4; + * + * Eigen::MatrixXi m(10, 10); + * m(0, 1) = 1; + * m(0, 2) = 2; + * m(0, 3) = 3; + * \endcode + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_MATRIX_PLUGIN. + * + * Some notes: + * + *

+ *
\anchor dense Dense versus sparse:
+ *
This %Matrix class handles dense, not sparse matrices and vectors. For sparse matrices and vectors, see the Sparse module. + * + * Dense matrices and vectors are plain usual arrays of coefficients. All the coefficients are stored, in an ordinary contiguous array. + * This is unlike Sparse matrices and vectors where the coefficients are stored as a list of nonzero coefficients.
+ * + *
\anchor fixedsize Fixed-size versus dynamic-size:
+ *
Fixed-size means that the numbers of rows and columns are known are compile-time. In this case, Eigen allocates the array + * of coefficients as a fixed-size array, as a class member. This makes sense for very small matrices, typically up to 4x4, sometimes up + * to 16x16. Larger matrices should be declared as dynamic-size even if one happens to know their size at compile-time. + * + * Dynamic-size means that the numbers of rows or columns are not necessarily known at compile-time. In this case they are runtime + * variables, and the array of coefficients is allocated dynamically on the heap. + * + * Note that \em dense matrices, be they Fixed-size or Dynamic-size, do not expand dynamically in the sense of a std::map. + * If you want this behavior, see the Sparse module.
+ * + *
\anchor maxrows _MaxRows and _MaxCols:
+ *
In most cases, one just leaves these parameters to the default values. + * These parameters mean the maximum size of rows and columns that the matrix may have. They are useful in cases + * when the exact numbers of rows and columns are not known are compile-time, but it is known at compile-time that they cannot + * exceed a certain value. This happens when taking dynamic-size blocks inside fixed-size matrices: in this case _MaxRows and _MaxCols + * are the dimensions of the original matrix, while _Rows and _Cols are Dynamic.
+ *
+ * + * ABI and storage layout + * + * The table below summarizes the ABI of some possible Matrix instances which is fixed thorough the lifetime of Eigen 3. + * + * + * + * + * + * + *
Matrix typeEquivalent C structure
\code Matrix \endcode\code + * struct { + * T *data; // with (size_t(data)%EIGEN_MAX_ALIGN_BYTES)==0 + * Eigen::Index rows, cols; + * }; + * \endcode
\code + * Matrix + * Matrix \endcode\code + * struct { + * T *data; // with (size_t(data)%EIGEN_MAX_ALIGN_BYTES)==0 + * Eigen::Index size; + * }; + * \endcode
\code Matrix \endcode\code + * struct { + * T data[Rows*Cols]; // with (size_t(data)%A(Rows*Cols*sizeof(T)))==0 + * }; + * \endcode
\code Matrix \endcode\code + * struct { + * T data[MaxRows*MaxCols]; // with (size_t(data)%A(MaxRows*MaxCols*sizeof(T)))==0 + * Eigen::Index rows, cols; + * }; + * \endcode
+ * Note that in this table Rows, Cols, MaxRows and MaxCols are all positive integers. A(S) is defined to the largest possible power-of-two + * smaller to EIGEN_MAX_STATIC_ALIGN_BYTES. + * + * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy, + * \ref TopicStorageOrders + */ + +template +class Matrix + : public PlainObjectBase > +{ + public: + + /** \brief Base class typedef. + * \sa PlainObjectBase + */ + typedef PlainObjectBase Base; + + enum { Options = _Options }; + + EIGEN_DENSE_PUBLIC_INTERFACE(Matrix) + + typedef typename Base::PlainObject PlainObject; + + using Base::base; + using Base::coeffRef; + + /** + * \brief Assigns matrices to each other. + * + * \note This is a special case of the templated operator=. Its purpose is + * to prevent a default operator= from hiding the templated operator=. + * + * \callgraph + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix& operator=(const Matrix& other) + { + return Base::_set(other); + } + + /** \internal + * \brief Copies the value of the expression \a other into \c *this with automatic resizing. + * + * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), + * it will be initialized. + * + * Note that copying a row-vector into a vector (and conversely) is allowed. + * The resizing, if any, is then done in the appropriate way so that row-vectors + * remain row-vectors and vectors remain vectors. + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix& operator=(const DenseBase& other) + { + return Base::_set(other); + } + + /* Here, doxygen failed to copy the brief information when using \copydoc */ + + /** + * \brief Copies the generic expression \a other into *this. + * \copydetails DenseBase::operator=(const EigenBase &other) + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix& operator=(const EigenBase &other) + { + return Base::operator=(other); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue& func) + { + return Base::operator=(func); + } + + /** \brief Default constructor. + * + * For fixed-size matrices, does nothing. + * + * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix + * is called a null matrix. This constructor is the unique way to create null matrices: resizing + * a matrix to 0 is not supported. + * + * \sa resize(Index,Index) + */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Matrix() : Base() + { + Base::_check_template_params(); + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + + // FIXME is it still needed + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit Matrix(internal::constructor_without_unaligned_array_assert) + : Base(internal::constructor_without_unaligned_array_assert()) + { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } + +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Matrix(Matrix&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_constructible::value) + : Base(std::move(other)) + { + Base::_check_template_params(); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Matrix& operator=(Matrix&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_assignable::value) + { + Base::operator=(std::move(other)); + return *this; + } +#endif + +#if EIGEN_HAS_CXX11 + /** \copydoc PlainObjectBase(const Scalar&, const Scalar&, const Scalar&, const Scalar&, const ArgTypes&... args) + * + * Example: \include Matrix_variadic_ctor_cxx11.cpp + * Output: \verbinclude Matrix_variadic_ctor_cxx11.out + * + * \sa Matrix(const std::initializer_list>&) + */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Matrix(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) + : Base(a0, a1, a2, a3, args...) {} + + /** \brief Constructs a Matrix and initializes it from the coefficients given as initializer-lists grouped by row. \cpp11 + * + * In the general case, the constructor takes a list of rows, each row being represented as a list of coefficients: + * + * Example: \include Matrix_initializer_list_23_cxx11.cpp + * Output: \verbinclude Matrix_initializer_list_23_cxx11.out + * + * Each of the inner initializer lists must contain the exact same number of elements, otherwise an assertion is triggered. + * + * In the case of a compile-time column vector, implicit transposition from a single row is allowed. + * Therefore VectorXd{{1,2,3,4,5}} is legal and the more verbose syntax + * RowVectorXd{{1},{2},{3},{4},{5}} can be avoided: + * + * Example: \include Matrix_initializer_list_vector_cxx11.cpp + * Output: \verbinclude Matrix_initializer_list_vector_cxx11.out + * + * In the case of fixed-sized matrices, the initializer list sizes must exactly match the matrix sizes, + * and implicit transposition is allowed for compile-time vectors only. + * + * \sa Matrix(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) + */ + EIGEN_DEVICE_FUNC + explicit EIGEN_STRONG_INLINE Matrix(const std::initializer_list>& list) : Base(list) {} +#endif // end EIGEN_HAS_CXX11 + +#ifndef EIGEN_PARSED_BY_DOXYGEN + + // This constructor is for both 1x1 matrices and dynamic vectors + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit Matrix(const T& x) + { + Base::_check_template_params(); + Base::template _init1(x); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Matrix(const T0& x, const T1& y) + { + Base::_check_template_params(); + Base::template _init2(x, y); + } + + +#else + /** \brief Constructs a fixed-sized matrix initialized with coefficients starting at \a data */ + EIGEN_DEVICE_FUNC + explicit Matrix(const Scalar *data); + + /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors + * + * This is useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass these parameters, so one should use the default constructor + * Matrix() instead. + * + * \warning This constructor is disabled for fixed-size \c 1x1 matrices. For instance, + * calling Matrix(1) will call the initialization constructor: Matrix(const Scalar&). + * For fixed-size \c 1x1 matrices it is therefore recommended to use the default + * constructor Matrix() instead, especially when using one of the non standard + * \c EIGEN_INITIALIZE_MATRICES_BY_{ZERO,\c NAN} macros (see \ref TopicPreprocessorDirectives). + */ + EIGEN_STRONG_INLINE explicit Matrix(Index dim); + /** \brief Constructs an initialized 1x1 matrix with the given coefficient + * \sa Matrix(const Scalar&, const Scalar&, const Scalar&, const Scalar&, const ArgTypes&...) */ + Matrix(const Scalar& x); + /** \brief Constructs an uninitialized matrix with \a rows rows and \a cols columns. + * + * This is useful for dynamic-size matrices. For fixed-size matrices, + * it is redundant to pass these parameters, so one should use the default constructor + * Matrix() instead. + * + * \warning This constructor is disabled for fixed-size \c 1x2 and \c 2x1 vectors. For instance, + * calling Matrix2f(2,1) will call the initialization constructor: Matrix(const Scalar& x, const Scalar& y). + * For fixed-size \c 1x2 or \c 2x1 vectors it is therefore recommended to use the default + * constructor Matrix() instead, especially when using one of the non standard + * \c EIGEN_INITIALIZE_MATRICES_BY_{ZERO,\c NAN} macros (see \ref TopicPreprocessorDirectives). + */ + EIGEN_DEVICE_FUNC + Matrix(Index rows, Index cols); + + /** \brief Constructs an initialized 2D vector with given coefficients + * \sa Matrix(const Scalar&, const Scalar&, const Scalar&, const Scalar&, const ArgTypes&...) */ + Matrix(const Scalar& x, const Scalar& y); + #endif // end EIGEN_PARSED_BY_DOXYGEN + + /** \brief Constructs an initialized 3D vector with given coefficients + * \sa Matrix(const Scalar&, const Scalar&, const Scalar&, const Scalar&, const ArgTypes&...) + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3) + m_storage.data()[0] = x; + m_storage.data()[1] = y; + m_storage.data()[2] = z; + } + /** \brief Constructs an initialized 4D vector with given coefficients + * \sa Matrix(const Scalar&, const Scalar&, const Scalar&, const Scalar&, const ArgTypes&...) + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w) + { + Base::_check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4) + m_storage.data()[0] = x; + m_storage.data()[1] = y; + m_storage.data()[2] = z; + m_storage.data()[3] = w; + } + + + /** \brief Copy constructor */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix(const Matrix& other) : Base(other) + { } + + /** \brief Copy constructor for generic expressions. + * \sa MatrixBase::operator=(const EigenBase&) + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix(const EigenBase &other) + : Base(other.derived()) + { } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index innerStride() const EIGEN_NOEXCEPT { return 1; } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index outerStride() const EIGEN_NOEXCEPT { return this->innerSize(); } + + /////////// Geometry module /////////// + + template + EIGEN_DEVICE_FUNC + explicit Matrix(const RotationBase& r); + template + EIGEN_DEVICE_FUNC + Matrix& operator=(const RotationBase& r); + + // allow to extend Matrix outside Eigen + #ifdef EIGEN_MATRIX_PLUGIN + #include EIGEN_MATRIX_PLUGIN + #endif + + protected: + template + friend struct internal::conservative_resize_like_impl; + + using Base::m_storage; +}; + +/** \defgroup matrixtypedefs Global matrix typedefs + * + * \ingroup Core_Module + * + * %Eigen defines several typedef shortcuts for most common matrix and vector types. + * + * The general patterns are the following: + * + * \c MatrixSizeType where \c Size can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size, + * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd + * for complex double. + * + * For example, \c Matrix3d is a fixed-size 3x3 matrix type of doubles, and \c MatrixXf is a dynamic-size matrix of floats. + * + * There are also \c VectorSizeType and \c RowVectorSizeType which are self-explanatory. For example, \c Vector4cf is + * a fixed-size vector of 4 complex floats. + * + * With \cpp11, template alias are also defined for common sizes. + * They follow the same pattern as above except that the scalar type suffix is replaced by a + * template parameter, i.e.: + * - `MatrixSize` where `Size` can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size. + * - `MatrixXSize` and `MatrixSizeX` where `Size` can be \c 2,\c 3,\c 4 for hybrid dynamic/fixed matrices. + * - `VectorSize` and `RowVectorSize` for column and row vectors. + * + * With \cpp11, you can also use fully generic column and row vector types: `Vector` and `RowVector`. + * + * \sa class Matrix + */ + +#define EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ +/** \ingroup matrixtypedefs */ \ +typedef Matrix Matrix##SizeSuffix##TypeSuffix; \ +/** \ingroup matrixtypedefs */ \ +typedef Matrix Vector##SizeSuffix##TypeSuffix; \ +/** \ingroup matrixtypedefs */ \ +typedef Matrix RowVector##SizeSuffix##TypeSuffix; + +#define EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \ +/** \ingroup matrixtypedefs */ \ +typedef Matrix Matrix##Size##X##TypeSuffix; \ +/** \ingroup matrixtypedefs */ \ +typedef Matrix Matrix##X##Size##TypeSuffix; + +#define EIGEN_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \ +EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \ +EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \ +EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \ +EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 4) + +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(int, i) +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(float, f) +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(double, d) +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cf) +EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cd) + +#undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES +#undef EIGEN_MAKE_TYPEDEFS +#undef EIGEN_MAKE_FIXED_TYPEDEFS + +#if EIGEN_HAS_CXX11 + +#define EIGEN_MAKE_TYPEDEFS(Size, SizeSuffix) \ +/** \ingroup matrixtypedefs */ \ +/** \brief \cpp11 */ \ +template \ +using Matrix##SizeSuffix = Matrix; \ +/** \ingroup matrixtypedefs */ \ +/** \brief \cpp11 */ \ +template \ +using Vector##SizeSuffix = Matrix; \ +/** \ingroup matrixtypedefs */ \ +/** \brief \cpp11 */ \ +template \ +using RowVector##SizeSuffix = Matrix; + +#define EIGEN_MAKE_FIXED_TYPEDEFS(Size) \ +/** \ingroup matrixtypedefs */ \ +/** \brief \cpp11 */ \ +template \ +using Matrix##Size##X = Matrix; \ +/** \ingroup matrixtypedefs */ \ +/** \brief \cpp11 */ \ +template \ +using Matrix##X##Size = Matrix; + +EIGEN_MAKE_TYPEDEFS(2, 2) +EIGEN_MAKE_TYPEDEFS(3, 3) +EIGEN_MAKE_TYPEDEFS(4, 4) +EIGEN_MAKE_TYPEDEFS(Dynamic, X) +EIGEN_MAKE_FIXED_TYPEDEFS(2) +EIGEN_MAKE_FIXED_TYPEDEFS(3) +EIGEN_MAKE_FIXED_TYPEDEFS(4) + +/** \ingroup matrixtypedefs + * \brief \cpp11 */ +template +using Vector = Matrix; + +/** \ingroup matrixtypedefs + * \brief \cpp11 */ +template +using RowVector = Matrix; + +#undef EIGEN_MAKE_TYPEDEFS +#undef EIGEN_MAKE_FIXED_TYPEDEFS + +#endif // EIGEN_HAS_CXX11 + +} // end namespace Eigen + +#endif // EIGEN_MATRIX_H diff --git a/Vendor/eigen/Eigen/src/Core/MatrixBase.h b/Vendor/eigen/Eigen/src/Core/MatrixBase.h new file mode 100644 index 0000000..45c3a59 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/MatrixBase.h @@ -0,0 +1,547 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2009 Benoit Jacob +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATRIXBASE_H +#define EIGEN_MATRIXBASE_H + +namespace Eigen { + +/** \class MatrixBase + * \ingroup Core_Module + * + * \brief Base class for all dense matrices, vectors, and expressions + * + * This class is the base that is inherited by all matrix, vector, and related expression + * types. Most of the Eigen API is contained in this class, and its base classes. Other important + * classes for the Eigen API are Matrix, and VectorwiseOp. + * + * Note that some methods are defined in other modules such as the \ref LU_Module LU module + * for all functions related to matrix inversions. + * + * \tparam Derived is the derived type, e.g. a matrix type, or an expression, etc. + * + * When writing a function taking Eigen objects as argument, if you want your function + * to take as argument any matrix, vector, or expression, just let it take a + * MatrixBase argument. As an example, here is a function printFirstRow which, given + * a matrix, vector, or expression \a x, prints the first row of \a x. + * + * \code + template + void printFirstRow(const Eigen::MatrixBase& x) + { + cout << x.row(0) << endl; + } + * \endcode + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_MATRIXBASE_PLUGIN. + * + * \sa \blank \ref TopicClassHierarchy + */ +template class MatrixBase + : public DenseBase +{ + public: +#ifndef EIGEN_PARSED_BY_DOXYGEN + typedef MatrixBase StorageBaseType; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::StorageIndex StorageIndex; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + + typedef DenseBase Base; + using Base::RowsAtCompileTime; + using Base::ColsAtCompileTime; + using Base::SizeAtCompileTime; + using Base::MaxRowsAtCompileTime; + using Base::MaxColsAtCompileTime; + using Base::MaxSizeAtCompileTime; + using Base::IsVectorAtCompileTime; + using Base::Flags; + + using Base::derived; + using Base::const_cast_derived; + using Base::rows; + using Base::cols; + using Base::size; + using Base::coeff; + using Base::coeffRef; + using Base::lazyAssign; + using Base::eval; + using Base::operator-; + using Base::operator+=; + using Base::operator-=; + using Base::operator*=; + using Base::operator/=; + + typedef typename Base::CoeffReturnType CoeffReturnType; + typedef typename Base::ConstTransposeReturnType ConstTransposeReturnType; + typedef typename Base::RowXpr RowXpr; + typedef typename Base::ColXpr ColXpr; +#endif // not EIGEN_PARSED_BY_DOXYGEN + + + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** type of the equivalent square matrix */ + typedef Matrix SquareMatrixType; +#endif // not EIGEN_PARSED_BY_DOXYGEN + + /** \returns the size of the main diagonal, which is min(rows(),cols()). + * \sa rows(), cols(), SizeAtCompileTime. */ + EIGEN_DEVICE_FUNC + inline Index diagonalSize() const { return (numext::mini)(rows(),cols()); } + + typedef typename Base::PlainObject PlainObject; + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal Represents a matrix with all coefficients equal to one another*/ + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; + /** \internal the return type of MatrixBase::adjoint() */ + typedef typename internal::conditional::IsComplex, + CwiseUnaryOp, ConstTransposeReturnType>, + ConstTransposeReturnType + >::type AdjointReturnType; + /** \internal Return type of eigenvalues() */ + typedef Matrix, internal::traits::ColsAtCompileTime, 1, ColMajor> EigenvaluesReturnType; + /** \internal the return type of identity */ + typedef CwiseNullaryOp,PlainObject> IdentityReturnType; + /** \internal the return type of unit vectors */ + typedef Block, SquareMatrixType>, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime> BasisReturnType; +#endif // not EIGEN_PARSED_BY_DOXYGEN + +#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase +#define EIGEN_DOC_UNARY_ADDONS(X,Y) +# include "../plugins/CommonCwiseBinaryOps.h" +# include "../plugins/MatrixCwiseUnaryOps.h" +# include "../plugins/MatrixCwiseBinaryOps.h" +# ifdef EIGEN_MATRIXBASE_PLUGIN +# include EIGEN_MATRIXBASE_PLUGIN +# endif +#undef EIGEN_CURRENT_STORAGE_BASE_CLASS +#undef EIGEN_DOC_UNARY_ADDONS + + /** Special case of the template operator=, in order to prevent the compiler + * from generating a default operator= (issue hit with g++ 4.1) + */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator=(const MatrixBase& other); + + // We cannot inherit here via Base::operator= since it is causing + // trouble with MSVC. + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator=(const DenseBase& other); + + template + EIGEN_DEVICE_FUNC + Derived& operator=(const EigenBase& other); + + template + EIGEN_DEVICE_FUNC + Derived& operator=(const ReturnByValue& other); + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator+=(const MatrixBase& other); + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator-=(const MatrixBase& other); + + template + EIGEN_DEVICE_FUNC + const Product + operator*(const MatrixBase &other) const; + + template + EIGEN_DEVICE_FUNC + const Product + lazyProduct(const MatrixBase &other) const; + + template + Derived& operator*=(const EigenBase& other); + + template + void applyOnTheLeft(const EigenBase& other); + + template + void applyOnTheRight(const EigenBase& other); + + template + EIGEN_DEVICE_FUNC + const Product + operator*(const DiagonalBase &diagonal) const; + + template + EIGEN_DEVICE_FUNC + typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType + dot(const MatrixBase& other) const; + + EIGEN_DEVICE_FUNC RealScalar squaredNorm() const; + EIGEN_DEVICE_FUNC RealScalar norm() const; + RealScalar stableNorm() const; + RealScalar blueNorm() const; + RealScalar hypotNorm() const; + EIGEN_DEVICE_FUNC const PlainObject normalized() const; + EIGEN_DEVICE_FUNC const PlainObject stableNormalized() const; + EIGEN_DEVICE_FUNC void normalize(); + EIGEN_DEVICE_FUNC void stableNormalize(); + + EIGEN_DEVICE_FUNC const AdjointReturnType adjoint() const; + EIGEN_DEVICE_FUNC void adjointInPlace(); + + typedef Diagonal DiagonalReturnType; + EIGEN_DEVICE_FUNC + DiagonalReturnType diagonal(); + + typedef typename internal::add_const >::type ConstDiagonalReturnType; + EIGEN_DEVICE_FUNC + ConstDiagonalReturnType diagonal() const; + + template struct DiagonalIndexReturnType { typedef Diagonal Type; }; + template struct ConstDiagonalIndexReturnType { typedef const Diagonal Type; }; + + template + EIGEN_DEVICE_FUNC + typename DiagonalIndexReturnType::Type diagonal(); + + template + EIGEN_DEVICE_FUNC + typename ConstDiagonalIndexReturnType::Type diagonal() const; + + typedef Diagonal DiagonalDynamicIndexReturnType; + typedef typename internal::add_const >::type ConstDiagonalDynamicIndexReturnType; + + EIGEN_DEVICE_FUNC + DiagonalDynamicIndexReturnType diagonal(Index index); + EIGEN_DEVICE_FUNC + ConstDiagonalDynamicIndexReturnType diagonal(Index index) const; + + template struct TriangularViewReturnType { typedef TriangularView Type; }; + template struct ConstTriangularViewReturnType { typedef const TriangularView Type; }; + + template + EIGEN_DEVICE_FUNC + typename TriangularViewReturnType::Type triangularView(); + template + EIGEN_DEVICE_FUNC + typename ConstTriangularViewReturnType::Type triangularView() const; + + template struct SelfAdjointViewReturnType { typedef SelfAdjointView Type; }; + template struct ConstSelfAdjointViewReturnType { typedef const SelfAdjointView Type; }; + + template + EIGEN_DEVICE_FUNC + typename SelfAdjointViewReturnType::Type selfadjointView(); + template + EIGEN_DEVICE_FUNC + typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; + + const SparseView sparseView(const Scalar& m_reference = Scalar(0), + const typename NumTraits::Real& m_epsilon = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC static const IdentityReturnType Identity(); + EIGEN_DEVICE_FUNC static const IdentityReturnType Identity(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const BasisReturnType Unit(Index size, Index i); + EIGEN_DEVICE_FUNC static const BasisReturnType Unit(Index i); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitX(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitY(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitZ(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitW(); + + EIGEN_DEVICE_FUNC + const DiagonalWrapper asDiagonal() const; + const PermutationWrapper asPermutation() const; + + EIGEN_DEVICE_FUNC + Derived& setIdentity(); + EIGEN_DEVICE_FUNC + Derived& setIdentity(Index rows, Index cols); + EIGEN_DEVICE_FUNC Derived& setUnit(Index i); + EIGEN_DEVICE_FUNC Derived& setUnit(Index newSize, Index i); + + bool isIdentity(const RealScalar& prec = NumTraits::dummy_precision()) const; + bool isDiagonal(const RealScalar& prec = NumTraits::dummy_precision()) const; + + bool isUpperTriangular(const RealScalar& prec = NumTraits::dummy_precision()) const; + bool isLowerTriangular(const RealScalar& prec = NumTraits::dummy_precision()) const; + + template + bool isOrthogonal(const MatrixBase& other, + const RealScalar& prec = NumTraits::dummy_precision()) const; + bool isUnitary(const RealScalar& prec = NumTraits::dummy_precision()) const; + + /** \returns true if each coefficients of \c *this and \a other are all exactly equal. + * \warning When using floating point scalar values you probably should rather use a + * fuzzy comparison such as isApprox() + * \sa isApprox(), operator!= */ + template + EIGEN_DEVICE_FUNC inline bool operator==(const MatrixBase& other) const + { return cwiseEqual(other).all(); } + + /** \returns true if at least one pair of coefficients of \c *this and \a other are not exactly equal to each other. + * \warning When using floating point scalar values you probably should rather use a + * fuzzy comparison such as isApprox() + * \sa isApprox(), operator== */ + template + EIGEN_DEVICE_FUNC inline bool operator!=(const MatrixBase& other) const + { return cwiseNotEqual(other).any(); } + + NoAlias EIGEN_DEVICE_FUNC noalias(); + + // TODO forceAlignedAccess is temporarily disabled + // Need to find a nicer workaround. + inline const Derived& forceAlignedAccess() const { return derived(); } + inline Derived& forceAlignedAccess() { return derived(); } + template inline const Derived& forceAlignedAccessIf() const { return derived(); } + template inline Derived& forceAlignedAccessIf() { return derived(); } + + EIGEN_DEVICE_FUNC Scalar trace() const; + + template EIGEN_DEVICE_FUNC RealScalar lpNorm() const; + + EIGEN_DEVICE_FUNC MatrixBase& matrix() { return *this; } + EIGEN_DEVICE_FUNC const MatrixBase& matrix() const { return *this; } + + /** \returns an \link Eigen::ArrayBase Array \endlink expression of this matrix + * \sa ArrayBase::matrix() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ArrayWrapper array() { return ArrayWrapper(derived()); } + /** \returns a const \link Eigen::ArrayBase Array \endlink expression of this matrix + * \sa ArrayBase::matrix() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const ArrayWrapper array() const { return ArrayWrapper(derived()); } + +/////////// LU module /////////// + + inline const FullPivLU fullPivLu() const; + inline const PartialPivLU partialPivLu() const; + + inline const PartialPivLU lu() const; + + EIGEN_DEVICE_FUNC + inline const Inverse inverse() const; + + template + inline void computeInverseAndDetWithCheck( + ResultType& inverse, + typename ResultType::Scalar& determinant, + bool& invertible, + const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() + ) const; + + template + inline void computeInverseWithCheck( + ResultType& inverse, + bool& invertible, + const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() + ) const; + + EIGEN_DEVICE_FUNC + Scalar determinant() const; + +/////////// Cholesky module /////////// + + inline const LLT llt() const; + inline const LDLT ldlt() const; + +/////////// QR module /////////// + + inline const HouseholderQR householderQr() const; + inline const ColPivHouseholderQR colPivHouseholderQr() const; + inline const FullPivHouseholderQR fullPivHouseholderQr() const; + inline const CompleteOrthogonalDecomposition completeOrthogonalDecomposition() const; + +/////////// Eigenvalues module /////////// + + inline EigenvaluesReturnType eigenvalues() const; + inline RealScalar operatorNorm() const; + +/////////// SVD module /////////// + + inline JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; + inline BDCSVD bdcSvd(unsigned int computationOptions = 0) const; + +/////////// Geometry module /////////// + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /// \internal helper struct to form the return type of the cross product + template struct cross_product_return_type { + typedef typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType Scalar; + typedef Matrix type; + }; + #endif // EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC +#ifndef EIGEN_PARSED_BY_DOXYGEN + inline typename cross_product_return_type::type +#else + inline PlainObject +#endif + cross(const MatrixBase& other) const; + + template + EIGEN_DEVICE_FUNC + inline PlainObject cross3(const MatrixBase& other) const; + + EIGEN_DEVICE_FUNC + inline PlainObject unitOrthogonal(void) const; + + EIGEN_DEVICE_FUNC + inline Matrix eulerAngles(Index a0, Index a1, Index a2) const; + + // put this as separate enum value to work around possible GCC 4.3 bug (?) + enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1&&RowsAtCompileTime==1 ? ((internal::traits::Flags&RowMajorBit)==RowMajorBit ? Horizontal : Vertical) + : ColsAtCompileTime==1 ? Vertical : Horizontal }; + typedef Homogeneous HomogeneousReturnType; + EIGEN_DEVICE_FUNC + inline HomogeneousReturnType homogeneous() const; + + enum { + SizeMinusOne = SizeAtCompileTime==Dynamic ? Dynamic : SizeAtCompileTime-1 + }; + typedef Block::ColsAtCompileTime==1 ? SizeMinusOne : 1, + internal::traits::ColsAtCompileTime==1 ? 1 : SizeMinusOne> ConstStartMinusOne; + typedef EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(ConstStartMinusOne,Scalar,quotient) HNormalizedReturnType; + EIGEN_DEVICE_FUNC + inline const HNormalizedReturnType hnormalized() const; + +////////// Householder module /////////// + + EIGEN_DEVICE_FUNC + void makeHouseholderInPlace(Scalar& tau, RealScalar& beta); + template + EIGEN_DEVICE_FUNC + void makeHouseholder(EssentialPart& essential, + Scalar& tau, RealScalar& beta) const; + template + EIGEN_DEVICE_FUNC + void applyHouseholderOnTheLeft(const EssentialPart& essential, + const Scalar& tau, + Scalar* workspace); + template + EIGEN_DEVICE_FUNC + void applyHouseholderOnTheRight(const EssentialPart& essential, + const Scalar& tau, + Scalar* workspace); + +///////// Jacobi module ///////// + + template + EIGEN_DEVICE_FUNC + void applyOnTheLeft(Index p, Index q, const JacobiRotation& j); + template + EIGEN_DEVICE_FUNC + void applyOnTheRight(Index p, Index q, const JacobiRotation& j); + +///////// SparseCore module ///////// + + template + EIGEN_STRONG_INLINE const typename SparseMatrixBase::template CwiseProductDenseReturnType::Type + cwiseProduct(const SparseMatrixBase &other) const + { + return other.cwiseProduct(derived()); + } + +///////// MatrixFunctions module ///////// + + typedef typename internal::stem_function::type StemFunction; +#define EIGEN_MATRIX_FUNCTION(ReturnType, Name, Description) \ + /** \returns an expression of the matrix Description of \c *this. \brief This function requires the unsupported MatrixFunctions module. To compute the coefficient-wise Description use ArrayBase::##Name . */ \ + const ReturnType Name() const; +#define EIGEN_MATRIX_FUNCTION_1(ReturnType, Name, Description, Argument) \ + /** \returns an expression of the matrix Description of \c *this. \brief This function requires the unsupported MatrixFunctions module. To compute the coefficient-wise Description use ArrayBase::##Name . */ \ + const ReturnType Name(Argument) const; + + EIGEN_MATRIX_FUNCTION(MatrixExponentialReturnValue, exp, exponential) + /** \brief Helper function for the unsupported MatrixFunctions module.*/ + const MatrixFunctionReturnValue matrixFunction(StemFunction f) const; + EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, cosh, hyperbolic cosine) + EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, sinh, hyperbolic sine) +#if EIGEN_HAS_CXX11_MATH + EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, atanh, inverse hyperbolic cosine) + EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, acosh, inverse hyperbolic cosine) + EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, asinh, inverse hyperbolic sine) +#endif + EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, cos, cosine) + EIGEN_MATRIX_FUNCTION(MatrixFunctionReturnValue, sin, sine) + EIGEN_MATRIX_FUNCTION(MatrixSquareRootReturnValue, sqrt, square root) + EIGEN_MATRIX_FUNCTION(MatrixLogarithmReturnValue, log, logarithm) + EIGEN_MATRIX_FUNCTION_1(MatrixPowerReturnValue, pow, power to \c p, const RealScalar& p) + EIGEN_MATRIX_FUNCTION_1(MatrixComplexPowerReturnValue, pow, power to \c p, const std::complex& p) + + protected: + EIGEN_DEFAULT_COPY_CONSTRUCTOR(MatrixBase) + EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(MatrixBase) + + private: + EIGEN_DEVICE_FUNC explicit MatrixBase(int); + EIGEN_DEVICE_FUNC MatrixBase(int,int); + template EIGEN_DEVICE_FUNC explicit MatrixBase(const MatrixBase&); + protected: + // mixing arrays and matrices is not legal + template Derived& operator+=(const ArrayBase& ) + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} + // mixing arrays and matrices is not legal + template Derived& operator-=(const ArrayBase& ) + {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} +}; + + +/*************************************************************************** +* Implementation of matrix base methods +***************************************************************************/ + +/** replaces \c *this by \c *this * \a other. + * + * \returns a reference to \c *this + * + * Example: \include MatrixBase_applyOnTheRight.cpp + * Output: \verbinclude MatrixBase_applyOnTheRight.out + */ +template +template +inline Derived& +MatrixBase::operator*=(const EigenBase &other) +{ + other.derived().applyThisOnTheRight(derived()); + return derived(); +} + +/** replaces \c *this by \c *this * \a other. It is equivalent to MatrixBase::operator*=(). + * + * Example: \include MatrixBase_applyOnTheRight.cpp + * Output: \verbinclude MatrixBase_applyOnTheRight.out + */ +template +template +inline void MatrixBase::applyOnTheRight(const EigenBase &other) +{ + other.derived().applyThisOnTheRight(derived()); +} + +/** replaces \c *this by \a other * \c *this. + * + * Example: \include MatrixBase_applyOnTheLeft.cpp + * Output: \verbinclude MatrixBase_applyOnTheLeft.out + */ +template +template +inline void MatrixBase::applyOnTheLeft(const EigenBase &other) +{ + other.derived().applyThisOnTheLeft(derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_MATRIXBASE_H diff --git a/Vendor/eigen/Eigen/src/Core/NestByValue.h b/Vendor/eigen/Eigen/src/Core/NestByValue.h new file mode 100644 index 0000000..b427576 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/NestByValue.h @@ -0,0 +1,85 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_NESTBYVALUE_H +#define EIGEN_NESTBYVALUE_H + +namespace Eigen { + +namespace internal { +template +struct traits > : public traits +{ + enum { + Flags = traits::Flags & ~NestByRefBit + }; +}; +} + +/** \class NestByValue + * \ingroup Core_Module + * + * \brief Expression which must be nested by value + * + * \tparam ExpressionType the type of the object of which we are requiring nesting-by-value + * + * This class is the return type of MatrixBase::nestByValue() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::nestByValue() + */ +template class NestByValue + : public internal::dense_xpr_base< NestByValue >::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) + + EIGEN_DEVICE_FUNC explicit inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR inline Index rows() const EIGEN_NOEXCEPT { return m_expression.rows(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR inline Index cols() const EIGEN_NOEXCEPT { return m_expression.cols(); } + + EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } + + EIGEN_DEVICE_FUNC const ExpressionType& nestedExpression() const { return m_expression; } + + protected: + const ExpressionType m_expression; +}; + +/** \returns an expression of the temporary version of *this. + */ +template +EIGEN_DEVICE_FUNC inline const NestByValue +DenseBase::nestByValue() const +{ + return NestByValue(derived()); +} + +namespace internal { + +// Evaluator of Solve -> eval into a temporary +template +struct evaluator > + : public evaluator +{ + typedef evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const NestByValue& xpr) + : Base(xpr.nestedExpression()) + {} +}; +} + +} // end namespace Eigen + +#endif // EIGEN_NESTBYVALUE_H diff --git a/Vendor/eigen/Eigen/src/Core/NoAlias.h b/Vendor/eigen/Eigen/src/Core/NoAlias.h new file mode 100644 index 0000000..570283d --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/NoAlias.h @@ -0,0 +1,109 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_NOALIAS_H +#define EIGEN_NOALIAS_H + +namespace Eigen { + +/** \class NoAlias + * \ingroup Core_Module + * + * \brief Pseudo expression providing an operator = assuming no aliasing + * + * \tparam ExpressionType the type of the object on which to do the lazy assignment + * + * This class represents an expression with special assignment operators + * assuming no aliasing between the target expression and the source expression. + * More precisely it alloas to bypass the EvalBeforeAssignBit flag of the source expression. + * It is the return type of MatrixBase::noalias() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::noalias() + */ +template class StorageBase> +class NoAlias +{ + public: + typedef typename ExpressionType::Scalar Scalar; + + EIGEN_DEVICE_FUNC + explicit NoAlias(ExpressionType& expression) : m_expression(expression) {} + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) + { + call_assignment_no_alias(m_expression, other.derived(), internal::assign_op()); + return m_expression; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) + { + call_assignment_no_alias(m_expression, other.derived(), internal::add_assign_op()); + return m_expression; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) + { + call_assignment_no_alias(m_expression, other.derived(), internal::sub_assign_op()); + return m_expression; + } + + EIGEN_DEVICE_FUNC + ExpressionType& expression() const + { + return m_expression; + } + + protected: + ExpressionType& m_expression; +}; + +/** \returns a pseudo expression of \c *this with an operator= assuming + * no aliasing between \c *this and the source expression. + * + * More precisely, noalias() allows to bypass the EvalBeforeAssignBit flag. + * Currently, even though several expressions may alias, only product + * expressions have this flag. Therefore, noalias() is only useful when + * the source expression contains a matrix product. + * + * Here are some examples where noalias is useful: + * \code + * D.noalias() = A * B; + * D.noalias() += A.transpose() * B; + * D.noalias() -= 2 * A * B.adjoint(); + * \endcode + * + * On the other hand the following example will lead to a \b wrong result: + * \code + * A.noalias() = A * B; + * \endcode + * because the result matrix A is also an operand of the matrix product. Therefore, + * there is no alternative than evaluating A * B in a temporary, that is the default + * behavior when you write: + * \code + * A = A * B; + * \endcode + * + * \sa class NoAlias + */ +template +NoAlias EIGEN_DEVICE_FUNC MatrixBase::noalias() +{ + return NoAlias(derived()); +} + +} // end namespace Eigen + +#endif // EIGEN_NOALIAS_H diff --git a/Vendor/eigen/Eigen/src/Core/NumTraits.h b/Vendor/eigen/Eigen/src/Core/NumTraits.h new file mode 100644 index 0000000..72eac5a --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/NumTraits.h @@ -0,0 +1,335 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_NUMTRAITS_H +#define EIGEN_NUMTRAITS_H + +namespace Eigen { + +namespace internal { + +// default implementation of digits10(), based on numeric_limits if specialized, +// 0 for integer types, and log10(epsilon()) otherwise. +template< typename T, + bool use_numeric_limits = std::numeric_limits::is_specialized, + bool is_integer = NumTraits::IsInteger> +struct default_digits10_impl +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { return std::numeric_limits::digits10; } +}; + +template +struct default_digits10_impl // Floating point +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { + using std::log10; + using std::ceil; + typedef typename NumTraits::Real Real; + return int(ceil(-log10(NumTraits::epsilon()))); + } +}; + +template +struct default_digits10_impl // Integer +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { return 0; } +}; + + +// default implementation of digits(), based on numeric_limits if specialized, +// 0 for integer types, and log2(epsilon()) otherwise. +template< typename T, + bool use_numeric_limits = std::numeric_limits::is_specialized, + bool is_integer = NumTraits::IsInteger> +struct default_digits_impl +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { return std::numeric_limits::digits; } +}; + +template +struct default_digits_impl // Floating point +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { + using std::log; + using std::ceil; + typedef typename NumTraits::Real Real; + return int(ceil(-log(NumTraits::epsilon())/log(static_cast(2)))); + } +}; + +template +struct default_digits_impl // Integer +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static int run() { return 0; } +}; + +} // end namespace internal + +namespace numext { +/** \internal bit-wise cast without changing the underlying bit representation. */ + +// TODO: Replace by std::bit_cast (available in C++20) +template +EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Tgt bit_cast(const Src& src) { +#if EIGEN_HAS_TYPE_TRAITS + // The behaviour of memcpy is not specified for non-trivially copyable types + EIGEN_STATIC_ASSERT(std::is_trivially_copyable::value, THIS_TYPE_IS_NOT_SUPPORTED); + EIGEN_STATIC_ASSERT(std::is_trivially_copyable::value && std::is_default_constructible::value, + THIS_TYPE_IS_NOT_SUPPORTED); +#endif + + EIGEN_STATIC_ASSERT(sizeof(Src) == sizeof(Tgt), THIS_TYPE_IS_NOT_SUPPORTED); + Tgt tgt; + EIGEN_USING_STD(memcpy) + memcpy(&tgt, &src, sizeof(Tgt)); + return tgt; +} +} // namespace numext + +/** \class NumTraits + * \ingroup Core_Module + * + * \brief Holds information about the various numeric (i.e. scalar) types allowed by Eigen. + * + * \tparam T the numeric type at hand + * + * This class stores enums, typedefs and static methods giving information about a numeric type. + * + * The provided data consists of: + * \li A typedef \c Real, giving the "real part" type of \a T. If \a T is already real, + * then \c Real is just a typedef to \a T. If \a T is \c std::complex then \c Real + * is a typedef to \a U. + * \li A typedef \c NonInteger, giving the type that should be used for operations producing non-integral values, + * such as quotients, square roots, etc. If \a T is a floating-point type, then this typedef just gives + * \a T again. Note however that many Eigen functions such as internal::sqrt simply refuse to + * take integers. Outside of a few cases, Eigen doesn't do automatic type promotion. Thus, this typedef is + * only intended as a helper for code that needs to explicitly promote types. + * \li A typedef \c Literal giving the type to use for numeric literals such as "2" or "0.5". For instance, for \c std::complex, Literal is defined as \c U. + * Of course, this type must be fully compatible with \a T. In doubt, just use \a T here. + * \li A typedef \a Nested giving the type to use to nest a value inside of the expression tree. If you don't know what + * this means, just use \a T here. + * \li An enum value \a IsComplex. It is equal to 1 if \a T is a \c std::complex + * type, and to 0 otherwise. + * \li An enum value \a IsInteger. It is equal to \c 1 if \a T is an integer type such as \c int, + * and to \c 0 otherwise. + * \li Enum values ReadCost, AddCost and MulCost representing a rough estimate of the number of CPU cycles needed + * to by move / add / mul instructions respectively, assuming the data is already stored in CPU registers. + * Stay vague here. No need to do architecture-specific stuff. If you don't know what this means, just use \c Eigen::HugeCost. + * \li An enum value \a IsSigned. It is equal to \c 1 if \a T is a signed type and to 0 if \a T is unsigned. + * \li An enum value \a RequireInitialization. It is equal to \c 1 if the constructor of the numeric type \a T must + * be called, and to 0 if it is safe not to call it. Default is 0 if \a T is an arithmetic type, and 1 otherwise. + * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), + * it returns a \a Real instead of a \a T. + * \li A dummy_precision() function returning a weak epsilon value. It is mainly used as a default + * value by the fuzzy comparison operators. + * \li highest() and lowest() functions returning the highest and lowest possible values respectively. + * \li digits() function returning the number of radix digits (non-sign digits for integers, mantissa for floating-point). This is + * the analogue of std::numeric_limits::digits + * which is used as the default implementation if specialized. + * \li digits10() function returning the number of decimal digits that can be represented without change. This is + * the analogue of std::numeric_limits::digits10 + * which is used as the default implementation if specialized. + * \li min_exponent() and max_exponent() functions returning the highest and lowest possible values, respectively, + * such that the radix raised to the power exponent-1 is a normalized floating-point number. These are equivalent to + * std::numeric_limits::min_exponent/ + * std::numeric_limits::max_exponent. + * \li infinity() function returning a representation of positive infinity, if available. + * \li quiet_NaN function returning a non-signaling "not-a-number", if available. + */ + +template struct GenericNumTraits +{ + enum { + IsInteger = std::numeric_limits::is_integer, + IsSigned = std::numeric_limits::is_signed, + IsComplex = 0, + RequireInitialization = internal::is_arithmetic::value ? 0 : 1, + ReadCost = 1, + AddCost = 1, + MulCost = 1 + }; + + typedef T Real; + typedef typename internal::conditional< + IsInteger, + typename internal::conditional::type, + T + >::type NonInteger; + typedef T Nested; + typedef T Literal; + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline Real epsilon() + { + return numext::numeric_limits::epsilon(); + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline int digits10() + { + return internal::default_digits10_impl::run(); + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline int digits() + { + return internal::default_digits_impl::run(); + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline int min_exponent() + { + return numext::numeric_limits::min_exponent; + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline int max_exponent() + { + return numext::numeric_limits::max_exponent; + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline Real dummy_precision() + { + // make sure to override this for floating-point types + return Real(0); + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline T highest() { + return (numext::numeric_limits::max)(); + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline T lowest() { + return IsInteger ? (numext::numeric_limits::min)() + : static_cast(-(numext::numeric_limits::max)()); + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline T infinity() { + return numext::numeric_limits::infinity(); + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline T quiet_NaN() { + return numext::numeric_limits::quiet_NaN(); + } +}; + +template struct NumTraits : GenericNumTraits +{}; + +template<> struct NumTraits + : GenericNumTraits +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline float dummy_precision() { return 1e-5f; } +}; + +template<> struct NumTraits : GenericNumTraits +{ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline double dummy_precision() { return 1e-12; } +}; + +template<> struct NumTraits + : GenericNumTraits +{ + EIGEN_CONSTEXPR + static inline long double dummy_precision() { return 1e-15l; } +}; + +template struct NumTraits > + : GenericNumTraits > +{ + typedef _Real Real; + typedef typename NumTraits<_Real>::Literal Literal; + enum { + IsComplex = 1, + RequireInitialization = NumTraits<_Real>::RequireInitialization, + ReadCost = 2 * NumTraits<_Real>::ReadCost, + AddCost = 2 * NumTraits::AddCost, + MulCost = 4 * NumTraits::MulCost + 2 * NumTraits::AddCost + }; + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline Real epsilon() { return NumTraits::epsilon(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline Real dummy_precision() { return NumTraits::dummy_precision(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline int digits10() { return NumTraits::digits10(); } +}; + +template +struct NumTraits > +{ + typedef Array ArrayType; + typedef typename NumTraits::Real RealScalar; + typedef Array Real; + typedef typename NumTraits::NonInteger NonIntegerScalar; + typedef Array NonInteger; + typedef ArrayType & Nested; + typedef typename NumTraits::Literal Literal; + + enum { + IsComplex = NumTraits::IsComplex, + IsInteger = NumTraits::IsInteger, + IsSigned = NumTraits::IsSigned, + RequireInitialization = 1, + ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * int(NumTraits::ReadCost), + AddCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * int(NumTraits::AddCost), + MulCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * int(NumTraits::MulCost) + }; + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline RealScalar epsilon() { return NumTraits::epsilon(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + static inline RealScalar dummy_precision() { return NumTraits::dummy_precision(); } + + EIGEN_CONSTEXPR + static inline int digits10() { return NumTraits::digits10(); } +}; + +template<> struct NumTraits + : GenericNumTraits +{ + enum { + RequireInitialization = 1, + ReadCost = HugeCost, + AddCost = HugeCost, + MulCost = HugeCost + }; + + EIGEN_CONSTEXPR + static inline int digits10() { return 0; } + +private: + static inline std::string epsilon(); + static inline std::string dummy_precision(); + static inline std::string lowest(); + static inline std::string highest(); + static inline std::string infinity(); + static inline std::string quiet_NaN(); +}; + +// Empty specialization for void to allow template specialization based on NumTraits::Real with T==void and SFINAE. +template<> struct NumTraits {}; + +template<> struct NumTraits : GenericNumTraits {}; + +} // end namespace Eigen + +#endif // EIGEN_NUMTRAITS_H diff --git a/Vendor/eigen/Eigen/src/Core/PartialReduxEvaluator.h b/Vendor/eigen/Eigen/src/Core/PartialReduxEvaluator.h new file mode 100644 index 0000000..29abf35 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/PartialReduxEvaluator.h @@ -0,0 +1,232 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011-2018 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PARTIALREDUX_H +#define EIGEN_PARTIALREDUX_H + +namespace Eigen { + +namespace internal { + + +/*************************************************************************** +* +* This file provides evaluators for partial reductions. +* There are two modes: +* +* - scalar path: simply calls the respective function on the column or row. +* -> nothing special here, all the tricky part is handled by the return +* types of VectorwiseOp's members. They embed the functor calling the +* respective DenseBase's member function. +* +* - vectorized path: implements a packet-wise reductions followed by +* some (optional) processing of the outcome, e.g., division by n for mean. +* +* For the vectorized path let's observe that the packet-size and outer-unrolling +* are both decided by the assignement logic. So all we have to do is to decide +* on the inner unrolling. +* +* For the unrolling, we can reuse "internal::redux_vec_unroller" from Redux.h, +* but be need to be careful to specify correct increment. +* +***************************************************************************/ + + +/* logic deciding a strategy for unrolling of vectorized paths */ +template +struct packetwise_redux_traits +{ + enum { + OuterSize = int(Evaluator::IsRowMajor) ? Evaluator::RowsAtCompileTime : Evaluator::ColsAtCompileTime, + Cost = OuterSize == Dynamic ? HugeCost + : OuterSize * Evaluator::CoeffReadCost + (OuterSize-1) * functor_traits::Cost, + Unrolling = Cost <= EIGEN_UNROLLING_LIMIT ? CompleteUnrolling : NoUnrolling + }; + +}; + +/* Value to be returned when size==0 , by default let's return 0 */ +template +EIGEN_DEVICE_FUNC +PacketType packetwise_redux_empty_value(const Func& ) { return pset1(0); } + +/* For products the default is 1 */ +template +EIGEN_DEVICE_FUNC +PacketType packetwise_redux_empty_value(const scalar_product_op& ) { return pset1(1); } + +/* Perform the actual reduction */ +template::Unrolling +> +struct packetwise_redux_impl; + +/* Perform the actual reduction with unrolling */ +template +struct packetwise_redux_impl +{ + typedef redux_novec_unroller Base; + typedef typename Evaluator::Scalar Scalar; + + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE + PacketType run(const Evaluator &eval, const Func& func, Index /*size*/) + { + return redux_vec_unroller::OuterSize>::template run(eval,func); + } +}; + +/* Add a specialization of redux_vec_unroller for size==0 at compiletime. + * This specialization is not required for general reductions, which is + * why it is defined here. + */ +template +struct redux_vec_unroller +{ + template + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE PacketType run(const Evaluator &, const Func& f) + { + return packetwise_redux_empty_value(f); + } +}; + +/* Perform the actual reduction for dynamic sizes */ +template +struct packetwise_redux_impl +{ + typedef typename Evaluator::Scalar Scalar; + typedef typename redux_traits::PacketType PacketScalar; + + template + EIGEN_DEVICE_FUNC + static PacketType run(const Evaluator &eval, const Func& func, Index size) + { + if(size==0) + return packetwise_redux_empty_value(func); + + const Index size4 = (size-1)&(~3); + PacketType p = eval.template packetByOuterInner(0,0); + Index i = 1; + // This loop is optimized for instruction pipelining: + // - each iteration generates two independent instructions + // - thanks to branch prediction and out-of-order execution we have independent instructions across loops + for(; i(i+0,0),eval.template packetByOuterInner(i+1,0)), + func.packetOp(eval.template packetByOuterInner(i+2,0),eval.template packetByOuterInner(i+3,0)))); + for(; i(i,0)); + return p; + } +}; + +template< typename ArgType, typename MemberOp, int Direction> +struct evaluator > + : evaluator_base > +{ + typedef PartialReduxExpr XprType; + typedef typename internal::nested_eval::type ArgTypeNested; + typedef typename internal::add_const_on_value_type::type ConstArgTypeNested; + typedef typename internal::remove_all::type ArgTypeNestedCleaned; + typedef typename ArgType::Scalar InputScalar; + typedef typename XprType::Scalar Scalar; + enum { + TraversalSize = Direction==int(Vertical) ? int(ArgType::RowsAtCompileTime) : int(ArgType::ColsAtCompileTime) + }; + typedef typename MemberOp::template Cost CostOpType; + enum { + CoeffReadCost = TraversalSize==Dynamic ? HugeCost + : TraversalSize==0 ? 1 + : int(TraversalSize) * int(evaluator::CoeffReadCost) + int(CostOpType::value), + + _ArgFlags = evaluator::Flags, + + _Vectorizable = bool(int(_ArgFlags)&PacketAccessBit) + && bool(MemberOp::Vectorizable) + && (Direction==int(Vertical) ? bool(_ArgFlags&RowMajorBit) : (_ArgFlags&RowMajorBit)==0) + && (TraversalSize!=0), + + Flags = (traits::Flags&RowMajorBit) + | (evaluator::Flags&(HereditaryBits&(~RowMajorBit))) + | (_Vectorizable ? PacketAccessBit : 0) + | LinearAccessBit, + + Alignment = 0 // FIXME this will need to be improved once PartialReduxExpr is vectorized + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType xpr) + : m_arg(xpr.nestedExpression()), m_functor(xpr.functor()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(TraversalSize==Dynamic ? HugeCost : (TraversalSize==0 ? 1 : int(CostOpType::value))); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Scalar coeff(Index i, Index j) const + { + return coeff(Direction==Vertical ? j : i); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Scalar coeff(Index index) const + { + return m_functor(m_arg.template subVector(index)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + PacketType packet(Index i, Index j) const + { + return packet(Direction==Vertical ? j : i); + } + + template + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC + PacketType packet(Index idx) const + { + enum { PacketSize = internal::unpacket_traits::size }; + typedef Block PanelType; + + PanelType panel(m_arg, + Direction==Vertical ? 0 : idx, + Direction==Vertical ? idx : 0, + Direction==Vertical ? m_arg.rows() : Index(PacketSize), + Direction==Vertical ? Index(PacketSize) : m_arg.cols()); + + // FIXME + // See bug 1612, currently if PacketSize==1 (i.e. complex with 128bits registers) then the storage-order of panel get reversed + // and methods like packetByOuterInner do not make sense anymore in this context. + // So let's just by pass "vectorization" in this case: + if(PacketSize==1) + return internal::pset1(coeff(idx)); + + typedef typename internal::redux_evaluator PanelEvaluator; + PanelEvaluator panel_eval(panel); + typedef typename MemberOp::BinaryOp BinaryOp; + PacketType p = internal::packetwise_redux_impl::template run(panel_eval,m_functor.binaryFunc(),m_arg.outerSize()); + return p; + } + +protected: + ConstArgTypeNested m_arg; + const MemberOp m_functor; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PARTIALREDUX_H diff --git a/Vendor/eigen/Eigen/src/Core/PermutationMatrix.h b/Vendor/eigen/Eigen/src/Core/PermutationMatrix.h new file mode 100644 index 0000000..69401bf --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/PermutationMatrix.h @@ -0,0 +1,605 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Benoit Jacob +// Copyright (C) 2009-2015 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PERMUTATIONMATRIX_H +#define EIGEN_PERMUTATIONMATRIX_H + +namespace Eigen { + +namespace internal { + +enum PermPermProduct_t {PermPermProduct}; + +} // end namespace internal + +/** \class PermutationBase + * \ingroup Core_Module + * + * \brief Base class for permutations + * + * \tparam Derived the derived class + * + * This class is the base class for all expressions representing a permutation matrix, + * internally stored as a vector of integers. + * The convention followed here is that if \f$ \sigma \f$ is a permutation, the corresponding permutation matrix + * \f$ P_\sigma \f$ is such that if \f$ (e_1,\ldots,e_p) \f$ is the canonical basis, we have: + * \f[ P_\sigma(e_i) = e_{\sigma(i)}. \f] + * This convention ensures that for any two permutations \f$ \sigma, \tau \f$, we have: + * \f[ P_{\sigma\circ\tau} = P_\sigma P_\tau. \f] + * + * Permutation matrices are square and invertible. + * + * Notice that in addition to the member functions and operators listed here, there also are non-member + * operator* to multiply any kind of permutation object with any kind of matrix expression (MatrixBase) + * on either side. + * + * \sa class PermutationMatrix, class PermutationWrapper + */ +template +class PermutationBase : public EigenBase +{ + typedef internal::traits Traits; + typedef EigenBase Base; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + enum { + Flags = Traits::Flags, + RowsAtCompileTime = Traits::RowsAtCompileTime, + ColsAtCompileTime = Traits::ColsAtCompileTime, + MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = Traits::MaxColsAtCompileTime + }; + typedef typename Traits::StorageIndex StorageIndex; + typedef Matrix + DenseMatrixType; + typedef PermutationMatrix + PlainPermutationType; + typedef PlainPermutationType PlainObject; + using Base::derived; + typedef Inverse InverseReturnType; + typedef void Scalar; + #endif + + /** Copies the other permutation into *this */ + template + Derived& operator=(const PermutationBase& other) + { + indices() = other.indices(); + return derived(); + } + + /** Assignment from the Transpositions \a tr */ + template + Derived& operator=(const TranspositionsBase& tr) + { + setIdentity(tr.size()); + for(Index k=size()-1; k>=0; --k) + applyTranspositionOnTheRight(k,tr.coeff(k)); + return derived(); + } + + /** \returns the number of rows */ + inline EIGEN_DEVICE_FUNC Index rows() const { return Index(indices().size()); } + + /** \returns the number of columns */ + inline EIGEN_DEVICE_FUNC Index cols() const { return Index(indices().size()); } + + /** \returns the size of a side of the respective square matrix, i.e., the number of indices */ + inline EIGEN_DEVICE_FUNC Index size() const { return Index(indices().size()); } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + void evalTo(MatrixBase& other) const + { + other.setZero(); + for (Index i=0; i=0 && j>=0 && i=0 && j>=0 && i + void assignTranspose(const PermutationBase& other) + { + for (Index i=0; i + void assignProduct(const Lhs& lhs, const Rhs& rhs) + { + eigen_assert(lhs.cols() == rhs.rows()); + for (Index i=0; i + inline PlainPermutationType operator*(const PermutationBase& other) const + { return PlainPermutationType(internal::PermPermProduct, derived(), other.derived()); } + + /** \returns the product of a permutation with another inverse permutation. + * + * \note \blank \note_try_to_help_rvo + */ + template + inline PlainPermutationType operator*(const InverseImpl& other) const + { return PlainPermutationType(internal::PermPermProduct, *this, other.eval()); } + + /** \returns the product of an inverse permutation with another permutation. + * + * \note \blank \note_try_to_help_rvo + */ + template friend + inline PlainPermutationType operator*(const InverseImpl& other, const PermutationBase& perm) + { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } + + /** \returns the determinant of the permutation matrix, which is either 1 or -1 depending on the parity of the permutation. + * + * This function is O(\c n) procedure allocating a buffer of \c n booleans. + */ + Index determinant() const + { + Index res = 1; + Index n = size(); + Matrix mask(n); + mask.fill(false); + Index r = 0; + while(r < n) + { + // search for the next seed + while(r=n) + break; + // we got one, let's follow it until we are back to the seed + Index k0 = r++; + mask.coeffRef(k0) = true; + for(Index k=indices().coeff(k0); k!=k0; k=indices().coeff(k)) + { + mask.coeffRef(k) = true; + res = -res; + } + } + return res; + } + + protected: + +}; + +namespace internal { +template +struct traits > + : traits > +{ + typedef PermutationStorage StorageKind; + typedef Matrix<_StorageIndex, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; + typedef _StorageIndex StorageIndex; + typedef void Scalar; +}; +} + +/** \class PermutationMatrix + * \ingroup Core_Module + * + * \brief Permutation matrix + * + * \tparam SizeAtCompileTime the number of rows/cols, or Dynamic + * \tparam MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. + * \tparam _StorageIndex the integer type of the indices + * + * This class represents a permutation matrix, internally stored as a vector of integers. + * + * \sa class PermutationBase, class PermutationWrapper, class DiagonalMatrix + */ +template +class PermutationMatrix : public PermutationBase > +{ + typedef PermutationBase Base; + typedef internal::traits Traits; + public: + + typedef const PermutationMatrix& Nested; + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + typedef typename Traits::StorageIndex StorageIndex; + #endif + + inline PermutationMatrix() + {} + + /** Constructs an uninitialized permutation matrix of given size. + */ + explicit inline PermutationMatrix(Index size) : m_indices(size) + { + eigen_internal_assert(size <= NumTraits::highest()); + } + + /** Copy constructor. */ + template + inline PermutationMatrix(const PermutationBase& other) + : m_indices(other.indices()) {} + + /** Generic constructor from expression of the indices. The indices + * array has the meaning that the permutations sends each integer i to indices[i]. + * + * \warning It is your responsibility to check that the indices array that you passes actually + * describes a permutation, i.e., each value between 0 and n-1 occurs exactly once, where n is the + * array's size. + */ + template + explicit inline PermutationMatrix(const MatrixBase& indices) : m_indices(indices) + {} + + /** Convert the Transpositions \a tr to a permutation matrix */ + template + explicit PermutationMatrix(const TranspositionsBase& tr) + : m_indices(tr.size()) + { + *this = tr; + } + + /** Copies the other permutation into *this */ + template + PermutationMatrix& operator=(const PermutationBase& other) + { + m_indices = other.indices(); + return *this; + } + + /** Assignment from the Transpositions \a tr */ + template + PermutationMatrix& operator=(const TranspositionsBase& tr) + { + return Base::operator=(tr.derived()); + } + + /** const version of indices(). */ + const IndicesType& indices() const { return m_indices; } + /** \returns a reference to the stored array representing the permutation. */ + IndicesType& indices() { return m_indices; } + + + /**** multiplication helpers to hopefully get RVO ****/ + +#ifndef EIGEN_PARSED_BY_DOXYGEN + template + PermutationMatrix(const InverseImpl& other) + : m_indices(other.derived().nestedExpression().size()) + { + eigen_internal_assert(m_indices.size() <= NumTraits::highest()); + StorageIndex end = StorageIndex(m_indices.size()); + for (StorageIndex i=0; i + PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) + : m_indices(lhs.indices().size()) + { + Base::assignProduct(lhs,rhs); + } +#endif + + protected: + + IndicesType m_indices; +}; + + +namespace internal { +template +struct traits,_PacketAccess> > + : traits > +{ + typedef PermutationStorage StorageKind; + typedef Map, _PacketAccess> IndicesType; + typedef _StorageIndex StorageIndex; + typedef void Scalar; +}; +} + +template +class Map,_PacketAccess> + : public PermutationBase,_PacketAccess> > +{ + typedef PermutationBase Base; + typedef internal::traits Traits; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + typedef typename IndicesType::Scalar StorageIndex; + #endif + + inline Map(const StorageIndex* indicesPtr) + : m_indices(indicesPtr) + {} + + inline Map(const StorageIndex* indicesPtr, Index size) + : m_indices(indicesPtr,size) + {} + + /** Copies the other permutation into *this */ + template + Map& operator=(const PermutationBase& other) + { return Base::operator=(other.derived()); } + + /** Assignment from the Transpositions \a tr */ + template + Map& operator=(const TranspositionsBase& tr) + { return Base::operator=(tr.derived()); } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + Map& operator=(const Map& other) + { + m_indices = other.m_indices; + return *this; + } + #endif + + /** const version of indices(). */ + const IndicesType& indices() const { return m_indices; } + /** \returns a reference to the stored array representing the permutation. */ + IndicesType& indices() { return m_indices; } + + protected: + + IndicesType m_indices; +}; + +template class TranspositionsWrapper; +namespace internal { +template +struct traits > +{ + typedef PermutationStorage StorageKind; + typedef void Scalar; + typedef typename _IndicesType::Scalar StorageIndex; + typedef _IndicesType IndicesType; + enum { + RowsAtCompileTime = _IndicesType::SizeAtCompileTime, + ColsAtCompileTime = _IndicesType::SizeAtCompileTime, + MaxRowsAtCompileTime = IndicesType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = IndicesType::MaxSizeAtCompileTime, + Flags = 0 + }; +}; +} + +/** \class PermutationWrapper + * \ingroup Core_Module + * + * \brief Class to view a vector of integers as a permutation matrix + * + * \tparam _IndicesType the type of the vector of integer (can be any compatible expression) + * + * This class allows to view any vector expression of integers as a permutation matrix. + * + * \sa class PermutationBase, class PermutationMatrix + */ +template +class PermutationWrapper : public PermutationBase > +{ + typedef PermutationBase Base; + typedef internal::traits Traits; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + #endif + + inline PermutationWrapper(const IndicesType& indices) + : m_indices(indices) + {} + + /** const version of indices(). */ + const typename internal::remove_all::type& + indices() const { return m_indices; } + + protected: + + typename IndicesType::Nested m_indices; +}; + + +/** \returns the matrix with the permutation applied to the columns. + */ +template +EIGEN_DEVICE_FUNC +const Product +operator*(const MatrixBase &matrix, + const PermutationBase& permutation) +{ + return Product + (matrix.derived(), permutation.derived()); +} + +/** \returns the matrix with the permutation applied to the rows. + */ +template +EIGEN_DEVICE_FUNC +const Product +operator*(const PermutationBase &permutation, + const MatrixBase& matrix) +{ + return Product + (permutation.derived(), matrix.derived()); +} + + +template +class InverseImpl + : public EigenBase > +{ + typedef typename PermutationType::PlainPermutationType PlainPermutationType; + typedef internal::traits PermTraits; + protected: + InverseImpl() {} + public: + typedef Inverse InverseType; + using EigenBase >::derived; + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename PermutationType::DenseMatrixType DenseMatrixType; + enum { + RowsAtCompileTime = PermTraits::RowsAtCompileTime, + ColsAtCompileTime = PermTraits::ColsAtCompileTime, + MaxRowsAtCompileTime = PermTraits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = PermTraits::MaxColsAtCompileTime + }; + #endif + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + void evalTo(MatrixBase& other) const + { + other.setZero(); + for (Index i=0; i friend + const Product + operator*(const MatrixBase& matrix, const InverseType& trPerm) + { + return Product(matrix.derived(), trPerm.derived()); + } + + /** \returns the matrix with the inverse permutation applied to the rows. + */ + template + const Product + operator*(const MatrixBase& matrix) const + { + return Product(derived(), matrix.derived()); + } +}; + +template +const PermutationWrapper MatrixBase::asPermutation() const +{ + return derived(); +} + +namespace internal { + +template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PERMUTATIONMATRIX_H diff --git a/Vendor/eigen/Eigen/src/Core/PlainObjectBase.h b/Vendor/eigen/Eigen/src/Core/PlainObjectBase.h new file mode 100644 index 0000000..e2ddbd1 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/PlainObjectBase.h @@ -0,0 +1,1128 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_DENSESTORAGEBASE_H +#define EIGEN_DENSESTORAGEBASE_H + +#if defined(EIGEN_INITIALIZE_MATRICES_BY_ZERO) +# define EIGEN_INITIALIZE_COEFFS +# define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED for(Index i=0;i::quiet_NaN(); +#else +# undef EIGEN_INITIALIZE_COEFFS +# define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED +#endif + +namespace Eigen { + +namespace internal { + +template struct check_rows_cols_for_overflow { + template + EIGEN_DEVICE_FUNC + static EIGEN_ALWAYS_INLINE void run(Index, Index) + { + } +}; + +template<> struct check_rows_cols_for_overflow { + template + EIGEN_DEVICE_FUNC + static EIGEN_ALWAYS_INLINE void run(Index rows, Index cols) + { + // http://hg.mozilla.org/mozilla-central/file/6c8a909977d3/xpcom/ds/CheckedInt.h#l242 + // we assume Index is signed + Index max_index = (std::size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed + bool error = (rows == 0 || cols == 0) ? false + : (rows > max_index / cols); + if (error) + throw_std_bad_alloc(); + } +}; + +template +struct conservative_resize_like_impl; + +template struct matrix_swap_impl; + +} // end namespace internal + +#ifdef EIGEN_PARSED_BY_DOXYGEN +namespace doxygen { + +// This is a workaround to doxygen not being able to understand the inheritance logic +// when it is hidden by the dense_xpr_base helper struct. +// Moreover, doxygen fails to include members that are not documented in the declaration body of +// MatrixBase if we inherits MatrixBase >, +// this is why we simply inherits MatrixBase, though this does not make sense. + +/** This class is just a workaround for Doxygen and it does not not actually exist. */ +template struct dense_xpr_base_dispatcher; +/** This class is just a workaround for Doxygen and it does not not actually exist. */ +template +struct dense_xpr_base_dispatcher > + : public MatrixBase {}; +/** This class is just a workaround for Doxygen and it does not not actually exist. */ +template +struct dense_xpr_base_dispatcher > + : public ArrayBase {}; + +} // namespace doxygen + +/** \class PlainObjectBase + * \ingroup Core_Module + * \brief %Dense storage base class for matrices and arrays. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN. + * + * \tparam Derived is the derived type, e.g., a Matrix or Array + * + * \sa \ref TopicClassHierarchy + */ +template +class PlainObjectBase : public doxygen::dense_xpr_base_dispatcher +#else +template +class PlainObjectBase : public internal::dense_xpr_base::type +#endif +{ + public: + enum { Options = internal::traits::Options }; + typedef typename internal::dense_xpr_base::type Base; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Scalar Scalar; + + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + typedef Derived DenseType; + + using Base::RowsAtCompileTime; + using Base::ColsAtCompileTime; + using Base::SizeAtCompileTime; + using Base::MaxRowsAtCompileTime; + using Base::MaxColsAtCompileTime; + using Base::MaxSizeAtCompileTime; + using Base::IsVectorAtCompileTime; + using Base::Flags; + + typedef Eigen::Map MapType; + typedef const Eigen::Map ConstMapType; + typedef Eigen::Map AlignedMapType; + typedef const Eigen::Map ConstAlignedMapType; + template struct StridedMapType { typedef Eigen::Map type; }; + template struct StridedConstMapType { typedef Eigen::Map type; }; + template struct StridedAlignedMapType { typedef Eigen::Map type; }; + template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; + + protected: + DenseStorage m_storage; + + public: + enum { NeedsToAlign = (SizeAtCompileTime != Dynamic) && (internal::traits::Alignment>0) }; + EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) + + EIGEN_DEVICE_FUNC + Base& base() { return *static_cast(this); } + EIGEN_DEVICE_FUNC + const Base& base() const { return *static_cast(this); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index rows() const EIGEN_NOEXCEPT { return m_storage.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index cols() const EIGEN_NOEXCEPT { return m_storage.cols(); } + + /** This is an overloaded version of DenseCoeffsBase::coeff(Index,Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeff(Index) const for details. */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& coeff(Index rowId, Index colId) const + { + if(Flags & RowMajorBit) + return m_storage.data()[colId + rowId * m_storage.cols()]; + else // column-major + return m_storage.data()[rowId + colId * m_storage.rows()]; + } + + /** This is an overloaded version of DenseCoeffsBase::coeff(Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeff(Index) const for details. */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const + { + return m_storage.data()[index]; + } + + /** This is an overloaded version of DenseCoeffsBase::coeffRef(Index,Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeffRef(Index,Index) const for details. */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& coeffRef(Index rowId, Index colId) + { + if(Flags & RowMajorBit) + return m_storage.data()[colId + rowId * m_storage.cols()]; + else // column-major + return m_storage.data()[rowId + colId * m_storage.rows()]; + } + + /** This is an overloaded version of DenseCoeffsBase::coeffRef(Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeffRef(Index) const for details. */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) + { + return m_storage.data()[index]; + } + + /** This is the const version of coeffRef(Index,Index) which is thus synonym of coeff(Index,Index). + * It is provided for convenience. */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& coeffRef(Index rowId, Index colId) const + { + if(Flags & RowMajorBit) + return m_storage.data()[colId + rowId * m_storage.cols()]; + else // column-major + return m_storage.data()[rowId + colId * m_storage.rows()]; + } + + /** This is the const version of coeffRef(Index) which is thus synonym of coeff(Index). + * It is provided for convenience. */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& coeffRef(Index index) const + { + return m_storage.data()[index]; + } + + /** \internal */ + template + EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const + { + return internal::ploadt + (m_storage.data() + (Flags & RowMajorBit + ? colId + rowId * m_storage.cols() + : rowId + colId * m_storage.rows())); + } + + /** \internal */ + template + EIGEN_STRONG_INLINE PacketScalar packet(Index index) const + { + return internal::ploadt(m_storage.data() + index); + } + + /** \internal */ + template + EIGEN_STRONG_INLINE void writePacket(Index rowId, Index colId, const PacketScalar& val) + { + internal::pstoret + (m_storage.data() + (Flags & RowMajorBit + ? colId + rowId * m_storage.cols() + : rowId + colId * m_storage.rows()), val); + } + + /** \internal */ + template + EIGEN_STRONG_INLINE void writePacket(Index index, const PacketScalar& val) + { + internal::pstoret(m_storage.data() + index, val); + } + + /** \returns a const pointer to the data array of this matrix */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar *data() const + { return m_storage.data(); } + + /** \returns a pointer to the data array of this matrix */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar *data() + { return m_storage.data(); } + + /** Resizes \c *this to a \a rows x \a cols matrix. + * + * This method is intended for dynamic-size matrices, although it is legal to call it on any + * matrix as long as fixed dimensions are left unchanged. If you only want to change the number + * of rows and/or of columns, you can use resize(NoChange_t, Index), resize(Index, NoChange_t). + * + * If the current number of coefficients of \c *this exactly matches the + * product \a rows * \a cols, then no memory allocation is performed and + * the current values are left unchanged. In all other cases, including + * shrinking, the data is reallocated and all previous values are lost. + * + * Example: \include Matrix_resize_int_int.cpp + * Output: \verbinclude Matrix_resize_int_int.out + * + * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t) + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void resize(Index rows, Index cols) + { + eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,rows==RowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,cols==ColsAtCompileTime) + && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,rows<=MaxRowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,cols<=MaxColsAtCompileTime) + && rows>=0 && cols>=0 && "Invalid sizes when resizing a matrix or array."); + internal::check_rows_cols_for_overflow::run(rows, cols); + #ifdef EIGEN_INITIALIZE_COEFFS + Index size = rows*cols; + bool size_changed = size != this->size(); + m_storage.resize(size, rows, cols); + if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + #else + m_storage.resize(rows*cols, rows, cols); + #endif + } + + /** Resizes \c *this to a vector of length \a size + * + * \only_for_vectors. This method does not work for + * partially dynamic matrices when the static dimension is anything other + * than 1. For example it will not work with Matrix. + * + * Example: \include Matrix_resize_int.cpp + * Output: \verbinclude Matrix_resize_int.out + * + * \sa resize(Index,Index), resize(NoChange_t, Index), resize(Index, NoChange_t) + */ + EIGEN_DEVICE_FUNC + inline void resize(Index size) + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(PlainObjectBase) + eigen_assert(((SizeAtCompileTime == Dynamic && (MaxSizeAtCompileTime==Dynamic || size<=MaxSizeAtCompileTime)) || SizeAtCompileTime == size) && size>=0); + #ifdef EIGEN_INITIALIZE_COEFFS + bool size_changed = size != this->size(); + #endif + if(RowsAtCompileTime == 1) + m_storage.resize(size, 1, size); + else + m_storage.resize(size, size, 1); + #ifdef EIGEN_INITIALIZE_COEFFS + if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + #endif + } + + /** Resizes the matrix, changing only the number of columns. For the parameter of type NoChange_t, just pass the special value \c NoChange + * as in the example below. + * + * Example: \include Matrix_resize_NoChange_int.cpp + * Output: \verbinclude Matrix_resize_NoChange_int.out + * + * \sa resize(Index,Index) + */ + EIGEN_DEVICE_FUNC + inline void resize(NoChange_t, Index cols) + { + resize(rows(), cols); + } + + /** Resizes the matrix, changing only the number of rows. For the parameter of type NoChange_t, just pass the special value \c NoChange + * as in the example below. + * + * Example: \include Matrix_resize_int_NoChange.cpp + * Output: \verbinclude Matrix_resize_int_NoChange.out + * + * \sa resize(Index,Index) + */ + EIGEN_DEVICE_FUNC + inline void resize(Index rows, NoChange_t) + { + resize(rows, cols()); + } + + /** Resizes \c *this to have the same dimensions as \a other. + * Takes care of doing all the checking that's needed. + * + * Note that copying a row-vector into a vector (and conversely) is allowed. + * The resizing, if any, is then done in the appropriate way so that row-vectors + * remain row-vectors and vectors remain vectors. + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void resizeLike(const EigenBase& _other) + { + const OtherDerived& other = _other.derived(); + internal::check_rows_cols_for_overflow::run(other.rows(), other.cols()); + const Index othersize = other.rows()*other.cols(); + if(RowsAtCompileTime == 1) + { + eigen_assert(other.rows() == 1 || other.cols() == 1); + resize(1, othersize); + } + else if(ColsAtCompileTime == 1) + { + eigen_assert(other.rows() == 1 || other.cols() == 1); + resize(othersize, 1); + } + else resize(other.rows(), other.cols()); + } + + /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. + * + * The method is intended for matrices of dynamic size. If you only want to change the number + * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or + * conservativeResize(Index, NoChange_t). + * + * Matrices are resized relative to the top-left element. In case values need to be + * appended to the matrix they will be uninitialized. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(Index rows, Index cols) + { + internal::conservative_resize_like_impl::run(*this, rows, cols); + } + + /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. + * + * As opposed to conservativeResize(Index rows, Index cols), this version leaves + * the number of columns unchanged. + * + * In case the matrix is growing, new rows will be uninitialized. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(Index rows, NoChange_t) + { + // Note: see the comment in conservativeResize(Index,Index) + conservativeResize(rows, cols()); + } + + /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. + * + * As opposed to conservativeResize(Index rows, Index cols), this version leaves + * the number of rows unchanged. + * + * In case the matrix is growing, new columns will be uninitialized. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index cols) + { + // Note: see the comment in conservativeResize(Index,Index) + conservativeResize(rows(), cols); + } + + /** Resizes the vector to \a size while retaining old values. + * + * \only_for_vectors. This method does not work for + * partially dynamic matrices when the static dimension is anything other + * than 1. For example it will not work with Matrix. + * + * When values are appended, they will be uninitialized. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(Index size) + { + internal::conservative_resize_like_impl::run(*this, size); + } + + /** Resizes the matrix to \a rows x \a cols of \c other, while leaving old values untouched. + * + * The method is intended for matrices of dynamic size. If you only want to change the number + * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or + * conservativeResize(Index, NoChange_t). + * + * Matrices are resized relative to the top-left element. In case values need to be + * appended to the matrix they will copied from \c other. + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResizeLike(const DenseBase& other) + { + internal::conservative_resize_like_impl::run(*this, other); + } + + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& operator=(const PlainObjectBase& other) + { + return _set(other); + } + + /** \sa MatrixBase::lazyAssign() */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& lazyAssign(const DenseBase& other) + { + _resize_to_match(other); + return Base::lazyAssign(other.derived()); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& operator=(const ReturnByValue& func) + { + resize(func.rows(), func.cols()); + return Base::operator=(func); + } + + // Prevent user from trying to instantiate PlainObjectBase objects + // by making all its constructor protected. See bug 1074. + protected: + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase() : m_storage() + { +// _check_template_params(); +// EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + // FIXME is it still needed ? + /** \internal */ + EIGEN_DEVICE_FUNC + explicit PlainObjectBase(internal::constructor_without_unaligned_array_assert) + : m_storage(internal::constructor_without_unaligned_array_assert()) + { +// _check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } +#endif + +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + PlainObjectBase(PlainObjectBase&& other) EIGEN_NOEXCEPT + : m_storage( std::move(other.m_storage) ) + { + } + + EIGEN_DEVICE_FUNC + PlainObjectBase& operator=(PlainObjectBase&& other) EIGEN_NOEXCEPT + { + _check_template_params(); + m_storage = std::move(other.m_storage); + return *this; + } +#endif + + /** Copy constructor */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const PlainObjectBase& other) + : Base(), m_storage(other.m_storage) { } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(Index size, Index rows, Index cols) + : m_storage(size, rows, cols) + { +// _check_template_params(); +// EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + + #if EIGEN_HAS_CXX11 + /** \brief Construct a row of column vector with fixed size from an arbitrary number of coefficients. \cpp11 + * + * \only_for_vectors + * + * This constructor is for 1D array or vectors with more than 4 coefficients. + * There exists C++98 analogue constructors for fixed-size array/vector having 1, 2, 3, or 4 coefficients. + * + * \warning To construct a column (resp. row) vector of fixed length, the number of values passed to this + * constructor must match the the fixed number of rows (resp. columns) of \c *this. + */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + PlainObjectBase(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) + : m_storage() + { + _check_template_params(); + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, sizeof...(args) + 4); + m_storage.data()[0] = a0; + m_storage.data()[1] = a1; + m_storage.data()[2] = a2; + m_storage.data()[3] = a3; + Index i = 4; + auto x = {(m_storage.data()[i++] = args, 0)...}; + static_cast(x); + } + + /** \brief Constructs a Matrix or Array and initializes it by elements given by an initializer list of initializer + * lists \cpp11 + */ + EIGEN_DEVICE_FUNC + explicit EIGEN_STRONG_INLINE PlainObjectBase(const std::initializer_list>& list) + : m_storage() + { + _check_template_params(); + + size_t list_size = 0; + if (list.begin() != list.end()) { + list_size = list.begin()->size(); + } + + // This is to allow syntax like VectorXi {{1, 2, 3, 4}} + if (ColsAtCompileTime == 1 && list.size() == 1) { + eigen_assert(list_size == static_cast(RowsAtCompileTime) || RowsAtCompileTime == Dynamic); + resize(list_size, ColsAtCompileTime); + std::copy(list.begin()->begin(), list.begin()->end(), m_storage.data()); + } else { + eigen_assert(list.size() == static_cast(RowsAtCompileTime) || RowsAtCompileTime == Dynamic); + eigen_assert(list_size == static_cast(ColsAtCompileTime) || ColsAtCompileTime == Dynamic); + resize(list.size(), list_size); + + Index row_index = 0; + for (const std::initializer_list& row : list) { + eigen_assert(list_size == row.size()); + Index col_index = 0; + for (const Scalar& e : row) { + coeffRef(row_index, col_index) = e; + ++col_index; + } + ++row_index; + } + } + } + #endif // end EIGEN_HAS_CXX11 + + /** \sa PlainObjectBase::operator=(const EigenBase&) */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const DenseBase &other) + : m_storage() + { + _check_template_params(); + resizeLike(other); + _set_noalias(other); + } + + /** \sa PlainObjectBase::operator=(const EigenBase&) */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase &other) + : m_storage() + { + _check_template_params(); + resizeLike(other); + *this = other.derived(); + } + /** \brief Copy constructor with in-place evaluation */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const ReturnByValue& other) + { + _check_template_params(); + // FIXME this does not automatically transpose vectors if necessary + resize(other.rows(), other.cols()); + other.evalTo(this->derived()); + } + + public: + + /** \brief Copies the generic expression \a other into *this. + * \copydetails DenseBase::operator=(const EigenBase &other) + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& operator=(const EigenBase &other) + { + _resize_to_match(other); + Base::operator=(other.derived()); + return this->derived(); + } + + /** \name Map + * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, + * while the AlignedMap() functions return aligned Map objects and thus should be called only with 16-byte-aligned + * \a data pointers. + * + * Here is an example using strides: + * \include Matrix_Map_stride.cpp + * Output: \verbinclude Matrix_Map_stride.out + * + * \see class Map + */ + //@{ + static inline ConstMapType Map(const Scalar* data) + { return ConstMapType(data); } + static inline MapType Map(Scalar* data) + { return MapType(data); } + static inline ConstMapType Map(const Scalar* data, Index size) + { return ConstMapType(data, size); } + static inline MapType Map(Scalar* data, Index size) + { return MapType(data, size); } + static inline ConstMapType Map(const Scalar* data, Index rows, Index cols) + { return ConstMapType(data, rows, cols); } + static inline MapType Map(Scalar* data, Index rows, Index cols) + { return MapType(data, rows, cols); } + + static inline ConstAlignedMapType MapAligned(const Scalar* data) + { return ConstAlignedMapType(data); } + static inline AlignedMapType MapAligned(Scalar* data) + { return AlignedMapType(data); } + static inline ConstAlignedMapType MapAligned(const Scalar* data, Index size) + { return ConstAlignedMapType(data, size); } + static inline AlignedMapType MapAligned(Scalar* data, Index size) + { return AlignedMapType(data, size); } + static inline ConstAlignedMapType MapAligned(const Scalar* data, Index rows, Index cols) + { return ConstAlignedMapType(data, rows, cols); } + static inline AlignedMapType MapAligned(Scalar* data, Index rows, Index cols) + { return AlignedMapType(data, rows, cols); } + + template + static inline typename StridedConstMapType >::type Map(const Scalar* data, const Stride& stride) + { return typename StridedConstMapType >::type(data, stride); } + template + static inline typename StridedMapType >::type Map(Scalar* data, const Stride& stride) + { return typename StridedMapType >::type(data, stride); } + template + static inline typename StridedConstMapType >::type Map(const Scalar* data, Index size, const Stride& stride) + { return typename StridedConstMapType >::type(data, size, stride); } + template + static inline typename StridedMapType >::type Map(Scalar* data, Index size, const Stride& stride) + { return typename StridedMapType >::type(data, size, stride); } + template + static inline typename StridedConstMapType >::type Map(const Scalar* data, Index rows, Index cols, const Stride& stride) + { return typename StridedConstMapType >::type(data, rows, cols, stride); } + template + static inline typename StridedMapType >::type Map(Scalar* data, Index rows, Index cols, const Stride& stride) + { return typename StridedMapType >::type(data, rows, cols, stride); } + + template + static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, const Stride& stride) + { return typename StridedConstAlignedMapType >::type(data, stride); } + template + static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, const Stride& stride) + { return typename StridedAlignedMapType >::type(data, stride); } + template + static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index size, const Stride& stride) + { return typename StridedConstAlignedMapType >::type(data, size, stride); } + template + static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index size, const Stride& stride) + { return typename StridedAlignedMapType >::type(data, size, stride); } + template + static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index rows, Index cols, const Stride& stride) + { return typename StridedConstAlignedMapType >::type(data, rows, cols, stride); } + template + static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index rows, Index cols, const Stride& stride) + { return typename StridedAlignedMapType >::type(data, rows, cols, stride); } + //@} + + using Base::setConstant; + EIGEN_DEVICE_FUNC Derived& setConstant(Index size, const Scalar& val); + EIGEN_DEVICE_FUNC Derived& setConstant(Index rows, Index cols, const Scalar& val); + EIGEN_DEVICE_FUNC Derived& setConstant(NoChange_t, Index cols, const Scalar& val); + EIGEN_DEVICE_FUNC Derived& setConstant(Index rows, NoChange_t, const Scalar& val); + + using Base::setZero; + EIGEN_DEVICE_FUNC Derived& setZero(Index size); + EIGEN_DEVICE_FUNC Derived& setZero(Index rows, Index cols); + EIGEN_DEVICE_FUNC Derived& setZero(NoChange_t, Index cols); + EIGEN_DEVICE_FUNC Derived& setZero(Index rows, NoChange_t); + + using Base::setOnes; + EIGEN_DEVICE_FUNC Derived& setOnes(Index size); + EIGEN_DEVICE_FUNC Derived& setOnes(Index rows, Index cols); + EIGEN_DEVICE_FUNC Derived& setOnes(NoChange_t, Index cols); + EIGEN_DEVICE_FUNC Derived& setOnes(Index rows, NoChange_t); + + using Base::setRandom; + Derived& setRandom(Index size); + Derived& setRandom(Index rows, Index cols); + Derived& setRandom(NoChange_t, Index cols); + Derived& setRandom(Index rows, NoChange_t); + + #ifdef EIGEN_PLAINOBJECTBASE_PLUGIN + #include EIGEN_PLAINOBJECTBASE_PLUGIN + #endif + + protected: + /** \internal Resizes *this in preparation for assigning \a other to it. + * Takes care of doing all the checking that's needed. + * + * Note that copying a row-vector into a vector (and conversely) is allowed. + * The resizing, if any, is then done in the appropriate way so that row-vectors + * remain row-vectors and vectors remain vectors. + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _resize_to_match(const EigenBase& other) + { + #ifdef EIGEN_NO_AUTOMATIC_RESIZING + eigen_assert((this->size()==0 || (IsVectorAtCompileTime ? (this->size() == other.size()) + : (rows() == other.rows() && cols() == other.cols()))) + && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); + EIGEN_ONLY_USED_FOR_DEBUG(other); + #else + resizeLike(other); + #endif + } + + /** + * \brief Copies the value of the expression \a other into \c *this with automatic resizing. + * + * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), + * it will be initialized. + * + * Note that copying a row-vector into a vector (and conversely) is allowed. + * The resizing, if any, is then done in the appropriate way so that row-vectors + * remain row-vectors and vectors remain vectors. + * + * \sa operator=(const MatrixBase&), _set_noalias() + * + * \internal + */ + // aliasing is dealt once in internal::call_assignment + // so at this stage we have to assume aliasing... and resising has to be done later. + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) + { + internal::call_assignment(this->derived(), other.derived()); + return this->derived(); + } + + /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which + * is the case when creating a new matrix) so one can enforce lazy evaluation. + * + * \sa operator=(const MatrixBase&), _set() + */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase& other) + { + // I don't think we need this resize call since the lazyAssign will anyways resize + // and lazyAssign will be called by the assign selector. + //_resize_to_match(other); + // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because + // it wouldn't allow to copy a row-vector into a column-vector. + internal::call_assignment_no_alias(this->derived(), other.derived(), internal::assign_op()); + return this->derived(); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init2(Index rows, Index cols, typename internal::enable_if::type* = 0) + { + const bool t0_is_integer_alike = internal::is_valid_index_type::value; + const bool t1_is_integer_alike = internal::is_valid_index_type::value; + EIGEN_STATIC_ASSERT(t0_is_integer_alike && + t1_is_integer_alike, + FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) + resize(rows,cols); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init2(const T0& val0, const T1& val1, typename internal::enable_if::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) + m_storage.data()[0] = Scalar(val0); + m_storage.data()[1] = Scalar(val1); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init2(const Index& val0, const Index& val1, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime==2,T1>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) + m_storage.data()[0] = Scalar(val0); + m_storage.data()[1] = Scalar(val1); + } + + // The argument is convertible to the Index type and we either have a non 1x1 Matrix, or a dynamic-sized Array, + // then the argument is meant to be the size of the object. + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(Index size, typename internal::enable_if< (Base::SizeAtCompileTime!=1 || !internal::is_convertible::value) + && ((!internal::is_same::XprKind,ArrayXpr>::value || Base::SizeAtCompileTime==Dynamic)),T>::type* = 0) + { + // NOTE MSVC 2008 complains if we directly put bool(NumTraits::IsInteger) as the EIGEN_STATIC_ASSERT argument. + const bool is_integer_alike = internal::is_valid_index_type::value; + EIGEN_UNUSED_VARIABLE(is_integer_alike); + EIGEN_STATIC_ASSERT(is_integer_alike, + FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) + resize(size); + } + + // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type can be implicitly converted) + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar& val0, typename internal::enable_if::value,T>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 1) + m_storage.data()[0] = val0; + } + + // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type match the index type) + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Index& val0, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime==1 + && internal::is_convertible::value,T*>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 1) + m_storage.data()[0] = Scalar(val0); + } + + // Initialize a fixed size matrix from a pointer to raw data + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar* data){ + this->_set_noalias(ConstMapType(data)); + } + + // Initialize an arbitrary matrix from a dense expression + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const DenseBase& other){ + this->_set_noalias(other); + } + + // Initialize an arbitrary matrix from an object convertible to the Derived type. + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Derived& other){ + this->_set_noalias(other); + } + + // Initialize an arbitrary matrix from a generic Eigen expression + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const EigenBase& other){ + this->derived() = other; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const ReturnByValue& other) + { + resize(other.rows(), other.cols()); + other.evalTo(this->derived()); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const RotationBase& r) + { + this->derived() = r; + } + + // For fixed-size Array + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar& val0, + typename internal::enable_if< Base::SizeAtCompileTime!=Dynamic + && Base::SizeAtCompileTime!=1 + && internal::is_convertible::value + && internal::is_same::XprKind,ArrayXpr>::value,T>::type* = 0) + { + Base::setConstant(val0); + } + + // For fixed-size Array + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Index& val0, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime!=Dynamic + && Base::SizeAtCompileTime!=1 + && internal::is_convertible::value + && internal::is_same::XprKind,ArrayXpr>::value,T*>::type* = 0) + { + Base::setConstant(val0); + } + + template + friend struct internal::matrix_swap_impl; + + public: + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal + * \brief Override DenseBase::swap() since for dynamic-sized matrices + * of same type it is enough to swap the data pointers. + */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void swap(DenseBase & other) + { + enum { SwapPointers = internal::is_same::value && Base::SizeAtCompileTime==Dynamic }; + internal::matrix_swap_impl::run(this->derived(), other.derived()); + } + + /** \internal + * \brief const version forwarded to DenseBase::swap + */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void swap(DenseBase const & other) + { Base::swap(other.derived()); } + + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void _check_template_params() + { + EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (int(Options)&RowMajor)==RowMajor) + && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, (int(Options)&RowMajor)==0) + && ((RowsAtCompileTime == Dynamic) || (RowsAtCompileTime >= 0)) + && ((ColsAtCompileTime == Dynamic) || (ColsAtCompileTime >= 0)) + && ((MaxRowsAtCompileTime == Dynamic) || (MaxRowsAtCompileTime >= 0)) + && ((MaxColsAtCompileTime == Dynamic) || (MaxColsAtCompileTime >= 0)) + && (MaxRowsAtCompileTime == RowsAtCompileTime || RowsAtCompileTime==Dynamic) + && (MaxColsAtCompileTime == ColsAtCompileTime || ColsAtCompileTime==Dynamic) + && (Options & (DontAlign|RowMajor)) == Options), + INVALID_MATRIX_TEMPLATE_PARAMETERS) + } + + enum { IsPlainObjectBase = 1 }; +#endif + public: + // These apparently need to be down here for nvcc+icc to prevent duplicate + // Map symbol. + template friend class Eigen::Map; + friend class Eigen::Map; + friend class Eigen::Map; +#if EIGEN_MAX_ALIGN_BYTES>0 + // for EIGEN_MAX_ALIGN_BYTES==0, AlignedMax==Unaligned, and many compilers generate warnings for friend-ing a class twice. + friend class Eigen::Map; + friend class Eigen::Map; +#endif +}; + +namespace internal { + +template +struct conservative_resize_like_impl +{ + #if EIGEN_HAS_TYPE_TRAITS + static const bool IsRelocatable = std::is_trivially_copyable::value; + #else + static const bool IsRelocatable = !NumTraits::RequireInitialization; + #endif + static void run(DenseBase& _this, Index rows, Index cols) + { + if (_this.rows() == rows && _this.cols() == cols) return; + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) + + if ( IsRelocatable + && (( Derived::IsRowMajor && _this.cols() == cols) || // row-major and we change only the number of rows + (!Derived::IsRowMajor && _this.rows() == rows) )) // column-major and we change only the number of columns + { + internal::check_rows_cols_for_overflow::run(rows, cols); + _this.derived().m_storage.conservativeResize(rows*cols,rows,cols); + } + else + { + // The storage order does not allow us to use reallocation. + Derived tmp(rows,cols); + const Index common_rows = numext::mini(rows, _this.rows()); + const Index common_cols = numext::mini(cols, _this.cols()); + tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); + _this.derived().swap(tmp); + } + } + + static void run(DenseBase& _this, const DenseBase& other) + { + if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; + + // Note: Here is space for improvement. Basically, for conservativeResize(Index,Index), + // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the + // dimensions is dynamic, one could use either conservativeResize(Index rows, NoChange_t) or + // conservativeResize(NoChange_t, Index cols). For these methods new static asserts like + // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) + EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(OtherDerived) + + if ( IsRelocatable && + (( Derived::IsRowMajor && _this.cols() == other.cols()) || // row-major and we change only the number of rows + (!Derived::IsRowMajor && _this.rows() == other.rows()) )) // column-major and we change only the number of columns + { + const Index new_rows = other.rows() - _this.rows(); + const Index new_cols = other.cols() - _this.cols(); + _this.derived().m_storage.conservativeResize(other.size(),other.rows(),other.cols()); + if (new_rows>0) + _this.bottomRightCorner(new_rows, other.cols()) = other.bottomRows(new_rows); + else if (new_cols>0) + _this.bottomRightCorner(other.rows(), new_cols) = other.rightCols(new_cols); + } + else + { + // The storage order does not allow us to use reallocation. + Derived tmp(other); + const Index common_rows = numext::mini(tmp.rows(), _this.rows()); + const Index common_cols = numext::mini(tmp.cols(), _this.cols()); + tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); + _this.derived().swap(tmp); + } + } +}; + +// Here, the specialization for vectors inherits from the general matrix case +// to allow calling .conservativeResize(rows,cols) on vectors. +template +struct conservative_resize_like_impl + : conservative_resize_like_impl +{ + typedef conservative_resize_like_impl Base; + using Base::run; + using Base::IsRelocatable; + + static void run(DenseBase& _this, Index size) + { + const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : size; + const Index new_cols = Derived::RowsAtCompileTime==1 ? size : 1; + if(IsRelocatable) + _this.derived().m_storage.conservativeResize(size,new_rows,new_cols); + else + Base::run(_this.derived(), new_rows, new_cols); + } + + static void run(DenseBase& _this, const DenseBase& other) + { + if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; + + const Index num_new_elements = other.size() - _this.size(); + + const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : other.rows(); + const Index new_cols = Derived::RowsAtCompileTime==1 ? other.cols() : 1; + if(IsRelocatable) + _this.derived().m_storage.conservativeResize(other.size(),new_rows,new_cols); + else + Base::run(_this.derived(), new_rows, new_cols); + + if (num_new_elements > 0) + _this.tail(num_new_elements) = other.tail(num_new_elements); + } +}; + +template +struct matrix_swap_impl +{ + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(MatrixTypeA& a, MatrixTypeB& b) + { + a.base().swap(b); + } +}; + +template +struct matrix_swap_impl +{ + EIGEN_DEVICE_FUNC + static inline void run(MatrixTypeA& a, MatrixTypeB& b) + { + static_cast(a).m_storage.swap(static_cast(b).m_storage); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_DENSESTORAGEBASE_H diff --git a/Vendor/eigen/Eigen/src/Core/Product.h b/Vendor/eigen/Eigen/src/Core/Product.h new file mode 100644 index 0000000..70a6c10 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Product.h @@ -0,0 +1,191 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PRODUCT_H +#define EIGEN_PRODUCT_H + +namespace Eigen { + +template class ProductImpl; + +namespace internal { + +template +struct traits > +{ + typedef typename remove_all::type LhsCleaned; + typedef typename remove_all::type RhsCleaned; + typedef traits LhsTraits; + typedef traits RhsTraits; + + typedef MatrixXpr XprKind; + + typedef typename ScalarBinaryOpTraits::Scalar, typename traits::Scalar>::ReturnType Scalar; + typedef typename product_promote_storage_type::ret>::ret StorageKind; + typedef typename promote_index_type::type StorageIndex; + + enum { + RowsAtCompileTime = LhsTraits::RowsAtCompileTime, + ColsAtCompileTime = RhsTraits::ColsAtCompileTime, + MaxRowsAtCompileTime = LhsTraits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsTraits::MaxColsAtCompileTime, + + // FIXME: only needed by GeneralMatrixMatrixTriangular + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsTraits::ColsAtCompileTime, RhsTraits::RowsAtCompileTime), + + // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. + Flags = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? RowMajorBit + : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 + : ( ((LhsTraits::Flags&NoPreferredStorageOrderBit) && (RhsTraits::Flags&RowMajorBit)) + || ((RhsTraits::Flags&NoPreferredStorageOrderBit) && (LhsTraits::Flags&RowMajorBit)) ) ? RowMajorBit + : NoPreferredStorageOrderBit + }; +}; + +} // end namespace internal + +/** \class Product + * \ingroup Core_Module + * + * \brief Expression of the product of two arbitrary matrices or vectors + * + * \tparam _Lhs the type of the left-hand side expression + * \tparam _Rhs the type of the right-hand side expression + * + * This class represents an expression of the product of two arbitrary matrices. + * + * The other template parameters are: + * \tparam Option can be DefaultProduct, AliasFreeProduct, or LazyProduct + * + */ +template +class Product : public ProductImpl<_Lhs,_Rhs,Option, + typename internal::product_promote_storage_type::StorageKind, + typename internal::traits<_Rhs>::StorageKind, + internal::product_type<_Lhs,_Rhs>::ret>::ret> +{ + public: + + typedef _Lhs Lhs; + typedef _Rhs Rhs; + + typedef typename ProductImpl< + Lhs, Rhs, Option, + typename internal::product_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + internal::product_type::ret>::ret>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(Product) + + typedef typename internal::ref_selector::type LhsNested; + typedef typename internal::ref_selector::type RhsNested; + typedef typename internal::remove_all::type LhsNestedCleaned; + typedef typename internal::remove_all::type RhsNestedCleaned; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Product(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) + { + eigen_assert(lhs.cols() == rhs.rows() + && "invalid matrix product" + && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index rows() const EIGEN_NOEXCEPT { return m_lhs.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR + Index cols() const EIGEN_NOEXCEPT { return m_rhs.cols(); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const LhsNestedCleaned& lhs() const { return m_lhs; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const RhsNestedCleaned& rhs() const { return m_rhs; } + + protected: + + LhsNested m_lhs; + RhsNested m_rhs; +}; + +namespace internal { + +template::ret> +class dense_product_base + : public internal::dense_xpr_base >::type +{}; + +/** Conversion to scalar for inner-products */ +template +class dense_product_base + : public internal::dense_xpr_base >::type +{ + typedef Product ProductXpr; + typedef typename internal::dense_xpr_base::type Base; +public: + using Base::derived; + typedef typename Base::Scalar Scalar; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE operator const Scalar() const + { + return internal::evaluator(derived()).coeff(0,0); + } +}; + +} // namespace internal + +// Generic API dispatcher +template +class ProductImpl : public internal::generic_xpr_base, MatrixXpr, StorageKind>::type +{ + public: + typedef typename internal::generic_xpr_base, MatrixXpr, StorageKind>::type Base; +}; + +template +class ProductImpl + : public internal::dense_product_base +{ + typedef Product Derived; + + public: + + typedef typename internal::dense_product_base Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + protected: + enum { + IsOneByOne = (RowsAtCompileTime == 1 || RowsAtCompileTime == Dynamic) && + (ColsAtCompileTime == 1 || ColsAtCompileTime == Dynamic), + EnableCoeff = IsOneByOne || Option==LazyProduct + }; + + public: + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index row, Index col) const + { + EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); + eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); + + return internal::evaluator(derived()).coeff(row,col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index i) const + { + EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); + eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); + + return internal::evaluator(derived()).coeff(i); + } + + +}; + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_H diff --git a/Vendor/eigen/Eigen/src/Core/ProductEvaluators.h b/Vendor/eigen/Eigen/src/Core/ProductEvaluators.h new file mode 100644 index 0000000..8cf294b --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/ProductEvaluators.h @@ -0,0 +1,1179 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2011 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +#ifndef EIGEN_PRODUCTEVALUATORS_H +#define EIGEN_PRODUCTEVALUATORS_H + +namespace Eigen { + +namespace internal { + +/** \internal + * Evaluator of a product expression. + * Since products require special treatments to handle all possible cases, + * we simply defer the evaluation logic to a product_evaluator class + * which offers more partial specialization possibilities. + * + * \sa class product_evaluator + */ +template +struct evaluator > + : public product_evaluator > +{ + typedef Product XprType; + typedef product_evaluator Base; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +// Catch "scalar * ( A * B )" and transform it to "(A*scalar) * B" +// TODO we should apply that rule only if that's really helpful +template +struct evaluator_assume_aliasing, + const CwiseNullaryOp, Plain1>, + const Product > > +{ + static const bool value = true; +}; +template +struct evaluator, + const CwiseNullaryOp, Plain1>, + const Product > > + : public evaluator > +{ + typedef CwiseBinaryOp, + const CwiseNullaryOp, Plain1>, + const Product > XprType; + typedef evaluator > Base; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) + : Base(xpr.lhs().functor().m_other * xpr.rhs().lhs() * xpr.rhs().rhs()) + {} +}; + + +template +struct evaluator, DiagIndex> > + : public evaluator, DiagIndex> > +{ + typedef Diagonal, DiagIndex> XprType; + typedef evaluator, DiagIndex> > Base; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) + : Base(Diagonal, DiagIndex>( + Product(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()), + xpr.index() )) + {} +}; + + +// Helper class to perform a matrix product with the destination at hand. +// Depending on the sizes of the factors, there are different evaluation strategies +// as controlled by internal::product_type. +template< typename Lhs, typename Rhs, + typename LhsShape = typename evaluator_traits::Shape, + typename RhsShape = typename evaluator_traits::Shape, + int ProductType = internal::product_type::value> +struct generic_product_impl; + +template +struct evaluator_assume_aliasing > { + static const bool value = true; +}; + +// This is the default evaluator implementation for products: +// It creates a temporary and call generic_product_impl +template +struct product_evaluator, ProductTag, LhsShape, RhsShape> + : public evaluator::PlainObject> +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef evaluator Base; + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + +// FIXME shall we handle nested_eval here?, +// if so, then we must take care at removing the call to nested_eval in the specializations (e.g., in permutation_matrix_product, transposition_matrix_product, etc.) +// typedef typename internal::nested_eval::type LhsNested; +// typedef typename internal::nested_eval::type RhsNested; +// typedef typename internal::remove_all::type LhsNestedCleaned; +// typedef typename internal::remove_all::type RhsNestedCleaned; +// +// const LhsNested lhs(xpr.lhs()); +// const RhsNested rhs(xpr.rhs()); +// +// generic_product_impl::evalTo(m_result, lhs, rhs); + + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +// The following three shortcuts are enabled only if the scalar types match exactly. +// TODO: we could enable them for different scalar types when the product is not vectorized. + +// Dense = Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> +{ + typedef Product SrcXprType; + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + // FIXME shall we handle nested_eval here? + generic_product_impl::evalTo(dst, src.lhs(), src.rhs()); + } +}; + +// Dense += Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::add_assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> +{ + typedef Product SrcXprType; + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + // FIXME shall we handle nested_eval here? + generic_product_impl::addTo(dst, src.lhs(), src.rhs()); + } +}; + +// Dense -= Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::sub_assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> +{ + typedef Product SrcXprType; + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + // FIXME shall we handle nested_eval here? + generic_product_impl::subTo(dst, src.lhs(), src.rhs()); + } +}; + + +// Dense ?= scalar * Product +// TODO we should apply that rule if that's really helpful +// for instance, this is not good for inner products +template< typename DstXprType, typename Lhs, typename Rhs, typename AssignFunc, typename Scalar, typename ScalarBis, typename Plain> +struct Assignment, const CwiseNullaryOp,Plain>, + const Product >, AssignFunc, Dense2Dense> +{ + typedef CwiseBinaryOp, + const CwiseNullaryOp,Plain>, + const Product > SrcXprType; + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const AssignFunc& func) + { + call_assignment_no_alias(dst, (src.lhs().functor().m_other * src.rhs().lhs())*src.rhs().rhs(), func); + } +}; + +//---------------------------------------- +// Catch "Dense ?= xpr + Product<>" expression to save one temporary +// FIXME we could probably enable these rules for any product, i.e., not only Dense and DefaultProduct + +template +struct evaluator_assume_aliasing::Scalar>, const OtherXpr, + const Product >, DenseShape > { + static const bool value = true; +}; + +template +struct evaluator_assume_aliasing::Scalar>, const OtherXpr, + const Product >, DenseShape > { + static const bool value = true; +}; + +template +struct assignment_from_xpr_op_product +{ + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const InitialFunc& /*func*/) + { + call_assignment_no_alias(dst, src.lhs(), Func1()); + call_assignment_no_alias(dst, src.rhs(), Func2()); + } +}; + +#define EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(ASSIGN_OP,BINOP,ASSIGN_OP2) \ + template< typename DstXprType, typename OtherXpr, typename Lhs, typename Rhs, typename DstScalar, typename SrcScalar, typename OtherScalar,typename ProdScalar> \ + struct Assignment, const OtherXpr, \ + const Product >, internal::ASSIGN_OP, Dense2Dense> \ + : assignment_from_xpr_op_product, internal::ASSIGN_OP, internal::ASSIGN_OP2 > \ + {} + +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(assign_op, scalar_sum_op,add_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(add_assign_op,scalar_sum_op,add_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(sub_assign_op,scalar_sum_op,sub_assign_op); + +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(assign_op, scalar_difference_op,sub_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(add_assign_op,scalar_difference_op,sub_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(sub_assign_op,scalar_difference_op,add_assign_op); + +//---------------------------------------- + +template +struct generic_product_impl +{ + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + dst.coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + dst.coeffRef(0,0) += (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst.coeffRef(0,0) -= (lhs.transpose().cwiseProduct(rhs)).sum(); } +}; + + +/*********************************************************************** +* Implementation of outer dense * dense vector product +***********************************************************************/ + +// Column major result +template +void EIGEN_DEVICE_FUNC outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const false_type&) +{ + evaluator rhsEval(rhs); + ei_declare_local_nested_eval(Lhs,lhs,Rhs::SizeAtCompileTime,actual_lhs); + // FIXME if cols is large enough, then it might be useful to make sure that lhs is sequentially stored + // FIXME not very good if rhs is real and lhs complex while alpha is real too + const Index cols = dst.cols(); + for (Index j=0; j +void EIGEN_DEVICE_FUNC outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const true_type&) +{ + evaluator lhsEval(lhs); + ei_declare_local_nested_eval(Rhs,rhs,Lhs::SizeAtCompileTime,actual_rhs); + // FIXME if rows is large enough, then it might be useful to make sure that rhs is sequentially stored + // FIXME not very good if lhs is real and rhs complex while alpha is real too + const Index rows = dst.rows(); + for (Index i=0; i +struct generic_product_impl +{ + template struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; + typedef typename Product::Scalar Scalar; + + // TODO it would be nice to be able to exploit our *_assign_op functors for that purpose + struct set { template EIGEN_DEVICE_FUNC void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; + struct add { template EIGEN_DEVICE_FUNC void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; + struct sub { template EIGEN_DEVICE_FUNC void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; + struct adds { + Scalar m_scale; + explicit adds(const Scalar& s) : m_scale(s) {} + template void EIGEN_DEVICE_FUNC operator()(const Dst& dst, const Src& src) const { + dst.const_cast_derived() += m_scale * src; + } + }; + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, set(), is_row_major()); + } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, add(), is_row_major()); + } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, sub(), is_row_major()); + } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + internal::outer_product_selector_run(dst, lhs, rhs, adds(alpha), is_row_major()); + } + +}; + + +// This base class provides default implementations for evalTo, addTo, subTo, in terms of scaleAndAddTo +template +struct generic_product_impl_base +{ + typedef typename Product::Scalar Scalar; + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst.setZero(); scaleAndAddTo(dst, lhs, rhs, Scalar(1)); } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { scaleAndAddTo(dst,lhs, rhs, Scalar(1)); } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { scaleAndAddTo(dst, lhs, rhs, Scalar(-1)); } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { Derived::scaleAndAddTo(dst,lhs,rhs,alpha); } + +}; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + typedef typename Product::Scalar Scalar; + enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; + typedef typename internal::remove_all::type>::type MatrixType; + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + // Fallback to inner product if both the lhs and rhs is a runtime vector. + if (lhs.rows() == 1 && rhs.cols() == 1) { + dst.coeffRef(0,0) += alpha * lhs.row(0).conjugate().dot(rhs.col(0)); + return; + } + LhsNested actual_lhs(lhs); + RhsNested actual_rhs(rhs); + internal::gemv_dense_selector::HasUsableDirectAccess) + >::run(actual_lhs, actual_rhs, dst, alpha); + } +}; + +template +struct generic_product_impl +{ + typedef typename Product::Scalar Scalar; + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // Same as: dst.noalias() = lhs.lazyProduct(rhs); + // but easier on the compiler side + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::assign_op()); + } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // dst.noalias() += lhs.lazyProduct(rhs); + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::add_assign_op()); + } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // dst.noalias() -= lhs.lazyProduct(rhs); + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::sub_assign_op()); + } + + // This is a special evaluation path called from generic_product_impl<...,GemmProduct> in file GeneralMatrixMatrix.h + // This variant tries to extract scalar multiples from both the LHS and RHS and factor them out. For instance: + // dst {,+,-}= (s1*A)*(B*s2) + // will be rewritten as: + // dst {,+,-}= (s1*s2) * (A.lazyProduct(B)) + // There are at least four benefits of doing so: + // 1 - huge performance gain for heap-allocated matrix types as it save costly allocations. + // 2 - it is faster than simply by-passing the heap allocation through stack allocation. + // 3 - it makes this fallback consistent with the heavy GEMM routine. + // 4 - it fully by-passes huge stack allocation attempts when multiplying huge fixed-size matrices. + // (see https://stackoverflow.com/questions/54738495) + // For small fixed sizes matrices, howver, the gains are less obvious, it is sometimes x2 faster, but sometimes x3 slower, + // and the behavior depends also a lot on the compiler... This is why this re-writting strategy is currently + // enabled only when falling back from the main GEMM. + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void eval_dynamic(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Func &func) + { + enum { + HasScalarFactor = blas_traits::HasScalarFactor || blas_traits::HasScalarFactor, + ConjLhs = blas_traits::NeedToConjugate, + ConjRhs = blas_traits::NeedToConjugate + }; + // FIXME: in c++11 this should be auto, and extractScalarFactor should also return auto + // this is important for real*complex_mat + Scalar actualAlpha = combine_scalar_factors(lhs, rhs); + + eval_dynamic_impl(dst, + blas_traits::extract(lhs).template conjugateIf(), + blas_traits::extract(rhs).template conjugateIf(), + func, + actualAlpha, + typename conditional::type()); + } + +protected: + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void eval_dynamic_impl(Dst& dst, const LhsT& lhs, const RhsT& rhs, const Func &func, const Scalar& s /* == 1 */, false_type) + { + EIGEN_UNUSED_VARIABLE(s); + eigen_internal_assert(s==Scalar(1)); + call_restricted_packet_assignment_no_alias(dst, lhs.lazyProduct(rhs), func); + } + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void eval_dynamic_impl(Dst& dst, const LhsT& lhs, const RhsT& rhs, const Func &func, const Scalar& s, true_type) + { + call_restricted_packet_assignment_no_alias(dst, s * lhs.lazyProduct(rhs), func); + } +}; + +// This specialization enforces the use of a coefficient-based evaluation strategy +template +struct generic_product_impl + : generic_product_impl {}; + +// Case 2: Evaluate coeff by coeff +// +// This is mostly taken from CoeffBasedProduct.h +// The main difference is that we add an extra argument to the etor_product_*_impl::run() function +// for the inner dimension of the product, because evaluator object do not know their size. + +template +struct etor_product_coeff_impl; + +template +struct etor_product_packet_impl; + +template +struct product_evaluator, ProductTag, DenseShape, DenseShape> + : evaluator_base > +{ + typedef Product XprType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit product_evaluator(const XprType& xpr) + : m_lhs(xpr.lhs()), + m_rhs(xpr.rhs()), + m_lhsImpl(m_lhs), // FIXME the creation of the evaluator objects should result in a no-op, but check that! + m_rhsImpl(m_rhs), // Moreover, they are only useful for the packet path, so we could completely disable them when not needed, + // or perhaps declare them on the fly on the packet method... We have experiment to check what's best. + m_innerDim(xpr.lhs().cols()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::MulCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::AddCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); +#if 0 + std::cerr << "LhsOuterStrideBytes= " << LhsOuterStrideBytes << "\n"; + std::cerr << "RhsOuterStrideBytes= " << RhsOuterStrideBytes << "\n"; + std::cerr << "LhsAlignment= " << LhsAlignment << "\n"; + std::cerr << "RhsAlignment= " << RhsAlignment << "\n"; + std::cerr << "CanVectorizeLhs= " << CanVectorizeLhs << "\n"; + std::cerr << "CanVectorizeRhs= " << CanVectorizeRhs << "\n"; + std::cerr << "CanVectorizeInner= " << CanVectorizeInner << "\n"; + std::cerr << "EvalToRowMajor= " << EvalToRowMajor << "\n"; + std::cerr << "Alignment= " << Alignment << "\n"; + std::cerr << "Flags= " << Flags << "\n"; +#endif + } + + // Everything below here is taken from CoeffBasedProduct.h + + typedef typename internal::nested_eval::type LhsNested; + typedef typename internal::nested_eval::type RhsNested; + + typedef typename internal::remove_all::type LhsNestedCleaned; + typedef typename internal::remove_all::type RhsNestedCleaned; + + typedef evaluator LhsEtorType; + typedef evaluator RhsEtorType; + + enum { + RowsAtCompileTime = LhsNestedCleaned::RowsAtCompileTime, + ColsAtCompileTime = RhsNestedCleaned::ColsAtCompileTime, + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsNestedCleaned::ColsAtCompileTime, RhsNestedCleaned::RowsAtCompileTime), + MaxRowsAtCompileTime = LhsNestedCleaned::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsNestedCleaned::MaxColsAtCompileTime + }; + + typedef typename find_best_packet::type LhsVecPacketType; + typedef typename find_best_packet::type RhsVecPacketType; + + enum { + + LhsCoeffReadCost = LhsEtorType::CoeffReadCost, + RhsCoeffReadCost = RhsEtorType::CoeffReadCost, + CoeffReadCost = InnerSize==0 ? NumTraits::ReadCost + : InnerSize == Dynamic ? HugeCost + : InnerSize * (NumTraits::MulCost + int(LhsCoeffReadCost) + int(RhsCoeffReadCost)) + + (InnerSize - 1) * NumTraits::AddCost, + + Unroll = CoeffReadCost <= EIGEN_UNROLLING_LIMIT, + + LhsFlags = LhsEtorType::Flags, + RhsFlags = RhsEtorType::Flags, + + LhsRowMajor = LhsFlags & RowMajorBit, + RhsRowMajor = RhsFlags & RowMajorBit, + + LhsVecPacketSize = unpacket_traits::size, + RhsVecPacketSize = unpacket_traits::size, + + // Here, we don't care about alignment larger than the usable packet size. + LhsAlignment = EIGEN_PLAIN_ENUM_MIN(LhsEtorType::Alignment,LhsVecPacketSize*int(sizeof(typename LhsNestedCleaned::Scalar))), + RhsAlignment = EIGEN_PLAIN_ENUM_MIN(RhsEtorType::Alignment,RhsVecPacketSize*int(sizeof(typename RhsNestedCleaned::Scalar))), + + SameType = is_same::value, + + CanVectorizeRhs = bool(RhsRowMajor) && (RhsFlags & PacketAccessBit) && (ColsAtCompileTime!=1), + CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit) && (RowsAtCompileTime!=1), + + EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + : (bool(RhsRowMajor) && !CanVectorizeLhs), + + Flags = ((int(LhsFlags) | int(RhsFlags)) & HereditaryBits & ~RowMajorBit) + | (EvalToRowMajor ? RowMajorBit : 0) + // TODO enable vectorization for mixed types + | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0) + | (XprType::IsVectorAtCompileTime ? LinearAccessBit : 0), + + LhsOuterStrideBytes = int(LhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename LhsNestedCleaned::Scalar)), + RhsOuterStrideBytes = int(RhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename RhsNestedCleaned::Scalar)), + + Alignment = bool(CanVectorizeLhs) ? (LhsOuterStrideBytes<=0 || (int(LhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,LhsAlignment))!=0 ? 0 : LhsAlignment) + : bool(CanVectorizeRhs) ? (RhsOuterStrideBytes<=0 || (int(RhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,RhsAlignment))!=0 ? 0 : RhsAlignment) + : 0, + + /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside + * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner + * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect + * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI. + */ + CanVectorizeInner = SameType + && LhsRowMajor + && (!RhsRowMajor) + && (int(LhsFlags) & int(RhsFlags) & ActualPacketAccessBit) + && (int(InnerSize) % packet_traits::size == 0) + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index row, Index col) const + { + return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); + } + + /* Allow index-based non-packet access. It is impossible though to allow index-based packed access, + * which is why we don't set the LinearAccessBit. + * TODO: this seems possible when the result is a vector + */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const CoeffReturnType coeff(Index index) const + { + const Index row = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? 0 : index; + const Index col = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? index : 0; + return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const PacketType packet(Index row, Index col) const + { + PacketType res; + typedef etor_product_packet_impl PacketImpl; + PacketImpl::run(row, col, m_lhsImpl, m_rhsImpl, m_innerDim, res); + return res; + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const PacketType packet(Index index) const + { + const Index row = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? 0 : index; + const Index col = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? index : 0; + return packet(row,col); + } + +protected: + typename internal::add_const_on_value_type::type m_lhs; + typename internal::add_const_on_value_type::type m_rhs; + + LhsEtorType m_lhsImpl; + RhsEtorType m_rhsImpl; + + // TODO: Get rid of m_innerDim if known at compile time + Index m_innerDim; +}; + +template +struct product_evaluator, LazyCoeffBasedProductMode, DenseShape, DenseShape> + : product_evaluator, CoeffBasedProductMode, DenseShape, DenseShape> +{ + typedef Product XprType; + typedef Product BaseProduct; + typedef product_evaluator Base; + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit product_evaluator(const XprType& xpr) + : Base(BaseProduct(xpr.lhs(),xpr.rhs())) + {} +}; + +/**************************************** +*** Coeff based product, Packet path *** +****************************************/ + +template +struct etor_product_packet_impl +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res) + { + etor_product_packet_impl::run(row, col, lhs, rhs, innerDim, res); + res = pmadd(pset1(lhs.coeff(row, Index(UnrollingIndex-1))), rhs.template packet(Index(UnrollingIndex-1), col), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res) + { + etor_product_packet_impl::run(row, col, lhs, rhs, innerDim, res); + res = pmadd(lhs.template packet(row, Index(UnrollingIndex-1)), pset1(rhs.coeff(Index(UnrollingIndex-1), col)), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res) + { + res = pmul(pset1(lhs.coeff(row, Index(0))),rhs.template packet(Index(0), col)); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res) + { + res = pmul(lhs.template packet(row, Index(0)), pset1(rhs.coeff(Index(0), col))); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res) + { + res = pset1(typename unpacket_traits::type(0)); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res) + { + res = pset1(typename unpacket_traits::type(0)); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res) + { + res = pset1(typename unpacket_traits::type(0)); + for(Index i = 0; i < innerDim; ++i) + res = pmadd(pset1(lhs.coeff(row, i)), rhs.template packet(i, col), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res) + { + res = pset1(typename unpacket_traits::type(0)); + for(Index i = 0; i < innerDim; ++i) + res = pmadd(lhs.template packet(row, i), pset1(rhs.coeff(i, col)), res); + } +}; + + +/*************************************************************************** +* Triangular products +***************************************************************************/ +template +struct triangular_product_impl; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + triangular_product_impl + ::run(dst, lhs.nestedExpression(), rhs, alpha); + } +}; + +template +struct generic_product_impl +: generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + triangular_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); + } +}; + + +/*************************************************************************** +* SelfAdjoint products +***************************************************************************/ +template +struct selfadjoint_product_impl; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static EIGEN_DEVICE_FUNC + void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + selfadjoint_product_impl::run(dst, lhs.nestedExpression(), rhs, alpha); + } +}; + +template +struct generic_product_impl +: generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + selfadjoint_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); + } +}; + + +/*************************************************************************** +* Diagonal products +***************************************************************************/ + +template +struct diagonal_product_evaluator_base + : evaluator_base +{ + typedef typename ScalarBinaryOpTraits::ReturnType Scalar; +public: + enum { + CoeffReadCost = int(NumTraits::MulCost) + int(evaluator::CoeffReadCost) + int(evaluator::CoeffReadCost), + + MatrixFlags = evaluator::Flags, + DiagFlags = evaluator::Flags, + + _StorageOrder = (Derived::MaxRowsAtCompileTime==1 && Derived::MaxColsAtCompileTime!=1) ? RowMajor + : (Derived::MaxColsAtCompileTime==1 && Derived::MaxRowsAtCompileTime!=1) ? ColMajor + : MatrixFlags & RowMajorBit ? RowMajor : ColMajor, + _SameStorageOrder = _StorageOrder == (MatrixFlags & RowMajorBit ? RowMajor : ColMajor), + + _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) + ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), + _SameTypes = is_same::value, + // FIXME currently we need same types, but in the future the next rule should be the one + //_Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagFlags)&PacketAccessBit))), + _Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) + && _SameTypes + && (_SameStorageOrder || (MatrixFlags&LinearAccessBit)==LinearAccessBit) + && (_ScalarAccessOnDiag || (bool(int(DiagFlags)&PacketAccessBit))), + _LinearAccessMask = (MatrixType::RowsAtCompileTime==1 || MatrixType::ColsAtCompileTime==1) ? LinearAccessBit : 0, + Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixFlags)) | (_Vectorizable ? PacketAccessBit : 0), + Alignment = evaluator::Alignment, + + AsScalarProduct = (DiagonalType::SizeAtCompileTime==1) + || (DiagonalType::SizeAtCompileTime==Dynamic && MatrixType::RowsAtCompileTime==1 && ProductOrder==OnTheLeft) + || (DiagonalType::SizeAtCompileTime==Dynamic && MatrixType::ColsAtCompileTime==1 && ProductOrder==OnTheRight) + }; + + EIGEN_DEVICE_FUNC diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag) + : m_diagImpl(diag), m_matImpl(mat) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::MulCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const + { + if(AsScalarProduct) + return m_diagImpl.coeff(0) * m_matImpl.coeff(idx); + else + return m_diagImpl.coeff(idx) * m_matImpl.coeff(idx); + } + +protected: + template + EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::true_type) const + { + return internal::pmul(m_matImpl.template packet(row, col), + internal::pset1(m_diagImpl.coeff(id))); + } + + template + EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::false_type) const + { + enum { + InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, + DiagonalPacketLoadMode = EIGEN_PLAIN_ENUM_MIN(LoadMode,((InnerSize%16) == 0) ? int(Aligned16) : int(evaluator::Alignment)) // FIXME hardcoded 16!! + }; + return internal::pmul(m_matImpl.template packet(row, col), + m_diagImpl.template packet(id)); + } + + evaluator m_diagImpl; + evaluator m_matImpl; +}; + +// diagonal * dense +template +struct product_evaluator, ProductTag, DiagonalShape, DenseShape> + : diagonal_product_evaluator_base, OnTheLeft> +{ + typedef diagonal_product_evaluator_base, OnTheLeft> Base; + using Base::m_diagImpl; + using Base::m_matImpl; + using Base::coeff; + typedef typename Base::Scalar Scalar; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef typename Lhs::DiagonalVectorType DiagonalType; + + + enum { StorageOrder = Base::_StorageOrder }; + + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(xpr.rhs(), xpr.lhs().diagonal()) + { + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_diagImpl.coeff(row) * m_matImpl.coeff(row, col); + } + +#ifndef EIGEN_GPUCC + template + EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const + { + // FIXME: NVCC used to complain about the template keyword, but we have to check whether this is still the case. + // See also similar calls below. + return this->template packet_impl(row,col, row, + typename internal::conditional::type()); + } + + template + EIGEN_STRONG_INLINE PacketType packet(Index idx) const + { + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } +#endif +}; + +// dense * diagonal +template +struct product_evaluator, ProductTag, DenseShape, DiagonalShape> + : diagonal_product_evaluator_base, OnTheRight> +{ + typedef diagonal_product_evaluator_base, OnTheRight> Base; + using Base::m_diagImpl; + using Base::m_matImpl; + using Base::coeff; + typedef typename Base::Scalar Scalar; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + enum { StorageOrder = Base::_StorageOrder }; + + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(xpr.lhs(), xpr.rhs().diagonal()) + { + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_matImpl.coeff(row, col) * m_diagImpl.coeff(col); + } + +#ifndef EIGEN_GPUCC + template + EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const + { + return this->template packet_impl(row,col, col, + typename internal::conditional::type()); + } + + template + EIGEN_STRONG_INLINE PacketType packet(Index idx) const + { + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } +#endif +}; + +/*************************************************************************** +* Products with permutation matrices +***************************************************************************/ + +/** \internal + * \class permutation_matrix_product + * Internal helper class implementing the product between a permutation matrix and a matrix. + * This class is specialized for DenseShape below and for SparseShape in SparseCore/SparsePermutation.h + */ +template +struct permutation_matrix_product; + +template +struct permutation_matrix_product +{ + typedef typename nested_eval::type MatrixType; + typedef typename remove_all::type MatrixTypeCleaned; + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Dest& dst, const PermutationType& perm, const ExpressionType& xpr) + { + MatrixType mat(xpr); + const Index n = Side==OnTheLeft ? mat.rows() : mat.cols(); + // FIXME we need an is_same for expression that is not sensitive to constness. For instance + // is_same_xpr, Block >::value should be true. + //if(is_same::value && extract_data(dst) == extract_data(mat)) + if(is_same_dense(dst, mat)) + { + // apply the permutation inplace + Matrix mask(perm.size()); + mask.fill(false); + Index r = 0; + while(r < perm.size()) + { + // search for the next seed + while(r=perm.size()) + break; + // we got one, let's follow it until we are back to the seed + Index k0 = r++; + Index kPrev = k0; + mask.coeffRef(k0) = true; + for(Index k=perm.indices().coeff(k0); k!=k0; k=perm.indices().coeff(k)) + { + Block(dst, k) + .swap(Block + (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); + + mask.coeffRef(k) = true; + kPrev = k; + } + } + } + else + { + for(Index i = 0; i < n; ++i) + { + Block + (dst, ((Side==OnTheLeft) ^ Transposed) ? perm.indices().coeff(i) : i) + + = + + Block + (mat, ((Side==OnTheRight) ^ Transposed) ? perm.indices().coeff(i) : i); + } + } + } +}; + +template +struct generic_product_impl +{ + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, lhs, rhs); + } +}; + +template +struct generic_product_impl +{ + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, rhs, lhs); + } +}; + +template +struct generic_product_impl, Rhs, PermutationShape, MatrixShape, ProductTag> +{ + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dest& dst, const Inverse& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, lhs.nestedExpression(), rhs); + } +}; + +template +struct generic_product_impl, MatrixShape, PermutationShape, ProductTag> +{ + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dest& dst, const Lhs& lhs, const Inverse& rhs) + { + permutation_matrix_product::run(dst, rhs.nestedExpression(), lhs); + } +}; + + +/*************************************************************************** +* Products with transpositions matrices +***************************************************************************/ + +// FIXME could we unify Transpositions and Permutation into a single "shape"?? + +/** \internal + * \class transposition_matrix_product + * Internal helper class implementing the product between a permutation matrix and a matrix. + */ +template +struct transposition_matrix_product +{ + typedef typename nested_eval::type MatrixType; + typedef typename remove_all::type MatrixTypeCleaned; + + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Dest& dst, const TranspositionType& tr, const ExpressionType& xpr) + { + MatrixType mat(xpr); + typedef typename TranspositionType::StorageIndex StorageIndex; + const Index size = tr.size(); + StorageIndex j = 0; + + if(!is_same_dense(dst,mat)) + dst = mat; + + for(Index k=(Transposed?size-1:0) ; Transposed?k>=0:k +struct generic_product_impl +{ + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, lhs, rhs); + } +}; + +template +struct generic_product_impl +{ + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, rhs, lhs); + } +}; + + +template +struct generic_product_impl, Rhs, TranspositionsShape, MatrixShape, ProductTag> +{ + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dest& dst, const Transpose& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, lhs.nestedExpression(), rhs); + } +}; + +template +struct generic_product_impl, MatrixShape, TranspositionsShape, ProductTag> +{ + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalTo(Dest& dst, const Lhs& lhs, const Transpose& rhs) + { + transposition_matrix_product::run(dst, rhs.nestedExpression(), lhs); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_EVALUATORS_H diff --git a/Vendor/eigen/Eigen/src/Core/Random.h b/Vendor/eigen/Eigen/src/Core/Random.h new file mode 100644 index 0000000..dab2ac8 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Random.h @@ -0,0 +1,218 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_RANDOM_H +#define EIGEN_RANDOM_H + +namespace Eigen { + +namespace internal { + +template struct scalar_random_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op) + inline const Scalar operator() () const { return random(); } +}; + +template +struct functor_traits > +{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false, IsRepeatable = false }; }; + +} // end namespace internal + +/** \returns a random matrix expression + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * The parameters \a rows and \a cols are the number of rows and of columns of + * the returned matrix. Must be compatible with this MatrixBase type. + * + * \not_reentrant + * + * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, + * it is redundant to pass \a rows and \a cols as arguments, so Random() should be used + * instead. + * + * + * Example: \include MatrixBase_random_int_int.cpp + * Output: \verbinclude MatrixBase_random_int_int.out + * + * This expression has the "evaluate before nesting" flag so that it will be evaluated into + * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected + * behavior with expressions involving random matrices. + * + * See DenseBase::NullaryExpr(Index, const CustomNullaryOp&) for an example using C++11 random generators. + * + * \sa DenseBase::setRandom(), DenseBase::Random(Index), DenseBase::Random() + */ +template +inline const typename DenseBase::RandomReturnType +DenseBase::Random(Index rows, Index cols) +{ + return NullaryExpr(rows, cols, internal::scalar_random_op()); +} + +/** \returns a random vector expression + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * The parameter \a size is the size of the returned vector. + * Must be compatible with this MatrixBase type. + * + * \only_for_vectors + * \not_reentrant + * + * This variant is meant to be used for dynamic-size vector types. For fixed-size types, + * it is redundant to pass \a size as argument, so Random() should be used + * instead. + * + * Example: \include MatrixBase_random_int.cpp + * Output: \verbinclude MatrixBase_random_int.out + * + * This expression has the "evaluate before nesting" flag so that it will be evaluated into + * a temporary vector whenever it is nested in a larger expression. This prevents unexpected + * behavior with expressions involving random matrices. + * + * \sa DenseBase::setRandom(), DenseBase::Random(Index,Index), DenseBase::Random() + */ +template +inline const typename DenseBase::RandomReturnType +DenseBase::Random(Index size) +{ + return NullaryExpr(size, internal::scalar_random_op()); +} + +/** \returns a fixed-size random matrix or vector expression + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you + * need to use the variants taking size arguments. + * + * Example: \include MatrixBase_random.cpp + * Output: \verbinclude MatrixBase_random.out + * + * This expression has the "evaluate before nesting" flag so that it will be evaluated into + * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected + * behavior with expressions involving random matrices. + * + * \not_reentrant + * + * \sa DenseBase::setRandom(), DenseBase::Random(Index,Index), DenseBase::Random(Index) + */ +template +inline const typename DenseBase::RandomReturnType +DenseBase::Random() +{ + return NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_random_op()); +} + +/** Sets all coefficients in this expression to random values. + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \not_reentrant + * + * Example: \include MatrixBase_setRandom.cpp + * Output: \verbinclude MatrixBase_setRandom.out + * + * \sa class CwiseNullaryOp, setRandom(Index), setRandom(Index,Index) + */ +template +EIGEN_DEVICE_FUNC inline Derived& DenseBase::setRandom() +{ + return *this = Random(rows(), cols()); +} + +/** Resizes to the given \a newSize, and sets all coefficients in this expression to random values. + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \only_for_vectors + * \not_reentrant + * + * Example: \include Matrix_setRandom_int.cpp + * Output: \verbinclude Matrix_setRandom_int.out + * + * \sa DenseBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, DenseBase::Random() + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setRandom(Index newSize) +{ + resize(newSize); + return setRandom(); +} + +/** Resizes to the given size, and sets all coefficients in this expression to random values. + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \not_reentrant + * + * \param rows the new number of rows + * \param cols the new number of columns + * + * Example: \include Matrix_setRandom_int_int.cpp + * Output: \verbinclude Matrix_setRandom_int_int.out + * + * \sa DenseBase::setRandom(), setRandom(Index), class CwiseNullaryOp, DenseBase::Random() + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setRandom(Index rows, Index cols) +{ + resize(rows, cols); + return setRandom(); +} + +/** Resizes to the given size, changing only the number of columns, and sets all + * coefficients in this expression to random values. For the parameter of type + * NoChange_t, just pass the special value \c NoChange. + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \not_reentrant + * + * \sa DenseBase::setRandom(), setRandom(Index), setRandom(Index, NoChange_t), class CwiseNullaryOp, DenseBase::Random() + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setRandom(NoChange_t, Index cols) +{ + return setRandom(rows(), cols); +} + +/** Resizes to the given size, changing only the number of rows, and sets all + * coefficients in this expression to random values. For the parameter of type + * NoChange_t, just pass the special value \c NoChange. + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \not_reentrant + * + * \sa DenseBase::setRandom(), setRandom(Index), setRandom(NoChange_t, Index), class CwiseNullaryOp, DenseBase::Random() + */ +template +EIGEN_STRONG_INLINE Derived& +PlainObjectBase::setRandom(Index rows, NoChange_t) +{ + return setRandom(rows, cols()); +} + +} // end namespace Eigen + +#endif // EIGEN_RANDOM_H diff --git a/Vendor/eigen/Eigen/src/Core/Redux.h b/Vendor/eigen/Eigen/src/Core/Redux.h new file mode 100644 index 0000000..b6790d1 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Redux.h @@ -0,0 +1,515 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_REDUX_H +#define EIGEN_REDUX_H + +namespace Eigen { + +namespace internal { + +// TODO +// * implement other kind of vectorization +// * factorize code + +/*************************************************************************** +* Part 1 : the logic deciding a strategy for vectorization and unrolling +***************************************************************************/ + +template +struct redux_traits +{ +public: + typedef typename find_best_packet::type PacketType; + enum { + PacketSize = unpacket_traits::size, + InnerMaxSize = int(Evaluator::IsRowMajor) + ? Evaluator::MaxColsAtCompileTime + : Evaluator::MaxRowsAtCompileTime, + OuterMaxSize = int(Evaluator::IsRowMajor) + ? Evaluator::MaxRowsAtCompileTime + : Evaluator::MaxColsAtCompileTime, + SliceVectorizedWork = int(InnerMaxSize)==Dynamic ? Dynamic + : int(OuterMaxSize)==Dynamic ? (int(InnerMaxSize)>=int(PacketSize) ? Dynamic : 0) + : (int(InnerMaxSize)/int(PacketSize)) * int(OuterMaxSize) + }; + + enum { + MightVectorize = (int(Evaluator::Flags)&ActualPacketAccessBit) + && (functor_traits::PacketAccess), + MayLinearVectorize = bool(MightVectorize) && (int(Evaluator::Flags)&LinearAccessBit), + MaySliceVectorize = bool(MightVectorize) && (int(SliceVectorizedWork)==Dynamic || int(SliceVectorizedWork)>=3) + }; + +public: + enum { + Traversal = int(MayLinearVectorize) ? int(LinearVectorizedTraversal) + : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) + : int(DefaultTraversal) + }; + +public: + enum { + Cost = Evaluator::SizeAtCompileTime == Dynamic ? HugeCost + : int(Evaluator::SizeAtCompileTime) * int(Evaluator::CoeffReadCost) + (Evaluator::SizeAtCompileTime-1) * functor_traits::Cost, + UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize)) + }; + +public: + enum { + Unrolling = Cost <= UnrollingLimit ? CompleteUnrolling : NoUnrolling + }; + +#ifdef EIGEN_DEBUG_ASSIGN + static void debug() + { + std::cerr << "Xpr: " << typeid(typename Evaluator::XprType).name() << std::endl; + std::cerr.setf(std::ios::hex, std::ios::basefield); + EIGEN_DEBUG_VAR(Evaluator::Flags) + std::cerr.unsetf(std::ios::hex); + EIGEN_DEBUG_VAR(InnerMaxSize) + EIGEN_DEBUG_VAR(OuterMaxSize) + EIGEN_DEBUG_VAR(SliceVectorizedWork) + EIGEN_DEBUG_VAR(PacketSize) + EIGEN_DEBUG_VAR(MightVectorize) + EIGEN_DEBUG_VAR(MayLinearVectorize) + EIGEN_DEBUG_VAR(MaySliceVectorize) + std::cerr << "Traversal" << " = " << Traversal << " (" << demangle_traversal(Traversal) << ")" << std::endl; + EIGEN_DEBUG_VAR(UnrollingLimit) + std::cerr << "Unrolling" << " = " << Unrolling << " (" << demangle_unrolling(Unrolling) << ")" << std::endl; + std::cerr << std::endl; + } +#endif +}; + +/*************************************************************************** +* Part 2 : unrollers +***************************************************************************/ + +/*** no vectorization ***/ + +template +struct redux_novec_unroller +{ + enum { + HalfLength = Length/2 + }; + + typedef typename Evaluator::Scalar Scalar; + + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE Scalar run(const Evaluator &eval, const Func& func) + { + return func(redux_novec_unroller::run(eval,func), + redux_novec_unroller::run(eval,func)); + } +}; + +template +struct redux_novec_unroller +{ + enum { + outer = Start / Evaluator::InnerSizeAtCompileTime, + inner = Start % Evaluator::InnerSizeAtCompileTime + }; + + typedef typename Evaluator::Scalar Scalar; + + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE Scalar run(const Evaluator &eval, const Func&) + { + return eval.coeffByOuterInner(outer, inner); + } +}; + +// This is actually dead code and will never be called. It is required +// to prevent false warnings regarding failed inlining though +// for 0 length run() will never be called at all. +template +struct redux_novec_unroller +{ + typedef typename Evaluator::Scalar Scalar; + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE Scalar run(const Evaluator&, const Func&) { return Scalar(); } +}; + +/*** vectorization ***/ + +template +struct redux_vec_unroller +{ + template + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE PacketType run(const Evaluator &eval, const Func& func) + { + enum { + PacketSize = unpacket_traits::size, + HalfLength = Length/2 + }; + + return func.packetOp( + redux_vec_unroller::template run(eval,func), + redux_vec_unroller::template run(eval,func) ); + } +}; + +template +struct redux_vec_unroller +{ + template + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE PacketType run(const Evaluator &eval, const Func&) + { + enum { + PacketSize = unpacket_traits::size, + index = Start * PacketSize, + outer = index / int(Evaluator::InnerSizeAtCompileTime), + inner = index % int(Evaluator::InnerSizeAtCompileTime), + alignment = Evaluator::Alignment + }; + return eval.template packetByOuterInner(outer, inner); + } +}; + +/*************************************************************************** +* Part 3 : implementation of all cases +***************************************************************************/ + +template::Traversal, + int Unrolling = redux_traits::Unrolling +> +struct redux_impl; + +template +struct redux_impl +{ + typedef typename Evaluator::Scalar Scalar; + + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE + Scalar run(const Evaluator &eval, const Func& func, const XprType& xpr) + { + eigen_assert(xpr.rows()>0 && xpr.cols()>0 && "you are using an empty matrix"); + Scalar res; + res = eval.coeffByOuterInner(0, 0); + for(Index i = 1; i < xpr.innerSize(); ++i) + res = func(res, eval.coeffByOuterInner(0, i)); + for(Index i = 1; i < xpr.outerSize(); ++i) + for(Index j = 0; j < xpr.innerSize(); ++j) + res = func(res, eval.coeffByOuterInner(i, j)); + return res; + } +}; + +template +struct redux_impl + : redux_novec_unroller +{ + typedef redux_novec_unroller Base; + typedef typename Evaluator::Scalar Scalar; + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE + Scalar run(const Evaluator &eval, const Func& func, const XprType& /*xpr*/) + { + return Base::run(eval,func); + } +}; + +template +struct redux_impl +{ + typedef typename Evaluator::Scalar Scalar; + typedef typename redux_traits::PacketType PacketScalar; + + template + static Scalar run(const Evaluator &eval, const Func& func, const XprType& xpr) + { + const Index size = xpr.size(); + + const Index packetSize = redux_traits::PacketSize; + const int packetAlignment = unpacket_traits::alignment; + enum { + alignment0 = (bool(Evaluator::Flags & DirectAccessBit) && bool(packet_traits::AlignedOnScalar)) ? int(packetAlignment) : int(Unaligned), + alignment = EIGEN_PLAIN_ENUM_MAX(alignment0, Evaluator::Alignment) + }; + const Index alignedStart = internal::first_default_aligned(xpr); + const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize); + const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize); + const Index alignedEnd2 = alignedStart + alignedSize2; + const Index alignedEnd = alignedStart + alignedSize; + Scalar res; + if(alignedSize) + { + PacketScalar packet_res0 = eval.template packet(alignedStart); + if(alignedSize>packetSize) // we have at least two packets to partly unroll the loop + { + PacketScalar packet_res1 = eval.template packet(alignedStart+packetSize); + for(Index index = alignedStart + 2*packetSize; index < alignedEnd2; index += 2*packetSize) + { + packet_res0 = func.packetOp(packet_res0, eval.template packet(index)); + packet_res1 = func.packetOp(packet_res1, eval.template packet(index+packetSize)); + } + + packet_res0 = func.packetOp(packet_res0,packet_res1); + if(alignedEnd>alignedEnd2) + packet_res0 = func.packetOp(packet_res0, eval.template packet(alignedEnd2)); + } + res = func.predux(packet_res0); + + for(Index index = 0; index < alignedStart; ++index) + res = func(res,eval.coeff(index)); + + for(Index index = alignedEnd; index < size; ++index) + res = func(res,eval.coeff(index)); + } + else // too small to vectorize anything. + // since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize. + { + res = eval.coeff(0); + for(Index index = 1; index < size; ++index) + res = func(res,eval.coeff(index)); + } + + return res; + } +}; + +// NOTE: for SliceVectorizedTraversal we simply bypass unrolling +template +struct redux_impl +{ + typedef typename Evaluator::Scalar Scalar; + typedef typename redux_traits::PacketType PacketType; + + template + EIGEN_DEVICE_FUNC static Scalar run(const Evaluator &eval, const Func& func, const XprType& xpr) + { + eigen_assert(xpr.rows()>0 && xpr.cols()>0 && "you are using an empty matrix"); + const Index innerSize = xpr.innerSize(); + const Index outerSize = xpr.outerSize(); + enum { + packetSize = redux_traits::PacketSize + }; + const Index packetedInnerSize = ((innerSize)/packetSize)*packetSize; + Scalar res; + if(packetedInnerSize) + { + PacketType packet_res = eval.template packet(0,0); + for(Index j=0; j(j,i)); + + res = func.predux(packet_res); + for(Index j=0; j::run(eval, func, xpr); + } + + return res; + } +}; + +template +struct redux_impl +{ + typedef typename Evaluator::Scalar Scalar; + + typedef typename redux_traits::PacketType PacketType; + enum { + PacketSize = redux_traits::PacketSize, + Size = Evaluator::SizeAtCompileTime, + VectorizedSize = (int(Size) / int(PacketSize)) * int(PacketSize) + }; + + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE + Scalar run(const Evaluator &eval, const Func& func, const XprType &xpr) + { + EIGEN_ONLY_USED_FOR_DEBUG(xpr) + eigen_assert(xpr.rows()>0 && xpr.cols()>0 && "you are using an empty matrix"); + if (VectorizedSize > 0) { + Scalar res = func.predux(redux_vec_unroller::template run(eval,func)); + if (VectorizedSize != Size) + res = func(res,redux_novec_unroller::run(eval,func)); + return res; + } + else { + return redux_novec_unroller::run(eval,func); + } + } +}; + +// evaluator adaptor +template +class redux_evaluator : public internal::evaluator<_XprType> +{ + typedef internal::evaluator<_XprType> Base; +public: + typedef _XprType XprType; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit redux_evaluator(const XprType &xpr) : Base(xpr) {} + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename XprType::PacketScalar PacketScalar; + + enum { + MaxRowsAtCompileTime = XprType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = XprType::MaxColsAtCompileTime, + // TODO we should not remove DirectAccessBit and rather find an elegant way to query the alignment offset at runtime from the evaluator + Flags = Base::Flags & ~DirectAccessBit, + IsRowMajor = XprType::IsRowMajor, + SizeAtCompileTime = XprType::SizeAtCompileTime, + InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeffByOuterInner(Index outer, Index inner) const + { return Base::coeff(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + PacketType packetByOuterInner(Index outer, Index inner) const + { return Base::template packet(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } + +}; + +} // end namespace internal + +/*************************************************************************** +* Part 4 : public API +***************************************************************************/ + + +/** \returns the result of a full redux operation on the whole matrix or vector using \a func + * + * The template parameter \a BinaryOp is the type of the functor \a func which must be + * an associative operator. Both current C++98 and C++11 functor styles are handled. + * + * \warning the matrix must be not empty, otherwise an assertion is triggered. + * + * \sa DenseBase::sum(), DenseBase::minCoeff(), DenseBase::maxCoeff(), MatrixBase::colwise(), MatrixBase::rowwise() + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::redux(const Func& func) const +{ + eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); + + typedef typename internal::redux_evaluator ThisEvaluator; + ThisEvaluator thisEval(derived()); + + // The initial expression is passed to the reducer as an additional argument instead of + // passing it as a member of redux_evaluator to help + return internal::redux_impl::run(thisEval, func, derived()); +} + +/** \returns the minimum of all coefficients of \c *this. + * In case \c *this contains NaN, NaNPropagation determines the behavior: + * NaNPropagation == PropagateFast : undefined + * NaNPropagation == PropagateNaN : result is NaN + * NaNPropagation == PropagateNumbers : result is minimum of elements that are not NaN + * \warning the matrix must be not empty, otherwise an assertion is triggered. + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::minCoeff() const +{ + return derived().redux(Eigen::internal::scalar_min_op()); +} + +/** \returns the maximum of all coefficients of \c *this. + * In case \c *this contains NaN, NaNPropagation determines the behavior: + * NaNPropagation == PropagateFast : undefined + * NaNPropagation == PropagateNaN : result is NaN + * NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN + * \warning the matrix must be not empty, otherwise an assertion is triggered. + */ +template +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::maxCoeff() const +{ + return derived().redux(Eigen::internal::scalar_max_op()); +} + +/** \returns the sum of all coefficients of \c *this + * + * If \c *this is empty, then the value 0 is returned. + * + * \sa trace(), prod(), mean() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::sum() const +{ + if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) + return Scalar(0); + return derived().redux(Eigen::internal::scalar_sum_op()); +} + +/** \returns the mean of all coefficients of *this +* +* \sa trace(), prod(), sum() +*/ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::mean() const +{ +#ifdef __INTEL_COMPILER + #pragma warning push + #pragma warning ( disable : 2259 ) +#endif + return Scalar(derived().redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); +#ifdef __INTEL_COMPILER + #pragma warning pop +#endif +} + +/** \returns the product of all coefficients of *this + * + * Example: \include MatrixBase_prod.cpp + * Output: \verbinclude MatrixBase_prod.out + * + * \sa sum(), mean(), trace() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename internal::traits::Scalar +DenseBase::prod() const +{ + if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) + return Scalar(1); + return derived().redux(Eigen::internal::scalar_product_op()); +} + +/** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal. + * + * \c *this can be any matrix, not necessarily square. + * + * \sa diagonal(), sum() + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename internal::traits::Scalar +MatrixBase::trace() const +{ + return derived().diagonal().sum(); +} + +} // end namespace Eigen + +#endif // EIGEN_REDUX_H diff --git a/Vendor/eigen/Eigen/src/Core/Ref.h b/Vendor/eigen/Eigen/src/Core/Ref.h new file mode 100644 index 0000000..c2a37ea --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Ref.h @@ -0,0 +1,381 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2012 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_REF_H +#define EIGEN_REF_H + +namespace Eigen { + +namespace internal { + +template +struct traits > + : public traits > +{ + typedef _PlainObjectType PlainObjectType; + typedef _StrideType StrideType; + enum { + Options = _Options, + Flags = traits >::Flags | NestByRefBit, + Alignment = traits >::Alignment + }; + + template struct match { + enum { + IsVectorAtCompileTime = PlainObjectType::IsVectorAtCompileTime || Derived::IsVectorAtCompileTime, + HasDirectAccess = internal::has_direct_access::ret, + StorageOrderMatch = IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)), + InnerStrideMatch = int(StrideType::InnerStrideAtCompileTime)==int(Dynamic) + || int(StrideType::InnerStrideAtCompileTime)==int(Derived::InnerStrideAtCompileTime) + || (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1), + OuterStrideMatch = IsVectorAtCompileTime + || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), + // NOTE, this indirection of evaluator::Alignment is needed + // to workaround a very strange bug in MSVC related to the instantiation + // of has_*ary_operator in evaluator. + // This line is surprisingly very sensitive. For instance, simply adding parenthesis + // as "DerivedAlignment = (int(evaluator::Alignment))," will make MSVC fail... + DerivedAlignment = int(evaluator::Alignment), + AlignmentMatch = (int(traits::Alignment)==int(Unaligned)) || (DerivedAlignment >= int(Alignment)), // FIXME the first condition is not very clear, it should be replaced by the required alignment + ScalarTypeMatch = internal::is_same::value, + MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch + }; + typedef typename internal::conditional::type type; + }; + +}; + +template +struct traits > : public traits {}; + +} + +template class RefBase + : public MapBase +{ + typedef typename internal::traits::PlainObjectType PlainObjectType; + typedef typename internal::traits::StrideType StrideType; + +public: + + typedef MapBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(RefBase) + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR inline Index innerStride() const + { + return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR inline Index outerStride() const + { + return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() + : IsVectorAtCompileTime ? this->size() + : int(Flags)&RowMajorBit ? this->cols() + : this->rows(); + } + + EIGEN_DEVICE_FUNC RefBase() + : Base(0,RowsAtCompileTime==Dynamic?0:RowsAtCompileTime,ColsAtCompileTime==Dynamic?0:ColsAtCompileTime), + // Stride<> does not allow default ctor for Dynamic strides, so let' initialize it with dummy values: + m_stride(StrideType::OuterStrideAtCompileTime==Dynamic?0:StrideType::OuterStrideAtCompileTime, + StrideType::InnerStrideAtCompileTime==Dynamic?0:StrideType::InnerStrideAtCompileTime) + {} + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(RefBase) + +protected: + + typedef Stride StrideBase; + + // Resolves inner stride if default 0. + static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index resolveInnerStride(Index inner) { + return inner == 0 ? 1 : inner; + } + + // Resolves outer stride if default 0. + static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index resolveOuterStride(Index inner, Index outer, Index rows, Index cols, bool isVectorAtCompileTime, bool isRowMajor) { + return outer == 0 ? isVectorAtCompileTime ? inner * rows * cols : isRowMajor ? inner * cols : inner * rows : outer; + } + + // Returns true if construction is valid, false if there is a stride mismatch, + // and fails if there is a size mismatch. + template + EIGEN_DEVICE_FUNC bool construct(Expression& expr) + { + // Check matrix sizes. If this is a compile-time vector, we do allow + // implicitly transposing. + EIGEN_STATIC_ASSERT( + EIGEN_PREDICATE_SAME_MATRIX_SIZE(PlainObjectType, Expression) + // If it is a vector, the transpose sizes might match. + || ( PlainObjectType::IsVectorAtCompileTime + && ((int(PlainObjectType::RowsAtCompileTime)==Eigen::Dynamic + || int(Expression::ColsAtCompileTime)==Eigen::Dynamic + || int(PlainObjectType::RowsAtCompileTime)==int(Expression::ColsAtCompileTime)) + && (int(PlainObjectType::ColsAtCompileTime)==Eigen::Dynamic + || int(Expression::RowsAtCompileTime)==Eigen::Dynamic + || int(PlainObjectType::ColsAtCompileTime)==int(Expression::RowsAtCompileTime)))), + YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES + ) + + // Determine runtime rows and columns. + Index rows = expr.rows(); + Index cols = expr.cols(); + if(PlainObjectType::RowsAtCompileTime==1) + { + eigen_assert(expr.rows()==1 || expr.cols()==1); + rows = 1; + cols = expr.size(); + } + else if(PlainObjectType::ColsAtCompileTime==1) + { + eigen_assert(expr.rows()==1 || expr.cols()==1); + rows = expr.size(); + cols = 1; + } + // Verify that the sizes are valid. + eigen_assert( + (PlainObjectType::RowsAtCompileTime == Dynamic) || (PlainObjectType::RowsAtCompileTime == rows)); + eigen_assert( + (PlainObjectType::ColsAtCompileTime == Dynamic) || (PlainObjectType::ColsAtCompileTime == cols)); + + + // If this is a vector, we might be transposing, which means that stride should swap. + const bool transpose = PlainObjectType::IsVectorAtCompileTime && (rows != expr.rows()); + // If the storage format differs, we also need to swap the stride. + const bool row_major = ((PlainObjectType::Flags)&RowMajorBit) != 0; + const bool expr_row_major = (Expression::Flags&RowMajorBit) != 0; + const bool storage_differs = (row_major != expr_row_major); + + const bool swap_stride = (transpose != storage_differs); + + // Determine expr's actual strides, resolving any defaults if zero. + const Index expr_inner_actual = resolveInnerStride(expr.innerStride()); + const Index expr_outer_actual = resolveOuterStride(expr_inner_actual, + expr.outerStride(), + expr.rows(), + expr.cols(), + Expression::IsVectorAtCompileTime != 0, + expr_row_major); + + // If this is a column-major row vector or row-major column vector, the inner-stride + // is arbitrary, so set it to either the compile-time inner stride or 1. + const bool row_vector = (rows == 1); + const bool col_vector = (cols == 1); + const Index inner_stride = + ( (!row_major && row_vector) || (row_major && col_vector) ) ? + ( StrideType::InnerStrideAtCompileTime > 0 ? Index(StrideType::InnerStrideAtCompileTime) : 1) + : swap_stride ? expr_outer_actual : expr_inner_actual; + + // If this is a column-major column vector or row-major row vector, the outer-stride + // is arbitrary, so set it to either the compile-time outer stride or vector size. + const Index outer_stride = + ( (!row_major && col_vector) || (row_major && row_vector) ) ? + ( StrideType::OuterStrideAtCompileTime > 0 ? Index(StrideType::OuterStrideAtCompileTime) : rows * cols * inner_stride) + : swap_stride ? expr_inner_actual : expr_outer_actual; + + // Check if given inner/outer strides are compatible with compile-time strides. + const bool inner_valid = (StrideType::InnerStrideAtCompileTime == Dynamic) + || (resolveInnerStride(Index(StrideType::InnerStrideAtCompileTime)) == inner_stride); + if (!inner_valid) { + return false; + } + + const bool outer_valid = (StrideType::OuterStrideAtCompileTime == Dynamic) + || (resolveOuterStride( + inner_stride, + Index(StrideType::OuterStrideAtCompileTime), + rows, cols, PlainObjectType::IsVectorAtCompileTime != 0, + row_major) + == outer_stride); + if (!outer_valid) { + return false; + } + + ::new (static_cast(this)) Base(expr.data(), rows, cols); + ::new (&m_stride) StrideBase( + (StrideType::OuterStrideAtCompileTime == 0) ? 0 : outer_stride, + (StrideType::InnerStrideAtCompileTime == 0) ? 0 : inner_stride ); + return true; + } + + StrideBase m_stride; +}; + +/** \class Ref + * \ingroup Core_Module + * + * \brief A matrix or vector expression mapping an existing expression + * + * \tparam PlainObjectType the equivalent matrix type of the mapped data + * \tparam Options specifies the pointer alignment in bytes. It can be: \c #Aligned128, , \c #Aligned64, \c #Aligned32, \c #Aligned16, \c #Aligned8 or \c #Unaligned. + * The default is \c #Unaligned. + * \tparam StrideType optionally specifies strides. By default, Ref implies a contiguous storage along the inner dimension (inner stride==1), + * but accepts a variable outer stride (leading dimension). + * This can be overridden by specifying strides. + * The type passed here must be a specialization of the Stride template, see examples below. + * + * This class provides a way to write non-template functions taking Eigen objects as parameters while limiting the number of copies. + * A Ref<> object can represent either a const expression or a l-value: + * \code + * // in-out argument: + * void foo1(Ref x); + * + * // read-only const argument: + * void foo2(const Ref& x); + * \endcode + * + * In the in-out case, the input argument must satisfy the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. + * By default, a Ref can reference any dense vector expression of float having a contiguous memory layout. + * Likewise, a Ref can reference any column-major dense matrix expression of float whose column's elements are contiguously stored with + * the possibility to have a constant space in-between each column, i.e. the inner stride must be equal to 1, but the outer stride (or leading dimension) + * can be greater than the number of rows. + * + * In the const case, if the input expression does not match the above requirement, then it is evaluated into a temporary before being passed to the function. + * Here are some examples: + * \code + * MatrixXf A; + * VectorXf a; + * foo1(a.head()); // OK + * foo1(A.col()); // OK + * foo1(A.row()); // Compilation error because here innerstride!=1 + * foo2(A.row()); // Compilation error because A.row() is a 1xN object while foo2 is expecting a Nx1 object + * foo2(A.row().transpose()); // The row is copied into a contiguous temporary + * foo2(2*a); // The expression is evaluated into a temporary + * foo2(A.col().segment(2,4)); // No temporary + * \endcode + * + * The range of inputs that can be referenced without temporary can be enlarged using the last two template parameters. + * Here is an example accepting an innerstride!=1: + * \code + * // in-out argument: + * void foo3(Ref > x); + * foo3(A.row()); // OK + * \endcode + * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involve more + * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overload internally calling a + * template function, e.g.: + * \code + * // in the .h: + * void foo(const Ref& A); + * void foo(const Ref >& A); + * + * // in the .cpp: + * template void foo_impl(const TypeOfA& A) { + * ... // crazy code goes here + * } + * void foo(const Ref& A) { foo_impl(A); } + * void foo(const Ref >& A) { foo_impl(A); } + * \endcode + * + * See also the following stackoverflow questions for further references: + * - Correct usage of the Eigen::Ref<> class + * + * \sa PlainObjectBase::Map(), \ref TopicStorageOrders + */ +template class Ref + : public RefBase > +{ + private: + typedef internal::traits Traits; + template + EIGEN_DEVICE_FUNC inline Ref(const PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0); + public: + + typedef RefBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Ref) + + + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC inline Ref(PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) + { + EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + // Construction must pass since we will not create temprary storage in the non-const case. + const bool success = Base::construct(expr.derived()); + EIGEN_UNUSED_VARIABLE(success) + eigen_assert(success); + } + template + EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) + #else + /** Implicit constructor from any dense expression */ + template + inline Ref(DenseBase& expr) + #endif + { + EIGEN_STATIC_ASSERT(bool(internal::is_lvalue::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + EIGEN_STATIC_ASSERT(!Derived::IsPlainObjectBase,THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + // Construction must pass since we will not create temporary storage in the non-const case. + const bool success = Base::construct(expr.const_cast_derived()); + EIGEN_UNUSED_VARIABLE(success) + eigen_assert(success); + } + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Ref) + +}; + +// this is the const ref version +template class Ref + : public RefBase > +{ + typedef internal::traits Traits; + public: + + typedef RefBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Ref) + + template + EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, + typename internal::enable_if::ScalarTypeMatch),Derived>::type* = 0) + { +// std::cout << match_helper::HasDirectAccess << "," << match_helper::OuterStrideMatch << "," << match_helper::InnerStrideMatch << "\n"; +// std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; +// std::cout << int(StrideType::InnerStrideAtCompileTime) << " - " << int(Derived::InnerStrideAtCompileTime) << "\n"; + construct(expr.derived(), typename Traits::template match::type()); + } + + EIGEN_DEVICE_FUNC inline Ref(const Ref& other) : Base(other) { + // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy + } + + template + EIGEN_DEVICE_FUNC inline Ref(const RefBase& other) { + construct(other.derived(), typename Traits::template match::type()); + } + + protected: + + template + EIGEN_DEVICE_FUNC void construct(const Expression& expr,internal::true_type) + { + // Check if we can use the underlying expr's storage directly, otherwise call the copy version. + if (!Base::construct(expr)) { + construct(expr, internal::false_type()); + } + } + + template + EIGEN_DEVICE_FUNC void construct(const Expression& expr, internal::false_type) + { + internal::call_assignment_no_alias(m_object,expr,internal::assign_op()); + Base::construct(m_object); + } + + protected: + TPlainObjectType m_object; +}; + +} // end namespace Eigen + +#endif // EIGEN_REF_H diff --git a/Vendor/eigen/Eigen/src/Core/Replicate.h b/Vendor/eigen/Eigen/src/Core/Replicate.h new file mode 100644 index 0000000..ab5be7e --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Replicate.h @@ -0,0 +1,142 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_REPLICATE_H +#define EIGEN_REPLICATE_H + +namespace Eigen { + +namespace internal { +template +struct traits > + : traits +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::XprKind XprKind; + typedef typename ref_selector::type MatrixTypeNested; + typedef typename remove_reference::type _MatrixTypeNested; + enum { + RowsAtCompileTime = RowFactor==Dynamic || int(MatrixType::RowsAtCompileTime)==Dynamic + ? Dynamic + : RowFactor * MatrixType::RowsAtCompileTime, + ColsAtCompileTime = ColFactor==Dynamic || int(MatrixType::ColsAtCompileTime)==Dynamic + ? Dynamic + : ColFactor * MatrixType::ColsAtCompileTime, + //FIXME we don't propagate the max sizes !!! + MaxRowsAtCompileTime = RowsAtCompileTime, + MaxColsAtCompileTime = ColsAtCompileTime, + IsRowMajor = MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1 ? 1 + : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 + : (MatrixType::Flags & RowMajorBit) ? 1 : 0, + + // FIXME enable DirectAccess with negative strides? + Flags = IsRowMajor ? RowMajorBit : 0 + }; +}; +} + +/** + * \class Replicate + * \ingroup Core_Module + * + * \brief Expression of the multiple replication of a matrix or vector + * + * \tparam MatrixType the type of the object we are replicating + * \tparam RowFactor number of repetitions at compile time along the vertical direction, can be Dynamic. + * \tparam ColFactor number of repetitions at compile time along the horizontal direction, can be Dynamic. + * + * This class represents an expression of the multiple replication of a matrix or vector. + * It is the return type of DenseBase::replicate() and most of the time + * this is the only way it is used. + * + * \sa DenseBase::replicate() + */ +template class Replicate + : public internal::dense_xpr_base< Replicate >::type +{ + typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; + typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Replicate) + typedef typename internal::remove_all::type NestedExpression; + + template + EIGEN_DEVICE_FUNC + inline explicit Replicate(const OriginalMatrixType& matrix) + : m_matrix(matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) + { + EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), + THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) + eigen_assert(RowFactor!=Dynamic && ColFactor!=Dynamic); + } + + template + EIGEN_DEVICE_FUNC + inline Replicate(const OriginalMatrixType& matrix, Index rowFactor, Index colFactor) + : m_matrix(matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) + { + EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), + THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) + } + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index rows() const { return m_matrix.rows() * m_rowFactor.value(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index cols() const { return m_matrix.cols() * m_colFactor.value(); } + + EIGEN_DEVICE_FUNC + const _MatrixTypeNested& nestedExpression() const + { + return m_matrix; + } + + protected: + MatrixTypeNested m_matrix; + const internal::variable_if_dynamic m_rowFactor; + const internal::variable_if_dynamic m_colFactor; +}; + +/** + * \return an expression of the replication of \c *this + * + * Example: \include MatrixBase_replicate.cpp + * Output: \verbinclude MatrixBase_replicate.out + * + * \sa VectorwiseOp::replicate(), DenseBase::replicate(Index,Index), class Replicate + */ +template +template +EIGEN_DEVICE_FUNC const Replicate +DenseBase::replicate() const +{ + return Replicate(derived()); +} + +/** + * \return an expression of the replication of each column (or row) of \c *this + * + * Example: \include DirectionWise_replicate_int.cpp + * Output: \verbinclude DirectionWise_replicate_int.out + * + * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate + */ +template +EIGEN_DEVICE_FUNC const typename VectorwiseOp::ReplicateReturnType +VectorwiseOp::replicate(Index factor) const +{ + return typename VectorwiseOp::ReplicateReturnType + (_expression(),Direction==Vertical?factor:1,Direction==Horizontal?factor:1); +} + +} // end namespace Eigen + +#endif // EIGEN_REPLICATE_H diff --git a/Vendor/eigen/Eigen/src/Core/Reshaped.h b/Vendor/eigen/Eigen/src/Core/Reshaped.h new file mode 100644 index 0000000..52de73b --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Reshaped.h @@ -0,0 +1,454 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2017 Gael Guennebaud +// Copyright (C) 2014 yoco +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_RESHAPED_H +#define EIGEN_RESHAPED_H + +namespace Eigen { + +/** \class Reshaped + * \ingroup Core_Module + * + * \brief Expression of a fixed-size or dynamic-size reshape + * + * \tparam XprType the type of the expression in which we are taking a reshape + * \tparam Rows the number of rows of the reshape we are taking at compile time (optional) + * \tparam Cols the number of columns of the reshape we are taking at compile time (optional) + * \tparam Order can be ColMajor or RowMajor, default is ColMajor. + * + * This class represents an expression of either a fixed-size or dynamic-size reshape. + * It is the return type of DenseBase::reshaped(NRowsType,NColsType) and + * most of the time this is the only way it is used. + * + * However, in C++98, if you want to directly maniputate reshaped expressions, + * for instance if you want to write a function returning such an expression, you + * will need to use this class. In C++11, it is advised to use the \em auto + * keyword for such use cases. + * + * Here is an example illustrating the dynamic case: + * \include class_Reshaped.cpp + * Output: \verbinclude class_Reshaped.out + * + * Here is an example illustrating the fixed-size case: + * \include class_FixedReshaped.cpp + * Output: \verbinclude class_FixedReshaped.out + * + * \sa DenseBase::reshaped(NRowsType,NColsType) + */ + +namespace internal { + +template +struct traits > : traits +{ + typedef typename traits::Scalar Scalar; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::XprKind XprKind; + enum{ + MatrixRows = traits::RowsAtCompileTime, + MatrixCols = traits::ColsAtCompileTime, + RowsAtCompileTime = Rows, + ColsAtCompileTime = Cols, + MaxRowsAtCompileTime = Rows, + MaxColsAtCompileTime = Cols, + XpxStorageOrder = ((int(traits::Flags) & RowMajorBit) == RowMajorBit) ? RowMajor : ColMajor, + ReshapedStorageOrder = (RowsAtCompileTime == 1 && ColsAtCompileTime != 1) ? RowMajor + : (ColsAtCompileTime == 1 && RowsAtCompileTime != 1) ? ColMajor + : XpxStorageOrder, + HasSameStorageOrderAsXprType = (ReshapedStorageOrder == XpxStorageOrder), + InnerSize = (ReshapedStorageOrder==int(RowMajor)) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), + InnerStrideAtCompileTime = HasSameStorageOrderAsXprType + ? int(inner_stride_at_compile_time::ret) + : Dynamic, + OuterStrideAtCompileTime = Dynamic, + + HasDirectAccess = internal::has_direct_access::ret + && (Order==int(XpxStorageOrder)) + && ((evaluator::Flags&LinearAccessBit)==LinearAccessBit), + + MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) + && (InnerStrideAtCompileTime == 1) + ? PacketAccessBit : 0, + //MaskAlignedBit = ((OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + FlagsRowMajorBit = (ReshapedStorageOrder==int(RowMajor)) ? RowMajorBit : 0, + FlagsDirectAccessBit = HasDirectAccess ? DirectAccessBit : 0, + Flags0 = traits::Flags & ( (HereditaryBits & ~RowMajorBit) | MaskPacketAccessBit), + + Flags = (Flags0 | FlagsLinearAccessBit | FlagsLvalueBit | FlagsRowMajorBit | FlagsDirectAccessBit) + }; +}; + +template class ReshapedImpl_dense; + +} // end namespace internal + +template class ReshapedImpl; + +template class Reshaped + : public ReshapedImpl::StorageKind> +{ + typedef ReshapedImpl::StorageKind> Impl; + public: + //typedef typename Impl::Base Base; + typedef Impl Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(Reshaped) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reshaped) + + /** Fixed-size constructor + */ + EIGEN_DEVICE_FUNC + inline Reshaped(XprType& xpr) + : Impl(xpr) + { + EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic,THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE) + eigen_assert(Rows * Cols == xpr.rows() * xpr.cols()); + } + + /** Dynamic-size constructor + */ + EIGEN_DEVICE_FUNC + inline Reshaped(XprType& xpr, + Index reshapeRows, Index reshapeCols) + : Impl(xpr, reshapeRows, reshapeCols) + { + eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==reshapeRows) + && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==reshapeCols)); + eigen_assert(reshapeRows * reshapeCols == xpr.rows() * xpr.cols()); + } +}; + +// The generic default implementation for dense reshape simply forward to the internal::ReshapedImpl_dense +// that must be specialized for direct and non-direct access... +template +class ReshapedImpl + : public internal::ReshapedImpl_dense >::HasDirectAccess> +{ + typedef internal::ReshapedImpl_dense >::HasDirectAccess> Impl; + public: + typedef Impl Base; + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ReshapedImpl) + EIGEN_DEVICE_FUNC inline ReshapedImpl(XprType& xpr) : Impl(xpr) {} + EIGEN_DEVICE_FUNC inline ReshapedImpl(XprType& xpr, Index reshapeRows, Index reshapeCols) + : Impl(xpr, reshapeRows, reshapeCols) {} +}; + +namespace internal { + +/** \internal Internal implementation of dense Reshaped in the general case. */ +template +class ReshapedImpl_dense + : public internal::dense_xpr_base >::type +{ + typedef Reshaped ReshapedType; + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ReshapedType) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ReshapedImpl_dense) + + typedef typename internal::ref_selector::non_const_type MatrixTypeNested; + typedef typename internal::remove_all::type NestedExpression; + + class InnerIterator; + + /** Fixed-size constructor + */ + EIGEN_DEVICE_FUNC + inline ReshapedImpl_dense(XprType& xpr) + : m_xpr(xpr), m_rows(Rows), m_cols(Cols) + {} + + /** Dynamic-size constructor + */ + EIGEN_DEVICE_FUNC + inline ReshapedImpl_dense(XprType& xpr, Index nRows, Index nCols) + : m_xpr(xpr), m_rows(nRows), m_cols(nCols) + {} + + EIGEN_DEVICE_FUNC Index rows() const { return m_rows; } + EIGEN_DEVICE_FUNC Index cols() const { return m_cols; } + + #ifdef EIGEN_PARSED_BY_DOXYGEN + /** \sa MapBase::data() */ + EIGEN_DEVICE_FUNC inline const Scalar* data() const; + EIGEN_DEVICE_FUNC inline Index innerStride() const; + EIGEN_DEVICE_FUNC inline Index outerStride() const; + #endif + + /** \returns the nested expression */ + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + nestedExpression() const { return m_xpr; } + + /** \returns the nested expression */ + EIGEN_DEVICE_FUNC + typename internal::remove_reference::type& + nestedExpression() { return m_xpr; } + + protected: + + MatrixTypeNested m_xpr; + const internal::variable_if_dynamic m_rows; + const internal::variable_if_dynamic m_cols; +}; + + +/** \internal Internal implementation of dense Reshaped in the direct access case. */ +template +class ReshapedImpl_dense + : public MapBase > +{ + typedef Reshaped ReshapedType; + typedef typename internal::ref_selector::non_const_type XprTypeNested; + public: + + typedef MapBase Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ReshapedType) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ReshapedImpl_dense) + + /** Fixed-size constructor + */ + EIGEN_DEVICE_FUNC + inline ReshapedImpl_dense(XprType& xpr) + : Base(xpr.data()), m_xpr(xpr) + {} + + /** Dynamic-size constructor + */ + EIGEN_DEVICE_FUNC + inline ReshapedImpl_dense(XprType& xpr, Index nRows, Index nCols) + : Base(xpr.data(), nRows, nCols), + m_xpr(xpr) + {} + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& nestedExpression() const + { + return m_xpr; + } + + EIGEN_DEVICE_FUNC + XprType& nestedExpression() { return m_xpr; } + + /** \sa MapBase::innerStride() */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index innerStride() const + { + return m_xpr.innerStride(); + } + + /** \sa MapBase::outerStride() */ + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index outerStride() const + { + return ((Flags&RowMajorBit)==RowMajorBit) ? this->cols() : this->rows(); + } + + protected: + + XprTypeNested m_xpr; +}; + +// Evaluators +template struct reshaped_evaluator; + +template +struct evaluator > + : reshaped_evaluator >::HasDirectAccess> +{ + typedef Reshaped XprType; + typedef typename XprType::Scalar Scalar; + // TODO: should check for smaller packet types + typedef typename packet_traits::type PacketScalar; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + HasDirectAccess = traits::HasDirectAccess, + +// RowsAtCompileTime = traits::RowsAtCompileTime, +// ColsAtCompileTime = traits::ColsAtCompileTime, +// MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, +// MaxColsAtCompileTime = traits::MaxColsAtCompileTime, +// +// InnerStrideAtCompileTime = traits::HasSameStorageOrderAsXprType +// ? int(inner_stride_at_compile_time::ret) +// : Dynamic, +// OuterStrideAtCompileTime = Dynamic, + + FlagsLinearAccessBit = (traits::RowsAtCompileTime == 1 || traits::ColsAtCompileTime == 1 || HasDirectAccess) ? LinearAccessBit : 0, + FlagsRowMajorBit = (traits::ReshapedStorageOrder==int(RowMajor)) ? RowMajorBit : 0, + FlagsDirectAccessBit = HasDirectAccess ? DirectAccessBit : 0, + Flags0 = evaluator::Flags & (HereditaryBits & ~RowMajorBit), + Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit | FlagsDirectAccessBit, + + PacketAlignment = unpacket_traits::alignment, + Alignment = evaluator::Alignment + }; + typedef reshaped_evaluator reshaped_evaluator_type; + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : reshaped_evaluator_type(xpr) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } +}; + +template +struct reshaped_evaluator + : evaluator_base > +{ + typedef Reshaped XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost /* TODO + cost of index computations */, + + Flags = (evaluator::Flags & (HereditaryBits /*| LinearAccessBit | DirectAccessBit*/)), + + Alignment = 0 + }; + + EIGEN_DEVICE_FUNC explicit reshaped_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_xpr(xpr) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + typedef std::pair RowCol; + + inline RowCol index_remap(Index rowId, Index colId) const + { + if(Order==ColMajor) + { + const Index nth_elem_idx = colId * m_xpr.rows() + rowId; + return RowCol(nth_elem_idx % m_xpr.nestedExpression().rows(), + nth_elem_idx / m_xpr.nestedExpression().rows()); + } + else + { + const Index nth_elem_idx = colId + rowId * m_xpr.cols(); + return RowCol(nth_elem_idx / m_xpr.nestedExpression().cols(), + nth_elem_idx % m_xpr.nestedExpression().cols()); + } + } + + EIGEN_DEVICE_FUNC + inline Scalar& coeffRef(Index rowId, Index colId) + { + EIGEN_STATIC_ASSERT_LVALUE(XprType) + const RowCol row_col = index_remap(rowId, colId); + return m_argImpl.coeffRef(row_col.first, row_col.second); + } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index rowId, Index colId) const + { + const RowCol row_col = index_remap(rowId, colId); + return m_argImpl.coeffRef(row_col.first, row_col.second); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index rowId, Index colId) const + { + const RowCol row_col = index_remap(rowId, colId); + return m_argImpl.coeff(row_col.first, row_col.second); + } + + EIGEN_DEVICE_FUNC + inline Scalar& coeffRef(Index index) + { + EIGEN_STATIC_ASSERT_LVALUE(XprType) + const RowCol row_col = index_remap(Rows == 1 ? 0 : index, + Rows == 1 ? index : 0); + return m_argImpl.coeffRef(row_col.first, row_col.second); + + } + + EIGEN_DEVICE_FUNC + inline const Scalar& coeffRef(Index index) const + { + const RowCol row_col = index_remap(Rows == 1 ? 0 : index, + Rows == 1 ? index : 0); + return m_argImpl.coeffRef(row_col.first, row_col.second); + } + + EIGEN_DEVICE_FUNC + inline const CoeffReturnType coeff(Index index) const + { + const RowCol row_col = index_remap(Rows == 1 ? 0 : index, + Rows == 1 ? index : 0); + return m_argImpl.coeff(row_col.first, row_col.second); + } +#if 0 + EIGEN_DEVICE_FUNC + template + inline PacketScalar packet(Index rowId, Index colId) const + { + const RowCol row_col = index_remap(rowId, colId); + return m_argImpl.template packet(row_col.first, row_col.second); + + } + + template + EIGEN_DEVICE_FUNC + inline void writePacket(Index rowId, Index colId, const PacketScalar& val) + { + const RowCol row_col = index_remap(rowId, colId); + m_argImpl.const_cast_derived().template writePacket + (row_col.first, row_col.second, val); + } + + template + EIGEN_DEVICE_FUNC + inline PacketScalar packet(Index index) const + { + const RowCol row_col = index_remap(RowsAtCompileTime == 1 ? 0 : index, + RowsAtCompileTime == 1 ? index : 0); + return m_argImpl.template packet(row_col.first, row_col.second); + } + + template + EIGEN_DEVICE_FUNC + inline void writePacket(Index index, const PacketScalar& val) + { + const RowCol row_col = index_remap(RowsAtCompileTime == 1 ? 0 : index, + RowsAtCompileTime == 1 ? index : 0); + return m_argImpl.template packet(row_col.first, row_col.second, val); + } +#endif +protected: + + evaluator m_argImpl; + const XprType& m_xpr; + +}; + +template +struct reshaped_evaluator +: mapbase_evaluator, + typename Reshaped::PlainObject> +{ + typedef Reshaped XprType; + typedef typename XprType::Scalar Scalar; + + EIGEN_DEVICE_FUNC explicit reshaped_evaluator(const XprType& xpr) + : mapbase_evaluator(xpr) + { + // TODO: for the 3.4 release, this should be turned to an internal assertion, but let's keep it as is for the beta lifetime + eigen_assert(((internal::UIntPtr(xpr.data()) % EIGEN_PLAIN_ENUM_MAX(1,evaluator::Alignment)) == 0) && "data is not aligned"); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_RESHAPED_H diff --git a/Vendor/eigen/Eigen/src/Core/ReturnByValue.h b/Vendor/eigen/Eigen/src/Core/ReturnByValue.h new file mode 100644 index 0000000..4dad13e --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/ReturnByValue.h @@ -0,0 +1,119 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009-2010 Gael Guennebaud +// Copyright (C) 2009-2010 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_RETURNBYVALUE_H +#define EIGEN_RETURNBYVALUE_H + +namespace Eigen { + +namespace internal { + +template +struct traits > + : public traits::ReturnType> +{ + enum { + // We're disabling the DirectAccess because e.g. the constructor of + // the Block-with-DirectAccess expression requires to have a coeffRef method. + // Also, we don't want to have to implement the stride stuff. + Flags = (traits::ReturnType>::Flags + | EvalBeforeNestingBit) & ~DirectAccessBit + }; +}; + +/* The ReturnByValue object doesn't even have a coeff() method. + * So the only way that nesting it in an expression can work, is by evaluating it into a plain matrix. + * So internal::nested always gives the plain return matrix type. + * + * FIXME: I don't understand why we need this specialization: isn't this taken care of by the EvalBeforeNestingBit ?? + * Answer: EvalBeforeNestingBit should be deprecated since we have the evaluators + */ +template +struct nested_eval, n, PlainObject> +{ + typedef typename traits::ReturnType type; +}; + +} // end namespace internal + +/** \class ReturnByValue + * \ingroup Core_Module + * + */ +template class ReturnByValue + : public internal::dense_xpr_base< ReturnByValue >::type, internal::no_assignment_operator +{ + public: + typedef typename internal::traits::ReturnType ReturnType; + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(ReturnByValue) + + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& dst) const + { static_cast(this)->evalTo(dst); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index rows() const EIGEN_NOEXCEPT { return static_cast(this)->rows(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index cols() const EIGEN_NOEXCEPT { return static_cast(this)->cols(); } + +#ifndef EIGEN_PARSED_BY_DOXYGEN +#define Unusable YOU_ARE_TRYING_TO_ACCESS_A_SINGLE_COEFFICIENT_IN_A_SPECIAL_EXPRESSION_WHERE_THAT_IS_NOT_ALLOWED_BECAUSE_THAT_WOULD_BE_INEFFICIENT + class Unusable{ + Unusable(const Unusable&) {} + Unusable& operator=(const Unusable&) {return *this;} + }; + const Unusable& coeff(Index) const { return *reinterpret_cast(this); } + const Unusable& coeff(Index,Index) const { return *reinterpret_cast(this); } + Unusable& coeffRef(Index) { return *reinterpret_cast(this); } + Unusable& coeffRef(Index,Index) { return *reinterpret_cast(this); } +#undef Unusable +#endif +}; + +template +template +EIGEN_DEVICE_FUNC Derived& DenseBase::operator=(const ReturnByValue& other) +{ + other.evalTo(derived()); + return derived(); +} + +namespace internal { + +// Expression is evaluated in a temporary; default implementation of Assignment is bypassed so that +// when a ReturnByValue expression is assigned, the evaluator is not constructed. +// TODO: Finalize port to new regime; ReturnByValue should not exist in the expression world + +template +struct evaluator > + : public evaluator::ReturnType> +{ + typedef ReturnByValue XprType; + typedef typename internal::traits::ReturnType PlainObject; + typedef evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + xpr.evalTo(m_result); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_RETURNBYVALUE_H diff --git a/Vendor/eigen/Eigen/src/Core/Reverse.h b/Vendor/eigen/Eigen/src/Core/Reverse.h new file mode 100644 index 0000000..28cdd76 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Reverse.h @@ -0,0 +1,217 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2009 Ricard Marxer +// Copyright (C) 2009-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_REVERSE_H +#define EIGEN_REVERSE_H + +namespace Eigen { + +namespace internal { + +template +struct traits > + : traits +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::XprKind XprKind; + typedef typename ref_selector::type MatrixTypeNested; + typedef typename remove_reference::type _MatrixTypeNested; + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + Flags = _MatrixTypeNested::Flags & (RowMajorBit | LvalueBit) + }; +}; + +template struct reverse_packet_cond +{ + static inline PacketType run(const PacketType& x) { return preverse(x); } +}; + +template struct reverse_packet_cond +{ + static inline PacketType run(const PacketType& x) { return x; } +}; + +} // end namespace internal + +/** \class Reverse + * \ingroup Core_Module + * + * \brief Expression of the reverse of a vector or matrix + * + * \tparam MatrixType the type of the object of which we are taking the reverse + * \tparam Direction defines the direction of the reverse operation, can be Vertical, Horizontal, or BothDirections + * + * This class represents an expression of the reverse of a vector. + * It is the return type of MatrixBase::reverse() and VectorwiseOp::reverse() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::reverse(), VectorwiseOp::reverse() + */ +template class Reverse + : public internal::dense_xpr_base< Reverse >::type +{ + public: + + typedef typename internal::dense_xpr_base::type Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) + typedef typename internal::remove_all::type NestedExpression; + using Base::IsRowMajor; + + protected: + enum { + PacketSize = internal::packet_traits::size, + IsColMajor = !IsRowMajor, + ReverseRow = (Direction == Vertical) || (Direction == BothDirections), + ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1, + ReversePacket = (Direction == BothDirections) + || ((Direction == Vertical) && IsColMajor) + || ((Direction == Horizontal) && IsRowMajor) + }; + typedef internal::reverse_packet_cond reverse_packet; + public: + + EIGEN_DEVICE_FUNC explicit inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } + + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) + + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index rows() const EIGEN_NOEXCEPT { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR + inline Index cols() const EIGEN_NOEXCEPT { return m_matrix.cols(); } + + EIGEN_DEVICE_FUNC inline Index innerStride() const + { + return -m_matrix.innerStride(); + } + + EIGEN_DEVICE_FUNC const typename internal::remove_all::type& + nestedExpression() const + { + return m_matrix; + } + + protected: + typename MatrixType::Nested m_matrix; +}; + +/** \returns an expression of the reverse of *this. + * + * Example: \include MatrixBase_reverse.cpp + * Output: \verbinclude MatrixBase_reverse.out + * + */ +template +EIGEN_DEVICE_FUNC inline typename DenseBase::ReverseReturnType +DenseBase::reverse() +{ + return ReverseReturnType(derived()); +} + + +//reverse const overload moved DenseBase.h due to a CUDA compiler bug + +/** This is the "in place" version of reverse: it reverses \c *this. + * + * In most cases it is probably better to simply use the reversed expression + * of a matrix. However, when reversing the matrix data itself is really needed, + * then this "in-place" version is probably the right choice because it provides + * the following additional benefits: + * - less error prone: doing the same operation with .reverse() requires special care: + * \code m = m.reverse().eval(); \endcode + * - this API enables reverse operations without the need for a temporary + * - it allows future optimizations (cache friendliness, etc.) + * + * \sa VectorwiseOp::reverseInPlace(), reverse() */ +template +EIGEN_DEVICE_FUNC inline void DenseBase::reverseInPlace() +{ + if(cols()>rows()) + { + Index half = cols()/2; + leftCols(half).swap(rightCols(half).reverse()); + if((cols()%2)==1) + { + Index half2 = rows()/2; + col(half).head(half2).swap(col(half).tail(half2).reverse()); + } + } + else + { + Index half = rows()/2; + topRows(half).swap(bottomRows(half).reverse()); + if((rows()%2)==1) + { + Index half2 = cols()/2; + row(half).head(half2).swap(row(half).tail(half2).reverse()); + } + } +} + +namespace internal { + +template +struct vectorwise_reverse_inplace_impl; + +template<> +struct vectorwise_reverse_inplace_impl +{ + template + static void run(ExpressionType &xpr) + { + const int HalfAtCompileTime = ExpressionType::RowsAtCompileTime==Dynamic?Dynamic:ExpressionType::RowsAtCompileTime/2; + Index half = xpr.rows()/2; + xpr.topRows(fix(half)) + .swap(xpr.bottomRows(fix(half)).colwise().reverse()); + } +}; + +template<> +struct vectorwise_reverse_inplace_impl +{ + template + static void run(ExpressionType &xpr) + { + const int HalfAtCompileTime = ExpressionType::ColsAtCompileTime==Dynamic?Dynamic:ExpressionType::ColsAtCompileTime/2; + Index half = xpr.cols()/2; + xpr.leftCols(fix(half)) + .swap(xpr.rightCols(fix(half)).rowwise().reverse()); + } +}; + +} // end namespace internal + +/** This is the "in place" version of VectorwiseOp::reverse: it reverses each column or row of \c *this. + * + * In most cases it is probably better to simply use the reversed expression + * of a matrix. However, when reversing the matrix data itself is really needed, + * then this "in-place" version is probably the right choice because it provides + * the following additional benefits: + * - less error prone: doing the same operation with .reverse() requires special care: + * \code m = m.reverse().eval(); \endcode + * - this API enables reverse operations without the need for a temporary + * + * \sa DenseBase::reverseInPlace(), reverse() */ +template +EIGEN_DEVICE_FUNC void VectorwiseOp::reverseInPlace() +{ + internal::vectorwise_reverse_inplace_impl::run(m_matrix); +} + +} // end namespace Eigen + +#endif // EIGEN_REVERSE_H diff --git a/Vendor/eigen/Eigen/src/Core/Select.h b/Vendor/eigen/Eigen/src/Core/Select.h new file mode 100644 index 0000000..7c86bf8 --- /dev/null +++ b/Vendor/eigen/Eigen/src/Core/Select.h @@ -0,0 +1,164 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2010 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_SELECT_H +#define EIGEN_SELECT_H + +namespace Eigen { + +/** \class Select + * \ingroup Core_Module + * + * \brief Expression of a coefficient wise version of the C++ ternary operator ?: + * + * \param ConditionMatrixType the type of the \em condition expression which must be a boolean matrix + * \param ThenMatrixType the type of the \em then expression + * \param ElseMatrixType the type of the \em else expression + * + * This class represents an expression of a coefficient wise version of the C++ ternary operator ?:. + * It is the return type of DenseBase::select() and most of the time this is the only way it is used. + * + * \sa DenseBase::select(const DenseBase&, const DenseBase&) const + */ + +namespace internal { +template +struct traits > + : traits +{ + typedef typename traits::Scalar Scalar; + typedef Dense StorageKind; + typedef typename traits::XprKind XprKind; + typedef typename ConditionMatrixType::Nested ConditionMatrixNested; + typedef typename ThenMatrixType::Nested ThenMatrixNested; + typedef typename ElseMatrixType::Nested ElseMatrixNested; + enum { + RowsAtCompileTime = ConditionMatrixType::RowsAtCompileTime, + ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, + MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, + Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & RowMajorBit + }; +}; +} + +template +class Select : public internal::dense_xpr_base< Select >::type, + internal::no_assignment_operator +{ + public: + + typedef typename internal::dense_xpr_base