ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
LineSet.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 #include <string>
11 
12 #include "cloudViewer/core/Dtype.h"
21 
22 namespace cloudViewer {
23 namespace t {
24 namespace geometry {
25 
28  device_(device),
29  point_attr_(TensorMap("positions")),
30  line_attr_(TensorMap("indices")) {}
31 
32 LineSet::LineSet(const core::Tensor &point_positions,
33  const core::Tensor &line_indices)
34  : LineSet([&]() {
35  core::AssertTensorDevice(line_indices, point_positions.GetDevice());
36  return point_positions.GetDevice();
37  }()) {
38  SetPointPositions(point_positions);
39  SetLineIndices(line_indices);
40 }
41 
42 LineSet LineSet::To(const core::Device &device, bool copy) const {
43  if (!copy && GetDevice() == device) {
44  return *this;
45  }
46  LineSet lineset(device);
47  for (const auto &kv : line_attr_) {
48  lineset.SetLineAttr(kv.first, kv.second.To(device, /*copy=*/true));
49  }
50  for (const auto &kv : point_attr_) {
51  lineset.SetPointAttr(kv.first, kv.second.To(device, /*copy=*/true));
52  }
53  return lineset;
54 }
55 
56 std::string LineSet::ToString() const {
57  std::string str = fmt::format("LineSet on {}\n", GetDevice().ToString());
58  if (point_attr_.size() == 0) {
59  str += "[0 points ()] Attributes: None.";
60  } else {
61  str += fmt::format(
62  "[{} points ({})] Attributes:", GetPointPositions().GetShape(0),
63  GetPointPositions().GetDtype().ToString());
64  }
65  if (point_attr_.size() == 1) {
66  str += " None.";
67  } else {
68  for (const auto &keyval : point_attr_) {
69  if (keyval.first == "positions") continue;
70  str += fmt::format(" {} (dtype = {}, shape = {}),", keyval.first,
71  keyval.second.GetDtype().ToString(),
72  keyval.second.GetShape().ToString());
73  }
74  str[str.size() - 1] = '.';
75  }
76  if (line_attr_.size() == 0) {
77  str += "\n[0 lines ()] Attributes: None.";
78  } else {
79  str += fmt::format(
80  "\n[{} lines ({})] Attributes:", GetLineIndices().GetShape(0),
81  GetLineIndices().GetDtype().ToString());
82  }
83  if (line_attr_.size() == 1) {
84  str += " None.";
85  } else {
86  for (const auto &keyval : line_attr_) {
87  if (keyval.first == "indices") continue;
88  str += fmt::format(" {} (dtype = {}, shape = {}),", keyval.first,
89  keyval.second.GetDtype().ToString(),
90  keyval.second.GetShape().ToString());
91  }
92  str[str.size() - 1] = '.';
93  }
94  return str;
95 }
96 
97 LineSet &LineSet::Transform(const core::Tensor &transformation) {
98  core::AssertTensorShape(transformation, {4, 4});
100  return *this;
101 }
102 
103 LineSet &LineSet::Translate(const core::Tensor &translation, bool relative) {
104  core::AssertTensorShape(translation, {3});
105 
106  core::Tensor transform =
107  translation.To(GetDevice(), GetPointPositions().GetDtype());
108 
109  if (!relative) {
110  transform -= GetCenter();
111  }
112  GetPointPositions() += transform;
113  return *this;
114 }
115 
116 LineSet &LineSet::Scale(double scale, const core::Tensor &center) {
117  core::AssertTensorShape(center, {3});
118 
119  const core::Tensor center_d =
120  center.To(GetDevice(), GetPointPositions().GetDtype());
121 
122  GetPointPositions().Sub_(center_d).Mul_(scale).Add_(center_d);
123  return *this;
124 }
125 
127  core::AssertTensorShape(R, {3, 3});
128  core::AssertTensorShape(center, {3});
130  return *this;
131 }
132 
134  const cloudViewer::geometry::LineSet &lineset_legacy,
135  core::Dtype float_dtype,
136  core::Dtype int_dtype,
137  const core::Device &device) {
138  if (float_dtype != core::Float32 && float_dtype != core::Float64) {
139  utility::LogError("float_dtype must be Float32 or Float64, but got {}.",
140  float_dtype.ToString());
141  }
142  if (int_dtype != core::Int32 && int_dtype != core::Int64) {
143  utility::LogError("int_dtype must be Int32 or Int64, but got {}.",
144  int_dtype.ToString());
145  }
146 
147  LineSet lineset(device);
148  if (lineset_legacy.HasPoints()) {
149  lineset.SetPointPositions(
151  lineset_legacy.points_, float_dtype, device));
152  } else {
153  utility::LogWarning("Creating from empty legacy LineSet.");
154  }
155  if (lineset_legacy.HasLines()) {
156  lineset.SetLineIndices(
158  lineset_legacy.lines_, int_dtype, device));
159  } else {
160  utility::LogWarning("Creating from legacy LineSet with no lines.");
161  }
162  if (lineset_legacy.HasColors()) {
163  lineset.SetLineColors(
165  lineset_legacy.colors_, float_dtype, device));
166  }
167  return lineset;
168 }
169 
171  cloudViewer::geometry::LineSet lineset_legacy;
172  if (HasPointPositions()) {
173  lineset_legacy.points_ =
176  }
177  if (HasLineIndices()) {
178  lineset_legacy.lines_ =
180  GetLineIndices());
181  }
182  if (HasLineColors()) {
183  lineset_legacy.colors_ =
185  GetLineColors());
186  }
187  return lineset_legacy;
188 }
189 
192 }
193 
195  const core::Tensor &axis,
196  int resolution,
197  double translation,
198  bool capping) const {
199  using namespace vtkutils;
200  return ExtrudeRotationTriangleMesh(*this, angle, axis, resolution,
201  translation, capping);
202 }
203 
205  double scale,
206  bool capping) const {
207  using namespace vtkutils;
208  return ExtrudeLinearTriangleMesh(*this, vector, scale, capping);
209 }
210 
213 }
214 
217  core::Tensor clipped_color = color.To(GetDevice());
218  if (color.GetDtype() == core::Float32 ||
219  color.GetDtype() == core::Float64) {
220  clipped_color = clipped_color.Clip(0.0f, 1.0f);
221  }
222  core::Tensor ls_colors =
224  clipped_color.GetDtype(), GetDevice());
225  ls_colors.AsRvalue() = clipped_color;
226  SetLineColors(ls_colors);
227 
228  return *this;
229 }
230 
232  int view_height_px,
233  const core::Tensor &intrinsic_in,
234  const core::Tensor &extrinsic_in,
235  double scale,
236  const core::Tensor &color) {
237  core::AssertTensorShape(intrinsic_in, {3, 3});
238  core::AssertTensorShape(extrinsic_in, {4, 4});
239  core::Tensor intrinsic = intrinsic_in.To(core::Float32, "CPU:0");
240  core::Tensor extrinsic = extrinsic_in.To(core::Float32, "CPU:0");
241 
242  // Calculate points for camera visualization
243  float w(view_width_px), h(view_height_px), s(scale);
244  float fx = intrinsic[0][0].Item<float>(),
245  fy = intrinsic[1][1].Item<float>(),
246  cx = intrinsic[0][2].Item<float>(),
247  cy = intrinsic[1][2].Item<float>();
248  core::Tensor points = core::Tensor::Init<float>({{0.f, 0.f, 0.f}, // origin
249  {0.f, 0.f, s},
250  {w * s, 0.f, s},
251  {w * s, h * s, s},
252  {0.f, h * s, s},
253  // Add XYZ axes
254  {fx * s, 0.f, 0.f},
255  {0.f, fy * s, 0.f},
256  {cx * s, cy * s, s}});
257  points = (intrinsic.Inverse().Matmul(points.T()) -
258  extrinsic.Slice(0, 0, 3).Slice(1, 3, 4))
259  .T()
260  .Matmul(extrinsic.Slice(0, 0, 3).Slice(1, 0, 3));
261 
262  // Add lines for camera frame and XYZ axes
263  core::Tensor lines = core::Tensor::Init<int>({{0, 1},
264  {0, 2},
265  {0, 3},
266  {0, 4},
267  {1, 2},
268  {2, 3},
269  {3, 4},
270  {4, 1},
271  // Add XYZ axes
272  {0, 5},
273  {0, 6},
274  {0, 7}});
275 
276  LineSet lineset(points, lines);
277  if (color.NumElements() == 3) {
278  lineset.PaintUniformColor(color);
279  } else {
280  lineset.PaintUniformColor(core::Tensor::Init<float>({0.f, 0.f, 1.f}));
281  }
282  auto &lscolors = lineset.GetLineColors();
283  lscolors[8] = core::Tensor::Init<float>({1.f, 0.f, 0.f}); // Red
284  lscolors[9] = core::Tensor::Init<float>({0.f, 1.f, 0.f}); // Green
285  lscolors[10] = core::Tensor::Init<float>({0.f, 0.f, 1.f}); // Blue
286 
287  return lineset;
288 }
289 
290 } // namespace geometry
291 } // namespace t
292 } // namespace cloudViewer
filament::Texture::InternalFormat format
int points
math::float4 color
#define AssertTensorDevice(tensor,...)
Definition: TensorCheck.h:45
#define AssertTensorShape(tensor,...)
Definition: TensorCheck.h:61
bool copy
Definition: VtkUtils.cpp:74
std::string ToString() const
Definition: Dtype.h:65
int64_t GetLength() const
Definition: Tensor.h:1125
Tensor Sub_(const Tensor &value)
Definition: Tensor.cpp:1153
Tensor Mul_(const Tensor &value)
Definition: Tensor.cpp:1189
Tensor Add_(const Tensor &value)
Definition: Tensor.cpp:1117
Device GetDevice() const override
Definition: Tensor.cpp:1435
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Definition: Tensor.cpp:400
Tensor Slice(int64_t dim, int64_t start, int64_t stop, int64_t step=1) const
Definition: Tensor.cpp:857
Tensor To(Dtype dtype, bool copy=false) const
Definition: Tensor.cpp:739
LineSet define a sets of lines in 3D. A typical application is to display the point cloud corresponde...
Definition: LineSet.h:29
bool HasColors() const
Returns true if the objects lines contains colors.
Definition: LineSet.h:85
std::vector< Eigen::Vector3d > points_
Points coordinates.
Definition: LineSet.h:156
std::vector< Eigen::Vector3d > colors_
RGB colors of lines.
Definition: LineSet.h:160
bool HasLines() const
Returns true if the object contains lines.
Definition: LineSet.h:82
std::vector< Eigen::Vector2i > lines_
Lines denoted by the index of points forming the line.
Definition: LineSet.h:158
bool HasPoints() const
Returns true if the object contains points.
Definition: LineSet.h:79
A bounding box that is aligned along the coordinate axes and defined by the min_bound and max_bound.
static AxisAlignedBoundingBox CreateFromPoints(const core::Tensor &points)
The base geometry class.
Definition: Geometry.h:23
GeometryType
Specifies possible geometry types.
Definition: Geometry.h:28
A LineSet contains points and lines joining them and optionally attributes on the points and lines.
Definition: LineSet.h:85
core::Device GetDevice() const override
Returns the device attribute of this LineSet.
Definition: LineSet.h:348
core::Tensor & GetLineIndices()
Definition: LineSet.h:157
core::Tensor GetCenter() const
Returns the center for point coordinates.
Definition: LineSet.h:296
std::string ToString() const
Text description.
Definition: LineSet.cpp:56
LineSet & Translate(const core::Tensor &translation, bool relative=true)
Translates the points and lines of the LineSet.
Definition: LineSet.cpp:103
LineSet & PaintUniformColor(const core::Tensor &color)
Assigns uniform color to all lines of the LineSet.
Definition: LineSet.cpp:215
OrientedBoundingBox GetOrientedBoundingBox() const
Create an oriented bounding box from point attribute "positions".
Definition: LineSet.cpp:211
void SetPointPositions(const core::Tensor &value)
Definition: LineSet.h:218
LineSet To(const core::Device &device, bool copy=false) const
Definition: LineSet.cpp:42
TriangleMesh ExtrudeLinear(const core::Tensor &vector, double scale=1.0, bool capping=true) const
Definition: LineSet.cpp:204
TriangleMesh ExtrudeRotation(double angle, const core::Tensor &axis, int resolution=16, double translation=0.0, bool capping=true) const
Definition: LineSet.cpp:194
static LineSet CreateCameraVisualization(int view_width_px, int view_height_px, const core::Tensor &intrinsic, const core::Tensor &extrinsic, double scale, const core::Tensor &color={})
Definition: LineSet.cpp:231
LineSet(const core::Device &device=core::Device("CPU:0"))
Construct an empty LineSet on the provided device.
Definition: LineSet.cpp:26
void SetLineAttr(const std::string &key, const core::Tensor &value)
Definition: LineSet.h:228
void SetLineColors(const core::Tensor &value)
Definition: LineSet.h:241
cloudViewer::geometry::LineSet ToLegacy() const
Convert to a legacy CloudViewer LineSet.
Definition: LineSet.cpp:170
core::Tensor & GetPointPositions()
Definition: LineSet.h:139
LineSet & Transform(const core::Tensor &transformation)
Transforms the points and lines of the LineSet.
Definition: LineSet.cpp:97
void SetPointAttr(const std::string &key, const core::Tensor &value)
Definition: LineSet.h:211
core::Tensor & GetLineColors()
Definition: LineSet.h:161
static geometry::LineSet FromLegacy(const cloudViewer::geometry::LineSet &lineset_legacy, core::Dtype float_dtype=core::Float32, core::Dtype int_dtype=core::Int64, const core::Device &device=core::Device("CPU:0"))
Definition: LineSet.cpp:133
AxisAlignedBoundingBox GetAxisAlignedBoundingBox() const
Create an axis-aligned bounding box from point attribute "positions".
Definition: LineSet.cpp:190
LineSet & Rotate(const core::Tensor &R, const core::Tensor &center)
Rotates the points and lines of the line set. Custom attributes (e.g.: point or line normals) are not...
Definition: LineSet.cpp:126
void SetLineIndices(const core::Tensor &value)
Set the value of the "indices" attribute in line_attr_.
Definition: LineSet.h:234
LineSet & Scale(double scale, const core::Tensor &center)
Scales the points and lines of the LineSet.
Definition: LineSet.cpp:116
A bounding box oriented along an arbitrary frame of reference.
static OrientedBoundingBox CreateFromPoints(const core::Tensor &points, bool robust=false, MethodOBBCreate method=MethodOBBCreate::MINIMAL_APPROX)
A triangle mesh contains vertices and triangles.
Definition: TriangleMesh.h:98
#define LogWarning(...)
Definition: Logging.h:72
#define LogError(...)
Definition: Logging.h:60
std::vector< Eigen::Vector2i > TensorToEigenVector2iVector(const core::Tensor &tensor)
Converts a tensor of shape (N, 2) to std::vector<Eigen::Vector2i>. An exception will be thrown if the...
core::Tensor EigenVector2iVectorToTensor(const std::vector< Eigen::Vector2i > &values, core::Dtype dtype, const core::Device &device)
Converts a vector of Eigen::Vector2i to a (N, 2) tensor. This function also takes care of dtype conve...
std::vector< Eigen::Vector3d > TensorToEigenVector3dVector(const core::Tensor &tensor)
Converts a tensor of shape (N, 3) to std::vector<Eigen::Vector3d>. An exception will be thrown if the...
core::Tensor EigenVector3dVectorToTensor(const std::vector< Eigen::Vector3d > &values, core::Dtype dtype, const core::Device &device)
Converts a vector of Eigen::Vector3d to a (N, 3) tensor. This function also takes care of dtype conve...
const Dtype Int64
Definition: Dtype.cpp:47
const Dtype Float64
Definition: Dtype.cpp:43
const Dtype Int32
Definition: Dtype.cpp:46
const Dtype Float32
Definition: Dtype.cpp:42
void TransformPoints(const core::Tensor &transformation, core::Tensor &points)
Definition: Transform.cpp:20
void RotatePoints(const core::Tensor &R, core::Tensor &points, const core::Tensor &center)
Definition: Transform.cpp:63
CLOUDVIEWER_LOCAL TriangleMesh ExtrudeLinearTriangleMesh(const Geometry &geometry, const core::Tensor &vector, double scale, bool capping)
Definition: VtkUtils.cpp:580
CLOUDVIEWER_LOCAL TriangleMesh ExtrudeRotationTriangleMesh(const Geometry &geometry, const double angle, const core::Tensor &axis, int resolution, double translation, bool capping)
Definition: VtkUtils.cpp:529
Generic file read and write utility for python interface.