Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions SolARFramework.pri
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ interfaces/datastructure/StorageCapabilities.h \
interfaces/datastructure/DetectedObject.h \
interfaces/api/solver/pose/ITrackablePose.h \
interfaces/api/input/devices/IDepthCamera.h \
interfaces/api/display/I3DMeshViewer.h \
interfaces/api/display/I3DOverlay.h \
interfaces/api/display/I3DPointsViewer.h \
interfaces/api/display/IImageViewer.h \
Expand Down Expand Up @@ -83,6 +84,7 @@ interfaces/api/service/IServiceManager.h \
interfaces/api/service/IAuthorizationChecker.h \
interfaces/api/service/IClientContextManager.h \
interfaces/api/map/I3DGaussianSplatting.h \
interfaces/api/map/I3DGaussianSplattingDensifier.h \
interfaces/api/map/IMeshing.h \
interfaces/api/map/IMultiViewStereo.h \
interfaces/api/map/IProcessMap.h \
Expand Down
15 changes: 15 additions & 0 deletions interfaces/api/display/I2DOverlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef SOLAR_I2DOVERLAY_H
#define SOLAR_I2DOVERLAY_H

#include <string>
#include "datastructure/MathDefinitions.h"
#include <xpcf/api/IComponentIntrospect.h>
#include <xpcf/core/helpers.h>
Expand Down Expand Up @@ -81,6 +82,20 @@ class XPCF_IGNORE I2DOverlay :
/// @param[in,out] displayImage The image on which the squared binary pattern will be drawn (on the whole image).
virtual void drawSBPattern (const SolAR::datastructure::SquaredBinaryPattern & pattern, SRef<SolAR::datastructure::Image> displayImage) = 0;

/// @brief Draw a loss/metric curve plot onto an image.
/// The whole image is used as the plotting canvas: axes, grid, the polyline of values
/// and numeric labels are rendered with drawing parameters taken from the configuration file.
/// Non-pure so existing I2DOverlay implementers remain valid; the default does nothing.
/// @param[in] values the ordered sequence of values to plot (e.g. per-iteration loss).
/// @param[in,out] displayImage the image used as the plot canvas.
/// @param[in] title (optional) a title label drawn on the plot.
virtual void drawLossCurve(const std::vector<float> & values,
SRef<SolAR::datastructure::Image> displayImage,
const std::string & title = "Loss")
{
(void)values; (void)displayImage; (void)title;
}

};
}
}
Expand Down
58 changes: 58 additions & 0 deletions interfaces/api/display/I3DMeshViewer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*******************************************************************************
* SolAR ARCloud
* (C) Copyright 2026 b<>com. All rights reserved.
*
* IDDN: FR.001.020021.005.S.C.2024.000.00000
* This software is the confidential intellectual property of b<>com.
* You shall not disclose it and shall use it only in accordance with
* the terms of the license agreement you entered into with b<>com.
*
********************************************************************************/
#ifndef SOLAR_API_DISPLAY_I3DMESHVIEWER_H
#define SOLAR_API_DISPLAY_I3DMESHVIEWER_H

#include <xpcf/api/IComponentIntrospect.h>
#include <xpcf/core/traits.h>
#include "core/Messages.h"
#include "datastructure/Mesh.h"
#include "datastructure/GeometryDefinitions.h"
#include "datastructure/MathDefinitions.h"

#include <vector>

namespace SolAR {
namespace api {
namespace display {

/**
* @class I3DMeshViewer
* @brief Display a triangle mesh in an interactive 3D OpenGL window.
* <TT>UUID: a9f5bdee-c3f6-4b7a-a1d2-1e2f3a4b5c6d</TT>
*/
class XPCF_IGNORE I3DMeshViewer : virtual public org::bcom::xpcf::IComponentIntrospect
{
public:
I3DMeshViewer() = default;
virtual ~I3DMeshViewer() = default;

/// @brief Display the mesh in a 3D window.
/// @param[in] mesh The triangle mesh to render.
/// @param[in] pose Current camera pose (world-to-camera transform used to draw a frustum overlay).
/// @param[in] keyframePoses Optional set of keyframe poses to overlay as frustums.
/// @return FrameworkReturnCode::_SUCCESS, or _STOP when the user requests to close the window.
virtual FrameworkReturnCode display(
const SRef<SolAR::datastructure::Mesh> & mesh,
const SolAR::datastructure::Transform3Df & pose,
const std::vector<SolAR::datastructure::Transform3Df> & keyframePoses = {}) = 0;
};

}
}
}

