10 #include <vtkActor2D.h>
11 #include <vtkCellArray.h>
13 #include <vtkObjectFactory.h>
14 #include <vtkPoints.h>
15 #include <vtkPolyData.h>
16 #include <vtkPolyDataMapper2D.h>
17 #include <vtkPropCollection.h>
18 #include <vtkProperty2D.h>
19 #include <vtkRenderer.h>
20 #include <vtkTextActor.h>
21 #include <vtkTextProperty.h>
22 #include <vtkWindow.h>
36 LabelSuffix(nullptr) {
100 if (this->Renderer && this->Renderer != ren) {
110 this->Superclass::SetRenderer(ren);
125 this->Superclass::BuildRepresentation();
129 if (this->GetNumberOfHandles() != 3) {
137 std::ostringstream labelStream;
138 labelStream.precision(2);
139 labelStream << std::fixed << this->
Angle <<
"°";
156 if (this->Renderer) {
157 double p1[3], center[3], p2[3];
158 this->GetHandlePosition(0, p1);
159 this->GetHandlePosition(1, center);
160 this->GetHandlePosition(2, p2);
163 double vec1[3], vec2[3];
164 vtkMath::Subtract(p1, center, vec1);
165 vtkMath::Subtract(p2, center, vec2);
166 double len1 = vtkMath::Norm(vec1);
167 double len2 = vtkMath::Norm(vec2);
168 vtkMath::Normalize(vec1);
169 vtkMath::Normalize(vec2);
173 bisector[0] = vec1[0] + vec2[0];
174 bisector[1] = vec1[1] + vec2[1];
175 bisector[2] = vec1[2] + vec2[2];
176 vtkMath::Normalize(bisector);
180 double dotProduct = vtkMath::Dot(vec1, vec2);
181 double angleRadians =
182 std::acos(std::max(-1.0, std::min(1.0, dotProduct)));
183 double angleDegrees = vtkMath::DegreesFromRadians(angleRadians);
187 if (angleDegrees > 180.0) {
188 bisector[0] = -bisector[0];
189 bisector[1] = -bisector[1];
190 bisector[2] = -bisector[2];
194 double minRayLength = std::min(len1, len2);
195 double radiusPercentage;
197 if (angleDegrees < 30.0) {
199 radiusPercentage = 0.30 - (angleDegrees / 30.0) * 0.05;
200 }
else if (angleDegrees < 90.0) {
202 radiusPercentage = 0.25 - ((angleDegrees - 30.0) / 60.0) * 0.05;
205 radiusPercentage = 0.20 - ((angleDegrees - 90.0) / 90.0) * 0.05;
208 double adaptiveRadius =
209 std::min(this->
ArcRadius, minRayLength * radiusPercentage);
210 adaptiveRadius = std::max(adaptiveRadius, minRayLength * 0.01);
211 adaptiveRadius = std::min(adaptiveRadius, minRayLength * 0.40);
217 double labelDistanceMultiplier;
218 if (angleDegrees < 30.0) {
221 labelDistanceMultiplier = 3.0 - (angleDegrees / 30.0) * 0.5;
222 }
else if (angleDegrees < 90.0) {
225 labelDistanceMultiplier =
226 2.5 - ((angleDegrees - 30.0) / 60.0) * 0.7;
230 labelDistanceMultiplier =
231 1.8 - ((angleDegrees - 90.0) / 90.0) * 0.3;
236 double labelDistance = adaptiveRadius * labelDistanceMultiplier;
238 labelPos[0] = center[0] + bisector[0] * labelDistance;
239 labelPos[1] = center[1] + bisector[1] * labelDistance;
240 labelPos[2] = center[2] + bisector[2] * labelDistance;
243 this->Renderer->SetWorldPoint(labelPos[0], labelPos[1], labelPos[2],
245 this->Renderer->WorldToDisplay();
246 double* displayCoord = this->Renderer->GetDisplayPoint();
254 double textWidth = bounds[1] - bounds[0];
259 double centeredX = displayCoord[0] - textWidth / 2.0;
273 vtkTypeBool repVisible = this->GetVisibility();
280 if (this->GetNumberOfHandles() < 3) {
285 double p1[3], center[3], p2[3];
286 this->GetHandlePosition(0, p1);
287 this->GetHandlePosition(1, center);
288 this->GetHandlePosition(2, p2);
291 double vec1[3], vec2[3];
292 vtkMath::Subtract(p1, center, vec1);
293 vtkMath::Subtract(p2, center, vec2);
297 double norm1 = vtkMath::Norm(vec1);
298 double norm2 = vtkMath::Norm(vec2);
300 if (norm1 < 1
e-10 || norm2 < 1
e-10) {
304 double dotProduct = vtkMath::Dot(vec1, vec2);
305 double cosAngle = dotProduct / (norm1 * norm2);
308 cosAngle = std::max(-1.0, std::min(1.0, cosAngle));
312 double angleRadians = std::acos(cosAngle);
313 return vtkMath::DegreesFromRadians(angleRadians);
317 if (this->GetNumberOfHandles() < 3 || !this->Renderer) {
322 double p1[3], center[3], p2[3];
323 this->GetHandlePosition(0, p1);
324 this->GetHandlePosition(1, center);
325 this->GetHandlePosition(2, p2);
328 double vec1[3], vec2[3];
329 vtkMath::Subtract(p1, center, vec1);
330 vtkMath::Subtract(p2, center, vec2);
331 double len1 = vtkMath::Norm(vec1);
332 double len2 = vtkMath::Norm(vec2);
333 vtkMath::Normalize(vec1);
334 vtkMath::Normalize(vec2);
337 double dotProduct = vtkMath::Dot(vec1, vec2);
338 double angleRadians = std::acos(std::max(-1.0, std::min(1.0, dotProduct)));
339 double angleDegrees = vtkMath::DegreesFromRadians(angleRadians);
344 double minRayLength = std::min(len1, len2);
345 double radiusPercentage;
347 if (angleDegrees < 30.0) {
350 radiusPercentage = 0.30 - (angleDegrees / 30.0) * 0.05;
351 }
else if (angleDegrees < 90.0) {
353 radiusPercentage = 0.25 - ((angleDegrees - 30.0) / 60.0) * 0.05;
357 radiusPercentage = 0.20 - ((angleDegrees - 90.0) / 90.0) * 0.05;
360 double adaptiveRadius =
361 std::min(this->
ArcRadius, minRayLength * radiusPercentage);
365 adaptiveRadius = std::max(adaptiveRadius, minRayLength * 0.01);
366 adaptiveRadius = std::min(adaptiveRadius, minRayLength * 0.40);
369 vtkNew<vtkPoints> arcPoints;
370 vtkNew<vtkCellArray> arcLines;
372 const int numArcPoints = 30;
374 for (
int i = 0; i <= numArcPoints; ++i) {
375 double t =
static_cast<double>(i) / numArcPoints;
378 double cosTheta = vtkMath::Dot(vec1, vec2);
379 double theta = std::acos(std::max(-1.0, std::min(1.0, cosTheta)));
381 double sinTheta = std::sin(theta);
382 double a = (sinTheta > 1
e-10) ? std::sin((1.0 - t) * theta) / sinTheta
384 double b = (sinTheta > 1
e-10) ? std::sin(t * theta) / sinTheta : t;
387 for (
int j = 0; j < 3; ++j) {
388 interpVec[j] =
a * vec1[j] + b * vec2[j];
390 vtkMath::Normalize(interpVec);
394 double arcPointWorld[3];
395 for (
int j = 0; j < 3; ++j) {
396 arcPointWorld[j] = center[j] + adaptiveRadius * interpVec[j];
400 this->Renderer->SetWorldPoint(arcPointWorld[0], arcPointWorld[1],
401 arcPointWorld[2], 1.0);
402 this->Renderer->WorldToDisplay();
403 double* displayCoord = this->Renderer->GetDisplayPoint();
406 arcPoints->InsertNextPoint(displayCoord[0], displayCoord[1], 0.0);
410 arcLines->InsertNextCell(numArcPoints + 1);
411 for (
int i = 0; i <= numArcPoints; ++i) {
412 arcLines->InsertCellPoint(i);
422 this->Superclass::SetVisibility(visible);
444 this->Superclass::GetActors2D(pc);
457 this->Superclass::ReleaseGraphicsResources(w);
467 int count = this->Superclass::RenderOverlay(viewport);
480 vtkViewport* viewport) {
481 int count = this->Superclass::RenderOpaqueGeometry(viewport);
484 count += this->
AngleArcActor->RenderOpaqueGeometry(viewport);
491 vtkViewport* viewport) {
492 int count = this->Superclass::RenderTranslucentPolygonalGeometry(viewport);
498 return this->Superclass::HasTranslucentPolygonalGeometry();
504 if (this->Renderer && this->GetNumberOfHandles() > 0) {
506 this->Renderer->SetDisplayPoint(pos);
507 this->Renderer->DisplayToWorld();
508 this->Renderer->GetWorldPoint(worldPos);
510 if (worldPos[3] != 0.0) {
511 worldPos[0] /= worldPos[3];
512 worldPos[1] /= worldPos[3];
513 worldPos[2] /= worldPos[3];
515 this->SetHandlePosition(0, worldPos);
521 if (this->Renderer && this->GetNumberOfHandles() > 0) {
523 this->GetHandlePosition(0, worldPos);
524 this->Renderer->SetWorldPoint(worldPos[0], worldPos[1], worldPos[2],
526 this->Renderer->WorldToDisplay();
527 this->Renderer->GetDisplayPoint(pos);
529 pos[0] = pos[1] = pos[2] = 0.0;
535 if (this->Renderer && this->GetNumberOfHandles() > 1) {
537 this->Renderer->SetDisplayPoint(pos);
538 this->Renderer->DisplayToWorld();
539 this->Renderer->GetWorldPoint(worldPos);
540 if (worldPos[3] != 0.0) {
541 worldPos[0] /= worldPos[3];
542 worldPos[1] /= worldPos[3];
543 worldPos[2] /= worldPos[3];
545 this->SetHandlePosition(1, worldPos);
551 if (this->Renderer && this->GetNumberOfHandles() > 1) {
553 this->GetHandlePosition(1, worldPos);
554 this->Renderer->SetWorldPoint(worldPos[0], worldPos[1], worldPos[2],
556 this->Renderer->WorldToDisplay();
557 this->Renderer->GetDisplayPoint(pos);
559 pos[0] = pos[1] = pos[2] = 0.0;
565 if (this->Renderer && this->GetNumberOfHandles() > 2) {
567 this->Renderer->SetDisplayPoint(pos);
568 this->Renderer->DisplayToWorld();
569 this->Renderer->GetWorldPoint(worldPos);
570 if (worldPos[3] != 0.0) {
571 worldPos[0] /= worldPos[3];
572 worldPos[1] /= worldPos[3];
573 worldPos[2] /= worldPos[3];
575 this->SetHandlePosition(2, worldPos);
581 if (this->Renderer && this->GetNumberOfHandles() > 2) {
583 this->GetHandlePosition(2, worldPos);
584 this->Renderer->SetWorldPoint(worldPos[0], worldPos[1], worldPos[2],
586 this->Renderer->WorldToDisplay();
587 this->Renderer->GetDisplayPoint(pos);
589 pos[0] = pos[1] = pos[2] = 0.0;
594 vtkHandleRepresentation*
602 vtkHandleRepresentation*
607 vtkHandleRepresentation*
Extended PolyLineRepresentation adding angle display functionality.
void GetPoint1DisplayPosition(double pos[3])
void SetVisibility(vtkTypeBool visible) override
Override SetVisibility to also control arc and label actors.
vtkPolyDataMapper2D * AngleArcMapper
void GetPoint2DisplayPosition(double pos[3])
int RenderOpaqueGeometry(vtkViewport *viewport) override
void SetPoint1DisplayPosition(double pos[3])
vtkTextActor * AngleLabelActor
vtkHandleRepresentation * GetPoint1Representation()
Compatibility: Get handle representations.
void SetRenderer(vtkRenderer *ren) override
Set the renderer for this representation.
vtkActor2D * AngleArcActor
vtkTypeBool ShowAngleLabel
int RenderOverlay(vtkViewport *viewport) override
void BuildAngleArc()
Build the angle arc geometry.
vtkHandleRepresentation * GetPoint2Representation()
void SetCenterDisplayPosition(double pos[3])
double GetAngle()
Calculate the angle formed by the three handles.
int RenderTranslucentPolygonalGeometry(vtkViewport *viewport) override
vtkTypeBool HasTranslucentPolygonalGeometry() override
void GetActors2D(vtkPropCollection *pc) override
Render the angle representation.
void BuildRepresentation() override
Build the representation for the angle measurement.
void ReleaseGraphicsResources(vtkWindow *w) override
Release graphics resources.
~cvConstrainedPolyLineRepresentation() override
cvConstrainedPolyLineRepresentation()
vtkPolyData * AngleArcPolyData
void GetCenterDisplayPosition(double pos[3])
vtkHandleRepresentation * GetCenterRepresentation()
void SetPoint2DisplayPosition(double pos[3])
vtkStandardNewMacro(cvConstrainedPolyLineRepresentation)