Mercurial > hg > orthanc-stone
comparison Samples/Deprecated/Sdl/TrackerSampleApp.cpp @ 1348:eac254fb6791 broker
Moved Application/Samples/* to Application/Samples/Deprecated/* (remaining) + moved Samples/* to Samples/Deprecated/*
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Tue, 07 Apr 2020 14:31:28 +0200 |
parents | Samples/Sdl/TrackerSampleApp.cpp@8a0a62189f46 |
children |
comparison
equal
deleted
inserted
replaced
1347:bfd77672d825 | 1348:eac254fb6791 |
---|---|
1 /** | |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 #include "TrackerSampleApp.h" | |
22 | |
23 #include "../../Framework/OpenGL/SdlOpenGLContext.h" | |
24 #include "../../Framework/Scene2D/CairoCompositor.h" | |
25 #include "../../Framework/Scene2D/ColorTextureSceneLayer.h" | |
26 #include "../../Framework/Scene2D/OpenGLCompositor.h" | |
27 #include "../../Framework/Scene2D/PanSceneTracker.h" | |
28 #include "../../Framework/Scene2D/RotateSceneTracker.h" | |
29 #include "../../Framework/Scene2D/Scene2D.h" | |
30 #include "../../Framework/Scene2D/ZoomSceneTracker.h" | |
31 #include "../../Framework/Scene2DViewport/UndoStack.h" | |
32 #include "../../Framework/Scene2DViewport/CreateAngleMeasureTracker.h" | |
33 #include "../../Framework/Scene2DViewport/CreateLineMeasureTracker.h" | |
34 #include "../../Framework/StoneInitialization.h" | |
35 | |
36 // From Orthanc framework | |
37 #include <Core/Logging.h> | |
38 #include <Core/OrthancException.h> | |
39 #include <Core/Images/Image.h> | |
40 #include <Core/Images/ImageProcessing.h> | |
41 #include <Core/Images/PngWriter.h> | |
42 | |
43 #include <boost/ref.hpp> | |
44 #include <boost/make_shared.hpp> | |
45 #include <SDL.h> | |
46 | |
47 #include <stdio.h> | |
48 | |
49 namespace OrthancStone | |
50 { | |
51 const char* MeasureToolToString(size_t i) | |
52 { | |
53 static const char* descs[] = { | |
54 "GuiTool_Rotate", | |
55 "GuiTool_Pan", | |
56 "GuiTool_Zoom", | |
57 "GuiTool_LineMeasure", | |
58 "GuiTool_CircleMeasure", | |
59 "GuiTool_AngleMeasure", | |
60 "GuiTool_EllipseMeasure", | |
61 "GuiTool_LAST" | |
62 }; | |
63 if (i >= GuiTool_LAST) | |
64 { | |
65 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Wrong tool index"); | |
66 } | |
67 return descs[i]; | |
68 } | |
69 | |
70 void TrackerSampleApp::SelectNextTool() | |
71 { | |
72 currentTool_ = static_cast<GuiTool>(currentTool_ + 1); | |
73 if (currentTool_ == GuiTool_LAST) | |
74 currentTool_ = static_cast<GuiTool>(0);; | |
75 printf("Current tool is now: %s\n", MeasureToolToString(currentTool_)); | |
76 } | |
77 | |
78 void TrackerSampleApp::DisplayInfoText() | |
79 { | |
80 // do not try to use stuff too early! | |
81 std::stringstream msg; | |
82 | |
83 for (std::map<std::string, std::string>::const_iterator kv = infoTextMap_.begin(); | |
84 kv != infoTextMap_.end(); ++kv) | |
85 { | |
86 msg << kv->first << " : " << kv->second << std::endl; | |
87 } | |
88 std::string msgS = msg.str(); | |
89 | |
90 TextSceneLayer* layerP = NULL; | |
91 if (controller_->GetScene().HasLayer(FIXED_INFOTEXT_LAYER_ZINDEX)) | |
92 { | |
93 TextSceneLayer& layer = dynamic_cast<TextSceneLayer&>( | |
94 controller_->GetScene().GetLayer(FIXED_INFOTEXT_LAYER_ZINDEX)); | |
95 layerP = &layer; | |
96 } | |
97 else | |
98 { | |
99 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer); | |
100 layerP = layer.get(); | |
101 layer->SetColor(0, 255, 0); | |
102 layer->SetFontIndex(1); | |
103 layer->SetBorder(20); | |
104 layer->SetAnchor(BitmapAnchor_TopLeft); | |
105 //layer->SetPosition(0,0); | |
106 controller_->GetScene().SetLayer(FIXED_INFOTEXT_LAYER_ZINDEX, layer.release()); | |
107 } | |
108 // position the fixed info text in the upper right corner | |
109 layerP->SetText(msgS.c_str()); | |
110 double cX = GetCompositor().GetCanvasWidth() * (-0.5); | |
111 double cY = GetCompositor().GetCanvasHeight() * (-0.5); | |
112 controller_->GetScene().GetCanvasToSceneTransform().Apply(cX,cY); | |
113 layerP->SetPosition(cX, cY); | |
114 } | |
115 | |
116 void TrackerSampleApp::DisplayFloatingCtrlInfoText(const PointerEvent& e) | |
117 { | |
118 ScenePoint2D p = e.GetMainPosition().Apply(controller_->GetScene().GetCanvasToSceneTransform()); | |
119 | |
120 char buf[128]; | |
121 sprintf(buf, "S:(%0.02f,%0.02f) C:(%0.02f,%0.02f)", | |
122 p.GetX(), p.GetY(), | |
123 e.GetMainPosition().GetX(), e.GetMainPosition().GetY()); | |
124 | |
125 if (controller_->GetScene().HasLayer(FLOATING_INFOTEXT_LAYER_ZINDEX)) | |
126 { | |
127 TextSceneLayer& layer = | |
128 dynamic_cast<TextSceneLayer&>(controller_->GetScene().GetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX)); | |
129 layer.SetText(buf); | |
130 layer.SetPosition(p.GetX(), p.GetY()); | |
131 } | |
132 else | |
133 { | |
134 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer); | |
135 layer->SetColor(0, 255, 0); | |
136 layer->SetText(buf); | |
137 layer->SetBorder(20); | |
138 layer->SetAnchor(BitmapAnchor_BottomCenter); | |
139 layer->SetPosition(p.GetX(), p.GetY()); | |
140 controller_->GetScene().SetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX, layer.release()); | |
141 } | |
142 } | |
143 | |
144 void TrackerSampleApp::HideInfoText() | |
145 { | |
146 controller_->GetScene().DeleteLayer(FLOATING_INFOTEXT_LAYER_ZINDEX); | |
147 } | |
148 | |
149 ScenePoint2D TrackerSampleApp::GetRandomPointInScene() const | |
150 { | |
151 unsigned int w = GetCompositor().GetCanvasWidth(); | |
152 LOG(TRACE) << "GetCompositor().GetCanvasWidth() = " << | |
153 GetCompositor().GetCanvasWidth(); | |
154 unsigned int h = GetCompositor().GetCanvasHeight(); | |
155 LOG(TRACE) << "GetCompositor().GetCanvasHeight() = " << | |
156 GetCompositor().GetCanvasHeight(); | |
157 | |
158 if ((w >= RAND_MAX) || (h >= RAND_MAX)) | |
159 LOG(WARNING) << "Canvas is too big : tools will not be randomly placed"; | |
160 | |
161 int x = rand() % w; | |
162 int y = rand() % h; | |
163 LOG(TRACE) << "random x = " << x << "random y = " << y; | |
164 | |
165 ScenePoint2D p = controller_->GetViewport().GetPixelCenterCoordinates(x, y); | |
166 LOG(TRACE) << "--> p.GetX() = " << p.GetX() << " p.GetY() = " << p.GetY(); | |
167 | |
168 ScenePoint2D r = p.Apply(controller_->GetScene().GetCanvasToSceneTransform()); | |
169 LOG(TRACE) << "--> r.GetX() = " << r.GetX() << " r.GetY() = " << r.GetY(); | |
170 return r; | |
171 } | |
172 | |
173 void TrackerSampleApp::CreateRandomMeasureTool() | |
174 { | |
175 static bool srandCalled = false; | |
176 if (!srandCalled) | |
177 { | |
178 srand(42); | |
179 srandCalled = true; | |
180 } | |
181 | |
182 int i = rand() % 2; | |
183 LOG(TRACE) << "random i = " << i; | |
184 switch (i) | |
185 { | |
186 case 0: | |
187 // line measure | |
188 { | |
189 boost::shared_ptr<CreateLineMeasureCommand> cmd = | |
190 boost::make_shared<CreateLineMeasureCommand>( | |
191 boost::ref(IObserver::GetBroker()), | |
192 controller_, | |
193 GetRandomPointInScene()); | |
194 cmd->SetEnd(GetRandomPointInScene()); | |
195 controller_->PushCommand(cmd); | |
196 } | |
197 break; | |
198 case 1: | |
199 // angle measure | |
200 { | |
201 boost::shared_ptr<CreateAngleMeasureCommand> cmd = | |
202 boost::make_shared<CreateAngleMeasureCommand>( | |
203 boost::ref(IObserver::GetBroker()), | |
204 controller_, | |
205 GetRandomPointInScene()); | |
206 cmd->SetCenter(GetRandomPointInScene()); | |
207 cmd->SetSide2End(GetRandomPointInScene()); | |
208 controller_->PushCommand(cmd); | |
209 } | |
210 break; | |
211 } | |
212 } | |
213 | |
214 void TrackerSampleApp::HandleApplicationEvent( | |
215 const SDL_Event & event) | |
216 { | |
217 DisplayInfoText(); | |
218 | |
219 if (event.type == SDL_MOUSEMOTION) | |
220 { | |
221 int scancodeCount = 0; | |
222 const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount); | |
223 | |
224 if (activeTracker_.get() == NULL && | |
225 SDL_SCANCODE_LALT < scancodeCount && | |
226 keyboardState[SDL_SCANCODE_LALT]) | |
227 { | |
228 // The "left-ctrl" key is down, while no tracker is present | |
229 // Let's display the info text | |
230 PointerEvent e; | |
231 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates( | |
232 event.button.x, event.button.y)); | |
233 | |
234 DisplayFloatingCtrlInfoText(e); | |
235 } | |
236 else if (activeTracker_.get() != NULL) | |
237 { | |
238 HideInfoText(); | |
239 //LOG(TRACE) << "(event.type == SDL_MOUSEMOTION)"; | |
240 if (activeTracker_.get() != NULL) | |
241 { | |
242 //LOG(TRACE) << "(activeTracker_.get() != NULL)"; | |
243 PointerEvent e; | |
244 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates( | |
245 event.button.x, event.button.y)); | |
246 | |
247 //LOG(TRACE) << "event.button.x = " << event.button.x << " " << | |
248 // "event.button.y = " << event.button.y; | |
249 LOG(TRACE) << "activeTracker_->PointerMove(e); " << | |
250 e.GetMainPosition().GetX() << " " << e.GetMainPosition().GetY(); | |
251 | |
252 activeTracker_->PointerMove(e); | |
253 if (!activeTracker_->IsAlive()) | |
254 activeTracker_.reset(); | |
255 } | |
256 } | |
257 else | |
258 { | |
259 HideInfoText(); | |
260 | |
261 PointerEvent e; | |
262 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(event.button.x, event.button.y)); | |
263 | |
264 ScenePoint2D scenePos = e.GetMainPosition().Apply( | |
265 controller_->GetScene().GetCanvasToSceneTransform()); | |
266 //auto measureTools = GetController()->HitTestMeasureTools(scenePos); | |
267 //LOG(TRACE) << "# of hit tests: " << measureTools.size(); | |
268 | |
269 // this returns the collection of measuring tools where hit test is true | |
270 std::vector<boost::shared_ptr<MeasureTool> > measureTools = controller_->HitTestMeasureTools(scenePos); | |
271 | |
272 // let's refresh the measuring tools highlighted state | |
273 // first let's tag them as "unhighlighted" | |
274 controller_->ResetMeasuringToolsHighlight(); | |
275 | |
276 // then immediately take the first one and ask it to highlight the | |
277 // measuring tool UI part that is hot | |
278 if (measureTools.size() > 0) | |
279 { | |
280 measureTools[0]->Highlight(scenePos); | |
281 } | |
282 } | |
283 } | |
284 else if (event.type == SDL_MOUSEBUTTONUP) | |
285 { | |
286 if (activeTracker_) | |
287 { | |
288 PointerEvent e; | |
289 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates(event.button.x, event.button.y)); | |
290 activeTracker_->PointerUp(e); | |
291 if (!activeTracker_->IsAlive()) | |
292 activeTracker_.reset(); | |
293 } | |
294 } | |
295 else if (event.type == SDL_MOUSEBUTTONDOWN) | |
296 { | |
297 PointerEvent e; | |
298 e.AddPosition(controller_->GetViewport().GetPixelCenterCoordinates( | |
299 event.button.x, event.button.y)); | |
300 if (activeTracker_) | |
301 { | |
302 activeTracker_->PointerDown(e); | |
303 if (!activeTracker_->IsAlive()) | |
304 activeTracker_.reset(); | |
305 } | |
306 else | |
307 { | |
308 // we ATTEMPT to create a tracker if need be | |
309 activeTracker_ = CreateSuitableTracker(event, e); | |
310 } | |
311 } | |
312 else if (event.type == SDL_KEYDOWN && | |
313 event.key.repeat == 0 /* Ignore key bounce */) | |
314 { | |
315 switch (event.key.keysym.sym) | |
316 { | |
317 case SDLK_ESCAPE: | |
318 if (activeTracker_) | |
319 { | |
320 activeTracker_->Cancel(); | |
321 if (!activeTracker_->IsAlive()) | |
322 activeTracker_.reset(); | |
323 } | |
324 break; | |
325 | |
326 case SDLK_t: | |
327 if (!activeTracker_) | |
328 SelectNextTool(); | |
329 else | |
330 { | |
331 LOG(WARNING) << "You cannot change the active tool when an interaction" | |
332 " is taking place"; | |
333 } | |
334 break; | |
335 | |
336 case SDLK_m: | |
337 CreateRandomMeasureTool(); | |
338 break; | |
339 case SDLK_s: | |
340 controller_->FitContent(GetCompositor().GetCanvasWidth(), | |
341 GetCompositor().GetCanvasHeight()); | |
342 break; | |
343 | |
344 case SDLK_z: | |
345 LOG(TRACE) << "SDLK_z has been pressed. event.key.keysym.mod == " << event.key.keysym.mod; | |
346 if (event.key.keysym.mod & KMOD_CTRL) | |
347 { | |
348 if (controller_->CanUndo()) | |
349 { | |
350 LOG(TRACE) << "Undoing..."; | |
351 controller_->Undo(); | |
352 } | |
353 else | |
354 { | |
355 LOG(WARNING) << "Nothing to undo!!!"; | |
356 } | |
357 } | |
358 break; | |
359 | |
360 case SDLK_y: | |
361 LOG(TRACE) << "SDLK_y has been pressed. event.key.keysym.mod == " << event.key.keysym.mod; | |
362 if (event.key.keysym.mod & KMOD_CTRL) | |
363 { | |
364 if (controller_->CanRedo()) | |
365 { | |
366 LOG(TRACE) << "Redoing..."; | |
367 controller_->Redo(); | |
368 } | |
369 else | |
370 { | |
371 LOG(WARNING) << "Nothing to redo!!!"; | |
372 } | |
373 } | |
374 break; | |
375 | |
376 case SDLK_c: | |
377 TakeScreenshot( | |
378 "screenshot.png", | |
379 GetCompositor().GetCanvasWidth(), | |
380 GetCompositor().GetCanvasHeight()); | |
381 break; | |
382 | |
383 default: | |
384 break; | |
385 } | |
386 } | |
387 } | |
388 | |
389 | |
390 void TrackerSampleApp::OnSceneTransformChanged( | |
391 const ViewportController::SceneTransformChanged& message) | |
392 { | |
393 DisplayInfoText(); | |
394 } | |
395 | |
396 boost::shared_ptr<IFlexiblePointerTracker> TrackerSampleApp::CreateSuitableTracker( | |
397 const SDL_Event & event, | |
398 const PointerEvent & e) | |
399 { | |
400 using namespace Orthanc; | |
401 | |
402 switch (event.button.button) | |
403 { | |
404 case SDL_BUTTON_MIDDLE: | |
405 return boost::shared_ptr<IFlexiblePointerTracker>(new PanSceneTracker | |
406 (controller_, e)); | |
407 | |
408 case SDL_BUTTON_RIGHT: | |
409 return boost::shared_ptr<IFlexiblePointerTracker>(new ZoomSceneTracker | |
410 (controller_, e, GetCompositor().GetCanvasHeight())); | |
411 | |
412 case SDL_BUTTON_LEFT: | |
413 { | |
414 //LOG(TRACE) << "CreateSuitableTracker: case SDL_BUTTON_LEFT:"; | |
415 // TODO: we need to iterate on the set of measuring tool and perform | |
416 // a hit test to check if a tracker needs to be created for edition. | |
417 // Otherwise, depending upon the active tool, we might want to create | |
418 // a "measuring tool creation" tracker | |
419 | |
420 // TODO: if there are conflicts, we should prefer a tracker that | |
421 // pertains to the type of measuring tool currently selected (TBD?) | |
422 boost::shared_ptr<IFlexiblePointerTracker> hitTestTracker = TrackerHitTest(e); | |
423 | |
424 if (hitTestTracker != NULL) | |
425 { | |
426 //LOG(TRACE) << "hitTestTracker != NULL"; | |
427 return hitTestTracker; | |
428 } | |
429 else | |
430 { | |
431 switch (currentTool_) | |
432 { | |
433 case GuiTool_Rotate: | |
434 //LOG(TRACE) << "Creating RotateSceneTracker"; | |
435 return boost::shared_ptr<IFlexiblePointerTracker>(new RotateSceneTracker( | |
436 controller_, e)); | |
437 case GuiTool_Pan: | |
438 return boost::shared_ptr<IFlexiblePointerTracker>(new PanSceneTracker( | |
439 controller_, e)); | |
440 case GuiTool_Zoom: | |
441 return boost::shared_ptr<IFlexiblePointerTracker>(new ZoomSceneTracker( | |
442 controller_, e, GetCompositor().GetCanvasHeight())); | |
443 //case GuiTool_AngleMeasure: | |
444 // return new AngleMeasureTracker(GetScene(), e); | |
445 //case GuiTool_CircleMeasure: | |
446 // return new CircleMeasureTracker(GetScene(), e); | |
447 //case GuiTool_EllipseMeasure: | |
448 // return new EllipseMeasureTracker(GetScene(), e); | |
449 case GuiTool_LineMeasure: | |
450 return boost::shared_ptr<IFlexiblePointerTracker>(new CreateLineMeasureTracker( | |
451 IObserver::GetBroker(), controller_, e)); | |
452 case GuiTool_AngleMeasure: | |
453 return boost::shared_ptr<IFlexiblePointerTracker>(new CreateAngleMeasureTracker( | |
454 IObserver::GetBroker(), controller_, e)); | |
455 case GuiTool_CircleMeasure: | |
456 LOG(ERROR) << "Not implemented yet!"; | |
457 return boost::shared_ptr<IFlexiblePointerTracker>(); | |
458 case GuiTool_EllipseMeasure: | |
459 LOG(ERROR) << "Not implemented yet!"; | |
460 return boost::shared_ptr<IFlexiblePointerTracker>(); | |
461 default: | |
462 throw OrthancException(ErrorCode_InternalError, "Wrong tool!"); | |
463 } | |
464 } | |
465 } | |
466 default: | |
467 return boost::shared_ptr<IFlexiblePointerTracker>(); | |
468 } | |
469 } | |
470 | |
471 | |
472 TrackerSampleApp::TrackerSampleApp(MessageBroker& broker) : IObserver(broker) | |
473 , currentTool_(GuiTool_Rotate) | |
474 , undoStack_(new UndoStack) | |
475 , viewport_("Hello", 1024, 1024, false) // False means we do NOT let Windows treat this as a legacy application that needs to be scaled | |
476 { | |
477 controller_ = boost::shared_ptr<ViewportController>( | |
478 new ViewportController(undoStack_, broker, viewport_)); | |
479 | |
480 controller_->RegisterObserverCallback( | |
481 new Callable<TrackerSampleApp, ViewportController::SceneTransformChanged> | |
482 (*this, &TrackerSampleApp::OnSceneTransformChanged)); | |
483 | |
484 TEXTURE_2x2_1_ZINDEX = 1; | |
485 TEXTURE_1x1_ZINDEX = 2; | |
486 TEXTURE_2x2_2_ZINDEX = 3; | |
487 LINESET_1_ZINDEX = 4; | |
488 LINESET_2_ZINDEX = 5; | |
489 FLOATING_INFOTEXT_LAYER_ZINDEX = 6; | |
490 FIXED_INFOTEXT_LAYER_ZINDEX = 7; | |
491 } | |
492 | |
493 void TrackerSampleApp::PrepareScene() | |
494 { | |
495 // Texture of 2x2 size | |
496 { | |
497 Orthanc::Image i(Orthanc::PixelFormat_RGB24, 2, 2, false); | |
498 | |
499 uint8_t* p = reinterpret_cast<uint8_t*>(i.GetRow(0)); | |
500 p[0] = 255; | |
501 p[1] = 0; | |
502 p[2] = 0; | |
503 | |
504 p[3] = 0; | |
505 p[4] = 255; | |
506 p[5] = 0; | |
507 | |
508 p = reinterpret_cast<uint8_t*>(i.GetRow(1)); | |
509 p[0] = 0; | |
510 p[1] = 0; | |
511 p[2] = 255; | |
512 | |
513 p[3] = 255; | |
514 p[4] = 0; | |
515 p[5] = 0; | |
516 | |
517 controller_->GetScene().SetLayer(TEXTURE_2x2_1_ZINDEX, new ColorTextureSceneLayer(i)); | |
518 | |
519 std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i)); | |
520 l->SetOrigin(-3, 2); | |
521 l->SetPixelSpacing(1.5, 1); | |
522 l->SetAngle(20.0 / 180.0 * M_PI); | |
523 controller_->GetScene().SetLayer(TEXTURE_2x2_2_ZINDEX, l.release()); | |
524 } | |
525 | |
526 // Texture of 1x1 size | |
527 { | |
528 Orthanc::Image i(Orthanc::PixelFormat_RGB24, 1, 1, false); | |
529 | |
530 uint8_t* p = reinterpret_cast<uint8_t*>(i.GetRow(0)); | |
531 p[0] = 255; | |
532 p[1] = 0; | |
533 p[2] = 0; | |
534 | |
535 std::unique_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i)); | |
536 l->SetOrigin(-2, 1); | |
537 l->SetAngle(20.0 / 180.0 * M_PI); | |
538 controller_->GetScene().SetLayer(TEXTURE_1x1_ZINDEX, l.release()); | |
539 } | |
540 | |
541 // Some lines | |
542 { | |
543 std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer); | |
544 | |
545 layer->SetThickness(1); | |
546 | |
547 PolylineSceneLayer::Chain chain; | |
548 chain.push_back(ScenePoint2D(0 - 0.5, 0 - 0.5)); | |
549 chain.push_back(ScenePoint2D(0 - 0.5, 2 - 0.5)); | |
550 chain.push_back(ScenePoint2D(2 - 0.5, 2 - 0.5)); | |
551 chain.push_back(ScenePoint2D(2 - 0.5, 0 - 0.5)); | |
552 layer->AddChain(chain, true, 255, 0, 0); | |
553 | |
554 chain.clear(); | |
555 chain.push_back(ScenePoint2D(-5, -5)); | |
556 chain.push_back(ScenePoint2D(5, -5)); | |
557 chain.push_back(ScenePoint2D(5, 5)); | |
558 chain.push_back(ScenePoint2D(-5, 5)); | |
559 layer->AddChain(chain, true, 0, 255, 0); | |
560 | |
561 double dy = 1.01; | |
562 chain.clear(); | |
563 chain.push_back(ScenePoint2D(-4, -4)); | |
564 chain.push_back(ScenePoint2D(4, -4 + dy)); | |
565 chain.push_back(ScenePoint2D(-4, -4 + 2.0 * dy)); | |
566 chain.push_back(ScenePoint2D(4, 2)); | |
567 layer->AddChain(chain, false, 0, 0, 255); | |
568 | |
569 controller_->GetScene().SetLayer(LINESET_1_ZINDEX, layer.release()); | |
570 } | |
571 | |
572 // Some text | |
573 { | |
574 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer); | |
575 layer->SetText("Hello"); | |
576 controller_->GetScene().SetLayer(LINESET_2_ZINDEX, layer.release()); | |
577 } | |
578 } | |
579 | |
580 | |
581 void TrackerSampleApp::DisableTracker() | |
582 { | |
583 if (activeTracker_) | |
584 { | |
585 activeTracker_->Cancel(); | |
586 activeTracker_.reset(); | |
587 } | |
588 } | |
589 | |
590 void TrackerSampleApp::TakeScreenshot(const std::string& target, | |
591 unsigned int canvasWidth, | |
592 unsigned int canvasHeight) | |
593 { | |
594 CairoCompositor compositor(controller_->GetScene(), canvasWidth, canvasHeight); | |
595 compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, FONT_SIZE_0, Orthanc::Encoding_Latin1); | |
596 compositor.Refresh(); | |
597 | |
598 Orthanc::ImageAccessor canvas; | |
599 compositor.GetCanvas().GetReadOnlyAccessor(canvas); | |
600 | |
601 Orthanc::Image png(Orthanc::PixelFormat_RGB24, canvas.GetWidth(), canvas.GetHeight(), false); | |
602 Orthanc::ImageProcessing::Convert(png, canvas); | |
603 | |
604 Orthanc::PngWriter writer; | |
605 writer.WriteToFile(target, png); | |
606 } | |
607 | |
608 | |
609 boost::shared_ptr<IFlexiblePointerTracker> TrackerSampleApp::TrackerHitTest(const PointerEvent & e) | |
610 { | |
611 // std::vector<boost::shared_ptr<MeasureTool>> measureTools_; | |
612 ScenePoint2D scenePos = e.GetMainPosition().Apply( | |
613 controller_->GetScene().GetCanvasToSceneTransform()); | |
614 | |
615 std::vector<boost::shared_ptr<MeasureTool> > measureTools = controller_->HitTestMeasureTools(scenePos); | |
616 | |
617 if (measureTools.size() > 0) | |
618 { | |
619 return measureTools[0]->CreateEditionTracker(e); | |
620 } | |
621 return boost::shared_ptr<IFlexiblePointerTracker>(); | |
622 } | |
623 | |
624 static void GLAPIENTRY | |
625 OpenGLMessageCallback(GLenum source, | |
626 GLenum type, | |
627 GLuint id, | |
628 GLenum severity, | |
629 GLsizei length, | |
630 const GLchar* message, | |
631 const void* userParam) | |
632 { | |
633 if (severity != GL_DEBUG_SEVERITY_NOTIFICATION) | |
634 { | |
635 fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", | |
636 (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), | |
637 type, severity, message); | |
638 } | |
639 } | |
640 | |
641 static bool g_stopApplication = false; | |
642 | |
643 ICompositor& TrackerSampleApp::GetCompositor() | |
644 { | |
645 using namespace Orthanc; | |
646 try | |
647 { | |
648 SdlViewport& viewport = dynamic_cast<SdlViewport&>(viewport_); | |
649 return viewport.GetCompositor(); | |
650 } | |
651 catch (std::bad_cast e) | |
652 { | |
653 throw OrthancException(ErrorCode_InternalError, "Wrong viewport type!"); | |
654 } | |
655 } | |
656 | |
657 const ICompositor& TrackerSampleApp::GetCompositor() const | |
658 { | |
659 using namespace Orthanc; | |
660 try | |
661 { | |
662 SdlViewport& viewport = const_cast<SdlViewport&>(dynamic_cast<const SdlViewport&>(viewport_)); | |
663 return viewport.GetCompositor(); | |
664 } | |
665 catch (std::bad_cast e) | |
666 { | |
667 throw OrthancException(ErrorCode_InternalError, "Wrong viewport type!"); | |
668 } | |
669 } | |
670 | |
671 | |
672 void TrackerSampleApp::Run() | |
673 { | |
674 controller_->FitContent(viewport_.GetCanvasWidth(), viewport_.GetCanvasHeight()); | |
675 | |
676 glEnable(GL_DEBUG_OUTPUT); | |
677 glDebugMessageCallback(OpenGLMessageCallback, 0); | |
678 | |
679 GetCompositor().SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, | |
680 FONT_SIZE_0, Orthanc::Encoding_Latin1); | |
681 GetCompositor().SetFont(1, Orthanc::EmbeddedResources::UBUNTU_FONT, | |
682 FONT_SIZE_1, Orthanc::Encoding_Latin1); | |
683 | |
684 while (!g_stopApplication) | |
685 { | |
686 GetCompositor().Refresh(); | |
687 | |
688 SDL_Event event; | |
689 while (!g_stopApplication && SDL_PollEvent(&event)) | |
690 { | |
691 if (event.type == SDL_QUIT) | |
692 { | |
693 g_stopApplication = true; | |
694 break; | |
695 } | |
696 else if (event.type == SDL_WINDOWEVENT && | |
697 event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) | |
698 { | |
699 DisableTracker(); // was: tracker.reset(NULL); | |
700 } | |
701 else if (event.type == SDL_KEYDOWN && | |
702 event.key.repeat == 0 /* Ignore key bounce */) | |
703 { | |
704 switch (event.key.keysym.sym) | |
705 { | |
706 case SDLK_f: | |
707 viewport_.GetWindow().ToggleMaximize(); | |
708 break; | |
709 | |
710 case SDLK_q: | |
711 g_stopApplication = true; | |
712 break; | |
713 default: | |
714 break; | |
715 } | |
716 } | |
717 HandleApplicationEvent(event); | |
718 } | |
719 SDL_Delay(1); | |
720 } | |
721 } | |
722 | |
723 void TrackerSampleApp::SetInfoDisplayMessage( | |
724 std::string key, std::string value) | |
725 { | |
726 if (value == "") | |
727 infoTextMap_.erase(key); | |
728 else | |
729 infoTextMap_[key] = value; | |
730 DisplayInfoText(); | |
731 } | |
732 | |
733 } |