XPCF_DEFINE_INTERFACE_TRAITS(SolAR::api::display::I3DMeshViewer,
"a9f5bdee-c3f6-4b7a-a1d2-1e2f3a4b5c6d",
"I3DMeshViewer",
"Display a 3D triangle mesh in an interactive OpenGL window");

#endif // SOLAR_API_DISPLAY_I3DMESHVIEWER_H
43 changes: 43 additions & 0 deletions interfaces/api/display/I3DPointsViewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,49 @@ class XPCF_IGNORE I3DPointsViewer :
/// @return FrameworkReturnCode::_SUCCESS if the window is created, else FrameworkReturnCode::_ERROR_
virtual FrameworkReturnCode buffer(const SRef<SolAR::datastructure::PointCloud> pointCloud,
const SRef<SolAR::datastructure::PointCloud> pointCloud2 = nullptr) = 0;

/// @brief Display a set of 3D Gaussians rendered as ellipsoid splats in a window.
/// The data is passed as flat, contiguous, libtorch-free float buffers so that
/// implementers (e.g. an OpenGL viewer) need no tensor library dependency.
/// The viewer is expected to own its interactive (orbit) camera, hence no pose is required.
/// @param[in] centers flat array of Gaussian centers, size 3*N (x,y,z per Gaussian).
/// @param[in] scales flat array of per-axis scales, size 3*N (sx,sy,sz per Gaussian).
/// @param[in] quaternions flat array of rotation quaternions, size 4*N (w,x,y,z per Gaussian).
/// @param[in] colors flat array of RGB colors in [0,1], size 3*N (r,g,b per Gaussian).
/// @param[in] opacities array of opacities in [0,1], size N.
/// @return FrameworkReturnCode::_SUCCESS if displayed, FrameworkReturnCode::_NOT_IMPLEMENTED
/// if the implementer does not support Gaussian display, else FrameworkReturnCode::_ERROR_.
virtual FrameworkReturnCode displayGaussians(const std::vector<float> & centers,
const std::vector<float> & scales,
const std::vector<float> & quaternions,
const std::vector<float> & colors,
const std::vector<float> & opacities)
{
(void)centers; (void)scales; (void)quaternions; (void)colors; (void)opacities;
return FrameworkReturnCode::_NOT_IMPLEMENTED;
}

