/*========================================================================= Program: ParaView Module: vtkSMCameraLink.cxx Copyright (c) Kitware, Inc. All rights reserved. See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkSMCameraLink.h" #include "vtkCallbackCommand.h" #include "vtkObjectFactory.h" #include "vtkPVXMLElement.h" #include "vtkRenderWindowInteractor.h" #include "vtkSmartPointer.h" #include "vtkSMMessage.h" #include "vtkSMProperty.h" #include "vtkSMRenderViewProxy.h" #include vtkStandardNewMacro(vtkSMCameraLink); //--------------------------------------------------------------------------- class vtkSMCameraLink::vtkInternals { public: static void UpdateViewCallback(vtkObject* caller, unsigned long eid, void* clientData, void* callData) { vtkSMCameraLink* camLink = reinterpret_cast(clientData); if (!camLink || !camLink->GetEnabled()) { return; } if(eid == vtkCommand::EndEvent && clientData && caller && callData) { int *interactive = reinterpret_cast(callData); camLink->UpdateViews(vtkSMProxy::SafeDownCast(caller), (*interactive==1)); } else if (eid == vtkCommand::StartInteractionEvent && clientData && caller) { camLink->StartInteraction(caller); } else if (eid == vtkCommand::EndInteractionEvent && clientData && caller) { camLink->EndInteraction(caller); } else if (eid == vtkCommand::ResetCameraEvent && clientData && caller) { camLink->ResetCamera(caller); } } struct LinkedCamera { LinkedCamera(vtkSMProxy* proxy, vtkSMCameraLink* camLink) : Proxy(proxy) { this->Observer = vtkSmartPointer::New(); this->Observer->SetClientData(camLink); this->Observer->SetCallback(vtkInternals::UpdateViewCallback); proxy->AddObserver(vtkCommand::EndEvent, this->Observer); vtkSMRenderViewProxy* rmp = vtkSMRenderViewProxy::SafeDownCast(proxy); if (rmp) { if (vtkRenderWindowInteractor* iren = rmp->GetInteractor()) { iren->AddObserver(vtkCommand::StartInteractionEvent, this->Observer); iren->AddObserver(vtkCommand::EndInteractionEvent, this->Observer); } rmp->AddObserver(vtkCommand::ResetCameraEvent, this->Observer); } }; ~LinkedCamera() { this->Proxy->RemoveObserver(this->Observer); vtkSMRenderViewProxy* rmp = vtkSMRenderViewProxy::SafeDownCast(this->Proxy); if (rmp) { vtkRenderWindowInteractor* iren = rmp->GetInteractor(); if(iren) { iren->RemoveObserver(this->Observer); } rmp->RemoveObserver(this->Observer); } } vtkSmartPointer Proxy; vtkSmartPointer Observer; LinkedCamera(const LinkedCamera&); LinkedCamera& operator=(const LinkedCamera&); }; typedef std::list LinkedProxiesType; LinkedProxiesType LinkedProxies; bool Updating; static const char* LinkedPropertyNames[]; vtkInternals() { this->Updating = false; } ~vtkInternals() { LinkedProxiesType::iterator iter; for(iter = this->LinkedProxies.begin(); iter != LinkedProxies.end(); ++iter) { delete *iter; } } }; //--------------------------------------------------------------------------- const char* vtkSMCameraLink::vtkInternals::LinkedPropertyNames[] = { /* from */ /* to */ "CameraPositionInfo", "CameraPosition", "CameraViewAngleInfo", "CameraViewAngle", "CameraFocalPointInfo", "CameraFocalPoint", "CameraViewUpInfo", "CameraViewUp", "CenterOfRotation", "CenterOfRotation", "CameraParallelScaleInfo", "CameraParallelScale", "RotationFactor", "RotationFactor", "CameraParallelProjection", "CameraParallelProjection", 0 }; //--------------------------------------------------------------------------- vtkSMCameraLink::vtkSMCameraLink() { this->Internals = new vtkInternals; this->SynchronizeInteractiveRenders = 1; } //--------------------------------------------------------------------------- vtkSMCameraLink::~vtkSMCameraLink() { delete this->Internals; } //--------------------------------------------------------------------------- void vtkSMCameraLink::AddLinkedProxy(vtkSMProxy* proxy, int updateDir) { // must be render module to link cameras if(vtkSMRenderViewProxy::SafeDownCast(proxy)) { this->Superclass::AddLinkedProxy(proxy, updateDir); if(updateDir == vtkSMLink::INPUT) { proxy->CreateVTKObjects(); // ensure that the proxy is created. // This is necessary since when loading state the proxy may not yet be // created, however we want to observer events on the // interactor. this->Internals->LinkedProxies.push_back( new vtkInternals::LinkedCamera(proxy, this)); } } } //--------------------------------------------------------------------------- void vtkSMCameraLink::RemoveLinkedProxy(vtkSMProxy* proxy) { this->Superclass::RemoveLinkedProxy(proxy); vtkInternals::LinkedProxiesType::iterator iter; for(iter = this->Internals->LinkedProxies.begin(); iter != this->Internals->LinkedProxies.end(); ++iter) { if((*iter)->Proxy == proxy) { delete *iter; this->Internals->LinkedProxies.erase(iter); break; } } } //--------------------------------------------------------------------------- void vtkSMCameraLink::PropertyModified(vtkSMProxy* fromProxy, const char* pname) { if (pname && strcmp(pname, "CenterOfRotation") == 0) { // We are linking center of rotations for linked views as well. // Center of rotation is not changed during interaction, hence // we listen to center of rotation changed events explicitly. this->UpdateViews(fromProxy, false); } } //--------------------------------------------------------------------------- void vtkSMCameraLink::UpdateVTKObjects(vtkSMProxy* vtkNotUsed(fromProxy)) { return; // do nothing } //--------------------------------------------------------------------------- void vtkSMCameraLink::CopyProperties(vtkSMProxy* caller) { const char** props = this->Internals->LinkedPropertyNames; for(; *props; props+=2) { vtkSMProperty* fromProp = caller->GetProperty(props[0]); int numObjects = this->GetNumberOfLinkedObjects(); for(int i=0; iGetLinkedProxy(i); if(p != caller && this->GetLinkedObjectDirection(i) == vtkSMLink::OUTPUT) { vtkSMProperty* toProp = p->GetProperty(props[1]); toProp->Copy(fromProp); p->UpdateProperty(props[1]); } } } } //--------------------------------------------------------------------------- void vtkSMCameraLink::UpdateViews(vtkSMProxy* caller, bool interactive) { if(this->Internals->Updating) { return; } this->Internals->Updating = true; this->CopyProperties(caller); int numObjects = this->GetNumberOfLinkedObjects(); for(int i=0; iGetLinkedProxy(i); if(this->GetLinkedObjectDirection(i) == vtkSMLink::OUTPUT && p != caller) { vtkSMRenderViewProxy* rmp; rmp = vtkSMRenderViewProxy::SafeDownCast(p); if(rmp) { if (interactive) { if (this->SynchronizeInteractiveRenders) { rmp->InteractiveRender(); } } else { rmp->StillRender(); } } } } this->Internals->Updating = false; } //--------------------------------------------------------------------------- void vtkSMCameraLink::StartInteraction(vtkObject* caller) { if (this->Internals->Updating) { return; } this->Internals->Updating = true; int numObjects = this->GetNumberOfLinkedObjects(); for(int i=0; iGetLinkedProxy(i)); if(rmp && this->GetLinkedObjectDirection(i) == vtkSMLink::OUTPUT && rmp->GetInteractor() != caller) { rmp->GetInteractor()->InvokeEvent(vtkCommand::StartInteractionEvent); } } this->Internals->Updating = false; } //--------------------------------------------------------------------------- void vtkSMCameraLink::EndInteraction(vtkObject* caller) { if (this->Internals->Updating) { return; } this->Internals->Updating = true; int numObjects = this->GetNumberOfLinkedObjects(); for(int i=0; iGetLinkedProxy(i)); if(rmp && this->GetLinkedObjectDirection(i) == vtkSMLink::OUTPUT && rmp->GetInteractor() != caller) { rmp->GetInteractor()->InvokeEvent(vtkCommand::EndInteractionEvent); } } this->Internals->Updating = false; } //--------------------------------------------------------------------------- void vtkSMCameraLink::ResetCamera(vtkObject* caller) { if (this->Internals->Updating) { return; } this->Internals->Updating = true; this->CopyProperties(vtkSMProxy::SafeDownCast(caller)); this->Internals->Updating = false; } //--------------------------------------------------------------------------- void vtkSMCameraLink::SaveXMLState(const char* linkname, vtkPVXMLElement* parent) { vtkPVXMLElement* root = vtkPVXMLElement::New(); Superclass::SaveXMLState(linkname, root); unsigned int numElems = root->GetNumberOfNestedElements(); for (unsigned int cc=0; cc < numElems; cc++) { vtkPVXMLElement* child = root->GetNestedElement(cc); child->SetName("CameraLink"); parent->AddNestedElement(child); } root->Delete(); } //--------------------------------------------------------------------------- void vtkSMCameraLink::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "SynchronizeInteractiveRenders: " << this->SynchronizeInteractiveRenders << endl; } //----------------------------------------------------------------------------- void vtkSMCameraLink::LoadState(const vtkSMMessage *msg, vtkSMProxyLocator *locator) { this->Superclass::LoadState(msg, locator); this->SetSynchronizeInteractiveRenders(msg->GetExtension(LinkState::sync_interactive_renders) ? 1:0); } //----------------------------------------------------------------------------- void vtkSMCameraLink::UpdateState() { this->Superclass::UpdateState(); this->State->SetExtension(LinkState::sync_interactive_renders, !!this->GetSynchronizeInteractiveRenders()); }