Skip to content

Commit

Permalink
Merge pull request #184 from allen-cell-animated/feature/flip-volume
Browse files Browse the repository at this point in the history
Feature/flip volume
  • Loading branch information
toloudis authored May 13, 2024
2 parents c04feb0 + b4cdd82 commit 549f5db
Show file tree
Hide file tree
Showing 23 changed files with 5,767 additions and 7,464 deletions.
34 changes: 34 additions & 0 deletions agave_app/AppearanceSettingsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,32 +134,50 @@ QAppearanceSettingsWidget::QAppearanceSettingsWidget(QWidget* pParent,
m_xscaleSpinner->setDecimals(6);
m_xscaleSpinner->setValue(1.0);
scaleSectionLayout->addWidget(m_xscaleSpinner, 0, 1);
m_xFlipCheckBox = new QCheckBox("Flip");
m_xFlipCheckBox->setStatusTip(tr("Invert volume in X dimension"));
m_xFlipCheckBox->setToolTip(tr("Invert volume in X dimension"));
scaleSectionLayout->addWidget(m_xFlipCheckBox, 0, 2);
QObject::connect(m_xscaleSpinner,
QOverload<double>::of(&QDoubleSpinner::valueChanged),
this,
&QAppearanceSettingsWidget::OnSetScaleX);
QObject::connect(
m_xFlipCheckBox, &QCheckBox::clicked, [this](bool flipValue) { this->OnFlipAxis(Axis::X, flipValue); });
scaleSectionLayout->addWidget(new QLabel("Y"), 1, 0);
m_yscaleSpinner = new QDoubleSpinner();
m_yscaleSpinner->setStatusTip(tr("Scale volume in Y dimension"));
m_yscaleSpinner->setToolTip(tr("Scale volume in Y dimension"));
m_yscaleSpinner->setDecimals(6);
m_yscaleSpinner->setValue(1.0);
scaleSectionLayout->addWidget(m_yscaleSpinner, 1, 1);
m_yFlipCheckBox = new QCheckBox("Flip");
m_yFlipCheckBox->setStatusTip(tr("Invert volume in Y dimension"));
m_yFlipCheckBox->setToolTip(tr("Invert volume in Y dimension"));
scaleSectionLayout->addWidget(m_yFlipCheckBox, 1, 2);
QObject::connect(m_yscaleSpinner,
QOverload<double>::of(&QDoubleSpinner::valueChanged),
this,
&QAppearanceSettingsWidget::OnSetScaleY);
QObject::connect(
m_yFlipCheckBox, &QCheckBox::clicked, [this](bool flipValue) { this->OnFlipAxis(Axis::Y, flipValue); });
scaleSectionLayout->addWidget(new QLabel("Z"), 2, 0);
m_zscaleSpinner = new QDoubleSpinner();
m_zscaleSpinner->setStatusTip(tr("Scale volume in Z dimension"));
m_zscaleSpinner->setToolTip(tr("Scale volume in Z dimension"));
m_zscaleSpinner->setDecimals(6);
m_zscaleSpinner->setValue(1.0);
scaleSectionLayout->addWidget(m_zscaleSpinner, 2, 1);
m_zFlipCheckBox = new QCheckBox("Flip");
m_zFlipCheckBox->setStatusTip(tr("Invert volume in Z dimension"));
m_zFlipCheckBox->setToolTip(tr("Invert volume in Z dimension"));
scaleSectionLayout->addWidget(m_zFlipCheckBox, 2, 2);
QObject::connect(m_zscaleSpinner,
QOverload<double>::of(&QDoubleSpinner::valueChanged),
this,
&QAppearanceSettingsWidget::OnSetScaleZ);
QObject::connect(
m_zFlipCheckBox, &QCheckBox::clicked, [this](bool flipValue) { this->OnFlipAxis(Axis::Z, flipValue); });

m_scaleSection->setContentLayout(*scaleSectionLayout);
m_MainLayout.addRow(m_scaleSection);
Expand Down Expand Up @@ -369,6 +387,18 @@ QAppearanceSettingsWidget::createSkyLightingControls()
return section;
}

void
QAppearanceSettingsWidget::OnFlipAxis(Axis axis, bool value)
{
if (!m_scene)
return;
int flipValue = value ? -1 : 1;
glm::ivec3 v = m_scene->m_volume->getVolumeAxesFlipped();
m_scene->m_volume->setVolumeAxesFlipped(
axis == Axis::X ? flipValue : v.x, axis == Axis::Y ? flipValue : v.y, axis == Axis::Z ? flipValue : v.z);
m_qrendersettings->renderSettings()->m_DirtyFlags.SetFlag(RenderParamsDirty);
}