/// @brief Display 3D Gaussians with view-dependent colour (spherical harmonics).
/// Same as displayGaussians() above, plus the higher-order SH coefficients so the
/// viewer can evaluate view-dependent colour per frame (degree 0 = DC is in @p colors).
/// @param[in] centers size 3*N. @param[in] scales size 3*N. @param[in] quaternions size 4*N.
/// @param[in] colors DC RGB base in [0,1], size 3*N. @param[in] opacities size N.
/// @param[in] shCoeffsRest higher-order SH coefficients, size N*3*K with K = coeffs per
/// channel for the degree (deg1=3, deg2=8, deg3=15); per Gaussian channel-major
/// [R(K) G(K) B(K)] (Inria/PLY f_rest order).
/// @param[in] shDegree SH degree of the rest coefficients (1, 2 or 3).
/// @return _SUCCESS, _NOT_IMPLEMENTED, or _ERROR_.
virtual FrameworkReturnCode displayGaussians(const std::vector<float> & centers,
const std::vector<float> & scales,
const std::vector<float> & quaternions,
const std::vector<float> & colors,
const std::vector<float> & opacities,
const std::vector<float> & shCoeffsRest,
int shDegree)
{
(void)shCoeffsRest; (void)shDegree;
return displayGaussians(centers, scales, quaternions, colors, opacities);
}
};
}
}
Expand Down
2 changes: 1 addition & 1 deletion interfaces/api/gs/I3DGSTrainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace gs {

/**
* @class I3DGSTrainer
* @brief <B>Returns trained 3DGS model from poses images.</B>
* @brief <B>Returns trained 3DGS model from posed images.</B>
* <TT>UUID: c4bed096-4d34-11f1-aa46-325096b39f47</TT>
*
* This class provides a solution to train 3DGS model.
Expand Down
14 changes: 13 additions & 1 deletion interfaces/api/map/I3DGaussianSplatting.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,25 @@ class XPCF_IGNORE I3DGaussianSplatting : virtual public IProcessMap
public:

/// @enum class GSProcessingStatus
/// @brief define the different status of processing
/// @brief define the different status of 3D Gaussian Splatting processing.
/// Values chain on after the base IProcessMap::ProcessingStatus (which ends at 4),
/// starting at 5, mirroring SfmProcessingStatus.
enum class GSProcessingStatus: std::underlying_type_t<ProcessingStatus> {
RUNNING_INITIALIZATION = 5, ///< seeding the Gaussian model from the input map
IDLE_INITIALIZATION_FINISHED, ///< Gaussian model initialized
RUNNING_TRAINING, ///< optimizing the Gaussians (forward/backward/densify)
IDLE_TRAINING_FINISHED, ///< optimization finished
RUNNING_EXPORT, ///< building the output map from the trained Gaussians
};

/// @brief return a string value of a ProcessingStatus value
std::string toString(ProcessingStatus status) final {
switch (static_cast<GSProcessingStatus>(status)) {
case GSProcessingStatus::RUNNING_INITIALIZATION: return "RUNNING_INITIALIZATION";
case GSProcessingStatus::IDLE_INITIALIZATION_FINISHED: return "IDLE_INITIALIZATION_FINISHED";
case GSProcessingStatus::RUNNING_TRAINING: return "RUNNING_TRAINING";
case GSProcessingStatus::IDLE_TRAINING_FINISHED: return "IDLE_TRAINING_FINISHED";
case GSProcessingStatus::RUNNING_EXPORT: return "RUNNING_EXPORT";
default: return IProcessMap::toString(status);
}
}
Expand Down
85 changes: 85 additions & 0 deletions interfaces/api/map/I3DGaussianSplattingDensifier.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* @copyright Copyright (c) 2026 B-com http://www.b-com.com/
*
* 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.
*/

#ifndef I3DGAUSSIANSPLATTINGDENSIFIER_H
#define I3DGAUSSIANSPLATTINGDENSIFIER_H

#include <api/map/IProcessMap.h>

namespace SolAR {
namespace api {
namespace map {

/**
* @class I3DGaussianSplattingDensifier
* @brief <B>Convert a trained 3D Gaussian Splatting map into a dense coloured point cloud map.</B>
* <TT>UUID: 44f7f040-4d38-4dcc-8e0f-a6580a93b8b0</TT>
*
* Mirrors I3DGaussianSplatting: it consumes a map whose point cloud carries one Gaussian
* per CloudPoint (means/featuresDc/normal/featuresRest/opacity/scale/quat) and produces a
* new map holding a dense, sampled point cloud (plain xyz + rgb CloudPoints). It does not
* perform any training: the input Gaussian map is assumed to be already trained.
*
*/

class XPCF_IGNORE I3DGaussianSplattingDensifier : virtual public IProcessMap
{
public:

/// @enum class DensifyProcessingStatus
/// @brief define the different status of 3DGS-to-point-cloud densification.
/// Values chain on after the base IProcessMap::ProcessingStatus (which ends at 4),
/// starting at 5, mirroring GSProcessingStatus.
enum class DensifyProcessingStatus: std::underlying_type_t<ProcessingStatus> {
RUNNING_LOAD = 5, ///< reading the Gaussian model from the input map
IDLE_LOAD_FINISHED, ///< Gaussian model loaded
RUNNING_SAMPLING, ///< sampling dense points from the Gaussians
IDLE_SAMPLING_FINISHED, ///< sampling finished
RUNNING_EXPORT, ///< building the output map from the dense points
};

/// @brief return a string value of a ProcessingStatus value
std::string toString(ProcessingStatus status) {
switch (static_cast<DensifyProcessingStatus>(status)) {
case DensifyProcessingStatus::RUNNING_LOAD: return "RUNNING_LOAD";
case DensifyProcessingStatus::IDLE_LOAD_FINISHED: return "IDLE_LOAD_FINISHED";
case DensifyProcessingStatus::RUNNING_SAMPLING: return "RUNNING_SAMPLING";
case DensifyProcessingStatus::IDLE_SAMPLING_FINISHED: return "IDLE_SAMPLING_FINISHED";
case DensifyProcessingStatus::RUNNING_EXPORT: return "RUNNING_EXPORT";
default: return IProcessMap::toString(status);
}
}

public:
///@brief I3DGaussianSplattingDensifier default constructor.
I3DGaussianSplattingDensifier() = default;

///@brief I3DGaussianSplattingDensifier default destructor.
virtual ~I3DGaussianSplattingDensifier() override = default;

};


} // namespace map
} // namespace api
} // namespace SolAR

XPCF_DEFINE_INTERFACE_TRAITS(SolAR::api::map::I3DGaussianSplattingDensifier,
"44f7f040-4d38-4dcc-8e0f-a6580a93b8b0",
"I3DGaussianSplattingDensifier",
"I3DGaussianSplattingDensifier interface description");

#endif // I3DGAUSSIANSPLATTINGDENSIFIER_H
1 change: 1 addition & 0 deletions interfaces/core/Log.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "SolARFrameworkDefinitions.h"
#include <fstream>
#include <spdlog/fmt/ostr.h>
#include <fmt/std.h> // external-fmt formatters for std::filesystem::path, std::thread::id, etc.
#include <vector>

#include <opentelemetry/instrumentation/spdlog/sink.h>
Expand Down
31 changes: 21 additions & 10 deletions interfaces/datastructure/Map.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,26 @@ enum class MapProcessingApplied: std::uint8_t {
*/
class MapProcessingStep {
public:
MapProcessingStep(const MapProcessingApplied& processingApplied, const std::string& originalMapUUID):
m_processingApplied{processingApplied}, m_originalMapUUID{originalMapUUID} {
const std::time_t t_c = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
MapProcessingStep(const MapProcessingApplied& processingApplied, const std::string& sourceMapUUID, const std::string& targetMapUUID):
m_processingApplied{processingApplied}, m_sourceMapUUID{sourceMapUUID}, m_targetMapUUID{targetMapUUID} {
const auto now = std::chrono::system_clock::now();
m_processingTimestamp = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
const std::time_t t_c = std::chrono::system_clock::to_time_t(now);
std::string dateTime = std::ctime(&t_c);
m_processingDateTime = dateTime.substr(0, dateTime.size() - 1);
}

MapProcessingStep(const MapProcessingApplied& processingApplied, const std::string& originalMapUUID, const std::string& processingDateTime):
m_processingApplied{processingApplied}, m_originalMapUUID{originalMapUUID}, m_processingDateTime{processingDateTime} {
MapProcessingStep(const MapProcessingApplied& processingApplied, const std::string& sourceMapUUID, const std::string& targetMapUUID, const uint64_t processingTimestamp, const std::string& processingDateTime):
m_processingApplied{processingApplied}, m_sourceMapUUID{sourceMapUUID}, m_targetMapUUID{targetMapUUID}, m_processingTimestamp(processingTimestamp), m_processingDateTime{processingDateTime} {
}

~MapProcessingStep() = default;

MapProcessingApplied getProcessingApplied() const { return m_processingApplied; }
std::string getOriginalMapUUID() const { return m_originalMapUUID; }
std::string getTimestamp() const { return m_processingDateTime; }
std::string getSourceMapUUID() const { return m_sourceMapUUID; }
std::string getTargetMapUUID() const { return m_targetMapUUID; }
uint64_t getTimestamp() const { return m_processingTimestamp; }
std::string getDateTime() const { return m_processingDateTime; }

private:
///
Expand All @@ -81,15 +85,19 @@ class MapProcessingStep {
MapProcessingStep() = default;

MapProcessingApplied m_processingApplied; // Processing applied to obtain the map
std::string m_originalMapUUID; // Original map processed to obtain the current map
std::string m_processingDateTime; // Date and time of the processing
std::string m_sourceMapUUID; // Source map to which the processing is applied
std::string m_targetMapUUID; // Target map resulting from processing (may be identical to the source map)
uint64_t m_processingTimestamp; // Timestamp of processing in seconds since epoch
std::string m_processingDateTime; // Date and time of the processing in a string format

friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int /* version */)
{
ar & m_processingApplied;
ar & m_originalMapUUID;
ar & m_sourceMapUUID;
ar & m_targetMapUUID;
ar & m_processingTimestamp;
ar & m_processingDateTime;
}
};
Expand Down Expand Up @@ -347,6 +355,9 @@ class SOLARFRAMEWORK_API Map : public Trackable {
bool isMapCompatible(datastructure::DescriptorType descriptorType,
datastructure::GlobalDescriptorType globalDescriptorType) const;

/// @brief Reset all processing steps of the map history
void resetMapProcessingHistory();

/// @brief Add a processing step to the map information
/// @param[in] mapProcessingStep the new step of processing applied to the map
void addMapProcessingStep(const MapProcessingStep & mapProcessingStep);
Expand Down
6 changes: 6 additions & 0 deletions src/datastructure/Map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@ bool Map::isMapCompatible(datastructure::DescriptorType descriptorType,
return true;
}

void Map::resetMapProcessingHistory()
{
m_mapProcessingHistory.clear();
}


void Map::addMapProcessingStep(const MapProcessingStep & mapProcessingStep)
{
m_mapProcessingHistory.push_back(mapProcessingStep);
Expand Down