fix transforms from handler
This commit is contained in:
@@ -71,11 +71,31 @@ vtkHandlerWidget::vtkHandlerWidget() {
|
||||
this->m_TranslationEnabled = true;
|
||||
this->m_RotationEnabled = true;
|
||||
this->m_ScalingEnabled = true;
|
||||
this->m_BaseMatrix = vtkSmartPointer<::vtkMatrix4x4>::New();
|
||||
this->m_BaseMatrix->Identity();
|
||||
this->CreateGizmos();
|
||||
}
|
||||
|
||||
vtkHandlerWidget::~vtkHandlerWidget() {}
|
||||
|
||||
void vtkHandlerWidget::SetProp3D(::vtkProp3D *prop) {
|
||||
if (this->Prop3D == prop) {
|
||||
return;
|
||||
}
|
||||
this->Prop3D = prop;
|
||||
if (this->Prop3D) {
|
||||
// Initialize m_BaseMatrix from the object's current matrix
|
||||
if (this->Prop3D->GetUserMatrix()) {
|
||||
this->m_BaseMatrix->DeepCopy(this->Prop3D->GetUserMatrix());
|
||||
} else {
|
||||
this->m_BaseMatrix->Identity();
|
||||
}
|
||||
this->m_TransformChain.clear(); // Clear any previous transform chain
|
||||
this->UpdateGizmoPosition();
|
||||
}
|
||||
this->Modified();
|
||||
}
|
||||
|
||||
void vtkHandlerWidget::SetEnabled(int enabling) {
|
||||
if (enabling) {
|
||||
if (this->Enabled)
|
||||
@@ -109,6 +129,8 @@ void vtkHandlerWidget::SetEnabled(int enabling) {
|
||||
this->Priority);
|
||||
i->AddObserver(::vtkCommand::RenderEvent, this->EventCallbackCommand,
|
||||
this->Priority);
|
||||
i->AddObserver(::vtkCommand::KeyPressEvent, this->EventCallbackCommand,
|
||||
this->Priority);
|
||||
|
||||
this->UpdateGizmoPosition();
|
||||
|
||||
@@ -181,6 +203,37 @@ void vtkHandlerWidget::ProcessEvents(::vtkObject *caller, unsigned long event,
|
||||
case ::vtkCommand::RenderEvent:
|
||||
self->UpdateGizmoPosition();
|
||||
break;
|
||||
case ::vtkCommand::KeyPressEvent:
|
||||
self->OnKeyPress();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void vtkHandlerWidget::OnKeyPress() {
|
||||
std::string key = this->Interactor->GetKeySym();
|
||||
bool ctrl = (this->Interactor->GetControlKey() != 0);
|
||||
|
||||
if (ctrl && key == "z") {
|
||||
if (!this->m_TransformChain.empty()) {
|
||||
std::cout << "Undoing last transform action..." << std::endl;
|
||||
this->m_TransformChain.pop_back();
|
||||
|
||||
// Update object from chain
|
||||
vtkNew<vtkTransform> total;
|
||||
total->PostMultiply();
|
||||
total->SetMatrix(this->m_BaseMatrix.GetPointer());
|
||||
for (auto& t : m_TransformChain) {
|
||||
total->Concatenate(t);
|
||||
}
|
||||
|
||||
if (this->Prop3D && this->Prop3D->GetUserMatrix()) {
|
||||
this->Prop3D->GetUserMatrix()->DeepCopy(total->GetMatrix());
|
||||
this->Prop3D->Modified();
|
||||
this->UpdateGizmoPosition();
|
||||
this->InvokeEvent(::vtkCommand::InteractionEvent, nullptr);
|
||||
this->Interactor->Render();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +282,17 @@ void vtkHandlerWidget::OnLeftButtonDown() {
|
||||
vtkNew<vtkMatrix4x4> vmat;
|
||||
this->Prop3D->SetUserMatrix(vmat);
|
||||
}
|
||||
this->m_InitialTransform->SetMatrix(this->Prop3D->GetUserMatrix());
|
||||
|
||||
// If the chain is empty, initialize base from current state?
|
||||
// Actually, if we just started selecting this object, we should have initialized BaseMatrix.
|
||||
// For now, let's keep m_InitialTransform as the state BEFORE this drag
|
||||
vtkNew<vtkTransform> current;
|
||||
current->PostMultiply();
|
||||
current->SetMatrix(this->m_BaseMatrix.GetPointer());
|
||||
for (auto& t : m_TransformChain) {
|
||||
current->Concatenate(t);
|
||||
}
|
||||
this->m_InitialTransform->SetMatrix(current->GetMatrix());
|
||||
}
|
||||
this->EventCallbackCommand->SetAbortFlag(1);
|
||||
this->InvokeEvent(::vtkCommand::StartInteractionEvent, nullptr);
|
||||
@@ -241,6 +304,27 @@ void vtkHandlerWidget::OnLeftButtonUp() {
|
||||
if (this->Interaction == IDLE)
|
||||
return;
|
||||
|
||||
// Finalize the current interaction into the chain
|
||||
int X = this->Interactor->GetEventPosition()[0];
|
||||
int Y = this->Interactor->GetEventPosition()[1];
|
||||
|
||||
// We need to re-calculate the final 'op' to store it
|
||||
// Actually, we could have stored it in OnMouseMove, but let's re-calculate or
|
||||
// just capture the delta between m_InitialTransform and current UserMatrix.
|
||||
if (this->Prop3D && this->Prop3D->GetUserMatrix()) {
|
||||
vtkNew<vtkMatrix4x4> inv;
|
||||
vtkMatrix4x4::Invert(this->m_InitialTransform->GetMatrix(), inv);
|
||||
|
||||
vtkNew<vtkMatrix4x4> final_op_mat;
|
||||
vtkMatrix4x4::Multiply4x4(this->Prop3D->GetUserMatrix(), inv, final_op_mat);
|
||||
|
||||
vtkNew<vtkTransform> final_op;
|
||||
final_op->SetMatrix(final_op_mat);
|
||||
|
||||
this->m_TransformChain.push_back(final_op);
|
||||
std::cout << "Action finalized. Chain size: " << this->m_TransformChain.size() << std::endl;
|
||||
}
|
||||
|
||||
this->Interaction = IDLE;
|
||||
this->EventCallbackCommand->SetAbortFlag(1);
|
||||
this->InvokeEvent(::vtkCommand::EndInteractionEvent, nullptr);
|
||||
@@ -390,19 +474,46 @@ void vtkHandlerWidget::OnMouseMove() {
|
||||
}
|
||||
break;
|
||||
case SCALE_X:
|
||||
mag = get_motion_magnitude(gx, gpos);
|
||||
op->Scale(std::max(0.1, 1.0 + mag), 1.0, 1.0);
|
||||
// Note: Scale might need orient_inv/orient if we want to scale along local axes nicely
|
||||
// but the current logic for scale already handles this if we concatenated basis.
|
||||
// For now we keep it simple since user only reported rotation issue.
|
||||
break;
|
||||
case SCALE_Y:
|
||||
mag = get_motion_magnitude(gy, gpos);
|
||||
op->Scale(1.0, std::max(0.1, 1.0 + mag), 1.0);
|
||||
break;
|
||||
case SCALE_Z:
|
||||
mag = get_motion_magnitude(gz, gpos);
|
||||
op->Scale(1.0, 1.0, std::max(0.1, 1.0 + mag));
|
||||
{
|
||||
// 1. Calculate magnitude
|
||||
if (this->Interaction == SCALE_X) mag = get_motion_magnitude(gx, gpos);
|
||||
else if (this->Interaction == SCALE_Y) mag = get_motion_magnitude(gy, gpos);
|
||||
else mag = get_motion_magnitude(gz, gpos);
|
||||
|
||||
double s = std::max(0.1, 1.0 + mag);
|
||||
|
||||
// 2. Build a strictly orthonormal basis from the gizmo axes
|
||||
double X[3] = {gx[0], gx[1], gx[2]};
|
||||
double Y[3] = {gy[0], gy[1], gy[2]};
|
||||
double Z[3];
|
||||
|
||||
vtkMath::Normalize(X);
|
||||
double dot = vtkMath::Dot(X, Y);
|
||||
for(int i=0; i<3; ++i) Y[i] -= dot * X[i];
|
||||
vtkMath::Normalize(Y);
|
||||
vtkMath::Cross(X, Y, Z); // Z is now orthogonal to X and Y
|
||||
|
||||
vtkNew<vtkMatrix4x4> basis;
|
||||
basis->Identity();
|
||||
for(int i=0; i<3; ++i) {
|
||||
basis->SetElement(i, 0, X[i]);
|
||||
basis->SetElement(i, 1, Y[i]);
|
||||
basis->SetElement(i, 2, Z[i]);
|
||||
}
|
||||
|
||||
vtkNew<vtkMatrix4x4> basis_inv;
|
||||
vtkMatrix4x4::Invert(basis, basis_inv);
|
||||
|
||||
// 3. Assemble oriented scale: T(gpos) * basis * S * basis_inv * T(-gpos)
|
||||
// With PostMultiply: Result = T(gpos) * (basis * (S * (basis_inv * (T(-gpos) * Ident))))
|
||||
op->Concatenate(basis_inv);
|
||||
if (this->Interaction == SCALE_X) op->Scale(s, 1.0, 1.0);
|
||||
else if (this->Interaction == SCALE_Y) op->Scale(1.0, s, 1.0);
|
||||
else op->Scale(1.0, 1.0, s);
|
||||
op->Concatenate(basis);
|
||||
}
|
||||
break;
|
||||
case ROT_CAM: {
|
||||
double camPos[3];
|
||||
@@ -428,16 +539,15 @@ void vtkHandlerWidget::OnMouseMove() {
|
||||
|
||||
op->Translate(gpos[0], gpos[1], gpos[2]);
|
||||
|
||||
// Apply op on top of the initial object state
|
||||
vtkNew<vtkTransform> final_t;
|
||||
final_t->PostMultiply();
|
||||
final_t->SetMatrix(this->m_InitialTransform->GetMatrix());
|
||||
final_t->Concatenate(op);
|
||||
// Total transform = Base * Chain * Interaction
|
||||
vtkNew<vtkTransform> total;
|
||||
total->PostMultiply();
|
||||
total->SetMatrix(this->m_InitialTransform->GetMatrix()); // m_InitialTransform is already Base*Chain
|
||||
total->Concatenate(op);
|
||||
|
||||
vtkMatrix4x4* targetMat = this->Prop3D->GetUserMatrix();
|
||||
if (targetMat) {
|
||||
targetMat->DeepCopy(final_t->GetMatrix());
|
||||
// std::cout << "Updated UserMatrix for interaction " << this->Interaction << std::endl;
|
||||
targetMat->DeepCopy(total->GetMatrix());
|
||||
}
|
||||
|
||||
this->Prop3D->Modified();
|
||||
|
||||
Reference in New Issue
Block a user