Skip to content

Commit 937123a

Browse files
committed
Merge branch 'seirios-camera_state'
2 parents 97fbb81 + 187732a commit 937123a

File tree

3 files changed

+232
-2
lines changed

3 files changed

+232
-2
lines changed

GUI/Qt/Components/ViewPanel3D.cxx

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#include "ViewPanel3D.h"
2+
#include "HistoryManager.h"
23
#include "LayerInspectorDialog.h"
34
#include "ui_ViewPanel3D.h"
45
#include "GlobalUIModel.h"
56
#include "Generic3DModel.h"
7+
#include "Generic3DRenderer.h"
68
#include "itkCommand.h"
79
#include "IRISException.h"
810
#include "IRISApplication.h"
@@ -71,6 +73,9 @@ ViewPanel3D::ViewPanel3D(QWidget *parent) :
7173
m_DropMenu->addAction(ui->actionSave_Viewpoint);
7274
m_DropMenu->addAction(ui->actionRestore_Viewpoint);
7375
m_DropMenu->addSeparator();
76+
m_DropMenu->addAction(ui->actionExport_Viewpoint);
77+
m_DropMenu->addAction(ui->actionImport_Viewpoint);
78+
m_DropMenu->addSeparator();
7479
m_DropMenu->addAction(ui->actionContinuous_Update);
7580
ui->actionContinuous_Update->setObjectName("actionContinuousUpdate");
7681
m_DropMenu->addSeparator();
@@ -408,6 +413,190 @@ void ViewPanel3D::on_actionRestore_Viewpoint_triggered()
408413
m_Model->RestoreCameraState();
409414
}
410415

