comparison UnitTestsSources/VolumeRenderingTests.cpp @ 1780:b7c9fd1e9fb0

unit test VolumeRendering.FitTexture
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 14 May 2021 11:39:11 +0200
parents 9ab251c03eda
children bf4b15b059ea
comparison
equal deleted inserted replaced
1779:9ab251c03eda 1780:b7c9fd1e9fb0
115 else 115 else
116 { 116 {
117 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); 117 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
118 } 118 }
119 } 119 }
120 120
121 121
122 TEST(VolumeRendering, Axial) 122 static Orthanc::ImageAccessor* Render(const OrthancStone::Scene2D& scene,
123 unsigned int width,
124 unsigned int height)
125 {
126 OrthancStone::CairoCompositor compositor(width, height);
127 compositor.Refresh(scene);
128
129 Orthanc::ImageAccessor rendered;
130 compositor.GetCanvas().GetReadOnlyAccessor(rendered);
131
132 return Orthanc::Image::Clone(rendered);
133 }
134
135
136
137 // Render the scene using the identity viewpoint (default)
138 static Orthanc::ImageAccessor* Render(OrthancStone::ISceneLayer* layer,
139 unsigned int width,
140 unsigned int height)
141 {
142 OrthancStone::Scene2D scene;
143 scene.SetLayer(0, layer);
144 return Render(scene, width, height);
145 }
146
147
148 enum SlicerType
149 {
150 SlicerType_MPR = 0,
151 SlicerType_Reslicer = 1
152 };
153
154
155 static OrthancStone::TextureBaseSceneLayer* SliceVolume(boost::shared_ptr<OrthancStone::DicomVolumeImage> volume,
156 const OrthancStone::CoordinateSystem3D& volumeCoordinates,
157 const OrthancStone::CoordinateSystem3D& cuttingPlane,
158 SlicerType type)
123 { 159 {
124 Orthanc::DicomMap dicom; 160 Orthanc::DicomMap dicom;
125 dicom.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false); 161 dicom.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false);
126 dicom.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false); 162 dicom.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false);
127 dicom.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop", false); 163 dicom.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop", false);
128 164
165 volume->SetDicomParameters(OrthancStone::DicomInstanceParameters(dicom));
166
167 std::unique_ptr<OrthancStone::IVolumeSlicer> slicer;
168
169 switch (type)
170 {
171 case SlicerType_MPR:
172 slicer.reset(new OrthancStone::DicomVolumeImageMPRSlicer(volume));
173 break;
174
175 case SlicerType_Reslicer:
176 slicer.reset(new OrthancStone::DicomVolumeImageReslicer(volume));
177 break;
178
179 default:
180 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
181 }
182
183 std::unique_ptr<OrthancStone::IVolumeSlicer::IExtractedSlice> slice(slicer->ExtractSlice(cuttingPlane));
184 if (slice->IsValid())
185 {
186 OrthancStone::CopyStyleConfigurator configurator;
187 return dynamic_cast<OrthancStone::TextureBaseSceneLayer*>(slice->CreateSceneLayer(&configurator, cuttingPlane));
188 }
189 else
190 {
191 return NULL;
192 }
193 }
194
195
196 static OrthancStone::TextureBaseSceneLayer* Slice3x3x1Pattern(const OrthancStone::CoordinateSystem3D& volumeCoordinates,
197 const OrthancStone::CoordinateSystem3D& cuttingPlane,
198 SlicerType type)
199 {
200 OrthancStone::VolumeImageGeometry geometry;
201 geometry.SetSizeInVoxels(3, 3, 1);
202 geometry.SetAxialGeometry(volumeCoordinates);
203
204 boost::shared_ptr<OrthancStone::DicomVolumeImage> volume(new OrthancStone::DicomVolumeImage);
205 volume->Initialize(geometry, Orthanc::PixelFormat_Grayscale8, false);
206
207 {
208 OrthancStone::ImageBuffer3D::SliceWriter writer(volume->GetPixelData(), OrthancStone::VolumeProjection_Axial, 0);
209 Assign3x3Pattern(writer.GetAccessor());
210 }
211
212 OrthancStone::Vector v = volume->GetGeometry().GetVoxelDimensions(OrthancStone::VolumeProjection_Axial);
213 if (!OrthancStone::LinearAlgebra::IsNear(1, v[0]) ||
214 !OrthancStone::LinearAlgebra::IsNear(1, v[1]) ||
215 !OrthancStone::LinearAlgebra::IsNear(1, v[2]))
216 {
217 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
218 }
219
220 return SliceVolume(volume, volumeCoordinates, cuttingPlane, type);
221 }
222
223
224 TEST(VolumeRendering, Axial)
225 {
129 OrthancStone::CoordinateSystem3D axial(OrthancStone::LinearAlgebra::CreateVector(-0.5, -0.5, 0), 226 OrthancStone::CoordinateSystem3D axial(OrthancStone::LinearAlgebra::CreateVector(-0.5, -0.5, 0),
130 OrthancStone::LinearAlgebra::CreateVector(1, 0, 0), 227 OrthancStone::LinearAlgebra::CreateVector(1, 0, 0),
131 OrthancStone::LinearAlgebra::CreateVector(0, 1, 0)); 228 OrthancStone::LinearAlgebra::CreateVector(0, 1, 0));
132 229
133 OrthancStone::VolumeImageGeometry geometry;
134 geometry.SetSizeInVoxels(3, 3, 1);
135 geometry.SetAxialGeometry(axial);
136
137 boost::shared_ptr<OrthancStone::DicomVolumeImage> volume(new OrthancStone::DicomVolumeImage);
138 volume->Initialize(geometry, Orthanc::PixelFormat_Grayscale8, false);
139 volume->SetDicomParameters(OrthancStone::DicomInstanceParameters(dicom));
140
141 {
142 OrthancStone::ImageBuffer3D::SliceWriter writer(volume->GetPixelData(), OrthancStone::VolumeProjection_Axial, 0);
143 Assign3x3Pattern(writer.GetAccessor());
144 }
145
146 OrthancStone::Vector v = volume->GetGeometry().GetVoxelDimensions(OrthancStone::VolumeProjection_Axial);
147 ASSERT_FLOAT_EQ(1, v[0]);
148 ASSERT_FLOAT_EQ(1, v[1]);
149 ASSERT_FLOAT_EQ(1, v[2]);
150
151 OrthancStone::CoordinateSystem3D viewpoint;
152
153 for (unsigned int mode = 0; mode < 2; mode++) 230 for (unsigned int mode = 0; mode < 2; mode++)
154 { 231 {
155 std::unique_ptr<OrthancStone::IVolumeSlicer> slicer; 232 OrthancStone::CoordinateSystem3D cuttingPlane;
156 233
157 if (mode == 1) 234 std::unique_ptr<OrthancStone::TextureBaseSceneLayer> layer(Slice3x3x1Pattern(axial, cuttingPlane, static_cast<SlicerType>(mode)));
158 { 235
159 slicer.reset(new OrthancStone::DicomVolumeImageReslicer(volume)); 236 ASSERT_TRUE(layer.get() != NULL);
160 }
161 else
162 {
163 slicer.reset(new OrthancStone::DicomVolumeImageMPRSlicer(volume));
164 }
165
166 std::unique_ptr<OrthancStone::IVolumeSlicer::IExtractedSlice> slice(slicer->ExtractSlice(viewpoint));
167 ASSERT_TRUE(slice->IsValid());
168
169 OrthancStone::CopyStyleConfigurator configurator;
170 std::unique_ptr<OrthancStone::ISceneLayer> layer(slice->CreateSceneLayer(&configurator, viewpoint));
171
172 ASSERT_EQ(OrthancStone::ISceneLayer::Type_FloatTexture, layer->GetType()); 237 ASSERT_EQ(OrthancStone::ISceneLayer::Type_FloatTexture, layer->GetType());
173 238
174 OrthancStone::Extent2D box; 239 OrthancStone::Extent2D box;
175 layer->GetBoundingBox(box); 240 layer->GetBoundingBox(box);
176 ASSERT_FLOAT_EQ(-1.0f, box.GetX1()); 241 ASSERT_FLOAT_EQ(-1.0f, box.GetX1());
191 ASSERT_FLOAT_EQ(150, GetPixelValue(texture, 0, 2)); 256 ASSERT_FLOAT_EQ(150, GetPixelValue(texture, 0, 2));
192 ASSERT_FLOAT_EQ(175, GetPixelValue(texture, 1, 2)); 257 ASSERT_FLOAT_EQ(175, GetPixelValue(texture, 1, 2));
193 ASSERT_FLOAT_EQ(200, GetPixelValue(texture, 2, 2)); 258 ASSERT_FLOAT_EQ(200, GetPixelValue(texture, 2, 2));
194 } 259 }
195 260
196 OrthancStone::Scene2D scene; // Scene is initialized with the identity viewpoint 261 std::unique_ptr<Orthanc::ImageAccessor> rendered(Render(layer.release(), 5, 5));
197 scene.SetLayer(0, layer.release()); 262 ASSERT_EQ(5u, rendered->GetWidth());
198 263 ASSERT_EQ(5u, rendered->GetHeight());
199 OrthancStone::CairoCompositor compositor(5, 5); 264 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 0));
200 compositor.Refresh(scene); 265 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 0));
201 266 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 2, 0));
202 Orthanc::ImageAccessor rendered; 267 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 3, 0));
203 compositor.GetCanvas().GetReadOnlyAccessor(rendered); 268 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 4, 0));
204 269 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 1));
205 ASSERT_EQ(5u, rendered.GetWidth()); 270 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 1));
206 ASSERT_EQ(5u, rendered.GetHeight()); 271 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 2, 1));
207 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 0)); 272 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 3, 1));
208 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 0)); 273 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 4, 1));
209 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 2, 0)); 274 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 2));
210 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 3, 0)); 275 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 2));
211 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 4, 0)); 276 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 2, 2));
212 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 1)); 277 ASSERT_FLOAT_EQ(25, GetPixelValue(*rendered, 3, 2));
213 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 1)); 278 ASSERT_FLOAT_EQ(50, GetPixelValue(*rendered, 4, 2));
214 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 2, 1)); 279 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 3));
215 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 3, 1)); 280 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 3));
216 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 4, 1)); 281 ASSERT_FLOAT_EQ(75, GetPixelValue(*rendered, 2, 3));
217 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 2)); 282 ASSERT_FLOAT_EQ(100, GetPixelValue(*rendered, 3, 3));
218 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 2)); 283 ASSERT_FLOAT_EQ(125, GetPixelValue(*rendered, 4, 3));
219 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 2, 2)); 284 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 4));
220 ASSERT_FLOAT_EQ(25, GetPixelValue(rendered, 3, 2)); 285 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 4));
221 ASSERT_FLOAT_EQ(50, GetPixelValue(rendered, 4, 2)); 286 ASSERT_FLOAT_EQ(150, GetPixelValue(*rendered, 2, 4));
222 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 3)); 287 ASSERT_FLOAT_EQ(175, GetPixelValue(*rendered, 3, 4));
223 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 3)); 288 ASSERT_FLOAT_EQ(200, GetPixelValue(*rendered, 4, 4));
224 ASSERT_FLOAT_EQ(75, GetPixelValue(rendered, 2, 3)); 289 }
225 ASSERT_FLOAT_EQ(100, GetPixelValue(rendered, 3, 3)); 290 }
226 ASSERT_FLOAT_EQ(125, GetPixelValue(rendered, 4, 3));
227 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 4));
228 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 4));
229 ASSERT_FLOAT_EQ(150, GetPixelValue(rendered, 2, 4));
230 ASSERT_FLOAT_EQ(175, GetPixelValue(rendered, 3, 4));
231 ASSERT_FLOAT_EQ(200, GetPixelValue(rendered, 4, 4));
232 }
233 }
234
235 291
236 292
237 TEST(VolumeRendering, TextureCorners) 293 TEST(VolumeRendering, TextureCorners)
238 { 294 {
239 // The origin of a 2D texture is the coordinate of the BORDER of the 295 // The origin of a 2D texture is the coordinate of the BORDER of the
245 301
246 { 302 {
247 std::unique_ptr<OrthancStone::ColorTextureSceneLayer> layer(new OrthancStone::ColorTextureSceneLayer(pixel)); 303 std::unique_ptr<OrthancStone::ColorTextureSceneLayer> layer(new OrthancStone::ColorTextureSceneLayer(pixel));
248 layer->SetOrigin(0, 0); 304 layer->SetOrigin(0, 0);
249 305
306 std::unique_ptr<Orthanc::ImageAccessor> rendered(Render(layer.release(), 2, 2));
307 ASSERT_EQ(2u, rendered->GetWidth());
308 ASSERT_EQ(2u, rendered->GetHeight());
309 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 0));
310 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 0));
311 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 1));
312 ASSERT_FLOAT_EQ(255, GetPixelValue(*rendered, 1, 1));
313 }
314
315 {
316 std::unique_ptr<OrthancStone::ColorTextureSceneLayer> layer(new OrthancStone::ColorTextureSceneLayer(pixel));
317 layer->SetOrigin(-0.01, 0);
318
319 std::unique_ptr<Orthanc::ImageAccessor> rendered(Render(layer.release(), 2, 2));
320 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 0));
321 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 0));
322 ASSERT_FLOAT_EQ(255, GetPixelValue(*rendered, 0, 1));
323 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 1));
324 }
325
326 {
327 std::unique_ptr<OrthancStone::ColorTextureSceneLayer> layer(new OrthancStone::ColorTextureSceneLayer(pixel));
328 layer->SetOrigin(-0.01, -0.01);
329
330 std::unique_ptr<Orthanc::ImageAccessor> rendered(Render(layer.release(), 2, 2));
331 ASSERT_FLOAT_EQ(255, GetPixelValue(*rendered, 0, 0));
332 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 0));
333 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 1));
334 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 1));
335 }
336
337 {
338 std::unique_ptr<OrthancStone::ColorTextureSceneLayer> layer(new OrthancStone::ColorTextureSceneLayer(pixel));
339 layer->SetOrigin(0, -0.01);
340
341 std::unique_ptr<Orthanc::ImageAccessor> rendered(Render(layer.release(), 2, 2));
342 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 0));
343 ASSERT_FLOAT_EQ(255, GetPixelValue(*rendered, 1, 0));
344 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 0, 1));
345 ASSERT_FLOAT_EQ(0, GetPixelValue(*rendered, 1, 1));
346 }
347 }
348
349
350
351 TEST(VolumeRendering, FitTexture)
352 {
353 Orthanc::Image pixel(Orthanc::PixelFormat_RGB24, 1, 1, false);
354 Orthanc::ImageProcessing::Set(pixel, 255, 0, 0, 255);
355
356 {
357 std::unique_ptr<OrthancStone::ColorTextureSceneLayer> layer(new OrthancStone::ColorTextureSceneLayer(pixel));
358 layer->SetOrigin(-42.0f, 35.0f);
359 layer->SetPixelSpacing(2, 3);
360
250 OrthancStone::Scene2D scene; 361 OrthancStone::Scene2D scene;
251 scene.SetLayer(0, layer.release()); 362 scene.SetLayer(0, layer.release());
252 363 scene.FitContent(30, 30);
253 OrthancStone::CairoCompositor compositor(2, 2); 364
254 compositor.Refresh(scene); 365 std::unique_ptr<Orthanc::ImageAccessor> rendered(Render(scene, 30, 30));
255 366 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 5, 30));
256 Orthanc::ImageAccessor rendered; 367 ASSERT_TRUE(IsConstRegion(255.0f, *rendered, 5, 0, 20, 30));
257 compositor.GetCanvas().GetReadOnlyAccessor(rendered); 368 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 25, 0, 5, 30));
258 369
259 ASSERT_EQ(2u, rendered.GetWidth()); 370 rendered.reset(Render(scene, 40, 30));
260 ASSERT_EQ(2u, rendered.GetHeight()); 371 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 10, 30));
261 372 ASSERT_TRUE(IsConstRegion(255.0f, *rendered, 10, 0, 20, 30));
262 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 0)); 373 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 30, 0, 5, 30));
263 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 0)); 374
264 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 1)); 375 scene.FitContent(40, 30);
265 ASSERT_FLOAT_EQ(255, GetPixelValue(rendered, 1, 1)); 376 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 10, 30));
266 } 377 ASSERT_TRUE(IsConstRegion(255.0f, *rendered, 10, 0, 20, 30));
267 378 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 30, 0, 5, 30));
268 { 379
269 std::unique_ptr<OrthancStone::ColorTextureSceneLayer> layer(new OrthancStone::ColorTextureSceneLayer(pixel)); 380 rendered.reset(Render(scene, 30, 36)); // The scene has not been fitted
270 layer->SetOrigin(-0.01, 0); 381 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 30, 3));
382 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 3, 36));
383 ASSERT_TRUE(IsConstRegion(255.0f, *rendered, 5, 3, 20, 30));
384 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 25, 0, 5, 36));
385 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 33, 30, 3));
386
387 scene.FitContent(30, 36); // Refit
388 rendered.reset(Render(scene, 30, 36));
389 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 3, 36));
390 ASSERT_TRUE(IsConstRegion(255.0f, *rendered, 3, 0, 24, 36));
391 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 27, 0, 3, 36));
392 }
393
394 {
395 std::unique_ptr<OrthancStone::ColorTextureSceneLayer> layer(new OrthancStone::ColorTextureSceneLayer(pixel));
396 layer->SetOrigin(42.0f, -35.0f);
397 layer->SetPixelSpacing(3, 2);
271 398
272 OrthancStone::Scene2D scene; 399 OrthancStone::Scene2D scene;
273 scene.SetLayer(0, layer.release()); 400 scene.SetLayer(0, layer.release());
274 401 scene.FitContent(30, 30);
275 OrthancStone::CairoCompositor compositor(2, 2); 402
276 compositor.Refresh(scene); 403 std::unique_ptr<Orthanc::ImageAccessor> rendered(Render(scene, 30, 30));
277 404 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 30, 5));
278 Orthanc::ImageAccessor rendered; 405 ASSERT_TRUE(IsConstRegion(255.0f, *rendered, 0, 5, 30, 20));
279 compositor.GetCanvas().GetReadOnlyAccessor(rendered); 406 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 25, 30, 5));
280 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 0)); 407
281 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 0)); 408 rendered.reset(Render(scene, 30, 40));
282 ASSERT_FLOAT_EQ(255, GetPixelValue(rendered, 0, 1)); 409 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 30, 10));
283 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 1)); 410 ASSERT_TRUE(IsConstRegion(255.0f, *rendered, 0, 10, 30, 20));
284 } 411 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 30, 30, 5));
285 412
286 { 413 scene.FitContent(30, 40);
287 std::unique_ptr<OrthancStone::ColorTextureSceneLayer> layer(new OrthancStone::ColorTextureSceneLayer(pixel)); 414 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 30, 10));
288 layer->SetOrigin(-0.01, -0.01); 415 ASSERT_TRUE(IsConstRegion(255.0f, *rendered, 0, 10, 30, 20));
289 416 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 30, 30, 5));
290 OrthancStone::Scene2D scene; 417
291 scene.SetLayer(0, layer.release()); 418 rendered.reset(Render(scene, 36, 30)); // The scene has not been fitted
292 419 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 3, 30));
293 OrthancStone::CairoCompositor compositor(2, 2); 420 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 36, 3));
294 compositor.Refresh(scene); 421 ASSERT_TRUE(IsConstRegion(255.0f, *rendered, 3, 5, 30, 20));
295 422 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 25, 36, 5));
296 Orthanc::ImageAccessor rendered; 423 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 33, 0, 3, 30));
297 compositor.GetCanvas().GetReadOnlyAccessor(rendered); 424
298 ASSERT_FLOAT_EQ(255, GetPixelValue(rendered, 0, 0)); 425 scene.FitContent(36, 30); // Refit
299 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 0)); 426 rendered.reset(Render(scene, 36, 30));
300 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 1)); 427 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 0, 36, 3));
301 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 1)); 428 ASSERT_TRUE(IsConstRegion(255.0f, *rendered, 0, 3, 36, 24));
302 } 429 ASSERT_TRUE(IsConstRegion(0.0f, *rendered, 0, 27, 36, 3));
303 430 }
304 { 431 }
305 std::unique_ptr<OrthancStone::ColorTextureSceneLayer> layer(new OrthancStone::ColorTextureSceneLayer(pixel));
306 layer->SetOrigin(0, -0.01);
307
308 OrthancStone::Scene2D scene;
309 scene.SetLayer(0, layer.release());
310
311 OrthancStone::CairoCompositor compositor(2, 2);
312 compositor.Refresh(scene);
313
314 Orthanc::ImageAccessor rendered;
315 compositor.GetCanvas().GetReadOnlyAccessor(rendered);
316 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 0));
317 ASSERT_FLOAT_EQ(255, GetPixelValue(rendered, 1, 0));
318 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 0, 1));
319 ASSERT_FLOAT_EQ(0, GetPixelValue(rendered, 1, 1));
320 }
321 }