comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 1812:db341679dc9f

ViewerViewport::StoneAnnotationsRegistry
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 25 May 2021 12:32:11 +0200
parents fdc6a8089eb9
children 53aa3f72b539
comparison
equal deleted inserted replaced
1811:fdc6a8089eb9 1812:db341679dc9f
1173 1173
1174 1174
1175 class ViewerViewport : public OrthancStone::ObserverBase<ViewerViewport> 1175 class ViewerViewport : public OrthancStone::ObserverBase<ViewerViewport>
1176 { 1176 {
1177 public: 1177 public:
1178 typedef std::map<std::string, boost::shared_ptr<Json::Value> > StoneAnnotationsRegistry;
1179
1178 class IObserver : public boost::noncopyable 1180 class IObserver : public boost::noncopyable
1179 { 1181 {
1180 public: 1182 public:
1181 virtual ~IObserver() 1183 virtual ~IObserver()
1182 { 1184 {
1578 bool hasFocusOnInstance_; 1580 bool hasFocusOnInstance_;
1579 std::string focusSopInstanceUid_; 1581 std::string focusSopInstanceUid_;
1580 size_t focusFrameNumber_; 1582 size_t focusFrameNumber_;
1581 1583
1582 // The coordinates of OsiriX annotations are expressed in 3D world coordinates 1584 // The coordinates of OsiriX annotations are expressed in 3D world coordinates
1583 boost::shared_ptr<OrthancStone::OsiriX::CollectionOfAnnotations> annotations_; 1585 boost::shared_ptr<OrthancStone::OsiriX::CollectionOfAnnotations> osiriXAnnotations_;
1584 1586
1585 // The coordinates of Stone annotations are expressed in 2D 1587 // The coordinates of Stone annotations are expressed in 2D
1586 // coordinates of the current texture, with (0,0) corresponding to 1588 // coordinates of the current texture, with (0,0) corresponding to
1587 // the center of the top-left pixel 1589 // the center of the top-left pixel
1588 boost::shared_ptr<OrthancStone::AnnotationsSceneLayer> annotationsStone_; 1590 boost::shared_ptr<OrthancStone::AnnotationsSceneLayer> stoneAnnotations_;
1591 boost::shared_ptr<StoneAnnotationsRegistry> stoneAnnotationsRegistry_;
1592
1589 1593
1590 void ScheduleNextPrefetch() 1594 void ScheduleNextPrefetch()
1591 { 1595 {
1592 while (!prefetchQueue_.empty()) 1596 while (!prefetchQueue_.empty())
1593 { 1597 {
1759 layer->SetPixelSpacing(pixelSpacingX, pixelSpacingY); 1763 layer->SetPixelSpacing(pixelSpacingX, pixelSpacingY);
1760 } 1764 }
1761 1765
1762 std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsOsiriX; 1766 std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsOsiriX;
1763 1767
1764 if (annotations_) 1768 if (osiriXAnnotations_)
1765 { 1769 {
1766 std::set<size_t> a; 1770 std::set<size_t> a;
1767 annotations_->LookupSopInstanceUid(a, instance.GetSopInstanceUid()); 1771 osiriXAnnotations_->LookupSopInstanceUid(a, instance.GetSopInstanceUid());
1768 if (plane.IsValid() && 1772 if (plane.IsValid() &&
1769 !a.empty()) 1773 !a.empty())
1770 { 1774 {
1771 annotationsOsiriX.reset(new OrthancStone::MacroSceneLayer); 1775 annotationsOsiriX.reset(new OrthancStone::MacroSceneLayer);
1772 // annotationsOsiriX->Reserve(a.size()); 1776 // annotationsOsiriX->Reserve(a.size());
1774 OrthancStone::OsiriXLayerFactory factory; 1778 OrthancStone::OsiriXLayerFactory factory;
1775 factory.SetColor(0, 255, 0); 1779 factory.SetColor(0, 255, 0);
1776 1780
1777 for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it) 1781 for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it)
1778 { 1782 {
1779 const OrthancStone::OsiriX::Annotation& annotation = annotations_->GetAnnotation(*it); 1783 const OrthancStone::OsiriX::Annotation& annotation = osiriXAnnotations_->GetAnnotation(*it);
1780 annotationsOsiriX->AddLayer(factory.Create(annotation, plane)); 1784 annotationsOsiriX->AddLayer(factory.Create(annotation, plane));
1781 } 1785 }
1786 }
1787 }
1788
1789 if (stoneAnnotationsRegistry_.get() == NULL)
1790 {
1791 stoneAnnotations_->Clear();
1792 }
1793 else
1794 {
1795 StoneAnnotationsRegistry::const_iterator found = stoneAnnotationsRegistry_->find(instance.GetSopInstanceUid());
1796 if (found == stoneAnnotationsRegistry_->end())
1797 {
1798 stoneAnnotations_->Clear();
1799 }
1800 else
1801 {
1802 stoneAnnotations_->Unserialize(*found->second);
1782 } 1803 }
1783 } 1804 }
1784 1805
1785 { 1806 {
1786 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); 1807 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock());
1803 lock->RefreshCanvasSize(); 1824 lock->RefreshCanvasSize();
1804 lock->GetCompositor().FitContent(scene); 1825 lock->GetCompositor().FitContent(scene);
1805 fitNextContent_ = false; 1826 fitNextContent_ = false;
1806 } 1827 }
1807 1828
1808 annotationsStone_->Render(scene); 1829 stoneAnnotations_->Render(scene);
1809 1830
1810 //lock->GetCompositor().Refresh(scene); 1831 //lock->GetCompositor().Refresh(scene);
1811 lock->Invalidate(); 1832 lock->Invalidate();
1812 } 1833 }
1813 } 1834 }
2008 hasFocusOnInstance_(false), 2029 hasFocusOnInstance_(false),
2009 focusFrameNumber_(0), 2030 focusFrameNumber_(0),
2010 synchronizationOffset_(OrthancStone::LinearAlgebra::CreateVector(0, 0, 0)), 2031 synchronizationOffset_(OrthancStone::LinearAlgebra::CreateVector(0, 0, 0)),
2011 synchronizationEnabled_(false), 2032 synchronizationEnabled_(false),
2012 centralPhysicalWidth_(1), 2033 centralPhysicalWidth_(1),
2013 centralPhysicalHeight_(1) 2034 centralPhysicalHeight_(1),
2035 stoneAnnotationsRegistry_(NULL)
2014 { 2036 {
2015 if (!framesCache_) 2037 if (!framesCache_)
2016 { 2038 {
2017 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); 2039 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
2018 } 2040 }
2037 2059
2038 emscripten_set_wheel_callback(viewport_->GetCanvasCssSelector().c_str(), this, true, OnWheel); 2060 emscripten_set_wheel_callback(viewport_->GetCanvasCssSelector().c_str(), this, true, OnWheel);
2039 2061
2040 SetWindowingPreset(); 2062 SetWindowingPreset();
2041 2063
2042 { 2064 stoneAnnotations_.reset(new OrthancStone::AnnotationsSceneLayer(LAYER_ANNOTATIONS_STONE));
2043 annotationsStone_.reset(new OrthancStone::AnnotationsSceneLayer(LAYER_ANNOTATIONS_STONE));
2044 annotationsStone_->AddSegmentAnnotation(OrthancStone::ScenePoint2D(0, 0),
2045 OrthancStone::ScenePoint2D(100, 100));
2046 annotationsStone_->AddAngleAnnotation(OrthancStone::ScenePoint2D(100, 50),
2047 OrthancStone::ScenePoint2D(150, 40),
2048 OrthancStone::ScenePoint2D(200, 50));
2049 annotationsStone_->AddCircleAnnotation(OrthancStone::ScenePoint2D(50, 200),
2050 OrthancStone::ScenePoint2D(100, 250));
2051 annotationsStone_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Edit);
2052 }
2053 } 2065 }
2054 2066
2055 2067
2056 void Handle(const OrthancStone::ViewportController::GrayscaleWindowingChanged& message) 2068 void Handle(const OrthancStone::ViewportController::GrayscaleWindowingChanged& message)
2057 { 2069 {
2128 { 2140 {
2129 dynamic_cast<const ICommand&>(message.GetOrigin().GetPayload()).Handle(message); 2141 dynamic_cast<const ICommand&>(message.GetOrigin().GetPayload()).Handle(message);
2130 } 2142 }
2131 2143
2132 2144
2133 void RefreshAnnotations() 2145 void RefreshAnnotations(bool save)
2134 { 2146 {
2135 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); 2147 {
2136 annotationsStone_->Render(lock->GetController().GetScene()); 2148 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock());
2137 lock->Invalidate(); 2149 stoneAnnotations_->Render(lock->GetController().GetScene());
2150 lock->Invalidate();
2151 }
2152
2153 if (save)
2154 {
2155 if (cursor_.get() != NULL &&
2156 frames_.get() != NULL)
2157 {
2158 const size_t cursorIndex = cursor_->GetCurrentIndex();
2159 const OrthancStone::DicomInstanceParameters& instance = frames_->GetInstanceOfFrame(cursorIndex);
2160
2161 boost::shared_ptr<Json::Value> v(new Json::Value);
2162 stoneAnnotations_->Serialize(*v);
2163 (*stoneAnnotationsRegistry_) [instance.GetSopInstanceUid()] = v;
2164 }
2165 }
2138 } 2166 }
2139 2167
2140 void Handle(const OrthancStone::ViewportController::SceneTransformChanged& message) 2168 void Handle(const OrthancStone::ViewportController::SceneTransformChanged& message)
2141 { 2169 {
2142 RefreshAnnotations(); 2170 RefreshAnnotations(false /* don't save */);
2143 } 2171 }
2144 2172
2145 void Handle(const OrthancStone::AnnotationsSceneLayer::AnnotationChangedMessage& message) 2173 void Handle(const OrthancStone::AnnotationsSceneLayer::AnnotationChangedMessage& message)
2146 { 2174 {
2147 RefreshAnnotations(); 2175 RefreshAnnotations(true /* save */);
2148 } 2176 }
2149 2177
2150 void Handle(const OrthancStone::AnnotationsSceneLayer::AnnotationAddedMessage& message) 2178 void Handle(const OrthancStone::AnnotationsSceneLayer::AnnotationAddedMessage& message)
2151 { 2179 {
2152 RefreshAnnotations(); 2180 RefreshAnnotations(true /* save */);
2153 LOG(WARNING) << "annotation added";
2154 } 2181 }
2155 2182
2156 void Handle(const OrthancStone::AnnotationsSceneLayer::AnnotationRemovedMessage& message) 2183 void Handle(const OrthancStone::AnnotationsSceneLayer::AnnotationRemovedMessage& message)
2157 { 2184 {
2158 RefreshAnnotations(); 2185 RefreshAnnotations(true /* save */);
2159 LOG(WARNING) << "annotation removed";
2160 } 2186 }
2161 2187
2162 public: 2188 public:
2163 virtual ~ViewerViewport() 2189 virtual ~ViewerViewport()
2164 { 2190 {
2189 2215
2190 viewport->Register<OrthancStone::ParseDicomSuccessMessage>( 2216 viewport->Register<OrthancStone::ParseDicomSuccessMessage>(
2191 lock->GetOracleObservable(), &ViewerViewport::Handle); 2217 lock->GetOracleObservable(), &ViewerViewport::Handle);
2192 2218
2193 viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationChangedMessage>( 2219 viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationChangedMessage>(
2194 *viewport->annotationsStone_, &ViewerViewport::Handle); 2220 *viewport->stoneAnnotations_, &ViewerViewport::Handle);
2195 2221
2196 viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationAddedMessage>( 2222 viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationAddedMessage>(
2197 *viewport->annotationsStone_, &ViewerViewport::Handle); 2223 *viewport->stoneAnnotations_, &ViewerViewport::Handle);
2198 2224
2199 viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationRemovedMessage>( 2225 viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationRemovedMessage>(
2200 *viewport->annotationsStone_, &ViewerViewport::Handle); 2226 *viewport->stoneAnnotations_, &ViewerViewport::Handle);
2201 } 2227 }
2202 2228
2203 { 2229 {
2204 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport->viewport_->Lock()); 2230 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport->viewport_->Lock());
2205 viewport->Register<OrthancStone::ViewportController::GrayscaleWindowingChanged>(lock->GetController(), &ViewerViewport::Handle); 2231 viewport->Register<OrthancStone::ViewportController::GrayscaleWindowingChanged>(lock->GetController(), &ViewerViewport::Handle);
2295 if (fitContent) 2321 if (fitContent)
2296 { 2322 {
2297 lock->GetCompositor().FitContent(lock->GetController().GetScene()); 2323 lock->GetCompositor().FitContent(lock->GetController().GetScene());
2298 } 2324 }
2299 2325
2300 annotationsStone_->Render(lock->GetController().GetScene()); 2326 stoneAnnotations_->ClearHover();
2327 stoneAnnotations_->Render(lock->GetController().GetScene());
2301 2328
2302 lock->Invalidate(); 2329 lock->Invalidate();
2303 } 2330 }
2304 2331
2305 void AcquireObserver(IObserver* observer) 2332 void AcquireObserver(IObserver* observer)
2637 { 2664 {
2638 { 2665 {
2639 std::unique_ptr<OrthancStone::IViewport::ILock> lock2(lock1->Lock()); 2666 std::unique_ptr<OrthancStone::IViewport::ILock> lock2(lock1->Lock());
2640 2667
2641 std::unique_ptr<OrthancStone::IFlexiblePointerTracker> t; 2668 std::unique_ptr<OrthancStone::IFlexiblePointerTracker> t;
2642 t.reset(viewer_.annotationsStone_->CreateTracker(event.GetMainPosition(), lock2->GetController().GetScene())); 2669 t.reset(viewer_.stoneAnnotations_->CreateTracker(event.GetMainPosition(), lock2->GetController().GetScene()));
2643 2670
2644 if (t.get() != NULL) 2671 if (t.get() != NULL)
2645 { 2672 {
2646 return t.release(); 2673 return t.release();
2647 } 2674 }
2660 virtual void HandleMouseHover(OrthancStone::IViewport& viewport, 2687 virtual void HandleMouseHover(OrthancStone::IViewport& viewport,
2661 const OrthancStone::PointerEvent& event) ORTHANC_OVERRIDE 2688 const OrthancStone::PointerEvent& event) ORTHANC_OVERRIDE
2662 { 2689 {
2663 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport.Lock()); 2690 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport.Lock());
2664 2691
2665 if (viewer_.annotationsStone_->SetMouseHover(event.GetMainPosition(), lock->GetController().GetScene())) 2692 if (viewer_.stoneAnnotations_->SetMouseHover(event.GetMainPosition(), lock->GetController().GetScene()))
2666 { 2693 {
2667 viewer_.annotationsStone_->Render(lock->GetController().GetScene()); 2694 viewer_.stoneAnnotations_->Render(lock->GetController().GetScene());
2668 lock->Invalidate(); 2695 lock->Invalidate();
2669 } 2696 }
2670 } 2697 }
2671 }; 2698 };
2672 2699
2682 void FitForPrint() 2709 void FitForPrint()
2683 { 2710 {
2684 viewport_->FitForPrint(); 2711 viewport_->FitForPrint();
2685 } 2712 }
2686 2713
2687 void SetAnnotations(boost::shared_ptr<OrthancStone::OsiriX::CollectionOfAnnotations> annotations) 2714 void SetOsiriXAnnotations(boost::shared_ptr<OrthancStone::OsiriX::CollectionOfAnnotations> annotations)
2688 { 2715 {
2689 annotations_ = annotations; 2716 osiriXAnnotations_ = annotations;
2690 } 2717 }
2691 2718
2692 void ScheduleFrameFocus(const std::string& sopInstanceUid, 2719 void ScheduleFrameFocus(const std::string& sopInstanceUid,
2693 unsigned int frameNumber) 2720 unsigned int frameNumber)
2694 { 2721 {
2773 void SetSynchronizedBrowsingEnabled(int enabled) 2800 void SetSynchronizedBrowsingEnabled(int enabled)
2774 { 2801 {
2775 OrthancStone::LinearAlgebra::AssignVector(synchronizationOffset_, 0, 0, 0); 2802 OrthancStone::LinearAlgebra::AssignVector(synchronizationOffset_, 0, 0, 0);
2776 synchronizationEnabled_ = enabled; 2803 synchronizationEnabled_ = enabled;
2777 } 2804 }
2805
2806
2807 void SetStoneAnnotationsRegistry(boost::shared_ptr<ViewerViewport::StoneAnnotationsRegistry>& registry)
2808 {
2809 stoneAnnotationsRegistry_ = registry;
2810 }
2778 }; 2811 };
2779 2812
2780 2813
2781 2814
2782 2815
2783 2816
2784 typedef std::map<std::string, boost::shared_ptr<ViewerViewport> > Viewports; 2817 typedef std::map<std::string, boost::shared_ptr<ViewerViewport> > Viewports;
2818
2785 static Viewports allViewports_; 2819 static Viewports allViewports_;
2786 static bool showReferenceLines_ = true; 2820 static bool showReferenceLines_ = true;
2787 static boost::shared_ptr<OrthancStone::OsiriX::CollectionOfAnnotations> annotations_; 2821 static boost::shared_ptr<OrthancStone::OsiriX::CollectionOfAnnotations> osiriXAnnotations_;
2822 static boost::shared_ptr<ViewerViewport::StoneAnnotationsRegistry> stoneAnnotationsRegistry_;
2788 2823
2789 2824
2790 static void UpdateReferenceLines() 2825 static void UpdateReferenceLines()
2791 { 2826 {
2792 if (showReferenceLines_) 2827 if (showReferenceLines_)
3045 { 3080 {
3046 boost::shared_ptr<ViewerViewport> viewport( 3081 boost::shared_ptr<ViewerViewport> viewport(
3047 ViewerViewport::Create(*context_, source_, canvas, framesCache_, softwareRendering_)); 3082 ViewerViewport::Create(*context_, source_, canvas, framesCache_, softwareRendering_));
3048 viewport->SetMouseButtonActions(leftButtonAction_, middleButtonAction_, rightButtonAction_); 3083 viewport->SetMouseButtonActions(leftButtonAction_, middleButtonAction_, rightButtonAction_);
3049 viewport->AcquireObserver(new WebAssemblyObserver); 3084 viewport->AcquireObserver(new WebAssemblyObserver);
3050 viewport->SetAnnotations(annotations_); 3085 viewport->SetOsiriXAnnotations(osiriXAnnotations_);
3086 viewport->SetStoneAnnotationsRegistry(stoneAnnotationsRegistry_);
3051 allViewports_[canvas] = viewport; 3087 allViewports_[canvas] = viewport;
3052 return viewport; 3088 return viewport;
3053 } 3089 }
3054 else 3090 else
3055 { 3091 {
3069 3105
3070 context_.reset(new OrthancStone::WebAssemblyLoadersContext(1, 4, 1)); 3106 context_.reset(new OrthancStone::WebAssemblyLoadersContext(1, 4, 1));
3071 context_->SetDicomCacheSize(128 * 1024 * 1024); // 128MB 3107 context_->SetDicomCacheSize(128 * 1024 * 1024); // 128MB
3072 3108
3073 framesCache_.reset(new FramesCache); 3109 framesCache_.reset(new FramesCache);
3074 annotations_.reset(new OrthancStone::OsiriX::CollectionOfAnnotations); 3110 osiriXAnnotations_.reset(new OrthancStone::OsiriX::CollectionOfAnnotations);
3111 stoneAnnotationsRegistry_.reset(new ViewerViewport::StoneAnnotationsRegistry);
3112
3113 {
3114 // TODO - TEST
3115 OrthancStone::AnnotationsSceneLayer l(0);
3116 l.AddSegmentAnnotation(OrthancStone::ScenePoint2D(0, 0),
3117 OrthancStone::ScenePoint2D(100, 100));
3118 l.AddAngleAnnotation(OrthancStone::ScenePoint2D(100, 50),
3119 OrthancStone::ScenePoint2D(150, 40),
3120 OrthancStone::ScenePoint2D(200, 50));
3121 l.AddCircleAnnotation(OrthancStone::ScenePoint2D(50, 200),
3122 OrthancStone::ScenePoint2D(100, 250));
3123 l.SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Edit);
3124 boost::shared_ptr<Json::Value> s(new Json::Value);
3125 l.Serialize(*s);
3126 (*stoneAnnotationsRegistry_) ["1.2.840.113543.6.6.4.7.64234348190163144631511103849051737563212"] = s;
3127 }
3128
3075 3129
3076 DISPATCH_JAVASCRIPT_EVENT("StoneInitialized"); 3130 DISPATCH_JAVASCRIPT_EVENT("StoneInitialized");
3077 } 3131 }
3078 3132
3079 3133
3529 { 3583 {
3530 try 3584 try
3531 { 3585 {
3532 if (clearPreviousAnnotations) 3586 if (clearPreviousAnnotations)
3533 { 3587 {
3534 annotations_->Clear(); 3588 osiriXAnnotations_->Clear();
3535 } 3589 }
3536 3590
3537 annotations_->LoadXml(xml); 3591 osiriXAnnotations_->LoadXml(xml);
3538 3592
3539 // Force redraw, as the annotations might have changed 3593 // Force redraw, as the annotations might have changed
3540 for (Viewports::iterator it = allViewports_.begin(); it != allViewports_.end(); ++it) 3594 for (Viewports::iterator it = allViewports_.begin(); it != allViewports_.end(); ++it)
3541 { 3595 {
3542 assert(it->second != NULL); 3596 assert(it->second != NULL);
3543 it->second->Redraw(); 3597 it->second->Redraw();
3544 } 3598 }
3545 3599
3546 if (annotations_->GetSize() == 0) 3600 if (osiriXAnnotations_->GetSize() == 0)
3547 { 3601 {
3548 stringBuffer_.clear(); 3602 stringBuffer_.clear();
3549 } 3603 }
3550 else 3604 else
3551 { 3605 {
3552 stringBuffer_ = annotations_->GetAnnotation(0).GetSeriesInstanceUid(); 3606 stringBuffer_ = osiriXAnnotations_->GetAnnotation(0).GetSeriesInstanceUid();
3553 } 3607 }
3554 3608
3555 LOG(WARNING) << "Loaded " << annotations_->GetSize() << " annotations from OsiriX"; 3609 LOG(WARNING) << "Loaded " << osiriXAnnotations_->GetSize() << " annotations from OsiriX";
3556 return 1; 3610 return 1;
3557 } 3611 }
3558 EXTERN_CATCH_EXCEPTIONS; 3612 EXTERN_CATCH_EXCEPTIONS;
3559 return 0; 3613 return 0;
3560 } 3614 }
3563 EMSCRIPTEN_KEEPALIVE 3617 EMSCRIPTEN_KEEPALIVE
3564 void FocusFirstOsiriXAnnotation(const char* canvas) 3618 void FocusFirstOsiriXAnnotation(const char* canvas)
3565 { 3619 {
3566 try 3620 try
3567 { 3621 {
3568 if (annotations_->GetSize() != 0) 3622 if (osiriXAnnotations_->GetSize() != 0)
3569 { 3623 {
3570 const OrthancStone::OsiriX::Annotation& annotation = annotations_->GetAnnotation(0); 3624 const OrthancStone::OsiriX::Annotation& annotation = osiriXAnnotations_->GetAnnotation(0);
3571 3625
3572 boost::shared_ptr<ViewerViewport> viewport = GetViewport(canvas); 3626 boost::shared_ptr<ViewerViewport> viewport = GetViewport(canvas);
3573 viewport->ScheduleFrameFocus(annotation.GetSopInstanceUid(), 0 /* focus on first frame */); 3627 viewport->ScheduleFrameFocus(annotation.GetSopInstanceUid(), 0 /* focus on first frame */);
3574 3628
3575 // Force redraw, as the annotations might already have changed 3629 // Force redraw, as the annotations might already have changed