Commit a4252322 authored by CAMP C++ Builder's avatar CAMP C++ Builder
Browse files

improved gui for MatrixProcessor

parent a4f616d0
......@@ -47,8 +47,10 @@ namespace campvis {
_matrixProcessor.s_validated.connect(this, &StreamingOIGTLDemo::onProcessorValidated);
_renderTargetID.setValue("IGTL.image.ImagerClient");
_matrixProcessor.p_matrixA.setValue("IGTL.transform.ProbeToTracker");
_matrixProcessor.p_matrixB.setValue("IGTL.transform.ReferenceToTracker");
_matrixProcessor.p_matrixAID.setValue("IGTL.transform.ProbeToTracker");
_matrixProcessor.p_matrixAType.selectByOption("data");
_matrixProcessor.p_matrixBID.setValue("IGTL.transform.ReferenceToTracker");
_matrixProcessor.p_matrixBType.selectByOption("data");
_igtlClient.p_address.setValue("127.0.0.1");
......
......@@ -35,185 +35,235 @@
namespace campvis {
const std::string MatrixProcessor::loggerCat_ = "CAMPVis.modules.core.MatrixProcessor";
MatrixProcessor::MatrixProcessor()
: AbstractProcessor()
, p_matrixA("MatrixA", "Matrix A", "matrixA")
, p_matrixB("MatrixB", "Matrix B", "matrixB")
, p_matrixAModifiers("MatrixAModifiers", "Matrix A Modifiers")
, p_matrixBModifiers("MatrixBModifiers", "Matrix B Modifiers")
, p_targetMatrixID("TargetMatrixID", "Target Matrix ID", "result.matrix", DataNameProperty::WRITE)
, lastdc_(nullptr)
GenericOption<std::string> typeOptions[2] = {
GenericOption<std::string>("fixed", "Fixed Matrix"),
GenericOption<std::string>("data", "Matrix from Data Container")
};
MatrixProcessor::MatrixProcessor()
: AbstractProcessor()
, p_matrixAType("MatrixA_Type", "Matrix A Source", typeOptions, 2)
, p_matrixAID("MatrixA_ID", "Matrix A", "matrixA", DataNameProperty::READ)
, p_matrixAString("MatrixA_String", "Matrix A String", "identity")
, p_matrixAModifiers("MatrixAModifiers", "Matrix A Modifiers")
, p_matrixBType("MatrixB_Type", "Matrix B Source", typeOptions, 2)
, p_matrixBID("MatrixB_ID", "Matrix B", "matrixB", DataNameProperty::READ)
, p_matrixBString("MatrixB_String", "Matrix B String", "identity")
, p_matrixBModifiers("MatrixBModifiers", "Matrix B Modifiers")
, p_targetMatrixID("TargetMatrixID", "Target Matrix ID", "result.matrix", DataNameProperty::WRITE)
, _lastdc(nullptr)
{
addProperty(p_matrixA, VALID);
addProperty(p_matrixAModifiers, VALID);
addProperty(p_matrixB, VALID);
addProperty(p_matrixBModifiers, VALID);
addProperty(p_targetMatrixID, VALID);
addProperty(p_matrixAType, INVALID_PROPERTIES);
addProperty(p_matrixAID, INVALID_RESULT);
addProperty(p_matrixAString, INVALID_RESULT);
addProperty(p_matrixAModifiers, INVALID_RESULT);
addProperty(p_matrixBType, INVALID_PROPERTIES);
addProperty(p_matrixBID, INVALID_RESULT);
addProperty(p_matrixBString, INVALID_RESULT);
addProperty(p_matrixBModifiers, INVALID_RESULT);
addProperty(p_targetMatrixID, INVALID_RESULT);
invalidate(INVALID_PROPERTIES);
}
MatrixProcessor::~MatrixProcessor() {
if (lastdc_)
lastdc_->s_dataAdded.disconnect(this);
MatrixProcessor::~MatrixProcessor() {
if (_lastdc)
_lastdc->s_dataAdded.disconnect(this);
}
void MatrixProcessor::init() {
void MatrixProcessor::init() {
}
void MatrixProcessor::deinit() {
void MatrixProcessor::deinit() {
}
void MatrixProcessor::updateResult(DataContainer& data) {
if (&data != lastdc_) {
if (lastdc_) {
lastdc_->s_dataAdded.disconnect(this);
}
data.s_dataAdded.connect(this, &MatrixProcessor::DataContainerDataAdded);
lastdc_ = &data;
}
void MatrixProcessor::updateResult(DataContainer& data) {
LINFO("Updating Result");
//if (&data != _lastdc) {
// if (_lastdc) {
// _lastdc->s_dataAdded.disconnect(this);
// }
tgt::mat4 matA = processMatrixString(p_matrixA.getValue(), data);
tgt::mat4 matB = processMatrixString(p_matrixB.getValue(), data);
// data.s_dataAdded.connect(this, &MatrixProcessor::DataContainerDataAdded);
// _lastdc = &data;
//}
tgt::mat4 matAProcessed = processModifierString(matA, p_matrixAModifiers.getValue());
tgt::mat4 matBProcessed = processModifierString(matB, p_matrixBModifiers.getValue());
tgt::mat4 matA = tgt::mat4::createIdentity();
if(p_matrixAType.getOptionValue() == "fixed")
matA = processMatrixString(p_matrixAString.getValue(), data);
else {
ScopedTypedData<TransformData> td(data, p_matrixAID.getValue());
if (td != 0) matA = td->getTransform();
}
tgt::mat4 matB = tgt::mat4::createIdentity();
if (p_matrixBType.getOptionValue() == "fixed")
matB = processMatrixString(p_matrixBString.getValue(), data);
else {
ScopedTypedData<TransformData> td(data, p_matrixBID.getValue());
if (td != 0) matB = td->getTransform();
}
tgt::mat4 matAProcessed = processModifierString(matA, p_matrixAModifiers.getValue());
tgt::mat4 matBProcessed = processModifierString(matB, p_matrixBModifiers.getValue());
tgt::mat4 result = matAProcessed * matBProcessed;
LDEBUG("Matrix A: " << std::endl << matA);
LDEBUG("Matrix A':" << std::endl << matAProcessed);
LDEBUG("Matrix B " << std::endl << matB);
LDEBUG("Matrix B':" << std::endl << matBProcessed);
LDEBUG("Result Matrix: " << std::endl << result);
LDEBUG(std::endl);
tgt::mat4 result = matAProcessed * matBProcessed;
TransformData * td = new TransformData(result);
LDEBUG("Matrix A: " << std::endl << matA);
LDEBUG("Matrix A':" << std::endl << matAProcessed);
LDEBUG("Matrix B: " << std::endl << matB);
LDEBUG("Matrix B':" << std::endl << matBProcessed);
LDEBUG("Result Matrix: " << std::endl << result);
LDEBUG(std::endl);
data.addData(p_targetMatrixID.getValue(), td);
TransformData * td = new TransformData(result);
data.addData(p_targetMatrixID.getValue(), td);
validate(INVALID_RESULT);
}
void MatrixProcessor::updateProperties(DataContainer& dataContainer)
{
// we invalidate just in case a hardcoded matrix or its modifiers have changed
invalidate(INVALID_RESULT);
}
tgt::mat4 MatrixProcessor::processMatrixString(std::string matrixString, DataContainer& data)
{
std::vector<std::string> tokens = StringUtils::split(matrixString, " ");
if (tokens.size() == 0 || tokens[0] == "identity") {
return tgt::mat4(tgt::mat4::identity);
}
// if we have exactly 16 tokens, we assume we have a matrix in numerical form
else if (tokens.size() == 16) {
tgt::mat4 mat;
float * p = mat.elem;
for (int i = 0; i < 16; i++) {
*p = static_cast<float>(atof(tokens[i].c_str()));
p++;
}
return mat;
}
// if the first token is "rot", we create an angle axis rotation matrix with the specified arguments
else if (tokens[0] == "rot") {
if (tokens.size() != 5) {
LWARNING("Rotation matrix string does not have the correct number of arguments!");
return tgt::mat4::createIdentity();
}
float angle;
tgt::vec3 axis;
angle = static_cast<float>(atof(tokens[1].c_str()));
axis[0] = static_cast<float>(atof(tokens[2].c_str()));
axis[1] = static_cast<float>(atof(tokens[3].c_str()));
axis[2] = static_cast<float>(atof(tokens[4].c_str()));
return tgt::mat4::createRotation(angle, axis);
}
else if (tokens[0] == "trans") {
if (tokens.size() != 4) {
LWARNING("Translation matrix string does not have the correct number of arguments!");
return tgt::mat4::createIdentity();
}
tgt::vec3 translation;
translation[0] = static_cast<float>(atof(tokens[1].c_str()));
translation[1] = static_cast<float>(atof(tokens[2].c_str()));
translation[2] = static_cast<float>(atof(tokens[3].c_str()));
return tgt::mat4::createTranslation(translation);
}
else if (tokens[0] == "scale") {
if (tokens.size() != 2 && tokens.size() != 4) {
LWARNING("Scaling matrix string does not have the correct number of arguments!");
return tgt::mat4::createIdentity();
}
tgt::vec3 scale;
scale[0] = static_cast<float>(atof(tokens[1].c_str()));
if (tokens.size() == 4) {
scale[1] = static_cast<float>(atof(tokens[2].c_str()));
scale[2] = static_cast<float>(atof(tokens[3].c_str()));
}
else {
scale[1] = scale[2] = scale[0];
}
return tgt::mat4::createScale(scale);
}
// if we cannot find another pattern, we assume we have a data container ID
else {
ScopedTypedData<TransformData> td(data, matrixString);
if (td == 0) {
LWARNING("Data Container ID \"" << matrixString << "\" was not suitable as input Matrix");
return tgt::mat4::createIdentity();
}
return td->getTransform();
}
}
tgt::mat4 MatrixProcessor::processModifierString(tgt::mat4 matrix, std::string modifiers)
{
int pos = 0;
tgt::mat4 result = matrix, tmp;
while (pos < modifiers.size())
{
switch (modifiers[pos]) {
case 'I':
if (!result.invert(tmp)) {
LWARNING("Matrix Inversion failed.");
}
else result = tmp;
break;
case 'T':
result = tgt::transpose(result);
break;
case '-':
result = tgt::mat4::zero - result;
break;
case 'r':
result = result.getRotationalPart();
break;
case 's':
result = tgt::mat4::createScale(result.getScalingPart());
break;
default:
LWARNING("Ignoring unknown modifier: " << modifiers[pos]);
}
}
return result;
}
void MatrixProcessor::DataContainerDataAdded(const std::string &name, const DataHandle &data)
{
if (name == p_matrixA.getValue() || name == p_matrixB.getValue())
invalidate(INVALID_RESULT);
}
void MatrixProcessor::updateProperties(DataContainer& dataContainer)
{
LINFO("Updating Properties");
if (p_matrixAType.getOptionValue() == "fixed") {
p_matrixAID.setVisible(false);
p_matrixAString.setVisible(true);
}
else {
p_matrixAID.setVisible(true);
p_matrixAString.setVisible(false);
}
if (p_matrixBType.getOptionValue() == "fixed") {
p_matrixBID.setVisible(false);
p_matrixBString.setVisible(true);
}
else {
p_matrixBID.setVisible(true);
p_matrixBString.setVisible(false);
}
validate(INVALID_PROPERTIES);
}
tgt::mat4 MatrixProcessor::processMatrixString(std::string matrixString, DataContainer& data)
{
std::vector<std::string> tokens = StringUtils::split(matrixString, " ");
if (tokens.size() == 0 || tokens[0] == "identity") {
return tgt::mat4(tgt::mat4::identity);
}
// if we have exactly 16 tokens, we assume we have a matrix in numerical form
else if (tokens.size() == 16) {
tgt::mat4 mat;
float * p = mat.elem;
for (int i = 0; i < 16; i++) {
*p = static_cast<float>(atof(tokens[i].c_str()));
p++;
}
return mat;
}
// if the first token is "rot", we create an angle axis rotation matrix with the specified arguments
else if (tokens[0] == "rot") {
if (tokens.size() != 5) {
LWARNING("Rotation matrix string does not have the correct number of arguments!");
return tgt::mat4::createIdentity();
}
float angle;
tgt::vec3 axis;
angle = static_cast<float>(atof(tokens[1].c_str()));
axis[0] = static_cast<float>(atof(tokens[2].c_str()));
axis[1] = static_cast<float>(atof(tokens[3].c_str()));
axis[2] = static_cast<float>(atof(tokens[4].c_str()));
return tgt::mat4::createRotation(angle, axis);
}
else if (tokens[0] == "trans") {
if (tokens.size() != 4) {
LWARNING("Translation matrix string does not have the correct number of arguments!");
return tgt::mat4::createIdentity();
}
tgt::vec3 translation;
translation[0] = static_cast<float>(atof(tokens[1].c_str()));
translation[1] = static_cast<float>(atof(tokens[2].c_str()));
translation[2] = static_cast<float>(atof(tokens[3].c_str()));
return tgt::mat4::createTranslation(translation);
}
else if (tokens[0] == "scale") {
if (tokens.size() != 2 && tokens.size() != 4) {
LWARNING("Scaling matrix string does not have the correct number of arguments!");
return tgt::mat4::createIdentity();
}
tgt::vec3 scale;
scale[0] = static_cast<float>(atof(tokens[1].c_str()));
if (tokens.size() == 4) {
scale[1] = static_cast<float>(atof(tokens[2].c_str()));
scale[2] = static_cast<float>(atof(tokens[3].c_str()));
}
else {
scale[1] = scale[2] = scale[0];
}
return tgt::mat4::createScale(scale);
}
// if we cannot find another pattern, we assume we have a data container ID
else {
ScopedTypedData<TransformData> td(data, matrixString);
if (td == 0) {
LWARNING("Data Container ID \"" << matrixString << "\" was not suitable as input Matrix");
return tgt::mat4::createIdentity();
}
return td->getTransform();
}
}
tgt::mat4 MatrixProcessor::processModifierString(tgt::mat4 matrix, std::string modifiers)
{
int pos = 0;
tgt::mat4 result = matrix, tmp;
while (pos < modifiers.size())
{
switch (modifiers[pos]) {
case 'I':
if (!result.invert(tmp)) {
LWARNING("Matrix Inversion failed.");
}
else result = tmp;
break;
case 'T':
result = tgt::transpose(result);
break;
case '-':
result = tgt::mat4::zero - result;
break;
case 'r':
result = result.getRotationalPart();
break;
case 's':
result = tgt::mat4::createScale(result.getScalingPart());
break;
default:
LWARNING("Ignoring unknown modifier: " << modifiers[pos]);
}
}
return result;
}
void MatrixProcessor::DataContainerDataAdded(const std::string &name, const DataHandle &data)
{
if (name == p_matrixAID.getValue() || name == p_matrixBID.getValue())
invalidate(INVALID_RESULT);
}
}
\ No newline at end of file
......@@ -31,10 +31,7 @@
#include <tgt/matrix.h>
#include "core/pipeline/abstractprocessor.h"
#include "core/properties/buttonproperty.h"
#include "core/properties/datanameproperty.h"
#include "core/properties/floatingpointproperty.h"
#include "core/properties/stringproperty.h"
#include "core/properties/allproperties.h"
namespace campvis {
/**
......@@ -51,6 +48,11 @@ namespace campvis {
*/
class MatrixProcessor : public AbstractProcessor {
public:
enum SourceType {
FIXED = 0,
DATA = 1
};
/// Constructor
MatrixProcessor();
......@@ -71,12 +73,17 @@ namespace campvis {
/// \see AbstractProcessor::getProcessorState()
virtual ProcessorState getProcessorState() const { return AbstractProcessor::EXPERIMENTAL; };
StringProperty p_matrixA; ///< first Matrix input for the computation. \see MatrixProcessor::processMatrixString()
StringProperty p_matrixB; ///< second Matrix input for the computation. \see MatrixProcessor::processMatrixString()
GenericOptionProperty<std::string> p_matrixAType;
DataNameProperty p_matrixAID; ///< first Matrix input for the computation. \see MatrixProcessor::processMatrixString()
StringProperty p_matrixAString;
StringProperty p_matrixAModifiers; ///< modifier string to be applied to matrix A. \see MatrixProcessor::processModifierString()
GenericOptionProperty<std::string> p_matrixBType;
DataNameProperty p_matrixBID; ///< first Matrix input for the computation. \see MatrixProcessor::processMatrixString()
StringProperty p_matrixBString;
StringProperty p_matrixBModifiers; ///< modifier string to be applied to matrix A. \see MatrixProcessor::processModifierString()
StringProperty p_matrixAModifiers; ///< modifier string to be applied to matrix A. \see MatrixProcessor::processModifierString()
StringProperty p_matrixBModifiers; ///< modifier string to be applied to matrix B. \see MatrixProcessor::processModifierString()
DataNameProperty p_targetMatrixID; ///< image ID for read image
......@@ -129,7 +136,7 @@ namespace campvis {
*/
tgt::mat4 processMatrixString(std::string matrixString, DataContainer& data);
DataContainer * lastdc_;
DataContainer * _lastdc;
static const std::string loggerCat_;
};
......
......@@ -39,7 +39,7 @@ namespace campvis {
OpenIGTLinkClient::OpenIGTLinkClient()
: AbstractProcessor()
, p_address("ServerAddress", "Server Address", "127.0.0.1", StringProperty::BASIC_STRING)
, p_address("ServerAddress", "Server Address", "127.0.0.1")
, p_port("ServerPort", "Server Port", 18944, 1, 65535, 1)
, p_deviceName("ServerDeviceName", "Device Name (empty to accept all)")
, p_connect("Connect", "Connect to Server")
......
......@@ -52,6 +52,7 @@ void main() {
}
}
else {
discard;
out_Color = vec4(1, 0, 0, 1);
//discard;
}
}
......@@ -39,6 +39,8 @@ namespace campvis {
, _imageReader()
, _mprRenderer(&_canvasSize)
, _compositor(&_canvasSize)
, _trackerPose()
, _igtlClient()
, _trackballEH(0)
{
addProperty(_camera);
......@@ -47,9 +49,12 @@ namespace campvis {
addEventListenerToBack(_trackballEH);
addProcessor(&_lsp);
addProcessor(&_igtlClient);
addProcessor(&_imageReader);
addProcessor(&_trackerPose);
addProcessor(&_mprRenderer);
addProcessor(&_compositor);
}
MprDemo::~MprDemo() {
......@@ -60,6 +65,8 @@ namespace campvis {
AutoEvaluationPipeline::init();
_imageReader.s_validated.connect(this, &MprDemo::onProcessorValidated);
_trackerPose.s_validated.connect(this, &MprDemo::onProcessorValidated);
_igtlClient.s_validated.connect(this, &MprDemo::onProcessorValidated);
_camera.addSharedProperty(&_mprRenderer.p_camera);
_mprRenderer.p_targetImageID.setValue("MPR");
......@@ -77,6 +84,14 @@ namespace campvis {
Geometry1DTransferFunction* tf = new Geometry1DTransferFunction(128, tgt::vec2(0.f, .08f));
tf->addGeometry(TFGeometry1D::createQuad(tgt::vec2(0.f, 1.f), tgt::col4(0, 0, 0, 255), tgt::col4(255, 255, 255, 255)));
_mprRenderer.p_transferFunction.replaceTF(tf);
_trackerPose.p_matrixAID.setValue("IGTL.transform.ProbeToTracker");
_trackerPose.p_matrixAType.selectByOption("data");
_trackerPose.p_matrixBID.setValue("IGTL.transform.ReferenceToTracker");
_trackerPose.p_matrixBType.selectByOption("data");
_trackerPose.p_matrixBModifiers.setValue("I");
_trackerPose.p_targetMatrixID.setValue("ProbeToReference");
_trackerPose.p_targetMatrixID.addSharedProperty(&_mprRenderer.p_transformationID);
}
void MprDemo::deinit() {
......
......@@ -33,6 +33,9 @@
#include "modules/vis/processors/mprrenderer.h"
#include "modules/vis/processors/rendertargetcompositor.h"
#include "modules/openigtlink/processors/openigtlinkclient.h"
#include "modules/openigtlink/processors/matrixprocessor.h"
namespace campvis {
class MprDemo : public AutoEvaluationPipeline {
public:
......@@ -72,6 +75,9 @@ namespace campvis {
MprRenderer _mprRenderer;
RenderTargetCompositor _compositor;
MatrixProcessor _trackerPose;
OpenIGTLinkClient _igtlClient;
TrackballNavigationEventListener* _trackballEH;
};
......
......@@ -40,6 +40,8 @@
#include "core/tools/quadrenderer.h"
#include "modules\openigtlink\datastructures\transformdata.h"
namespace campvis {
const std::string MprRenderer::loggerCat_ = "CAMPVis.modules.vis.MprRenderer";
......@@ -48,6 +50,7 @@ namespace campvis {
, p_sourceImageID("sourceImageID", "Input Image", "", DataNameProperty::READ)
, p_targetImageID("targetImageID", "Output Image", "", DataNameProperty::WRITE)
, p_camera("Camera", "Camera")
, p_transformationID("transformationID", "Input Transformation", "", DataNameProperty::READ)
, p_planeNormal("PlaneNormal", "Clipping Plane Normal", tgt::vec3(0.f, 0.f, 1.f), tgt::vec3(-1.f), tgt::vec3(1.f), tgt::vec3(.1f), tgt::ivec3(2))
, p_planeDistance("PlaneDistance", "Clipping Plane Distance", 0.f, -1000.f, 1000.f, 1.f, 1)
, p_planeSize("PlaneSize", "Clipping Plane Size", 100.f, 0.f, 1000.f, 1.f, 1)
......@@ -59,6 +62,7 @@ namespace campvis {
addProperty(p_sourceImageID, INVALID_RESULT | INVALID_PROPERTIES);
addProperty(p_targetImageID);
addProperty(p_camera);
addProperty(p_transformationID);
addProperty(p_planeNormal);
addProperty(p_planeDistance);
addProperty(p_planeSize);
......@@ -96,20 +100,41 @@ namespace campvis {
if (abs(tgt::dot(temp, n) > 0.9))
temp = tgt::vec3(0.0, 1.0, 0.0);
tgt::vec3 inPlaneA = tgt::normalize(tgt::cross(n, temp)) * 0.5f * p_planeSize.getValue();
tgt::vec3 inPlaneB = tgt::normalize(tgt::cross(n, inPlaneA)) * 0.5f * p_planeSize.getValue();
tgt::vec3 base = (n * -p_planeDistance.getValue());
// move to image center if wanted
if (p_relativeToImageCenter.getValue())
base += img->getParent()->getWorldBounds().center();
tgt::vec3 inPlaneA;
tgt::vec3 inPlaneB;
tgt::vec3 base;
<