<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">2016-09-11 16:17 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="">2016-09-09 11:08 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span><wbr>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>2016-09-09 11:04 GMT+02:00 Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span><wbr>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><div><div><div>Hi all,<br><br></div>I have a hopefully simple question:<br><br></div>Since the bounds of a vtkImageData start and end in the center of the corner voxels, if I want to place two volumes in the world adjacent (right next to eachother) using SetPosition, will I have to compensate for this, to avoid the volumes overlapping by 0.5*spacing_of_first_volume + 0.5*spacing_of_second_volume ?<br></div></div></div></blockquote><div><br></div></span><div>I guess this is really two questions:<br><br></div><div>1) Is the (visual, in world) size of a volume in the first dimension (extent[1] - extent[0]) * spacing[2] or (extent[1] - extent[0] + 1) * spacing[2].<br>2) Will SetPosition move the volume such that the center of the corner voxel is at the given world position?<br></div></div></div></div></blockquote><div><br></div></span><div>Okay, I made the following small test program:<br><br>#include <iostream><br><br>#include <vtkColorTransferFunction.h><br>#include <vtkGPUVolumeRayCastMapper.h><br>#include <vtkPiecewiseFunction.h><br>#include <vtkRenderer.h><br>#include <vtkRenderWindow.h><br>#include <vtkRenderWindowInteractor.h><br>#include <vtkSmartPointer.h><br>#include <vtkVolume.h><br>#include <vtkVolumeProperty.h><br>#include <vtkXMLImageDataReader.h><br>#include <vtkCubeAxesActor.h><br>#include <vtkTextProperty.h><br><br>int main(int argc, char* argv[])<br>{<br>  if (argc != 2) {<br>    std::cerr << "Usage: " << argv[0] << "<file>" << std::endl;<br>    return 1;<br>  }<br> <br>  auto reader = vtkSmartPointer<<wbr>vtkXMLImageDataReader>::New();<br>  reader->SetFileName(argv[1]);<br>  reader->Update();<br> <br>  auto mapper = vtkSmartPointer<<wbr>vtkGPUVolumeRayCastMapper>::<wbr>New();<br>  mapper->SetInputConnection(<wbr>reader->GetOutputPort());<br> <br>  auto color = vtkSmartPointer<<wbr>vtkColorTransferFunction>::<wbr>New();<br>  color->AddRGBPoint(0.0, 0.0, 0.0, 1.0); // blue<br>  color->AddRGBPoint(1.0, 0.0, 0.0, 1.0); // blue<br><br>  auto opacity = vtkSmartPointer<<wbr>vtkPiecewiseFunction>::New();<br>  opacity->AddPoint(0.0, 0.4);<br>  opacity->AddPoint(1.0, 0.4);<br><br>  auto property = vtkSmartPointer<<wbr>vtkVolumeProperty>::New();<br>  property->SetColor(color);<br>  property->SetScalarOpacity(<wbr>opacity);<br><br>  auto volume = vtkSmartPointer<vtkVolume>::<wbr>New();<br>  volume->SetMapper(mapper);<br>  volume->SetProperty(property);<br>  volume->SetPosition(0, 0, 0);<br><br>  auto renderer = vtkSmartPointer<vtkRenderer>::<wbr>New();<br>  renderer->AddVolume(volume);<br><br>  // Cube axes actor<br>  auto cubeAxesActor = vtkSmartPointer<<wbr>vtkCubeAxesActor>::New();<br>  cubeAxesActor->SetBounds(0, 4, 0, 4, 0, 4);<br>  cubeAxesActor->SetCamera(<wbr>renderer->GetActiveCamera());<br>  cubeAxesActor-><wbr>GetTitleTextProperty(0)-><wbr>SetColor(1.0, 0.0, 0.0);<br>  cubeAxesActor-><wbr>GetLabelTextProperty(0)-><wbr>SetColor(1.0, 0.0, 0.0);<br>  cubeAxesActor-><wbr>GetTitleTextProperty(1)-><wbr>SetColor(0.0, 1.0, 0.0);<br>  cubeAxesActor-><wbr>GetLabelTextProperty(1)-><wbr>SetColor(0.0, 1.0, 0.0);<br>  cubeAxesActor-><wbr>GetTitleTextProperty(2)-><wbr>SetColor(0.0, 0.0, 1.0);<br>  cubeAxesActor-><wbr>GetLabelTextProperty(2)-><wbr>SetColor(0.0, 0.0, 1.0);<br>  cubeAxesActor-><wbr>DrawXGridlinesOn();<br>  cubeAxesActor-><wbr>DrawYGridlinesOn();<br>  cubeAxesActor-><wbr>DrawZGridlinesOn();<br>  cubeAxesActor-><wbr>SetGridLineLocation(VTK_GRID_<wbr>LINES_FURTHEST);<br>  renderer->AddActor(<wbr>cubeAxesActor);<br><br>  renderer->ResetCamera();<br><br>  auto renderWindow = vtkSmartPointer<<wbr>vtkRenderWindow>::New();<br>  renderWindow->AddRenderer(<wbr>renderer);<br> <br>  auto interactor = vtkSmartPointer<<wbr>vtkRenderWindowInteractor>::<wbr>New();<br>  interactor->SetRenderWindow(<wbr>renderWindow);<br>  interactor->Initialize();<br> <br>  interactor->Start();<br> <br>  return EXIT_SUCCESS;<br>}<br><br></div><div>And then loaded each of the following three files, containing a 2x2x2 (extent: 0 1 0 1 0 1), a 3x3x3 (extent: 0 2 0 2 0 2) and a 4x4x4 (extent: 0 3 0 3 0 3) image, all of them with spacing 1.0 1.0 1.0:<br><br><!-- 2x2x2 image --><br><VTKFile type="ImageData" version="0.1" byte_order="LittleEndian"><br>    <ImageData WholeExtent="0 1 0 1 0 1" Origin="0 0 0" Spacing="1.0 1.0 1.0"><br>        <Piece Extent="0 1 0 1 0 1"><br>            <PointData Scalars="density"><br>                <DataArray type="Float32" Name="density" format="ascii"><br>                    1.0 1.0<br>                    1.0 1.0<br>                    1.0 1.0<br>                    1.0 1.0<br>                    1.0 1.0<br>                    1.0 1.0<br>                    1.0 1.0<br>                    1.0 1.0<br>                </DataArray><br>            </PointData><br>        </Piece><br>    </ImageData><br></VTKFile><br><br><!-- 3x3x3 image --><br><VTKFile type="ImageData" version="0.1" byte_order="LittleEndian"><br>    <ImageData WholeExtent="0 2 0 2 0 2" Origin="0 0 0" Spacing="1.0 1.0 1.0"><br>        <Piece Extent="0 2 0 2 0 2"><br>            <PointData Scalars="density"><br>                <DataArray type="Float32" Name="density" format="ascii"><br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                </DataArray><br>            </PointData><br>        </Piece><br>    </ImageData><br></VTKFile><br><br><!-- 4x4x4 image --><br><VTKFile type="ImageData" version="0.1" byte_order="LittleEndian"><br>    <ImageData WholeExtent="0 3 0 3 0 3" Origin="0 0 0" Spacing="1.0 1.0 1.0"><br>        <Piece Extent="0 3 0 3 0 3"><br>            <PointData Scalars="density"><br>                <DataArray type="Float32" Name="density" format="ascii"><br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                    1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0<br>                </DataArray><br>            </PointData><br>        </Piece><br>    </ImageData><br></VTKFile><br><br></div><div>I'm attaching the result.<br><br></div><div>As you can see, the 2x2x2 volume has a visual dimension of 1x1x1, the 3x3x3 a visual dimension of 2x2x2 and the 4x4x4 a visual dimension of 3x3x3, so one less than what I would have expected.<br><br></div><div>I thought that with e.g. a 2x2x2 volume with spacing 1.0 1.0 1.0, I would get 2x2x2 area occupied when the volume is mapped into the world.<br><br></div><div>If someone could clarify what is going on here, it would be much appreciated.<br><br></div><div>I understand now that to "stack" my volumes adjacently on top of each other, I should add extent[5] * spacing[2], not (extent[5] + 1) * spacing[2] (I don't have access to the vtkVolume at that point, so can't use GetBounds), and that it's precisely this position I should give to SetPosition (no need to "compensate" for the half spacing to the voxel center).<br><br></div><div>But I'm still surprised that a volume containing 2x2x2 voxels values gives a 1x1x1 visual rendering.<span class="HOEnZb"><font color="#888888"><br></font></span></div></div></div></div></blockquote><div><br></div><div>Okay, I think I understand now: The voxel values are mapped to grid intersections in the world. So in the 2x2x2 case, the 8 scalar values are mapped to (0,0,0), (0,0,1), (0,1,0), (0,1,1), (1,0,0), (1,0,1), (1,1,0) and (1,1,1) in world coordinates, and the visual representation of that is a cube with corners in those points, colored according to scalars. When I played around with the 2x2x2 example and colored it in alternating red/blue it helped me understand. Quite interesting to see how it calculates the colors based on how you look at that little volume actually :)<br><br></div><div>Elvis<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><span class="HOEnZb"><font color="#888888"><br></font></span></div><span class="HOEnZb"><font color="#888888"><div>Elvis<br></div></font></span><span class=""><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>Elvis<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><div><br></div>Thanks in advance,<br></div>Elvis<br></div>
</blockquote></div><br></div></div>
</blockquote></span></div><br></div></div>
</blockquote></div><br></div></div>