ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
cvConstrainedLineRepresentation.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 // VTK
11 #include <vtkActor.h>
12 #include <vtkAxisActor2D.h>
13 #include <vtkCoordinate.h>
14 #include <vtkMath.h>
15 #include <vtkObjectFactory.h>
16 #include <vtkPointHandleRepresentation3D.h>
17 #include <vtkProperty.h>
18 #include <vtkProperty2D.h>
19 #include <vtkRenderer.h>
20 #include <vtkTextProperty.h>
21 #include <vtkWindow.h>
22 
23 // STL
24 #include <cstdio>
25 #include <sstream>
26 
28 
29 //------------------------------------------------------------------------------
31  : ShowLabel(1),
32  LabelFormat(nullptr),
33  LabelSuffix(nullptr),
34  RulerMode(0),
35  RulerDistance(1.0),
36  NumberOfRulerTicks(5),
37  Scale(1.0),
38  Distance(0.0) {
39  // Initialize AxisProperty (following ParaView vtkDistanceRepresentation2D
40  // exactly)
41  this->AxisProperty = vtkProperty2D::New();
42  this->AxisProperty->SetColor(1.0, 1.0, 1.0); // White color
43 
44  // Initialize AxisActor (following ParaView vtkDistanceRepresentation2D)
45  this->AxisActor = vtkAxisActor2D::New();
46 
47  // CRITICAL: Use World coordinate system (ParaView way), NOT Display
48  this->AxisActor->GetPoint1Coordinate()->SetCoordinateSystemToWorld();
49  this->AxisActor->GetPoint2Coordinate()->SetCoordinateSystemToWorld();
50 
51  this->AxisActor->SetNumberOfLabels(5);
52  this->AxisActor->LabelVisibilityOff(); // ParaView default
53  this->AxisActor->AdjustLabelsOff();
54  this->AxisActor->SetProperty(this->AxisProperty);
55  this->AxisActor->SetTitle(
56  "Distance"); // ParaView uses Title for distance label
57 
58  // CRITICAL: Hide the axis line itself to avoid double-line rendering
59  // We only want to show the title (distance label), not the axis line
60  // The actual line is already rendered by vtkLineRepresentation
61  this->AxisActor->AxisVisibilityOff(); // Hide axis line
62  this->AxisActor->TickVisibilityOff(); // Hide tick marks
63 
64  // Configure title text property (compact appearance)
65  this->AxisActor->GetTitleTextProperty()->SetFontSize(
66  8); // Default font size (will be overridden by user settings)
67  this->AxisActor->GetTitleTextProperty()->SetBold(0); // Not bold
68  this->AxisActor->GetTitleTextProperty()->SetItalic(0); // Not italic
69  this->AxisActor->GetTitleTextProperty()->SetShadow(1);
70  this->AxisActor->GetTitleTextProperty()->SetFontFamilyToArial();
71  this->AxisActor->GetTitleTextProperty()->SetColor(1.0, 1.0, 1.0);
72 
73  // Use vtkAxisActor2D's font scaling mechanism (affects both title and
74  // labels) Set font factors once during initialization - these should not be
75  // changed in BuildRepresentation() as they would interfere with user font
76  // size settings
77  this->AxisActor->SetFontFactor(
78  1.0); // Use 1.0 to respect user's font size settings
79  this->AxisActor->SetLabelFactor(0.8); // Slightly smaller for axis labels
80 
81  // Default label format (ParaView default)
82  this->SetLabelFormat("%-#6.3g");
83 }
84 
85 //------------------------------------------------------------------------------
87  // Following ParaView vtkDistanceRepresentation2D destructor
88  if (this->AxisProperty) {
89  this->AxisProperty->Delete();
90  }
91  if (this->AxisActor) {
92  this->AxisActor->Delete();
93  }
94  if (this->LabelFormat) {
95  delete[] this->LabelFormat;
96  }
97  if (this->LabelSuffix) {
98  delete[] this->LabelSuffix;
99  }
100 }
101 
102 //------------------------------------------------------------------------------
104  double p1[3], p2[3];
105  this->GetPoint1WorldPosition(p1);
106  this->GetPoint2WorldPosition(p2);
107  return sqrt(vtkMath::Distance2BetweenPoints(p1, p2));
108 }
109 
110 //------------------------------------------------------------------------------
112  if (this->Scale != scale && scale > 0.0) {
113  this->Scale = scale;
114  this->Modified();
115  }
116 }
117 
118 //------------------------------------------------------------------------------
120  // Call parent class BuildRepresentation
121  this->Superclass::BuildRepresentation();
122 
123  // Following ParaView vtkDistanceRepresentation2D::BuildRepresentation()
124  // exactly
125 
126  // Compute the distance and set the label
127  double p1[3], p2[3];
128  this->GetPoint1WorldPosition(p1);
129  this->GetPoint2WorldPosition(p2);
130  this->Distance = sqrt(vtkMath::Distance2BetweenPoints(p1, p2));
131 
132  // Set axis position in WORLD coordinates (ParaView way)
133  this->AxisActor->GetPoint1Coordinate()->SetValue(p1);
134  this->AxisActor->GetPoint2Coordinate()->SetValue(p2);
135 
136  // Configure ruler mode (ParaView way)
137  this->AxisActor->SetRulerMode(this->RulerMode);
138  if (this->Scale != 0.0) {
139  this->AxisActor->SetRulerDistance(this->RulerDistance / this->Scale);
140  }
141  this->AxisActor->SetNumberOfLabels(this->NumberOfRulerTicks);
142 
143  // CRITICAL: Always hide the axis line to avoid double-line rendering
144  // Only show ticks in RulerMode
145  this->AxisActor->AxisVisibilityOff();
146  if (this->RulerMode) {
147  this->AxisActor->TickVisibilityOn(); // Show ticks only in ruler mode
148  } else {
149  this->AxisActor->TickVisibilityOff(); // Hide ticks in normal mode
150  }
151 
152  // Format and set the distance label as AxisActor Title (ParaView way)
153  if (this->LabelFormat) {
154  char labelString[512];
155  snprintf(labelString, sizeof(labelString), this->LabelFormat,
156  this->Distance * this->Scale);
157 
158  // Append instance label suffix if present (e.g., " #1", " #2")
159  if (this->LabelSuffix) {
160  strncat(labelString, this->LabelSuffix,
161  sizeof(labelString) - strlen(labelString) - 1);
162  }
163 
164  this->AxisActor->SetTitle(labelString);
165  }
166 
167  // NOTE: Font properties (size, bold, italic, shadow, color) and font
168  // factors should NOT be set here as they would override user customizations
169  // set via applyFontProperties(). Font properties are initialized in the
170  // constructor and can be customized by the user. BuildRepresentation() is
171  // called frequently (on every render), so setting font properties here
172  // would continuously reset user preferences.
173 
174  // Control visibility (ShowLabel controls the entire AxisActor visibility)
175  this->AxisActor->SetVisibility(this->ShowLabel);
176 }
177 
178 //------------------------------------------------------------------------------
180  // Following ParaView vtkDistanceRepresentation2D::RenderOverlay() exactly
181  this->BuildRepresentation();
182 
183  int count = this->Superclass::RenderOverlay(viewport);
184 
185  if (this->AxisActor->GetVisibility()) {
186  count += this->AxisActor->RenderOverlay(viewport);
187  }
188 
189  return count;
190 }
191 
192 //------------------------------------------------------------------------------
194  vtkViewport* viewport) {
195  // Following ParaView vtkDistanceRepresentation2D::RenderOpaqueGeometry()
196  // exactly
197  this->BuildRepresentation();
198 
199  int count = this->Superclass::RenderOpaqueGeometry(viewport);
200 
201  if (this->AxisActor->GetVisibility()) {
202  count += this->AxisActor->RenderOpaqueGeometry(viewport);
203  }
204 
205  return count;
206 }
207 
208 //------------------------------------------------------------------------------
210  vtkPointHandleRepresentation3D* handle) {
211  if (!handle) {
212  return;
213  }
214 
215  // Save current positions
216  double p1[3] = {0, 0, 0};
217  double p2[3] = {0, 0, 0};
218  if (this->Point1Representation) {
219  this->Point1Representation->GetWorldPosition(p1);
220  }
221  if (this->Point2Representation) {
222  this->Point2Representation->GetWorldPosition(p2);
223  }
224 
225  // Get the actual class name to check if it's our custom type
226  const char* className = handle->GetClassName();
227  bool isCustomType =
228  (strcmp(className, "cvCustomAxisHandleRepresentation") == 0);
229 
230  // Replace Point1Representation
231  if (this->Point1Representation) {
232  this->Point1Representation->Delete();
233  }
234  if (isCustomType) {
235  // Use NewInstance for our custom type - it should work correctly
236  this->Point1Representation =
237  static_cast<vtkPointHandleRepresentation3D*>(
238  handle->NewInstance());
239  } else {
240  // For standard types, create a copy
241  this->Point1Representation = handle->NewInstance();
242  }
243  this->Point1Representation->ShallowCopy(handle);
244  this->Point1Representation->SetWorldPosition(p1);
245 
246  // Replace Point2Representation
247  if (this->Point2Representation) {
248  this->Point2Representation->Delete();
249  }
250  if (isCustomType) {
251  this->Point2Representation =
252  static_cast<vtkPointHandleRepresentation3D*>(
253  handle->NewInstance());
254  } else {
255  this->Point2Representation = handle->NewInstance();
256  }
257  this->Point2Representation->ShallowCopy(handle);
258  this->Point2Representation->SetWorldPosition(p2);
259 
260  // Replace LineHandleRepresentation
261  if (this->LineHandleRepresentation) {
262  this->LineHandleRepresentation->Delete();
263  }
264  if (isCustomType) {
265  this->LineHandleRepresentation =
266  static_cast<vtkPointHandleRepresentation3D*>(
267  handle->NewInstance());
268  } else {
269  this->LineHandleRepresentation = handle->NewInstance();
270  }
271  this->LineHandleRepresentation->ShallowCopy(handle);
272 
273  this->Modified();
274 }
275 
276 //------------------------------------------------------------------------------
277 void cvConstrainedLineRepresentation::PrintSelf(ostream& os, vtkIndent indent) {
278  this->Superclass::PrintSelf(os, indent);
279 
280  os << indent << "Show Label: " << this->ShowLabel << "\n";
281  os << indent
282  << "Label Format: " << (this->LabelFormat ? this->LabelFormat : "(none)")
283  << "\n";
284  os << indent << "Ruler Mode: " << this->RulerMode << "\n";
285  os << indent << "Ruler Distance: " << this->RulerDistance << "\n";
286  os << indent << "Number Of Ruler Ticks: " << this->NumberOfRulerTicks
287  << "\n";
288  os << indent << "Scale: " << this->Scale << "\n";
289 }
int count
Extended LineRepresentation with distance display and ruler features.
void ReplaceHandleRepresentations(vtkPointHandleRepresentation3D *handle)
Replace handle representations with custom types (runtime version)
void BuildRepresentation() override
Override BuildRepresentation to update distance display.
void SetScale(double scale)
Set/Get scale factor.
virtual double GetDistance()
Get distance between the two points.
int RenderOpaqueGeometry(vtkViewport *viewport) override
int RenderOverlay(vtkViewport *viewport) override
Override to render distance label and ticks.
void PrintSelf(ostream &os, vtkIndent indent) override
vtkStandardNewMacro(cvConstrainedLineRepresentation)