10 #include <vtkActor2D.h>
11 #include <vtkAlgorithmOutput.h>
12 #include <vtkCamera.h>
13 #include <vtkCoordinate.h>
14 #include <vtkLineSource.h>
15 #include <vtkPolyData.h>
16 #include <vtkPolyDataMapper2D.h>
17 #include <vtkProperty2D.h>
18 #include <vtkRenderWindow.h>
19 #include <vtkRenderWindowInteractor.h>
20 #include <vtkRenderer.h>
21 #include <vtkSmartPointer.h>
22 #include <vtkTextActor.h>
23 #include <vtkTextProperty.h>
25 #include <QApplication>
26 #include <QCoreApplication>
27 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
28 #include <QDesktopWidget>
30 #include <QProcessEnvironment>
40 dpiScale = getPlatformAwareDPIScale();
44 lineSource->SetPoint1(0.0, 0.0, 0.0);
45 lineSource->SetPoint2(100.0, 0.0, 0.0);
48 mapper->SetInputConnection(lineSource->GetOutputPort());
51 lineActor->SetMapper(mapper);
52 lineActor->GetProperty()->SetColor(1.0, 1.0, 1.0);
53 lineActor->GetProperty()->SetLineWidth(3.0 * dpiScale);
57 textActor->SetInput(
"1 m");
58 int optimizedFontSize = getOptimizedFontSize(18);
59 textActor->GetTextProperty()->SetFontSize(optimizedFontSize);
60 textActor->GetTextProperty()->SetColor(1.0, 1.0, 1.0);
61 textActor->GetTextProperty()->SetJustificationToCentered();
62 textActor->GetTextProperty()->SetVerticalJustificationToTop();
64 textActor->SetPosition(100.0 * dpiScale, 25.0 * dpiScale);
67 leftTickActor = createTickActor(0.0, 0.0, 10.0 * dpiScale);
68 rightTickActor = createTickActor(100.0, 0.0, 10.0 * dpiScale);
71 renderer->AddActor2D(lineActor);
72 renderer->AddActor2D(textActor);
73 renderer->AddActor2D(leftTickActor);
74 renderer->AddActor2D(rightTickActor);
82 lineActor->SetVisibility(v);
83 textActor->SetVisibility(v);
84 leftTickActor->SetVisibility(v);
85 rightTickActor->SetVisibility(v);
88 double ScaleBarWidget::getDPIScale() {
90 if (!QApplication::instance()) {
95 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
96 QScreen* screen = QApplication::primaryScreen();
98 return screen->devicePixelRatio();
103 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
104 QCoreApplication* coreApp = QCoreApplication::instance();
105 QApplication* app = qobject_cast<QApplication*>(coreApp);
107 return app->devicePixelRatio();
112 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
113 QDesktopWidget* desktop = QApplication::desktop();
116 int physicalDPI = desktop->physicalDpiX();
117 int logicalDPI = desktop->logicalDpiX();
118 if (logicalDPI > 0) {
119 return static_cast<double>(physicalDPI) / logicalDPI;
125 const char* qt_scale_factor = qgetenv(
"QT_SCALE_FACTOR");
126 if (qt_scale_factor) {
128 double scale = QString(qt_scale_factor).toDouble(&ok);
129 if (ok && scale > 0) {
137 int ScaleBarWidget::getOptimizedFontSize(
int baseFontSize) {
139 QScreen* screen = QApplication::primaryScreen();
145 QSize screenSize = screen->size();
146 int screenWidth = screenSize.width();
147 int screenHeight = screenSize.height();
148 int screenDPI = screen->physicalDotsPerInch();
149 int dpiScale =
static_cast<int>(getDPIScale());
152 int platformBaseSize = baseFontSize;
156 platformBaseSize = baseFontSize;
159 platformBaseSize = std::max(12, baseFontSize - (dpiScale - 1) * 3);
161 #elif defined(Q_OS_WIN)
163 if (screenDPI > 120) {
165 platformBaseSize = std::max(12, baseFontSize - 2);
166 }
else if (screenDPI < 96) {
168 platformBaseSize = baseFontSize + 2;
170 #elif defined(Q_OS_LINUX)
172 if (screenWidth >= 1920 && screenHeight >= 1080) {
174 platformBaseSize = std::max(12, baseFontSize - 2);
175 }
else if (screenWidth < 1366) {
177 platformBaseSize = baseFontSize + 2;
182 int resolutionFactor = 0;
183 if (screenWidth >= 2560 && screenHeight >= 1440) {
185 resolutionFactor = -1;
186 }
else if (screenWidth < 1366) {
188 resolutionFactor = 1;
192 int finalSize = platformBaseSize + resolutionFactor;
195 finalSize = std::max(10, std::min(32, finalSize));
200 double ScaleBarWidget::getPlatformAwareDPIScale() {
201 double dpiScale = getDPIScale();
202 QScreen* screen = QApplication::primaryScreen();
208 QSize screenSize = screen->size();
209 int screenWidth = screenSize.width();
210 int screenHeight = screenSize.height();
211 int screenDPI = screen->physicalDotsPerInch();
214 double adjustedScale = dpiScale;
220 adjustedScale = 1.0 + (dpiScale - 1.0) * 0.6;
222 #elif defined(Q_OS_WIN)
224 if (screenDPI > 120) {
226 adjustedScale = std::min(adjustedScale, 1.4);
227 }
else if (screenDPI < 96) {
229 adjustedScale = std::max(adjustedScale, 1.0);
231 #elif defined(Q_OS_LINUX)
233 if (screenWidth >= 2560 && screenHeight >= 1440) {
235 adjustedScale = std::min(adjustedScale, 1.2);
236 }
else if (screenWidth < 1366) {
238 adjustedScale = std::max(adjustedScale, 1.0);
243 adjustedScale = std::max(0.8, std::min(1.8, adjustedScale));
245 return adjustedScale;
252 lineSource->SetPoint1(
x,
y, 0.0);
253 lineSource->SetPoint2(
x,
y + length, 0.0);
256 mapper->SetInputConnection(lineSource->GetOutputPort());
259 actor->SetMapper(mapper);
260 actor->GetProperty()->SetColor(1.0, 1.0, 1.0);
261 actor->GetProperty()->SetLineWidth(2.0 * dpiScale);
267 vtkRenderWindowInteractor* interactor) {
268 if (!visible || !renderer || !renderer->GetRenderWindow())
return;
272 double currentDPIScale = getPlatformAwareDPIScale();
273 if (std::abs(currentDPIScale - dpiScale) > 0.1) {
274 dpiScale = currentDPIScale;
278 int optimizedFontSize = getOptimizedFontSize(18);
279 textActor->GetTextProperty()->SetFontSize(optimizedFontSize);
280 textActor->GetTextProperty()->SetJustificationToCentered();
281 textActor->GetTextProperty()->SetVerticalJustificationToTop();
284 lineActor->GetProperty()->SetLineWidth(3.0 * dpiScale);
287 leftTickActor->GetProperty()->SetLineWidth(2.0 * dpiScale);
289 if (rightTickActor) {
290 rightTickActor->GetProperty()->SetLineWidth(2.0 * dpiScale);
295 int*
size = renderer->GetRenderWindow()->GetSize();
299 int barPixelLen =
static_cast<int>(
300 (winW / 6.0) * dpiScale);
303 double bottomMargin = 25.0 * dpiScale;
305 static_cast<double>(winW) / 2.0;
306 double bottomY = bottomMargin;
309 double p1[3] = {centerX -
static_cast<double>(barPixelLen) / 2.0, bottomY,
311 double p2[3] = {centerX +
static_cast<double>(barPixelLen) / 2.0, bottomY,
314 double world1[4], world2[4];
315 renderer->SetDisplayPoint(
static_cast<int>(p1[0]),
static_cast<int>(p1[1]),
317 renderer->DisplayToWorld();
318 memcpy(world1, renderer->GetWorldPoint(),
sizeof(
double) * 4);
319 renderer->SetDisplayPoint(
static_cast<int>(p2[0]),
static_cast<int>(p2[1]),
321 renderer->DisplayToWorld();
322 memcpy(world2, renderer->GetWorldPoint(),
sizeof(
double) * 4);
324 double dx = (world2[0] / world2[3]) - (world1[0] / world1[3]);
325 double dy = (world2[1] / world2[3]) - (world1[1] / world1[3]);
326 double dz = (world2[2] / world2[3]) - (world1[2] / world1[3]);
327 double dist = sqrt(dx * dx + dy * dy + dz * dz);
329 double showLen = dist;
330 std::string unit =
"m";
331 if (showLen < 0.01) {
334 }
else if (showLen < 1) {
337 }
else if (showLen > 1000) {
342 double niceLen = showLen;
344 niceLen = round(showLen / 10) * 10;
345 else if (showLen > 1)
346 niceLen = round(showLen);
348 niceLen = round(showLen * 10) / 10.0;
350 auto mapper =
dynamic_cast<vtkPolyDataMapper2D*
>(lineActor->GetMapper());
352 auto lineSource =
dynamic_cast<vtkLineSource*
>(
353 mapper->GetInputConnection(0, 0)->GetProducer());
355 lineSource->SetPoint1(p1[0], p1[1], 0.0);
356 lineSource->SetPoint2(p2[0], p2[1], 0.0);
357 lineSource->Update();
361 if (leftTickActor && rightTickActor) {
363 dynamic_cast<vtkPolyDataMapper2D*
>(leftTickActor->GetMapper());
365 dynamic_cast<vtkPolyDataMapper2D*
>(rightTickActor->GetMapper());
367 if (leftMapper && rightMapper) {
368 auto leftSource =
dynamic_cast<vtkLineSource*
>(
369 leftMapper->GetInputConnection(0, 0)->GetProducer());
370 auto rightSource =
dynamic_cast<vtkLineSource*
>(
371 rightMapper->GetInputConnection(0, 0)->GetProducer());
373 if (leftSource && rightSource) {
374 double tickLength = 8.0 * dpiScale;
375 leftSource->SetPoint1(p1[0], p1[1], 0.0);
376 leftSource->SetPoint2(p1[0], p1[1] + tickLength, 0.0);
377 leftSource->Update();
379 rightSource->SetPoint1(p2[0], p2[1], 0.0);
380 rightSource->SetPoint2(p2[0], p2[1] + tickLength, 0.0);
381 rightSource->Update();
387 std::ostringstream oss;
389 oss << std::fixed << niceLen <<
" " << unit;
390 textActor->SetInput(oss.str().c_str());
393 textActor->GetTextProperty()->SetJustificationToCentered();
394 textActor->GetTextProperty()->SetVerticalJustificationToTop();
397 double textX = centerX;
399 double textY = bottomY - 10.0 * dpiScale;
400 textActor->SetPosition(textX, textY);