416+
template <unsigned int VDim>
417+
vnl_vector_fixed<double, VDim>
418+
read_json_array(QJsonObject &json, const char *field)
419+
{
420+
vnl_vector_fixed<double, VDim> vec;
421+
QString error =
422+
QCoreApplication::translate("ViewPanel3D", "JSON error: %1: expected an array of %2 numbers")
423+
.arg(field)
424+
.arg(VDim);
425+
426+
if(!json[field].isArray() || json[field].toArray().count() != VDim)
427+
throw error;
428+
429+
for(unsigned int i = 0; i < VDim; ++i)
430+
{
431+
if(!json[field][i].isDouble())
432+
throw error;
433+
vec[i] = json[field][i].toDouble();
434+
}
435+
436+
return vec;
437+
}
438+
439+
double
440+
read_json_double(QJsonObject &json, const char *field)
441+
{
442+
QString error = QCoreApplication::translate("ViewPanel3D", "JSON error: %1: expected a number").arg(field);
443+
444+
if (!json[field].isDouble())
445+
throw error;
446+
447+
return json[field].toDouble();
448+
}
449+
450+
bool
451+
read_json_bool(QJsonObject &json, const char *field)
452+
{
453+
QString error = QCoreApplication::translate("ViewPanel3D", "JSON error: %1: expected a boolean").arg(field);
454+
455+
if (!json[field].isBool())
456+
throw error;
457+
458+
return json[field].isBool();
459+
}
460+
461+
462+
void ViewPanel3D::LoadCameraViewpoint(QString file)
463+
{
464+
QFile loadFile(file);
465+
if (!loadFile.open(QIODevice::ReadOnly))
466+
QMessageBox::warning(this, "Import camera viewpoint error",
467+
QString("I/O error: ") + loadFile.errorString());
468+
469+
QByteArray loadData = loadFile.readAll();
470+
QJsonParseError jsonError;
471+
QJsonDocument loadDoc(QJsonDocument::fromJson(loadData, &jsonError));
472+
473+
try
474+
{
475+
if (loadDoc.isNull())
476+
throw tr("JSON error %1").arg(jsonError.errorString());
477+
478+
QJsonObject json_main = loadDoc.object();
479+
480+
if(!json_main["file_type"].isString() || json_main["file_type"].toString() != "itksnap_camera_viewpoint")
481+
throw tr("JSON error: 'file_type' field is missing or malformed");
482+
483+
if(!json_main["version"].isString())
484+
throw tr("JSON error: 'version' field is missing");
485+
486+
if(!json_main["camera"].isObject())
487+
throw tr("JSON error: 'camera' field is missing or not an object");
488+
489+
// Read the camera properties
490+
QJsonObject json_camera = json_main["camera"].toObject();
491+
492+
// QJsonArray to Vector3d
493+
Vector3d camPosition = read_json_array<3>(json_camera, "position");
494+
Vector3d camFocalPoint = read_json_array<3>(json_camera, "focal_point");
495+
Vector3d camViewUp = read_json_array<3>(json_camera, "view_up");
496+
Vector2d camClippingRange = read_json_array<2>(json_camera, "clipping_range");
497+
double camViewAngle = read_json_double(json_camera, "view_angle");
498+
double camParallelScale = read_json_double(json_camera, "parallel_scale");
499+
int camParallelProjection = read_json_bool(json_camera, "parallel_projection");
500+
501+
CameraState cam = { .position = camPosition,
502+
.focal_point = camFocalPoint,
503+
.view_up = camViewUp,
504+
.clipping_range = camClippingRange,
505+
.view_angle = camViewAngle,
506+
.parallel_scale = camParallelScale,
507+
.parallel_projection = camParallelProjection };
508+
509+
m_Model->GetRenderer()->SetCameraState(cam);
510+
511+
m_Model->GetParentUI()->GetSystemInterface()->GetHistoryManager()->UpdateHistory(
512+
"CameraViewpoint", file.toStdString(), true);
513+
}
514+
catch (QString &error_str)
515+
{
516+
QMessageBox::warning(this, tr("Import camera viewpoint error"), error_str);
517+
}
518+
}
519+
520+
void ViewPanel3D::SaveCameraViewpoint(QString file)
521+
{
522+
CameraState cam = m_Model->GetRenderer()->GetCameraState();
523+
QJsonObject json_main;
524+
QJsonObject json_camera;
525+
526+
// Vector3d to QJsonArray
527+
QJsonArray camPosition;
528+
for (const double& x : cam.position)
529+
camPosition += x;
530+
531+
// Vector3d to QJsonArray
532+
QJsonArray camFocalPoint;
533+
for (const double& x : cam.focal_point)
534+
camFocalPoint += x;
535+
536+
// Vector3d to QJsonArray
537+
QJsonArray camViewUp;
538+
for (const double& x : cam.view_up)
539+
camViewUp += x;
540+
541+
// Vector2d to QJsonArray
542+
QJsonArray camClippingRange;
543+
for (const double& x : cam.clipping_range)
544+
camClippingRange += x;
545+
546+
// Fields from vtkCamera
547+
json_camera["position"] = camPosition;
548+
json_camera["focal_point"] = camFocalPoint;
549+
json_camera["view_up"] = camViewUp;
550+
json_camera["clipping_range"] = camClippingRange;
551+
json_camera["view_angle"] = QJsonValue(cam.view_angle);
552+
json_camera["parallel_scale"] = QJsonValue(cam.parallel_scale);
553+
json_camera["parallel_projection"] = QJsonValue(cam.parallel_projection).toBool();
554+
555+
// Main json with header and version
556+
json_main["file_type"] = QJsonValue("itksnap_camera_viewpoint");
557+
json_main["version"] = QJsonValue("1.0.0");
558+
json_main["camera"] = json_camera;
559+
560+
QFile saveFile(file);
561+
if (!saveFile.open(QIODevice::WriteOnly)
562+
|| saveFile.write(QJsonDocument(json_main).toJson()) == -1)
563+
QMessageBox::warning(this, tr("Export camera viewpoint error"),
564+
tr("I/O error: %1").arg(saveFile.errorString()));
565+
566+
m_Model->GetParentUI()->GetSystemInterface()->GetHistoryManager()->UpdateHistory(
567+
"CameraViewpoint", file.toStdString(), true);
568+
}
569+
570+
void ViewPanel3D::on_actionImport_Viewpoint_triggered()
571+
{
572+
// Ask for a filename
573+
QString selection = ShowSimpleOpenDialogWithHistory(this,
574+
m_Model->GetParentUI(),
575+
"CameraViewpoint",
576+
tr("Load Camera Viewpoint - ITK-SNAP"),
577+
tr("Camera Viewpoint JSON File"),
578+
tr("Camera Files (%1)").arg("*.json"));
579+
580+
// Open the labels from the selection
581+
if(selection.length())
582+
LoadCameraViewpoint(selection);
583+
}
584+
585+
void ViewPanel3D::on_actionExport_Viewpoint_triggered()
586+
{
587+
// Ask for a filename
588+
QString selection = ShowSimpleSaveDialogWithHistory(
589+
this, m_Model->GetParentUI(), "CameraViewpoint",
590+
tr("Save Camera Viewpoint - ITK-SNAP"),
591+
tr("Camera Viewpoint JSON File"),
592+
tr("Camera Files (%1)").arg("*.json"),
593+
true);
594+
595+
// Open the labels from the selection
596+
if(selection.length())
597+
SaveCameraViewpoint(selection);
598+
}
599+
411600
void ViewPanel3D::on_actionContinuous_Update_triggered()
412601
{
413602
ui->btnUpdateMesh->setVisible(!ui->actionContinuous_Update->isChecked());

GUI/Qt/Components/ViewPanel3D.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ private slots:
6969

7070
void on_actionRestore_Viewpoint_triggered();
7171

72+
void on_actionImport_Viewpoint_triggered();
73+
74+
void on_actionExport_Viewpoint_triggered();
75+
7276
void on_actionContinuous_Update_triggered();
7377

7478
void on_btnFlip_clicked();
@@ -115,6 +119,15 @@ private slots:
115119

116120
void UpdateMeshLayerMenu();
117121

122+
// Load camera viewpoint
123+
void LoadCameraViewpoint(QString file);
124+
125+
// Save camera viewpoint
126+
void SaveCameraViewpoint(QString file);
127+
128+
// Apply color bar visibility based on the active mesh layer type
129+
void ApplyDefaultColorBarVisibility();
130+
118131
void ProgressCallback(itk::Object *source, const itk::EventObject &event);
119132

120133
void UpdateContextButtonLocation();

GUI/Qt/Components/ViewPanel3D.ui

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,10 +379,13 @@ font-size: 11px;
379379
</action>
380380
<action name="actionSave_Viewpoint">
381381
<property name="text">
382-
<string>Save Viewpoint</string>
382+
<string>Bookmark Viewpoint</string>
383+
</property>
384+
<property name="toolTip">
385+
<string>Creates a bookmark for the current camera viewpoint</string>
383386
</property>
384387
<property name="shortcut">
385-
<string>Ctrl+K, S</string>
388+
<string>Ctrl+K, B</string>
386389
</property>
387390
<property name="shortcutContext">
388391
<enum>Qt::ShortcutContext::WindowShortcut</enum>
@@ -392,10 +395,35 @@ font-size: 11px;
392395
<property name="text">
393396
<string>Restore Viewpoint</string>
394397
</property>
398+
<property name="toolTip">
399+
<string>Restores the current camera viewpoint from the bookmark</string>
400+
</property>
395401
<property name="shortcut">
396402
<string>Ctrl+K, R</string>
397403
</property>
398404
</action>
405+
<action name="actionImport_Viewpoint">
406+
<property name="text">
407+
<string>Import Viewpoint ...</string>
408+
</property>
409+
<property name="toolTip">
410+
<string>Import camera viewpoint from a file</string>
411+
</property>
412+
<property name="shortcut">
413+
<string>Ctrl+K, I</string>
414+
</property>
415+
</action>
416+
<action name="actionExport_Viewpoint">
417+
<property name="text">
418+
<string>Export Viewpoint ...</string>
419+
</property>
420+
<property name="toolTip">
421+
<string>Export camera viewpoint to a file</string>
422+
</property>
423+
<property name="shortcut">
424+
<string>Ctrl+K, E</string>
425+
</property>
426+
</action>
399427
<action name="actionContinuous_Update">
400428
<property name="checkable">
401429
<bool>true</bool>

0 commit comments

Comments
 (0)