void
QAppearanceSettingsWidget::OnSetScaleX(double value)
{
Expand Down Expand Up @@ -848,6 +878,10 @@ QAppearanceSettingsWidget::onNewImage(Scene* scene)
m_xscaleSpinner->setValue(m_scene->m_volume->physicalSizeX());
m_yscaleSpinner->setValue(m_scene->m_volume->physicalSizeY());
m_zscaleSpinner->setValue(m_scene->m_volume->physicalSizeZ());
glm::ivec3 v = m_scene->m_volume->getVolumeAxesFlipped();
m_xFlipCheckBox->setChecked(v.x < 0);
m_yFlipCheckBox->setChecked(v.y < 0);
m_zFlipCheckBox->setChecked(v.z < 0);

QColor cbbox = QColor::fromRgbF(m_scene->m_material.m_boundingBoxColor[0],
m_scene->m_material.m_boundingBoxColor[1],
Expand Down
11 changes: 11 additions & 0 deletions agave_app/AppearanceSettingsWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ class RenderSettings;
class Scene;
class Section;

enum Axis
{
X = 0,
Y = 1,
Z = 2
};

class QAppearanceSettingsWidget : public QGroupBox
{
Q_OBJECT
Expand Down Expand Up @@ -73,6 +80,7 @@ public slots:
void OnSetScaleX(double value);
void OnSetScaleY(double value);
void OnSetScaleZ(double value);
void OnFlipAxis(Axis axis, bool value);

private:
Scene* m_scene;
Expand All @@ -95,8 +103,11 @@ public slots:

Section* m_scaleSection;
QDoubleSpinner* m_xscaleSpinner;
QCheckBox* m_xFlipCheckBox;
QDoubleSpinner* m_yscaleSpinner;
QCheckBox* m_yFlipCheckBox;
QDoubleSpinner* m_zscaleSpinner;
QCheckBox* m_zFlipCheckBox;
QCheckBox m_showBoundingBoxCheckBox;
QColorPushButton m_boundingBoxColorButton;
QCheckBox m_showScaleBarCheckBox;
Expand Down
40 changes: 21 additions & 19 deletions agave_app/Serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ struct ViewerState
// [[xm, xM], [ym, yM], [zm, zM]]
std::array<std::array<float, 2>, 3> clipRegion = { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f };

std::array<float, 3> scale = { 1, 1, 1 }; // m_scaleX, m_scaleY, m_scaleZ
std::array<float, 3> scale = { 1, 1, 1 }; // m_scaleX, m_scaleY, m_scaleZ
std::array<int, 3> flipAxis = { 1, 1, 1 }; // 1 is unflipped, -1 is flipped

CameraSettings_V1 camera;

Expand All @@ -106,28 +107,29 @@ struct ViewerState
{
return datasets == other.datasets && version == other.version && pathTracer == other.pathTracer &&
timeline == other.timeline && clipRegion == other.clipRegion && scale == other.scale &&
camera == other.camera && backgroundColor == other.backgroundColor &&
flipAxis == other.flipAxis && camera == other.camera && backgroundColor == other.backgroundColor &&
boundingBoxColor == other.boundingBoxColor && showBoundingBox == other.showBoundingBox &&
showScaleBar == other.showScaleBar && channels == other.channels && density == other.density &&
lights == other.lights && capture == other.capture;
}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(ViewerState,
datasets,
version,
rendererType,
pathTracer,
timeline,
clipRegion,
scale,
camera,
backgroundColor,
boundingBoxColor,
showBoundingBox,
channels,
density,
lights,
capture,
showScaleBar)
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ViewerState,
datasets,
version,
rendererType,
pathTracer,
timeline,
clipRegion,
scale,
flipAxis,
camera,
backgroundColor,
boundingBoxColor,
showBoundingBox,
channels,
density,
lights,
capture,
showScaleBar)
};

ViewerState
Expand Down
4 changes: 4 additions & 0 deletions agave_app/ViewerState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ stateToPythonScript(const Serialize::ViewerState& s)
ss << obj << SetPrimaryRayStepSizeCommand({ s.pathTracer.primaryStepSize }).toPythonString() << std::endl;
ss << obj << SetSecondaryRayStepSizeCommand({ s.pathTracer.secondaryStepSize }).toPythonString() << std::endl;
ss << obj << SetVoxelScaleCommand({ s.scale[0], s.scale[1], s.scale[2] }).toPythonString() << std::endl;
ss << obj
<< SetFlipAxisCommand({ s.flipAxis[0] < 0 ? -1 : 1, s.flipAxis[1] < 0 ? -1 : 1, s.flipAxis[2] < 0 ? -1 : 1 })
.toPythonString()
<< std::endl;
ss << obj
<< SetClipRegionCommand({ s.clipRegion[0][0],
s.clipRegion[0][1],
Expand Down
5 changes: 5 additions & 0 deletions agave_app/agaveGui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,7 @@ agaveGui::viewerStateToApp(const Serialize::ViewerState& v)
m_currentScene = v.datasets[0].scene;

m_appScene.m_volume->setPhysicalSize(v.scale[0], v.scale[1], v.scale[2]);
m_appScene.m_volume->setVolumeAxesFlipped(v.flipAxis[0], v.flipAxis[1], v.flipAxis[2]);

m_appScene.m_material.m_backgroundColor[0] = v.backgroundColor[0];
m_appScene.m_material.m_backgroundColor[1] = v.backgroundColor[1];
Expand Down Expand Up @@ -1039,6 +1040,10 @@ agaveGui::appToViewerState()
v.scale[0] = m_appScene.m_volume->physicalSizeX();
v.scale[1] = m_appScene.m_volume->physicalSizeY();
v.scale[2] = m_appScene.m_volume->physicalSizeZ();
glm::ivec3 vflip = m_appScene.m_volume->getVolumeAxesFlipped();
v.flipAxis[0] = vflip.x > 0 ? 1 : -1;
v.flipAxis[1] = vflip.y > 0 ? 1 : -1;
v.flipAxis[2] = vflip.z > 0 ? 1 : -1;
}

v.backgroundColor = { m_appScene.m_material.m_backgroundColor[0],
Expand Down
1 change: 1 addition & 0 deletions agave_app/commandBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ commandBuffer::processBuffer()
CMD_CASE(TrackballCameraCommand);
CMD_CASE(LoadDataCommand);
CMD_CASE(ShowScaleBarCommand);
CMD_CASE(SetFlipAxisCommand);
default:
// ERROR UNRECOGNIZED COMMAND SIGNATURE.
// PRINT OUT PREVIOUS! BAIL OUT! OR DO SOMETHING CLEVER AND CORRECT!
Expand Down
16 changes: 16 additions & 0 deletions agave_pyclient/agave_pyclient/agave.py
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,22 @@ def show_scale_bar(self, on: int):
# 45
self.cb.add_command("SHOW_SCALE_BAR", on)

def set_flip_axis(self, x: int, y: int, z: int):
"""
Flip the volume data on any axis
Parameters
----------
x: int
-1 to flip, 1 to not flip
y: int
-1 to flip, 1 to not flip
z: int
-1 to flip, 1 to not flip
"""
# 46
self.cb.add_command("SET_FLIP_AXIS", x, y, z)

def batch_render_turntable(
self, number_of_frames=90, direction=1, output_name="frame", first_frame=0
):
Expand Down
1 change: 1 addition & 0 deletions agave_pyclient/agave_pyclient/commandbuffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
# path, scene, multiresolution level, t, channel indices, region
"LOAD_DATA": [44, "S", "I32", "I32", "I32", "I32A", "I32A"],
"SHOW_SCALE_BAR": [45, "I32"],
"SET_FLIP_AXIS": [46, "I32", "I32", "I32"],
}


Expand Down
19 changes: 16 additions & 3 deletions renderlib/ImageXYZC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ ImageXYZC::ImageXYZC(uint32_t x,
, m_scaleY(sy)
, m_scaleZ(sz)
, m_spatialUnits(spatialUnits)
, m_flipped(1, 1, 1)
{
for (uint32_t i = 0; i < m_c; ++i) {
m_channels.push_back(new Channelu16(x, y, z, reinterpret_cast<uint16_t*>(ptr(i))));
Expand Down Expand Up @@ -79,9 +80,21 @@ ImageXYZC::maxPixelDimension() const
void
ImageXYZC::setPhysicalSize(float x, float y, float z)
{
m_scaleX = x;
m_scaleY = y;
m_scaleZ = z;
m_scaleX = abs(x);
m_scaleY = abs(y);
m_scaleZ = abs(z);
}

void
ImageXYZC::setVolumeAxesFlipped(int x, int y, int z)
{
m_flipped = glm::ivec3(x < 0 ? -1 : 1, y < 0 ? -1 : 1, z < 0 ? -1 : 1);
}

glm::ivec3
ImageXYZC::getVolumeAxesFlipped() const
{
return m_flipped;
}

float
Expand Down
10 changes: 10 additions & 0 deletions renderlib/ImageXYZC.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,28 @@ class ImageXYZC

void setPhysicalSize(float x, float y, float z);

// +1 means do not flip, -1 means flip
void setVolumeAxesFlipped(int x, int y, int z);

uint32_t sizeX() const;
uint32_t sizeY() const;
uint32_t sizeZ() const;
uint32_t maxPixelDimension() const;

// should always return positive values
float physicalSizeX() const;
float physicalSizeY() const;
float physicalSizeZ() const;

std::string spatialUnits() const;

glm::vec3 getNormalizedDimensions() const;

glm::vec3 getPhysicalDimensions() const;

// +1 means do not flip, -1 means flip
glm::ivec3 getVolumeAxesFlipped() const;

uint32_t sizeC() const;

uint32_t sizeOfElement() const;
Expand All @@ -114,6 +123,7 @@ class ImageXYZC
uint32_t m_x, m_y, m_z, m_c, m_bpp;
uint8_t* m_data;
float m_scaleX, m_scaleY, m_scaleZ;
glm::ivec3 m_flipped;
std::string m_spatialUnits;
std::vector<Channelu16*> m_channels;
};
45 changes: 43 additions & 2 deletions renderlib/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,8 +550,7 @@ LoadVolumeFromFileCommand::execute(ExecutionContext* c)
void
SetTimeCommand::execute(ExecutionContext* c)
{
LOG_DEBUG << "SetTime command: "
<< " T=" << m_data.m_time;
LOG_DEBUG << "SetTime command: " << " T=" << m_data.m_time;

// setting same time is a no-op.
if (m_data.m_time == c->m_appScene->m_timeLine.currentTime()) {
Expand Down Expand Up @@ -733,13 +732,22 @@ ShowScaleBarCommand::execute(ExecutionContext* c)
c->m_appScene->m_showScaleBar = m_data.m_on ? true : false;
}

void
SetFlipAxisCommand::execute(ExecutionContext* c)
{
LOG_DEBUG << "SetFlipAxis " << m_data.m_x << " " << m_data.m_y << " " << m_data.m_z;
c->m_appScene->m_volume->setVolumeAxesFlipped(m_data.m_x, m_data.m_y, m_data.m_z);
c->m_renderSettings->m_DirtyFlags.SetFlag(RenderParamsDirty);
}

SessionCommand*
SessionCommand::parse(ParseableStream* c)
{
SessionCommandD data;
data.m_name = c->parseString();
return new SessionCommand(data);
}

size_t
SessionCommand::write(WriteableStream* o) const
{
Expand Down Expand Up @@ -1630,6 +1638,27 @@ ShowScaleBarCommand::write(WriteableStream* o) const
return bytesWritten;
}

SetFlipAxisCommand*
SetFlipAxisCommand::parse(ParseableStream* c)
{
SetFlipAxisCommandD data;
data.m_x = c->parseInt32();
data.m_y = c->parseInt32();
data.m_z = c->parseInt32();
return new SetFlipAxisCommand(data);
}

size_t
SetFlipAxisCommand::write(WriteableStream* o) const
{
size_t bytesWritten = 0;
bytesWritten += o->writeInt32(m_ID);
bytesWritten += o->writeInt32(m_data.m_x);
bytesWritten += o->writeInt32(m_data.m_y);
bytesWritten += o->writeInt32(m_data.m_z);
return bytesWritten;
}

std::string
SessionCommand::toPythonString() const
{
Expand Down Expand Up @@ -2082,3 +2111,15 @@ ShowScaleBarCommand::toPythonString() const
ss << ")";
return ss.str();
}

std::string
SetFlipAxisCommand::toPythonString() const
{
std::ostringstream ss;
ss << PythonName() << "(";
ss << m_data.m_x << ", ";
ss << m_data.m_y << ", ";
ss << m_data.m_z;
ss << ")";
return ss.str();
}
Loading

0 comments on commit 549f5db

Please sign in to comment.