三维频谱marker

This commit is contained in:
2026-08-22 23:43:44 +08:00
parent 7c3f27474b
commit 9540f257e5
12 changed files with 294 additions and 71 deletions
@@ -9,10 +9,12 @@
#include <cmath>
#include <cstring>
#include <limits>
#include <iomanip>
#include <map>
#include <memory>
#include <mutex>
#include <numbers>
#include <sstream>
#include <stdexcept>
#include <string>
#include <utility>
@@ -800,7 +802,22 @@ void Datoviz_Visual_Backend::create_scene(
throw std::runtime_error("failed to enable Datoviz item queries");
wants_item_interaction = true;
}
visuals_.push_back({registration.identity, family, visual, 0});
DvzText* coordinate_text{};
if (family == Visual_Family::marker) {
coordinate_text = dvz_text(panel_, 0);
DvzTextPlacement placement = dvz_text_placement();
placement.mode = DVZ_TEXT_PLACEMENT_DATA;
placement.anchor = DVZ_SCENE_ANCHOR_DATA;
placement.depth_test = false;
DvzTextStyle style = dvz_text_style();
style.renderer = DVZ_TEXT_RENDERER_MSDF_ATLAS;
style.size_px = 12.0F;
if (coordinate_text == nullptr ||
dvz_text_set_placement(coordinate_text, &placement) != DVZ_OK ||
dvz_text_set_style(coordinate_text, &style) != DVZ_OK)
throw std::runtime_error("failed to create Datoviz marker coordinate labels");
}
visuals_.push_back({registration.identity, family, visual, coordinate_text, 0});
}
if (wants_item_interaction) {
item_interaction_ = dvz_item_interaction(panel_, nullptr);
@@ -1096,6 +1113,41 @@ void Datoviz_Visual_Backend::apply_visual(
if (point.revision == target.applied_revision) return;
const auto& data = *point.data;
auto* visual = target.visual;
if (target.coordinate_text != nullptr) {
std::vector<std::string> strings;
std::vector<DvzTextItem> items;
if (point.visible) {
strings.reserve(data.positions.size());
items.reserve(data.positions.size());
for (std::size_t index = 0; index < data.positions.size(); ++index) {
if (index >= data.coordinate_label_visibility.size() ||
!data.coordinate_label_visibility[index]) continue;
const auto& source = data.positions[index];
const auto& matrix = point.transform.values;
const float x = matrix[0] * source[0] + matrix[1] * source[1] + matrix[2] * source[2] + matrix[3];
const float y = matrix[4] * source[0] + matrix[5] * source[1] + matrix[6] * source[2] + matrix[7];
const float z = matrix[8] * source[0] + matrix[9] * source[1] + matrix[10] * source[2] + matrix[11];
std::ostringstream stream;
stream << std::fixed << std::setprecision(3)
<< "X " << x << " Y " << y << " Z " << z;
strings.push_back(std::move(stream).str());
DvzTextItem item{};
item.struct_size = sizeof(DvzTextItem);
item.position[0] = x; item.position[1] = y; item.position[2] = z;
item.offset[0] = 10.0F; item.offset[1] = -10.0F;
item.anchor[0] = 0.0F; item.anchor[1] = 1.0F;
item.size_px = 12.0F;
item.color = {235, 244, 255, 255};
items.push_back(item);
}
}
for (std::size_t index = 0; index < items.size(); ++index)
items[index].string = strings[index].c_str();
if (dvz_text_set_items(target.coordinate_text,
items.empty() ? nullptr : items.data(),
static_cast<std::uint32_t>(items.size())) != DVZ_OK)
throw std::runtime_error("failed to upload Datoviz marker coordinate labels");
}
{
mat4 transform{};
for (std::size_t row = 0; row < 4; ++row)
@@ -56,6 +56,7 @@ private:
Visual_Identity identity{}; /* Scene 注册的稳定身份。 */
Visual_Family family{Visual_Family::point}; /* 原生 Visual 的确定 family。 */
DvzVisual* visual{}; /* 由 Datoviz Scene 拥有。 */
DvzText* coordinate_text{}; /* Marker 的数据坐标 XYZ 标注。 */
std::uint64_t applied_revision{}; /* 此 Visual 已上传的 Prepare 版本。 */
};
void require_domain() const;
@@ -10,6 +10,7 @@ struct Prepared_Visual_Data {
std::vector<std::array<float, 2>> sigma{}; /* Splat 椭圆标准差字段。 */
std::vector<float> angles{}; /* Splat、Marker 旋转角字段。 */
std::vector<std::uint32_t> shapes{}; /* Marker 形状字段。 */
std::vector<std::uint8_t> coordinate_label_visibility{}; /* Marker XYZ 标签逐项开关。 */
std::vector<std::array<float, 3>> secondary_positions{}; /* 线段终点或向量字段。 */
std::vector<std::array<float, 3>> normals{}; /* Primitive、Mesh 法线字段。 */
std::vector<std::array<float, 2>> extents{}; /* Image、Labels 尺寸字段。 */
+1
View File
@@ -26,6 +26,7 @@ struct Marker {
Pixel_Distance diameter_px{12.0F}; /* 标记直径,单位为像素;必须为正数。 */
Coordinate_3D angle{}; /* 标记旋转角,单位为弧度。 */
Marker_Shape shape{Marker_Shape::disc}; /* 标记图形。 */
bool coordinate_label_visible{false}; /* 是否显示由此 Marker 实际位置派生的 XYZ 标签。 */
bool operator==(const Marker&) const = default;
};
struct Sphere {
+1 -1
View File
@@ -9,7 +9,7 @@ inline void Splat_Spec::prepare(const std::vector<Item>& items, Prepared_Visual_
inline bool Pixel_Spec::valid(const Item& item) noexcept { return finite(item.position) && finite(item.size_px) && item.size_px > 0.0F; }
inline void Pixel_Spec::prepare(const std::vector<Item>& items, Prepared_Visual_Data& output) { reserve_common(output, items.size()); for (const auto& item : items) { output.positions.push_back({item.position.x, item.position.y, item.position.z}); output.colors.push_back(channels(item.color)); output.sizes.push_back(item.size_px); } }
inline bool Marker_Spec::valid(const Item& item) noexcept { return finite(item.position) && finite(item.diameter_px) && item.diameter_px > 0.0F && finite(item.angle); }
inline void Marker_Spec::prepare(const std::vector<Item>& items, Prepared_Visual_Data& output) { reserve_common(output, items.size()); output.angles.reserve(items.size()); output.shapes.reserve(items.size()); for (const auto& item : items) { output.positions.push_back({item.position.x, item.position.y, item.position.z}); output.colors.push_back(channels(item.color)); output.sizes.push_back(item.diameter_px); output.angles.push_back(item.angle); output.shapes.push_back(static_cast<std::uint32_t>(item.shape)); } }
inline void Marker_Spec::prepare(const std::vector<Item>& items, Prepared_Visual_Data& output) { reserve_common(output, items.size()); output.angles.reserve(items.size()); output.shapes.reserve(items.size()); output.coordinate_label_visibility.reserve(items.size()); for (const auto& item : items) { output.positions.push_back({item.position.x, item.position.y, item.position.z}); output.colors.push_back(channels(item.color)); output.sizes.push_back(item.diameter_px); output.angles.push_back(item.angle); output.shapes.push_back(static_cast<std::uint32_t>(item.shape)); output.coordinate_label_visibility.push_back(item.coordinate_label_visible); } }
inline bool Sphere_Spec::valid(const Item& item) noexcept { return finite(item.center) && finite(item.radius) && item.radius > 0.0F; }
inline void Sphere_Spec::prepare(const std::vector<Item>& items, Prepared_Visual_Data& output) { reserve_common(output, items.size()); for (const auto& item : items) { output.positions.push_back({item.center.x, item.center.y, item.center.z}); output.colors.push_back(channels(item.color)); output.sizes.push_back(item.radius); } }
inline bool Segment_Spec::valid(const Item& item) noexcept { return finite(item.start) && finite(item.end) && finite(item.width_px) && item.width_px > 0.0F; }