20 #include <Inventor/SbSphere.h>
22 #include <Inventor/nodes/SoNode.h>
23 #include <Inventor/nodes/SoCamera.h>
24 #include <Inventor/nodes/SoPerspectiveCamera.h>
25 #include <Inventor/nodes/SoOrthographicCamera.h>
26 #include <Inventor/nodes/SoGroup.h>
28 #include <Inventor/actions/SoSearchAction.h>
29 #include <Inventor/actions/SoGetBoundingBoxAction.h>
30 #include <Inventor/actions/SoGetMatrixAction.h>
32 #include <Inventor/sensors/SoTimerSensor.h>
105 SoSFVec3f & position, SoSFFloat & nearDistance,
106 SoSFFloat & farDistance, SoSFFloat & focalDistance,
114 static std::map<SoCamera*,VP1CameraHelper*>
helpers;
119 double duration_in_secs );
127 const SbVec3f& lookat = SbVec3f(999,999,999),
const SbVec3f& upvec = SbVec3f(999,999,999) );
129 const SbVec3f& lookat = SbVec3f(999,999,999),
const SbVec3f& upvec = SbVec3f(999,999,999) );
133 const SbVec3f& lookat = SbVec3f(999,999,999),
const SbVec3f& upvec = SbVec3f(999,999,999) );
135 void die(
bool abnormal =
true)
165 const QString& outputdir,
172 VP1Msg::messageDebug(
"VP1CameraHelper::setOutputImagesMode ERROR: Bad input. Null render area.");
179 if (!QDir(outputdir).
exists()) {
180 VP1Msg::messageDebug(
"VP1CameraHelper::setOutputImagesMode ERROR: Bad input. Output dir "+outputdir+
" does not exist.");
183 if (width<1||width>4000||height<1||height>4000) {
203 : QObject(0), m_d(
new Imp)
211 it->second->forceAbort();
238 if (!camera||!sceneroot)
290 if (camera->position.getValue()!=last_cameraposition
291 ||camera->orientation.getValue()!=last_cameraorient)
293 if (!camera_isperspective
294 &&
static_cast<SoOrthographicCamera*
>(camera)->height!=last_camera_ortho_height)
302 const QByteArray& camstate,
303 double duration_in_secs,
double clipVolPercent,
double lastClipVolPercent,
bool varySpeed,
310 helper->m_d->actual_animatedZoomToCameraState( camstate,duration_in_secs );
311 helper->m_d->varySpeed=varySpeed;
312 helper->m_d->clipVol_startPercentage=lastClipVolPercent;
313 helper->m_d->clipVol_percentage=lastClipVolPercent;
314 helper->m_d->clipVol_endPercentage=clipVolPercent;
315 helper->m_d->forceCircular = forceCircular;
321 double duration_in_secs )
323 if (!camera||camstate==QByteArray()||duration_in_secs<0.0) {
328 if (instanceInvalid()) {
329 if (seeksensor->isScheduled())
330 seeksensor->unschedule();
335 targetCamState = camstate;
337 const bool perspective(camera->getTypeId().isDerivedFrom(SoPerspectiveCamera::getClassTypeId()));
338 SoCamera * targetcam = perspective ?
static_cast<SoCamera*
>(
new SoPerspectiveCamera)
339 :
static_cast<SoCamera*
>(
new SoOrthographicCamera);
341 QByteArray ba = camstate;
348 camera_isperspective = perspective;
349 camerastartposition = camera->position.getValue();
350 camerastartorient = camera->orientation.getValue();
351 camerastart_nearDistance = camera->nearDistance.getValue();
352 camerastart_farDistance = camera->farDistance.getValue();
353 camerastart_focalDistance = camera->focalDistance.getValue();
354 cameraendposition = targetcam->position.getValue();
355 cameraendorient = targetcam->orientation.getValue();
356 cameraend_nearDistance = targetcam->nearDistance.getValue();
357 cameraend_farDistance = targetcam->farDistance.getValue();
358 cameraend_focalDistance = targetcam->focalDistance.getValue();
360 camerastart_ortho_height =
static_cast<SoOrthographicCamera*
>(camera)->height.getValue();
361 cameraend_ortho_height =
static_cast<SoOrthographicCamera*
>(targetcam)->height.getValue();
365 startSeekTimer( duration_in_secs );
372 SoPath *
path,
double duration_in_secs,
double ,
double slack,
373 const SbVec3f& lookat,
const SbVec3f& upvec,
bool varySpeed,
377 helper->m_d->actual_animatedZoomToPath(
path,duration_in_secs, slack, lookat, upvec );
378 helper->m_d->varySpeed=varySpeed;
379 helper->m_d->forceCircular = forceCircular;
385 const SbVec3f& lookat,
const SbVec3f& upvec )
387 if (!
path||instanceInvalid()) {
392 if (slack<=0.0||duration_in_secs<0.0) {
397 if (instanceInvalid()) {
398 if (seeksensor->isScheduled())
399 seeksensor->unschedule();
403 SbViewportRegion dummyvp;
404 SoGetBoundingBoxAction mybboxaction(dummyvp);
405 mybboxaction.apply(
path);
406 SbBox3f box = mybboxaction.getBoundingBox();
408 actual_animatedZoomToBBox(box, duration_in_secs, slack, lookat,upvec);
414 SoNode*subtreeroot,
double duration_in_secs,
double ,
double ,
double slack,
415 const SbVec3f& lookat,
const SbVec3f& upvec,
bool varySpeed,
419 helper->m_d->actual_animatedZoomToSubTree( subtreeroot,duration_in_secs,slack,lookat,upvec );
420 helper->m_d->varySpeed=varySpeed;
421 helper->m_d->forceCircular = forceCircular;
427 const SbVec3f& lookat,
const SbVec3f& upvec)
429 if (!subtreeroot||instanceInvalid()) {
434 if (slack<=0.0||duration_in_secs<0.0) {
439 if (instanceInvalid()) {
444 SoSearchAction mysearchaction;
445 mysearchaction.setNode(subtreeroot);
446 mysearchaction.apply(sceneroot);
447 SoPath *
mypath = mysearchaction.getPath();
449 VP1Msg::messageDebug(
"VP1CameraHelper WARNING: Cancelled operation due to failure to locate path to node.");
453 actual_animatedZoomToPath(
mypath, duration_in_secs, slack, lookat,upvec );
455 mysearchaction.reset();
461 const SbBox3f& box,
double duration_in_secs,
double ,
double slack,
462 const SbVec3f& lookat,
const SbVec3f& upvec ,
bool varySpeed,
467 helper->m_d->actual_animatedZoomToBBox( box,duration_in_secs,slack,lookat,upvec );
468 helper->m_d->varySpeed=varySpeed;
469 helper->m_d->forceCircular = forceCircular;
475 const SbVec3f& lookat,
const SbVec3f& upvec )
477 if (instanceInvalid()) {
482 if (slack<=0.0||duration_in_secs<0.0) {
487 if (instanceInvalid()) {
496 SbBox3f actualbbox = box;
498 float minx, miny, minz, maxx, maxy, maxz;
499 actualbbox.getBounds (minx, miny, minz, maxx, maxy, maxz);
500 float dx(maxx-minx),
cx(0.5*(maxx+minx));
501 float dy(maxy-miny),
cy(0.5*(maxy+miny));
502 float dz(maxz-minz), cz(0.5*(maxz+minz));
503 actualbbox.setBounds (
cx-0.5*slack*
dx,
cy-0.5*slack*
dy, cz-0.5*slack*dz,
504 cx+0.5*slack*
dx,
cy+0.5*slack*
dy, cz+0.5*slack*dz);
509 SoSFVec3f target_position;
510 SoSFFloat target_nearDistance;
511 SoSFFloat target_farDistance;
512 SoSFFloat target_focalDistance;
513 bool currentcamera_isperspective;
514 SoSFFloat target_ortho_height;
516 camerastartorient = camera->orientation.getValue();
518 bool changeorient(
false);
519 if (lookat==SbVec3f(999,999,999)&&upvec==SbVec3f(999,999,999)) {
520 cameraendorient = camerastartorient;
524 SbVec3f actual_lookat(lookat);
525 if (lookat==SbVec3f(999,999,999)) {
527 SbRotation camrot = camera->orientation.getValue();
528 actual_lookat = SbVec3f(0.0
f, 0.0
f, -1.0
f);
529 camrot.multVec(actual_lookat, actual_lookat);
531 SbVec3f actual_upvec(upvec);
532 if (upvec==SbVec3f(999,999,999)) {
534 SbRotation camrot = camera->orientation.getValue();
535 actual_upvec = SbVec3f(0.0
f, 1.0
f, 0.0
f);
536 camrot.multVec(actual_upvec, actual_upvec);
549 camera->orientation.setValue(cameraendorient);
550 if (!getCameraParametersForBBox( actualbbox,
551 target_position, target_nearDistance,
552 target_farDistance, target_focalDistance,
553 currentcamera_isperspective,target_ortho_height)) {
557 camerastartposition = camera->position.getValue();
558 cameraendposition = target_position.getValue();
560 camerastart_nearDistance = camera->nearDistance.getValue();
561 cameraend_nearDistance = target_nearDistance;
562 camerastart_farDistance = camera->farDistance.getValue();
563 cameraend_farDistance = target_farDistance;
564 camerastart_focalDistance = camera->focalDistance.getValue();
565 cameraend_focalDistance = target_focalDistance;
566 camera_isperspective = currentcamera_isperspective;
567 if (camera_isperspective) {
568 camerastart_ortho_height = 1.0f;
569 cameraend_ortho_height = camerastart_ortho_height;
571 SoOrthographicCamera * orthocam =
static_cast<SoOrthographicCamera*
>(camera);
574 camera->orientation.setValue(camerastartorient);
578 camerastart_ortho_height = orthocam->height.getValue();
579 cameraend_ortho_height = target_ortho_height;
582 camera->orientation.setValue(camerastartorient);
586 startSeekTimer(duration_in_secs);
593 SbVec3f targetpoint,
double duration_in_secs,
double ,
bool varySpeed,
597 helper->m_d->actual_animatedZoomToPoint( targetpoint,duration_in_secs );
598 helper->m_d->varySpeed=varySpeed;
599 helper->m_d->forceCircular = forceCircular;
606 seekperiod =
static_cast<float>(duration_in_secs);
608 if (seeksensor->isScheduled())
609 seeksensor->unschedule();
611 seeksensor->setBaseTime(SbTime::getTimeOfDay());
612 seeksensor->schedule();
621 if (instanceInvalid()) {
626 if (duration_in_secs<0.0) {
631 if (instanceInvalid()) {
636 camerastartposition = camera->position.getValue();
637 camerastartorient = camera->orientation.getValue();
642 camerastart_nearDistance = camera->nearDistance.getValue();
643 cameraend_nearDistance = camerastart_nearDistance;
644 camerastart_farDistance = camera->farDistance.getValue();
645 cameraend_farDistance = camerastart_farDistance;
646 camerastart_focalDistance = camera->focalDistance.getValue();
647 cameraend_focalDistance = camerastart_focalDistance;
649 camera_isperspective=!(camera->getTypeId() == SoOrthographicCamera::getClassTypeId());
650 camerastart_ortho_height = 1.0f;
651 cameraend_ortho_height = camerastart_ortho_height;
655 SbMatrix cameramatrix, camerainverse;
656 getCameraCoordinateSystem(camera,
660 camerainverse.multVecMatrix(targetpoint, targetpoint);
661 float fd = seekdistance;
662 if (!seekdistanceabs)
663 fd *= (targetpoint - camera->position.getValue()).
length()/100.0f;
664 camera->focalDistance =
fd;
666 SbVec3f
dir = targetpoint - camerastartposition;
672 camera->orientation.getValue().multVec(SbVec3f(0, 0, -1), olddir);
673 SbRotation diffrot(olddir,
dir);
674 cameraendposition = targetpoint -
fd *
dir;
675 cameraendorient = camera->orientation.getValue() * diffrot;
677 startSeekTimer(duration_in_secs);
689 if (
d->instanceInvalid() ||
d->lastParsChanged()) {
694 SoTimerSensor * sensor = (SoTimerSensor *)
s;
700 if (
d->ntotframes<0) {
702 d->ntotframes =
std::max(1,
static_cast<int>((
d->fps)*(
d->seekperiod)+0.5));
708 t = ( (
d->iframe+1==
d->ntotframes) ? 1.0
f :
static_cast<float>((
d->iframe+1)*1.0/(
d->ntotframes*1.0)) );
716 if ((
t > 1.0
f) || (
d->fps<=0&&(
t + sensor->getInterval().getValue()/
d->seekperiod > 1.0f)))
t = 1.0f;
718 d->clipVol_percentage =
d->clipVol_startPercentage+(
d->clipVol_endPercentage -
d->clipVol_startPercentage)*
t;
719 emit
d->theclass->clipVolumePercentageOfATLAS(
d->clipVol_percentage);
721 bool end = (
t == 1.0f);
726 if (
d->camera->position.getValue()!=
d->cameraendposition) {
727 double rBegin=
d->camerastartposition.length();
728 double rEnd=
d->cameraendposition.length();
729 double lengthRatio = rEnd/rBegin;
730 SbVec3f
u =
d->camerastartposition;
u.normalize();
731 SbVec3f
v =
d->cameraendposition;
v.normalize();
733 if (
d->forceCircular||(lengthRatio>0.99 && lengthRatio<1.01 && angle<0.95*M_PI && angle>0.05*
M_PI)) {
734 double r = rBegin + (rEnd-rBegin)*
t;
735 SbVec3f
w =
u.cross(
v);
740 d->camera->position=
z;
742 d->camera->position =
d->camerastartposition + (
d->cameraendposition -
d->camerastartposition) *
t;
745 if (
d->camera->orientation.getValue()!=
d->cameraendorient)
746 d->camera->orientation = SbRotation::slerp(
d->camerastartorient,
d->cameraendorient,
t);
754 if (
d->camera->focalDistance!=
d->cameraend_focalDistance)
755 d->camera->focalDistance.setValue(
d->camerastart_focalDistance.getValue()*(1-
t) +
d->cameraend_focalDistance.getValue()*
t);
756 if (!
d->camera_isperspective) {
757 SoOrthographicCamera * orthocam =
static_cast<SoOrthographicCamera*
>(
d->camera);
758 if (orthocam&&orthocam->height!=
d->cameraend_ortho_height)
759 orthocam->height.setValue(
d->camerastart_ortho_height.getValue()*(1-
t) +
d->cameraend_ortho_height.getValue()*
t);
764 if (
d->ntotframes>0) {
767 if (
d->seekperiod>0.0) {
770 d->width,
d->height,
false);
781 if (
d->targetCamState!=QByteArray()) {
794 QString& lastOfExistingFiles,
795 QString& nextAvailableFile )
797 lastOfExistingFiles=
"";
813 if (instance_invalid)
815 if (!camera||camera_ref!=camera->getRefCount()) {
816 instance_invalid=
true;
820 if (sceneroot->getRefCount()<=1) {
821 instance_invalid=
true;
822 VP1Msg::messageDebug(
"VP1CameraHelper WARNING: Cancelled operation due to sceneroot being unref'ed.");
835 searchaction->reset();
836 searchaction->setSearchingAll(
TRUE);
837 searchaction->setInterest(SoSearchAction::FIRST);
838 searchaction->setNode(cameraarg);
839 searchaction->apply(
root);
842 if (searchaction->getPath()) {
843 matrixaction->apply(searchaction->getPath());
844 matrix = matrixaction->getMatrix();
845 inverse = matrixaction->getInverse();
847 searchaction->reset();
852 SoSFVec3f & position, SoSFFloat & nearDistance,
853 SoSFFloat & farDistance, SoSFFloat & focalDistance,
857 float aspect = camera->aspectRatio.getValue();
861 if (camera->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
863 }
else if (camera->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
870 SbVec3f cameradirection;
871 camera->orientation.getValue().multVec(SbVec3f(0, 0, -1), cameradirection);
872 position.setValue(box.getCenter() + -cameradirection);
876 bs.circumscribe(box);
877 float radius = bs.getRadius();
882 float aspectradius =
radius / (aspect < 1.0f ? aspect : 1.0f);
884 SoPerspectiveCamera * perspcam =
static_cast<SoPerspectiveCamera*
>(camera);
889 SbVec3f direction = position.getValue() - box.getCenter();
890 (void) direction.normalize();
892 aspectradius + (aspectradius/
float(
atan(perspcam->heightAngle.getValue())));
893 position.setValue(box.getCenter() + direction * movelength);
898 height = 2 *
radius / aspect;
904 SbVec3f direction = position.getValue() - box.getCenter();
905 (void) direction.normalize();
906 position.setValue(box.getCenter() + direction *
radius);
912 float distance_to_midpoint = (position.getValue() - box.getCenter()).
length();
913 nearDistance = distance_to_midpoint -
radius;
914 farDistance = distance_to_midpoint +
radius;
921 focalDistance = distance_to_midpoint;
929 const float epsilon = 0.00001f;
932 if (
dir.sqrLength()==0.0f||
up.sqrLength()==0.0f) {
934 "view and up direction vectors that are not both non-zero");
935 return SbRotation(SbVec3f(0.0
f, 0.0
f, 1.0
f), 0.0
f);
943 SbVec3f dir0(0.0
f, 0.0
f, -1.0
f), up0(0.0
f, 1.0
f, 0.0
f);
946 SbRotation rot(dir0,
dir);
949 if (fabs(
dir.dot(
up))>1.0f-epsilon) {
951 "view and up direction vectors that are essentially parallel."
952 " Choosing new arbitrary up direction.");
953 up =
dir.cross(SbVec3f(1.0
f,1.0
f,0.0
f));
955 if (fabs(
dir.dot(
up))>1.0f-epsilon) {
956 up =
dir.cross(SbVec3f(1.0
f,0.0
f,1.0
f));
958 if (fabs(
dir.dot(
up))>1.0f-epsilon) {
974 if (
up.length()<epsilon) {
981 rot.multVec(up0,up0);
982 up0 = up0 -
dir*(
dir.dot(up0));
983 if (up0.length()<epsilon) {
991 return rot*SbRotation(up0,
up);