From 02d7a14aaacbbbb65b5d38c1d27d4812bca2bf98 Mon Sep 17 00:00:00 2001 From: ThomasDuvinage Date: Thu, 8 Aug 2024 10:04:57 +0900 Subject: [PATCH 01/73] [CMake] Set CHOREONOID_USE_PYTHON2 variable in config file --- cmake/ChoreonoidConfig.cmake.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/ChoreonoidConfig.cmake.in b/cmake/ChoreonoidConfig.cmake.in index 230a88e13..17932ae82 100644 --- a/cmake/ChoreonoidConfig.cmake.in +++ b/cmake/ChoreonoidConfig.cmake.in @@ -49,6 +49,7 @@ set(CHOREONOID_COMPILE_DEFINITIONS "@compile_definitions@") set(CHOREONOID_DEFAULT_FVISIBILITY_HIDDEN @CHOREONOID_DEFAULT_FVISIBILITY_HIDDEN@) set(CHOREONOID_INCLUDE_DIRS "@include_dirs@") set(CHOREONOID_LIBRARY_DIRS "@library_dirs@") +set(CHOREONOID_USE_PYTHON2 @CNOID_USE_PYTHON2@) if(@has_boost_libs_for_util_libs@) find_package(Boost @boost_version@ EXACT COMPONENTS @boost_components_for_util_libs@) From dc9f4b2cd8e357d116226fec7b76efe32d86fbf2 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Sat, 20 Jul 2024 22:27:52 +0900 Subject: [PATCH 02/73] Add the setTransparency function to SphereMarker --- src/Util/SceneMarkers.cpp | 8 ++++++-- src/Util/SceneMarkers.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Util/SceneMarkers.cpp b/src/Util/SceneMarkers.cpp index 8470e17d0..e08ebf624 100644 --- a/src/Util/SceneMarkers.cpp +++ b/src/Util/SceneMarkers.cpp @@ -235,7 +235,6 @@ void SphereMarker::initialize(double radius, const Vector3f& color, float transp void SphereMarker::setRadius(double r) { scale->setScale(r); - scale->notifyUpdate(); } @@ -243,10 +242,15 @@ void SphereMarker::setColor(const Vector3f& c) { material->setDiffuseColor(c); material->setEmissiveColor(c); - material->notifyUpdate(); } +void SphereMarker::setTransparency(float transparency) +{ + material->setTransparency(transparency); +} + + BoundingBoxMarker::BoundingBoxMarker(const BoundingBox& bbox, const Vector3f& color, float transparency, double width) { setAttribute(Marker); diff --git a/src/Util/SceneMarkers.h b/src/Util/SceneMarkers.h index 6ae458f06..9ca2b2438 100644 --- a/src/Util/SceneMarkers.h +++ b/src/Util/SceneMarkers.h @@ -67,6 +67,8 @@ class CNOID_EXPORT SphereMarker : public SgPosTransform SphereMarker(double radius, const Vector3f& color, float transparency = 0.0f); void setRadius(double r); void setColor(const Vector3f& c); + void setTransparency(float transparency); + private: void initialize(double radius, const Vector3f& color, float transparency); SgScaleTransformPtr scale; From b1e7d0bf06b974accd521dcd52aa1682c7e8c8c6 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 12 Jul 2024 22:11:47 +0900 Subject: [PATCH 03/73] Add ZmpDevice --- include/cnoid/ZmpDevice | 1 + src/Body/CMakeLists.txt | 2 + src/Body/MarkerDevice.cpp | 2 - src/Body/ZmpDevice.cpp | 124 ++++++++++++++++++++++++++++++++++++++ src/Body/ZmpDevice.h | 43 +++++++++++++ 5 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 include/cnoid/ZmpDevice create mode 100644 src/Body/ZmpDevice.cpp create mode 100644 src/Body/ZmpDevice.h diff --git a/include/cnoid/ZmpDevice b/include/cnoid/ZmpDevice new file mode 100644 index 000000000..9d753bab7 --- /dev/null +++ b/include/cnoid/ZmpDevice @@ -0,0 +1 @@ +#include "src/Body/ZmpDevice.h" diff --git a/src/Body/CMakeLists.txt b/src/Body/CMakeLists.txt index 45199f0a2..ab2d4fbd8 100644 --- a/src/Body/CMakeLists.txt +++ b/src/Body/CMakeLists.txt @@ -56,6 +56,7 @@ set(sources BodyKinematicsKit.cpp KinematicBodySet.cpp LeggedBodyHelper.cpp + ZmpDevice.cpp BodyCollisionLinkFilter.cpp BodyCollisionDetector.cpp BodyCollisionDetectorUtil.cpp @@ -144,6 +145,7 @@ set(headers BodyKinematicsKit.h KinematicBodySet.h LeggedBodyHelper.h + ZmpDevice.h PenetrationBlocker.h ForwardDynamics.h ForwardDynamicsABM.h diff --git a/src/Body/MarkerDevice.cpp b/src/Body/MarkerDevice.cpp index 1501d4414..dfcf8ad46 100644 --- a/src/Body/MarkerDevice.cpp +++ b/src/Body/MarkerDevice.cpp @@ -301,5 +301,3 @@ registerMarkerDevice( return marker->writeSpecifications(info); }); } - - diff --git a/src/Body/ZmpDevice.cpp b/src/Body/ZmpDevice.cpp new file mode 100644 index 000000000..b4547c221 --- /dev/null +++ b/src/Body/ZmpDevice.cpp @@ -0,0 +1,124 @@ +#include "ZmpDevice.h" +#include "StdBodyFileUtil.h" +#include + +using namespace std; +using namespace cnoid; + + +ZmpDevice::ZmpDevice() +{ + zmp_.setZero(); + on_ = true; +} + + +ZmpDevice::ZmpDevice(const ZmpDevice& org, bool copyStateOnly, CloneMap* cloneMap) + : Device(org, copyStateOnly) +{ + copyZmpDeviceStateFrom(org); +} + + +ZmpDevice::~ZmpDevice() +{ + +} + + +const char* ZmpDevice::typeName() const +{ + return "ZmpDevice"; +} + + +void ZmpDevice::copyZmpDeviceStateFrom(const ZmpDevice& other) +{ + zmp_ = other.zmp_; + on_ = other.on_; +} + + +void ZmpDevice::copyStateFrom(const DeviceState& other) +{ + if(typeid(other) != typeid(ZmpDevice)){ + throw std::invalid_argument("Type mismatch in the Device::copyStateFrom function"); + } + copyZmpDeviceStateFrom(static_cast(other)); +} + + +DeviceState* ZmpDevice::cloneState() const +{ + return new ZmpDevice(*this, true, nullptr); + +} + + +Referenced* ZmpDevice::doClone(CloneMap* cloneMap) const +{ + return new ZmpDevice(*this, false, cloneMap); +} + + +void ZmpDevice::forEachActualType(std::function func) +{ + if(!func(typeid(ZmpDevice))){ + Device::forEachActualType(func); + } +} + + +bool ZmpDevice::on() const +{ + return on_; +} + + +void ZmpDevice::on(bool on) +{ + on_ = on; +} + + +int ZmpDevice::stateSize() const +{ + return 2; +} + + +const double* ZmpDevice::readState(const double* buf) +{ + int i = 0; + on_ = buf[i++]; + zmp_[0] = buf[i++]; + zmp_[1] = buf[i++]; + zmp_[2] = buf[i++]; + return buf + i; +} + + +double* ZmpDevice::writeState(double* out_buf) const +{ + int i = 0; + out_buf[i++] = on_ ? 1.0 : 0.0; + out_buf[i++] = zmp_[0]; + out_buf[i++] = zmp_[1]; + out_buf[i++] = zmp_[2]; + return out_buf + i; +} + + +namespace { + +StdBodyFileDeviceTypeRegistration +registerZmpDevice( + "ZmpDevice", + [](StdBodyLoader* loader, const Mapping* info){ + ZmpDevicePtr device = new ZmpDevice; + return loader->readDevice(device, info); + }, + [](StdBodyWriter* /* writer */, Mapping* /* info */, const ZmpDevice* /* zmpDevice */){ + return true; + }); +} diff --git a/src/Body/ZmpDevice.h b/src/Body/ZmpDevice.h new file mode 100644 index 000000000..c1767bce1 --- /dev/null +++ b/src/Body/ZmpDevice.h @@ -0,0 +1,43 @@ +#ifndef CNOID_BODY_ZMP_DEVICE_H +#define CNOID_BODY_ZMP_DEVICE_H + +#include "Device.h" +#include "exportdecl.h" + +namespace cnoid { + +class CNOID_EXPORT ZmpDevice : public Device +{ +public: + ZmpDevice(); + virtual ~ZmpDevice(); + + virtual const char* typeName() const override; + void copyZmpDeviceStateFrom(const ZmpDevice& other); + virtual void copyStateFrom(const DeviceState& other) override; + virtual DeviceState* cloneState() const override; + virtual void forEachActualType(std::function func) override; + virtual int stateSize() const override; + virtual const double* readState(const double* buf) override; + virtual double* writeState(double* out_buf) const override; + + virtual bool on() const override; + virtual void on(bool on) override; + + const Vector3& zmp() const { return zmp_; }; + void setZmp(const Vector3& zmp) { zmp_ = zmp; } + +protected: + ZmpDevice(const ZmpDevice& org, bool copyStateOnly, CloneMap* cloneMap); + virtual Referenced* doClone(CloneMap* cloneMap) const override; + +private: + Vector3 zmp_; + bool on_; +}; + +typedef ref_ptr ZmpDevicePtr; + +} + +#endif From 4c1bc6d9a435612f48ff7a0d34e710cf653d1743 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 19 Jul 2024 16:22:18 +0900 Subject: [PATCH 04/73] Add API to access the ZMP device to LeggedBodyHelper --- src/Body/LeggedBodyHelper.cpp | 35 +++++++++++++++++++++++++++++++++++ src/Body/LeggedBodyHelper.h | 9 ++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Body/LeggedBodyHelper.cpp b/src/Body/LeggedBodyHelper.cpp index 3ec96a785..b4900d5fd 100644 --- a/src/Body/LeggedBodyHelper.cpp +++ b/src/Body/LeggedBodyHelper.cpp @@ -263,3 +263,38 @@ Vector3 LeggedBodyHelper::homeCopOfSoles() const } return p / n; } + + +ZmpDevice* LeggedBodyHelper::getOrCreateZmpDevice() +{ + if(!zmpDevice_){ + if(isValid_){ + zmpDevice_ = body_->findDevice(); + if(!zmpDevice_){ + zmpDevice_ = new ZmpDevice; + body_->addDevice(zmpDevice_, body_->rootLink()); + } + } + } + return zmpDevice_; +} + + +Vector3 LeggedBodyHelper::zmp() const +{ + if(zmpDevice_){ + return zmpDevice_->zmp(); + } + return Vector3::Zero(); +} + + +void LeggedBodyHelper::setZmp(const Vector3& zmp, bool doNotify) +{ + if(getOrCreateZmpDevice()){ + zmpDevice_->setZmp(zmp); + if(doNotify){ + zmpDevice_->notifyStateChange(); + } + } +} diff --git a/src/Body/LeggedBodyHelper.h b/src/Body/LeggedBodyHelper.h index c5ff6c06f..2096422d4 100644 --- a/src/Body/LeggedBodyHelper.h +++ b/src/Body/LeggedBodyHelper.h @@ -3,6 +3,7 @@ #include "Body.h" #include "InverseKinematics.h" +#include "ZmpDevice.h" #include #include "exportdecl.h" @@ -48,7 +49,11 @@ class CNOID_EXPORT LeggedBodyHelper : public Referenced Vector3 homeCopOfSoles() const; const Isometry3& toeOffset(int footIndex) const { return footInfos[footIndex].toeOffset; }; - + + ZmpDevice* getOrCreateZmpDevice(); + Vector3 zmp() const; + void setZmp(const Vector3& zmp, bool doNotify = false); + private: BodyPtr body_; bool isValid_; @@ -65,6 +70,8 @@ class CNOID_EXPORT LeggedBodyHelper : public Referenced }; std::vector> footInfos; + + ZmpDevicePtr zmpDevice_; }; typedef ref_ptr LeggedBodyHelperPtr; From 84471d827d32719ac9f0da491673a496c7a76a34 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 19 Jul 2024 16:22:50 +0900 Subject: [PATCH 05/73] Fix classes accessing ZMP to use LeggedBodyHelper --- src/BodyPlugin/BodyLinkView.cpp | 22 ++-- src/BodyPlugin/LeggedBodyBar.cpp | 6 +- src/BodyPlugin/OperableSceneBody.cpp | 145 ++++++++++++++++---------- src/BodyPlugin/ZMPSeqItem.cpp | 13 +-- src/PoseSeqPlugin/PoseSeqEngine.cpp | 5 +- src/PoseSeqPlugin/PoseSeqViewBase.cpp | 10 +- src/PoseSeqPlugin/PoseSeqViewBase.h | 6 +- 7 files changed, 128 insertions(+), 79 deletions(-) diff --git a/src/BodyPlugin/BodyLinkView.cpp b/src/BodyPlugin/BodyLinkView.cpp index 2fa285d66..53ef740a6 100644 --- a/src/BodyPlugin/BodyLinkView.cpp +++ b/src/BodyPlugin/BodyLinkView.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -726,11 +727,10 @@ void BodyLinkView::Impl::updateKinematicState(bool blockSignals) } } - if(currentBodyItem->isLeggedBody()){ - const Vector3& zmp = currentBodyItem->zmp(); - for(int i=0; i < 3; ++i){ - zmpXyzSpin[i].setValue(zmp[i]); - } + auto legged = getLeggedBodyHelper(currentBodyItem->body()); + Vector3 zmp = legged->zmp(); + for(int i=0; i < 3; ++i){ + zmpXyzSpin[i].setValue(zmp[i]); } if(blockSignals){ @@ -963,12 +963,14 @@ void BodyLinkView::Impl::doInverseKinematics(Vector3 p, Matrix3 R) void BodyLinkView::Impl::onZmpXyzChanged() { if(currentBodyItem){ - Vector3 zmp; - for(int i=0; i < 3; ++i){ - zmp[i] = zmpXyzSpin[i].value(); + auto legged = getLeggedBodyHelper(currentBodyItem->body()); + if(legged->isValid()){ + Vector3 zmp; + for(int i=0; i < 3; ++i){ + zmp[i] = zmpXyzSpin[i].value(); + } + legged->setZmp(zmp, true); } - currentBodyItem->setZmp(zmp); - currentBodyItem->notifyKinematicStateChange(false); } } diff --git a/src/BodyPlugin/LeggedBodyBar.cpp b/src/BodyPlugin/LeggedBodyBar.cpp index 046c6a3c0..affbc9cba 100644 --- a/src/BodyPlugin/LeggedBodyBar.cpp +++ b/src/BodyPlugin/LeggedBodyBar.cpp @@ -1,6 +1,7 @@ #include "LeggedBodyBar.h" #include "BodySelectionManager.h" #include "BodyItem.h" +#include #include #include #include @@ -135,7 +136,10 @@ void LeggedBodyBar::Impl::onZmpButtonClicked(BodyItem::PositionType position) applyBodyItemOperation( [this, position](BodyItem* bodyItem){ if(auto p = bodyItem->getParticularPosition(position)){ - bodyItem->editZmp(*p); + auto legged = getLeggedBodyHelper(bodyItem->body()); + if(legged->isValid()){ + legged->setZmp(*p, true); + } } }); } diff --git a/src/BodyPlugin/OperableSceneBody.cpp b/src/BodyPlugin/OperableSceneBody.cpp index eecc1ace8..fca99f201 100644 --- a/src/BodyPlugin/OperableSceneBody.cpp +++ b/src/BodyPlugin/OperableSceneBody.cpp @@ -35,6 +35,33 @@ namespace { enum LinkOperationType { None, FK, IK, SimInterference }; +class ZmpMarker : public SphereMarker +{ + ZmpDevicePtr zmpDevice; + ScopedConnection zmpDeviceConnection; + SgUpdate update; + +public: + ZmpMarker(LeggedBodyHelper* legged); + void setActive(bool on); + void setZmp(const Vector3& zmp); +}; + +typedef ref_ptr ZmpMarkerPtr; + +double calcMarkerRadius(Link* link) +{ + if(auto shape = link->visualShape()){ + const BoundingBox& bb = shape->boundingBox(); + if(bb.empty()){ + return 1.0; // Is this OK? + } + double V = ((bb.max().x() - bb.min().x()) * (bb.max().y() - bb.min().y()) * (bb.max().z() - bb.min().z())); + return pow(V, 1.0 / 3.0) * 0.6; + } + return 1.0; +} + } namespace cnoid { @@ -54,7 +81,6 @@ class OperableSceneLink::Impl Impl(OperableSceneBody* sceneBody, OperableSceneLink* self); OperableSceneBody* operableSceneBody(); - double calcMarkerRadius() const; void showOrigin(bool on); void showCenterOfMass(bool on); }; @@ -120,8 +146,7 @@ class OperableSceneBody::Impl SgGroupPtr markerGroup; CrossMarkerPtr cmMarker; CrossMarkerPtr cmProjectionMarker; - SphereMarkerPtr zmpMarker; - Vector3 orgZmpPos; + ZmpMarkerPtr zmpMarker; double bodyMarkerRadius; bool isCmVisible; bool isCmProjectionVisible; @@ -156,10 +181,9 @@ class OperableSceneBody::Impl double calcLinkMarkerRadius(SceneLink* sceneLink) const; void ensureCmMarker(); void ensureCmProjectionMarker(); - LeggedBodyHelper* checkLeggedBody(); - bool ensureZmpMarker(); void showCenterOfMass(bool on); void showCmProjection(bool on); + LeggedBodyHelper* checkLeggedBody(); void showZmp(bool on); void makeLinkFree(OperableSceneLink* sceneLink); void setBaseLink(OperableSceneLink* sceneLink); @@ -288,20 +312,6 @@ void OperableSceneLink::setVisible(bool on) } -double OperableSceneLink::Impl::calcMarkerRadius() const -{ - if(auto shape = self->visualShape()){ - const BoundingBox& bb = shape->boundingBox(); - if(bb.empty()){ - return 1.0; // Is this OK? - } - double V = ((bb.max().x() - bb.min().x()) * (bb.max().y() - bb.min().y()) * (bb.max().z() - bb.min().z())); - return pow(V, 1.0 / 3.0) * 0.6; - } - return 1.0; -} - - void OperableSceneLink::showOrigin(bool on) { impl->showOrigin(on); @@ -366,7 +376,7 @@ void OperableSceneLink::Impl::showCenterOfMass(bool on) if(on != isCenterOfMassShown){ if(on){ if(!cmMarker){ - auto radius = calcMarkerRadius(); + auto radius = calcMarkerRadius(self->link()); cmMarker = new CrossMarker(radius, Vector3f(0.0f, 1.0f, 0.0f), 2.0); cmMarker->setName("CenterOfMass"); } @@ -620,9 +630,6 @@ void OperableSceneBody::Impl::onKinematicStateChanged() com(2) = 0.0; cmProjectionMarker->setTranslation(com); } - if(isZmpVisible){ - zmpMarker->setTranslation(bodyItem->zmp()); - } if(activeSimulatorItem){ if(dragMode == LINK_VIRTUAL_ELASTIC_STRING){ @@ -828,32 +835,6 @@ void OperableSceneBody::Impl::ensureCmProjectionMarker() } -LeggedBodyHelper* OperableSceneBody::Impl::checkLeggedBody() -{ - auto legged = getLeggedBodyHelper(self->body()); - if(!legged->isValid() || legged->numFeet() == 0){ - legged = nullptr; - } - return legged; -} - - -bool OperableSceneBody::Impl::ensureZmpMarker() -{ - if(!zmpMarker){ - if(auto legged = checkLeggedBody()){ - Link* footLink = legged->footLink(0); - auto sceneLink = self->operableSceneLink(footLink->index()); - double radius = sceneLink->impl->calcMarkerRadius(); - zmpMarker = new SphereMarker(radius, Vector3f(0.0f, 1.0f, 0.0f), 0.3f); - zmpMarker->addChild(new CrossMarker(radius * 2.5, Vector3f(0.0f, 1.0f, 0.0f), 2.0f)); - zmpMarker->setName("ZMP"); - } - } - return (zmpMarker != nullptr); -} - - void OperableSceneBody::Impl::showCenterOfMass(bool on) { isCmVisible = on; @@ -890,24 +871,79 @@ void OperableSceneBody::Impl::showCmProjection(bool on) } +LeggedBodyHelper* OperableSceneBody::Impl::checkLeggedBody() +{ + auto legged = getLeggedBodyHelper(self->body()); + if(!legged->isValid() || legged->numFeet() == 0){ + legged = nullptr; + } + return legged; +} + + void OperableSceneBody::Impl::showZmp(bool on) { if(on){ - if(ensureZmpMarker()){ - zmpMarker->setTranslation(bodyItem->zmp()); + if(auto legged = checkLeggedBody()){ + if(!zmpMarker){ + zmpMarker = new ZmpMarker(legged); + } markerGroup->addChildOnce(zmpMarker, update); isZmpVisible = true; } } else { if(zmpMarker){ markerGroup->removeChild(zmpMarker, update); - zmpMarker.reset(); } isZmpVisible = false; } } +ZmpMarker::ZmpMarker(LeggedBodyHelper* legged) +{ + setName("ZMP"); + + Link* footLink = legged->footLink(0); + double radius = calcMarkerRadius(footLink); + setRadius(radius); + setColor(Vector3f(0.0f, 1.0f, 0.0f)); + setTransparency(0.3f); + + addChild(new CrossMarker(radius * 2.5, Vector3f(0.0f, 1.0f, 0.0f), 2.0f)); + + zmpDevice = legged->getOrCreateZmpDevice(); + + update.setAction(SgUpdate::GeometryModified); + + sigGraphConnection().connect( + [this](bool on){ setActive(on); }); +} + + +void ZmpMarker::setActive(bool on) +{ + if(on){ + setTranslation(zmpDevice->zmp()); + zmpDeviceConnection = + zmpDevice->sigStateChanged().connect( + [this](){ + setTranslation(zmpDevice->zmp()); + notifyUpdate(update); + }); + } else { + zmpDeviceConnection.disconnect(); + } +} + + +void ZmpMarker::setZmp(const Vector3& zmp) +{ + zmpDevice->setZmp(zmp); + zmpDevice->notifyStateChange(); +} + + void OperableSceneBody::Impl::makeLinkFree(OperableSceneLink* sceneLink) { if(bodyItem->currentBaseLink() == sceneLink->link()){ @@ -2002,7 +2038,7 @@ void OperableSceneBody::Impl::finishForcedPosition() void OperableSceneBody::Impl::startZmpTranslation(SceneWidgetEvent* event) { - dragProjector.setInitialTranslation(bodyItem->zmp()); + dragProjector.setInitialTranslation(zmpMarker->translation()); dragProjector.setTranslationPlaneNormal(Vector3::UnitZ()); if(dragProjector.startTranslation(event)){ dragMode = ZMP_TRANSLATION; @@ -2015,8 +2051,7 @@ void OperableSceneBody::Impl::dragZmpTranslation(SceneWidgetEvent* event) if(dragProjector.dragTranslation(event)){ Vector3 p = dragProjector.position().translation(); p.z() = dragProjector.initialPosition().translation().z(); - bodyItem->setZmp(p); - bodyItem->notifyKinematicStateChange(true); + zmpMarker->setZmp(p); dragged = true; } } diff --git a/src/BodyPlugin/ZMPSeqItem.cpp b/src/BodyPlugin/ZMPSeqItem.cpp index b2a9b601e..c59435add 100644 --- a/src/BodyPlugin/ZMPSeqItem.cpp +++ b/src/BodyPlugin/ZMPSeqItem.cpp @@ -2,6 +2,7 @@ #include "BodyItem.h" #include "BodyMotionItem.h" #include "BodyMotionEngine.h" +#include #include #include #include @@ -15,28 +16,28 @@ namespace { class ZMPSeqEngine : public TimeSyncItemEngine { shared_ptr seq; - weak_ref_ptr bodyItemRef; + LeggedBodyHelperPtr legged; ScopedConnection connection; public: ZMPSeqEngine(ZMPSeqItem* seqItem, BodyItem* bodyItem) : TimeSyncItemEngine(seqItem), - seq(seqItem->zmpseq()), - bodyItemRef(bodyItem) + seq(seqItem->zmpseq()) { + legged = getLeggedBodyHelper(bodyItem->body()); connection = seqItem->sigUpdated().connect([this](){ refresh(); }); } virtual bool onTimeChanged(double time) override { bool isValidTime = false; - if(auto bodyItem = bodyItemRef.lock()){ + if(legged->isValid()){ if(!seq->empty()){ const Vector3& zmp = seq->at(seq->clampFrameIndex(seq->frameOfTime(time), isValidTime)); if(seq->isRootRelative()){ - bodyItem->setZmp(bodyItem->body()->rootLink()->T() * zmp); + legged->setZmp(legged->body()->rootLink()->T() * zmp, true); } else { - bodyItem->setZmp(zmp); + legged->setZmp(zmp, true); } } } diff --git a/src/PoseSeqPlugin/PoseSeqEngine.cpp b/src/PoseSeqPlugin/PoseSeqEngine.cpp index 47bbc6c68..e52fc11bd 100644 --- a/src/PoseSeqPlugin/PoseSeqEngine.cpp +++ b/src/PoseSeqPlugin/PoseSeqEngine.cpp @@ -3,6 +3,7 @@ #include "BodyMotionGenerationBar.h" #include #include +#include #include using namespace cnoid; @@ -16,6 +17,7 @@ class PoseSeqEngine : public TimeSyncItemEngine PoseSeqInterpolatorPtr interpolator; BodyMotionGenerationBar* bodyMotionGenerationBar; LinkTraverse fkTraverse; + LeggedBodyHelperPtr legged; ScopedConnectionSet connections; PoseSeqEngine(PoseSeqItem* poseSeqItem, BodyItem* bodyItem) @@ -24,6 +26,7 @@ class PoseSeqEngine : public TimeSyncItemEngine { interpolator = poseSeqItem->interpolator(); bodyMotionGenerationBar = BodyMotionGenerationBar::instance(); + legged = getLeggedBodyHelper(bodyItem->body()); connections.add( poseSeqItem->sigUpdated().connect([this](){ refresh(); })); @@ -58,7 +61,7 @@ class PoseSeqEngine : public TimeSyncItemEngine auto zmp = interpolator->ZMP(); if(zmp){ - bodyItem->setZmp(*zmp); + legged->setZmp(*zmp, true); } bodyItem->notifyKinematicStateChange(true); diff --git a/src/PoseSeqPlugin/PoseSeqViewBase.cpp b/src/PoseSeqPlugin/PoseSeqViewBase.cpp index b76125d9c..32758ab0d 100644 --- a/src/PoseSeqPlugin/PoseSeqViewBase.cpp +++ b/src/PoseSeqPlugin/PoseSeqViewBase.cpp @@ -465,9 +465,9 @@ bool PoseSeqViewBase::toggleZmp(BodyKeyPose* pose, bool on) { bool modified = false; if(on){ - const Vector3& zmp = currentBodyItem->zmp(); + auto zmp = legged->zmp(); if(!pose->isZmpValid() || zmp != pose->zmp()){ - pose->setZmp(currentBodyItem->zmp()); + pose->setZmp(zmp); modified = true; } } else { @@ -684,6 +684,7 @@ void PoseSeqViewBase::setCurrentPoseSeqItem(PoseSeqItem* poseSeqItem) seq.reset(); currentBodyItem.reset(); body.reset(); + legged.reset(); if(!poseSeqItem){ if(linkTreeWidget->bodyItem()){ @@ -703,6 +704,7 @@ void PoseSeqViewBase::setCurrentPoseSeqItem(PoseSeqItem* poseSeqItem) currentBodyItem = poseSeqItem->findOwnerItem(); if(currentBodyItem){ body = currentBodyItem->body(); + legged = getLeggedBodyHelper(body); } linkTreeWidget->setBodyItem(currentBodyItem); if(currentBodyItem){ @@ -1316,7 +1318,7 @@ PoseSeq::iterator PoseSeqViewBase::insertBodyKeyPose() } if(isChecked(zmpRow, validPartColumn)){ - pose->setZmp(currentBodyItem->zmp()); + pose->setZmp(legged->zmp()); hasValidPart = true; if(isChecked(zmpRow, stationaryPointColumn)){ pose->setZmpStationaryPoint(); @@ -1435,7 +1437,7 @@ bool PoseSeqViewBase::setCurrentBodyStateToPose(BodyKeyPose* pose, bool onlySele } if(pose->isZmpValid()){ - const Vector3& zmp = currentBodyItem->zmp(); + auto zmp = legged->zmp(); if(zmp != pose->zmp()){ pose->setZmp(zmp); updated = true; diff --git a/src/PoseSeqPlugin/PoseSeqViewBase.h b/src/PoseSeqPlugin/PoseSeqViewBase.h index ad30d2a1c..f2c6c3a83 100644 --- a/src/PoseSeqPlugin/PoseSeqViewBase.h +++ b/src/PoseSeqPlugin/PoseSeqViewBase.h @@ -6,16 +6,17 @@ #include #include #include -#include #include #include #include #include +#include +#include +#include #include #include #include #include -#include #include #include #include @@ -43,6 +44,7 @@ class PoseSeqViewBase bool isSelectedPoseMoving; BodyItemPtr currentBodyItem; BodyPtr body; + LeggedBodyHelperPtr legged; double currentTime; double timeScale; Signal sigCurrentTimeChanged; From 90c5d5ab8ecc1544f4feefdd048242f88498bd39 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 19 Jul 2024 16:23:42 +0900 Subject: [PATCH 06/73] Remove the ZMP attribute from BodyItem --- src/BodyPlugin/BodyItem.cpp | 86 ++++++-------------------- src/BodyPlugin/BodyItem.h | 4 -- src/BodyPlugin/pybind11/PyBodyItem.cpp | 3 - 3 files changed, 19 insertions(+), 74 deletions(-) diff --git a/src/BodyPlugin/BodyItem.cpp b/src/BodyPlugin/BodyItem.cpp index d60be7de0..407cf21fc 100644 --- a/src/BodyPlugin/BodyItem.cpp +++ b/src/BodyPlugin/BodyItem.cpp @@ -45,12 +45,6 @@ const bool TRACE_FUNCTIONS = false; vector bodyFilesToLoad; -class BodyStateEx : public BodyState -{ -public: - Vector3 zmp; -}; - class BodyLocation : public LocationProxy { public: @@ -103,11 +97,11 @@ class KinematicStateRecord : public EditRecord public: BodyItemPtr bodyItem; BodyItem::Impl* bodyItemImpl; - BodyStateEx newState; - BodyStateEx oldState; + BodyState newState; + BodyState oldState; KinematicStateRecord(BodyItem::Impl* bodyItemImpl); - KinematicStateRecord(BodyItem::Impl* bodyItemImpl, const BodyStateEx& oldState); + KinematicStateRecord(BodyItem::Impl* bodyItemImpl, const BodyState& oldState); KinematicStateRecord(const KinematicStateRecord& org); virtual EditRecord* clone() const override; @@ -161,8 +155,8 @@ class BodyItem::Impl unique_ptr kinematicsKitManager; shared_ptr pinDragIK; - BodyStateEx initialState; - BodyStateEx lastEditState; + BodyState initialState; + BodyState lastEditState; BodyPtr exchangedMultiplexBody; @@ -173,7 +167,6 @@ class BodyItem::Impl Signal sigContinuousKinematicUpdateStateChanged; LeggedBodyHelperPtr legged; - Vector3 zmp; static unique_ptr renderableItemUtil; @@ -188,8 +181,6 @@ class BodyItem::Impl void setBody(Body* body); void notifyModelUpdate(int flags); void setCurrentBaseLink(Link* link, bool forceUpdate, bool doNotify); - void storeKinematicStateEx(BodyStateEx& state); - void restoreKinematicStateEx(const BodyStateEx& state); bool makeRootFixed(); bool makeRootFree(); BodyItemKinematicsKitManager* getOrCreateKinematicsKitManager(); @@ -312,7 +303,6 @@ BodyItem::Impl::Impl(BodyItem* self, const Impl& org, CloneMap* cloneMap) { isAttachmentEnabled = org.isAttachmentEnabled; transparency = org.transparency; - zmp = org.zmp; isCollisionDetectionEnabled = org.isCollisionDetectionEnabled; isSelfCollisionDetectionEnabled = org.isSelfCollisionDetectionEnabled; @@ -359,7 +349,6 @@ void BodyItem::Impl::initBody(bool calledFromCopyConstructor) if(!calledFromCopyConstructor){ setCurrentBaseLink(nullptr, true, false); - zmp.setZero(); self->storeInitialState(); } @@ -402,7 +391,6 @@ bool BodyItem::Impl::doAssign(const Item* srcItem) isAttachmentEnabled = srcImpl->isAttachmentEnabled; isLocationLocked = srcImpl->isLocationLocked; transparency = srcImpl->transparency; - zmp = srcImpl->zmp; isCollisionDetectionEnabled = srcImpl->isCollisionDetectionEnabled; isSelfCollisionDetectionEnabled = srcImpl->isSelfCollisionDetectionEnabled; @@ -462,7 +450,7 @@ void BodyItem::onTreePathChanged() void BodyItem::onConnectedToRoot() { - impl->storeKinematicStateEx(impl->lastEditState); + storeKinematicState(impl->lastEditState); } @@ -649,36 +637,22 @@ void BodyItem::storeKinematicState(BodyState& state) } -void BodyItem::Impl::storeKinematicStateEx(BodyStateEx& state) -{ - state.storeMultiplexStateOfBody(body); - state.zmp = zmp; -} - - void BodyItem::restoreKinematicState(const BodyState& state) { state.restoreMultiplexStateToBody(impl->body); } -void BodyItem::Impl::restoreKinematicStateEx(const BodyStateEx& state) -{ - state.restoreMultiplexStateToBody(body); - zmp = state.zmp; -} - - void BodyItem::storeInitialState() { Item::setConsistentWithProjectArchive(false); - impl->storeKinematicStateEx(impl->initialState); + storeKinematicState(impl->initialState); } void BodyItem::restoreInitialState(bool doNotify) { - impl->restoreKinematicStateEx(impl->initialState); + restoreKinematicState(impl->initialState); if(doNotify){ notifyKinematicStateUpdate(); } @@ -948,8 +922,9 @@ stdx::optional BodyItem::getParticularPosition(PositionType position) void BodyItem::Impl::getParticularPosition(BodyItem::PositionType position, stdx::optional& pos) { if(position == BodyItem::ZERO_MOMENT_POINT){ - pos = zmp; - + if(self->isLeggedBody()){ + pos = legged->zmp(); + } } else { if(position == BodyItem::CM_PROJECTION){ pos = self->centerOfMass(); @@ -976,25 +951,6 @@ void BodyItem::Impl::getParticularPosition(BodyItem::PositionType position, stdx } -const Vector3& BodyItem::zmp() const -{ - return impl->zmp; -} - - -void BodyItem::setZmp(const Vector3& zmp) -{ - impl->zmp = zmp; -} - - -void BodyItem::editZmp(const Vector3& zmp) -{ - setZmp(zmp); - notifyKinematicStateUpdate(); -} - - void BodyItem::Impl::notifyKinematicStateChange(bool requestFK, bool requestVelFK, bool requestAccFK, bool isDirect) { updateElements.reset(); @@ -1080,7 +1036,7 @@ void BodyItem::notifyKinematicStateUpdate(bool doNotifyStateChange) auto record = new KinematicStateRecord(impl, impl->lastEditState); UnifiedEditHistory::instance()->addRecord(record); - impl->storeKinematicStateEx(impl->lastEditState); + storeKinematicState(impl->lastEditState); } @@ -1813,8 +1769,6 @@ bool BodyItem::Impl::store(Archive& archive) archive.write("transparency", transparency); } - write(archive, "zmp", zmp); - return true; } @@ -1896,8 +1850,6 @@ bool BodyItem::Impl::restore(const Archive& archive) setTransparency(t); } - read(archive, "zmp", zmp); - isUpdateNotificationOnSubTreeRestoredRequested = false; isNonRootLinkStateRestorationOnSubTreeRestoredRequested = false; @@ -2080,18 +2032,18 @@ KinematicStateRecord::KinematicStateRecord(BodyItem::Impl* bodyItemImpl) bodyItem(bodyItemImpl->self), bodyItemImpl(bodyItemImpl) { - bodyItemImpl->storeKinematicStateEx(newState); + bodyItem->storeKinematicState(newState); oldState = newState; } -KinematicStateRecord::KinematicStateRecord(BodyItem::Impl* bodyItemImpl, const BodyStateEx& oldState) +KinematicStateRecord::KinematicStateRecord(BodyItem::Impl* bodyItemImpl, const BodyState& oldState) : EditRecord(bodyItemImpl->self), bodyItem(bodyItemImpl->self), bodyItemImpl(bodyItemImpl), oldState(oldState) { - bodyItemImpl->storeKinematicStateEx(newState); + bodyItem->storeKinematicState(newState); } @@ -2124,8 +2076,8 @@ std::string KinematicStateRecord::label() const bool KinematicStateRecord::undo() { - bodyItemImpl->restoreKinematicStateEx(oldState); - bodyItemImpl->storeKinematicStateEx(bodyItemImpl->lastEditState); + bodyItem->restoreKinematicState(oldState); + bodyItem->storeKinematicState(bodyItemImpl->lastEditState); bodyItemImpl->notifyKinematicStateChange(false, false, false, true); return true; } @@ -2133,8 +2085,8 @@ bool KinematicStateRecord::undo() bool KinematicStateRecord::redo() { - bodyItemImpl->restoreKinematicStateEx(newState); - bodyItemImpl->storeKinematicStateEx(bodyItemImpl->lastEditState); + bodyItem->restoreKinematicState(newState); + bodyItem->storeKinematicState(bodyItemImpl->lastEditState); bodyItemImpl->notifyKinematicStateChange(false, false, false, true); return true; } diff --git a/src/BodyPlugin/BodyItem.h b/src/BodyPlugin/BodyItem.h index 6a6c66670..bdfe6d6b3 100644 --- a/src/BodyPlugin/BodyItem.h +++ b/src/BodyPlugin/BodyItem.h @@ -175,10 +175,6 @@ class CNOID_EXPORT BodyItem : public Item, public LocatableItem, public Renderab bool isLeggedBody() const; bool doLegIkToMoveCm(const Vector3& c, bool onlyProjectionToFloor = false); - const Vector3& zmp() const; - void setZmp(const Vector3& zmp); - void editZmp(const Vector3& zmp); - enum PositionType { CM_PROJECTION, HOME_COP, LEFT_HOME_COP, RIGHT_HOME_COP, ZERO_MOMENT_POINT }; stdx::optional getParticularPosition(PositionType posType); diff --git a/src/BodyPlugin/pybind11/PyBodyItem.cpp b/src/BodyPlugin/pybind11/PyBodyItem.cpp index eaa8599ab..5fc3dd66c 100644 --- a/src/BodyPlugin/pybind11/PyBodyItem.cpp +++ b/src/BodyPlugin/pybind11/PyBodyItem.cpp @@ -51,8 +51,6 @@ void exportBodyItem(py::module m) .def("clearCollisions", &BodyItem::clearCollisions) .def_property_readonly("centerOfMass", &BodyItem::centerOfMass) .def("doLegIkToMoveCm", &BodyItem::doLegIkToMoveCm) - .def_property_readonly("zmp", &BodyItem::zmp) - .def("setZmp", &BodyItem::setZmp) .def("setStance", &BodyItem::setStance) // deprecated @@ -62,7 +60,6 @@ void exportBodyItem(py::module m) .def("getCurrentBaseLink", &BodyItem::currentBaseLink) .def("getSigKinematicStateChanged", &BodyItem::sigKinematicStateChanged) .def("getCenterOfMass", &BodyItem::centerOfMass) - .def("getZmp", &BodyItem::zmp) // This function has been removed. The following is an incomplete wrapper. .def("makeBodyStatic", [](BodyItem& self){ self.body()->setRootLinkFixed(true); }) ; From e9a784293c5f33d6c0bd2d1ba39931d1374ac626 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 24 Jul 2024 14:24:24 +0900 Subject: [PATCH 07/73] Fix the copy constructor of SgGroup to stop the shallow copy of the child nodes when a clone map is not given --- src/Util/SceneGraph.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Util/SceneGraph.cpp b/src/Util/SceneGraph.cpp index c40da25fa..fdc84c4c4 100644 --- a/src/Util/SceneGraph.cpp +++ b/src/Util/SceneGraph.cpp @@ -457,15 +457,6 @@ SgGroup::SgGroup(const SgGroup& org, CloneMap* cloneMap) } } } - } else { - // shallow copy - /** - \todo Stop the shallow copy of the child nodes. - Only the attributes of this node should be copied when the clone map is not used. - */ - for(auto& child : org){ - addChild(child); - } } if(org.hasValidBoundingBoxCache()){ From fba59a1f1b82f4206a044f823849f8c1344ac1e0 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 22 Jul 2024 17:16:46 +0900 Subject: [PATCH 08/73] Add CameraItem and CameraConfigDialog --- include/cnoid/CameraConfigDialog | 1 + include/cnoid/CameraItem | 1 + src/Base/App.cpp | 6 +- src/Base/CMakeLists.txt | 8 +- src/Base/CameraConfigDialog.cpp | 476 ++++++++++++++++++++++++++++++ src/Base/CameraConfigDialog.h | 45 +++ src/Base/CameraItem.cpp | 479 +++++++++++++++++++++++++++++++ src/Base/CameraItem.h | 80 ++++++ 8 files changed, 1092 insertions(+), 4 deletions(-) create mode 100644 include/cnoid/CameraConfigDialog create mode 100644 include/cnoid/CameraItem create mode 100644 src/Base/CameraConfigDialog.cpp create mode 100644 src/Base/CameraConfigDialog.h create mode 100644 src/Base/CameraItem.cpp create mode 100644 src/Base/CameraItem.h diff --git a/include/cnoid/CameraConfigDialog b/include/cnoid/CameraConfigDialog new file mode 100644 index 000000000..d435473d8 --- /dev/null +++ b/include/cnoid/CameraConfigDialog @@ -0,0 +1 @@ +#include "src/Base/CameraConfigDialog.h" diff --git a/include/cnoid/CameraItem b/include/cnoid/CameraItem new file mode 100644 index 000000000..33cde2de6 --- /dev/null +++ b/include/cnoid/CameraItem @@ -0,0 +1 @@ +#include "src/Base/CameraItem.h" diff --git a/src/Base/App.cpp b/src/Base/App.cpp index ded9e50e8..1e746ca9e 100644 --- a/src/Base/App.cpp +++ b/src/Base/App.cpp @@ -20,10 +20,11 @@ #include "ExtCommandItem.h" #include "SceneItem.h" #include "SceneGeometryMeasurementTracker.h" +#include "CameraItem.h" +#include "LightingItem.h" #include "PointSetItem.h" #include "PointSetGeometryMeasurementTracker.h" #include "MultiPointSetItem.h" -#include "LightingItem.h" #include "AbstractTextItem.h" #include "ScriptItem.h" #include "MessageLogItem.h" @@ -434,13 +435,14 @@ void App::Impl::initialize() ReferencedObjectSeqItem::initializeClass(ext); SceneItem::initializeClass(ext); SceneGeometryMeasurementTracker::initializeClass(); + CameraItem::initializeClass(ext); + LightingItem::initializeClass(ext); PointSetItem::initializeClass(ext); PointSetGeometryMeasurementTracker::initializeClass(); MultiPointSetItem::initializeClass(ext); AbstractTextItem::initializeClass(ext); ScriptItem::initializeClass(ext); MessageLogItem::initializeClass(ext); - LightingItem::initializeClass(ext); CoordinateFrameListItem::initializeClass(ext); CoordinateFrameItem::initializeClass(ext); PositionTagGroupItem::initializeClass(ext); diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index 14f7ad72e..1ab37bccb 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -130,6 +130,9 @@ set(sources SceneItemFileIO.cpp SceneGeometryMeasurementTracker.cpp GeneralSceneFileImporterBase.cpp + CameraItem.cpp + CameraConfigDialog.cpp + LightingItem.cpp PointSetItem.cpp PointSetGeometryMeasurementTracker.cpp MultiPointSetItem.cpp @@ -149,7 +152,6 @@ set(sources TaskView.cpp VirtualJoystickView.cpp MessageLogItem.cpp - LightingItem.cpp QtSvgUtil.cpp ) @@ -285,6 +287,9 @@ set(headers SceneItem.h SceneItemFileIO.h GeneralSceneFileImporterBase.h + CameraItem.h + CameraConfigDialog.h + LightingItem.h PointSetItem.h MultiPointSetItem.h PositionTagGroupItem.h @@ -302,7 +307,6 @@ set(headers TextEdit.h TaskView.h MessageLogItem.h - LightingItem.h QtEventUtil.h QVariantUtil.h QtSvgUtil.h diff --git a/src/Base/CameraConfigDialog.cpp b/src/Base/CameraConfigDialog.cpp new file mode 100644 index 000000000..bf4dec89e --- /dev/null +++ b/src/Base/CameraConfigDialog.cpp @@ -0,0 +1,476 @@ +#include "CameraConfigDialog.h" +#include "CameraItem.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gettext.h" + +using namespace std; +using namespace cnoid; + +namespace cnoid { + +class CameraConfigDialog::Impl +{ +public: + CameraConfigDialog* self; + CameraItemPtr cameraItem; + LineEdit nameEdit; + RadioButton perspectiveRadio; + RadioButton orthographicRadio; + LengthSpinBox positionSpins[3]; + DoubleSpinBox directionSpins[3]; + DoubleSpinBox upSpins[3]; + DoubleSpinBox nearClipSpin; + DoubleSpinBox farClipSpin; + DoubleSpinBox fovSpin; + CheckBox interactiveViewpointChangeCheck; + QVBoxLayout* alignVBox; + QVBoxLayout* optionVBox1; + QVBoxLayout* optionVBox2; + ConnectionSet widgetConnections; + + CheckBox activationInSceneViewCheck; + Connection activationCheckConnection; + + ScopedConnection cameraConnection; + + Impl(CameraConfigDialog* self); + void showToConfigureCameraItem(CameraItem* cameraItem); + void setCameraItem(CameraItem* cameraItem); + void updateWidgetsWithCurrentCameraStates(); + void setVectorElementSpins(const Vector3& v, LengthSpinBox spins[]); + void setVectorElementSpins(const Vector3& v, DoubleSpinBox spins[]); + void onNameEditingFinished(const std::string& name); + void alignWithBuiltinCamera(); + void onCameraTypeRadioChanged(int type); + void onCameraPositionSpinValueChanged(); + void onFieldOfViewSpinValueChanged(double fov); + void onClipDistanceSpinValueChanged(); + void onInteractiveViewpointChangeToggled(bool on); +}; + +} + + +CameraConfigDialog* CameraConfigDialog::instance() +{ + static CameraConfigDialog* instance_ = new CameraConfigDialog; + return instance_; +} + + +CameraConfigDialog::CameraConfigDialog() +{ + impl = new Impl(this); +} + + +CameraConfigDialog::Impl::Impl(CameraConfigDialog* self_) + : self(self_) +{ + auto vbox = new QVBoxLayout; + self->setLayout(vbox); + + auto hbox = new QHBoxLayout; + hbox->addWidget(new QLabel(_("Name:"))); + widgetConnections.add( + nameEdit.sigEditingFinished().connect( + [this](){ onNameEditingFinished(nameEdit.text().toStdString()); })); + hbox->addWidget(&nameEdit); + vbox->addLayout(hbox); + + hbox = new QHBoxLayout; + alignVBox = new QVBoxLayout; + auto alignButton = new PushButton(_("Align with the builtin camera")); + alignButton->sigClicked().connect( + [this](){ alignWithBuiltinCamera(); }); + alignVBox->addWidget(alignButton); + hbox->addStretch(); + hbox->addLayout(alignVBox); + hbox->addStretch(); + vbox->addLayout(hbox); + + optionVBox1 = new QVBoxLayout; + vbox->addLayout(optionVBox1); + + hbox = new QHBoxLayout; + hbox->addWidget(new QLabel(_("Camera type:"))); + auto cameraTypeGroup = new ButtonGroup; + perspectiveRadio.setText(_("Perspective")); + perspectiveRadio.setChecked(true); + cameraTypeGroup->addButton(&perspectiveRadio, CameraItem::Perspective); + hbox->addWidget(&perspectiveRadio); + orthographicRadio.setText(_("Orthographic")); + cameraTypeGroup->addButton(&orthographicRadio, CameraItem::Orthographic); + hbox->addWidget(&orthographicRadio); + widgetConnections.add( + cameraTypeGroup->sigButtonToggled().connect( + [this](int type, bool on){ + if(on){ + onCameraTypeRadioChanged(type); + } + })); + hbox->addStretch(); + vbox->addLayout(hbox); + + auto grid = new QGridLayout; + grid->addWidget(new QLabel(_("Position:")), 0, 0); + grid->addWidget(new QLabel(_("Look-at:")), 1, 0); + grid->addWidget(new QLabel(_("Up vector:")), 2, 0); + + DoubleSpinBox* spins[3][3]; + for(int i=0; i < 3; ++i){ + auto spin = &positionSpins[i]; + spin->setMeterRange(-9.999, 9.999); + spin->setMeterSingleStep(0.001); + spins[0][i] = spin; + spins[1][i] = &directionSpins[i]; + spins[2][i] = &upSpins[i]; + } + for(int i=1; i < 3; ++i){ + for(int j=0; j < 3; ++j){ + auto spin = spins[i][j]; + spin->setDecimals(3); + spin->setRange(-9.999, 9.999); + spin->setSingleStep(0.001); + } + } + const char* xyzLabels[] = { "X", "Y", "Z" }; + for(int i=0; i < 3; ++i){ + for(int j=0; j < 3; ++j){ + grid->addWidget(new QLabel(xyzLabels[j]), i, j * 2 + 1); + auto spin = spins[i][j]; + widgetConnections.add( + spin->sigValueChanged().connect( + [this](double){ onCameraPositionSpinValueChanged(); })); + grid->addWidget(spin, i, j * 2 + 2); + } + } + vbox->addLayout(grid); + + hbox = new QHBoxLayout; + hbox->addWidget(new QLabel(_("Field of View:"))); + fovSpin.setDecimals(0); + fovSpin.setRange(1.0, 179.0); + widgetConnections.add( + fovSpin.sigValueChanged().connect( + [this](double value){ onFieldOfViewSpinValueChanged(value); })); + hbox->addWidget(&fovSpin); + hbox->addWidget(new QLabel(_("[deg]"))); + hbox->addStretch(); + vbox->addLayout(hbox); + + hbox = new QHBoxLayout; + hbox->addWidget(new QLabel(_("Near Clip:"))); + nearClipSpin.setDecimals(3); + nearClipSpin.setRange(0.001, 9.999); + nearClipSpin.setSingleStep(0.001); + widgetConnections.add( + nearClipSpin.sigValueChanged().connect( + [this](double){ onClipDistanceSpinValueChanged(); })); + hbox->addWidget(&nearClipSpin); + + hbox->addWidget(new QLabel(_("Far Clip:"))); + farClipSpin.setDecimals(1); + farClipSpin.setRange(0.1, 999.9); + farClipSpin.setSingleStep(1.0); + widgetConnections.add( + farClipSpin.sigValueChanged().connect( + [this](double){ onClipDistanceSpinValueChanged(); })); + hbox->addWidget(&farClipSpin); + hbox->addStretch(); + vbox->addLayout(hbox); + + optionVBox2 = new QVBoxLayout; + vbox->addLayout(optionVBox2); + + interactiveViewpointChangeCheck.setText(_("Interactive viewpoint change")); + widgetConnections.add( + interactiveViewpointChangeCheck.sigToggled().connect( + [this](bool on){ onInteractiveViewpointChangeToggled(on); })); + vbox->addWidget(&interactiveViewpointChangeCheck); + + activationInSceneViewCheck.setText(_("Activate in the scene view")); + activationCheckConnection = + activationInSceneViewCheck.sigToggled().connect( + [this](bool on){ cameraItem->activateCameraInSceneView(SceneView::lastFocusSceneView(), on); }); + vbox->addWidget(&activationInSceneViewCheck); + + auto buttonBox = new QDialogButtonBox(self); + auto okButton = new PushButton(_("&OK")); + buttonBox->addButton(okButton, QDialogButtonBox::AcceptRole); + connect(buttonBox, &QDialogButtonBox::accepted, self, &QDialog::accept); + vbox->addWidget(buttonBox); + + self->setWindowPositionKeepingMode(true); +} + + +CameraConfigDialog::~CameraConfigDialog() +{ + delete impl; +} + + +CameraItem* CameraConfigDialog::showToCreateCameraItem(Item* parentItem) +{ + setWindowTitle(_("Camera Creation")); + + CameraItemPtr cameraItem = new CameraItem; + cameraItem->setName(_("Camera")); + cameraItem->setChecked(true); + cameraItem->setInteractiveViewpointChangeEnabled(false); + + cameraItem->cameraTransform()->setPosition( + Isometry3::Identity() * AngleAxis(PI / 2.0, Vector3::UnitZ()) * AngleAxis(PI, Vector3::UnitX())); + + parentItem->addChildItem(cameraItem); + + impl->showToConfigureCameraItem(cameraItem); + + return cameraItem; +} + + +void CameraConfigDialog::showToConfigureCameraItem(CameraItem* cameraItem) +{ + setWindowTitle(_("Camera Configuration")); + impl->showToConfigureCameraItem(cameraItem); +} + + +void CameraConfigDialog::Impl::showToConfigureCameraItem(CameraItem* cameraItem) +{ + setCameraItem(cameraItem); + self->show(); +} + + +QVBoxLayout* CameraConfigDialog::alignVBox() +{ + return impl->alignVBox; +} + + +QVBoxLayout* CameraConfigDialog::optionVBox1() +{ + return impl->optionVBox1; +} + + +QVBoxLayout* CameraConfigDialog::optionVBox2() +{ + return impl->optionVBox2; +} + + +CameraItem* CameraConfigDialog::cameraItem() +{ + return impl->cameraItem; +} + + +void CameraConfigDialog::Impl::setCameraItem(CameraItem* cameraItem) +{ + cameraConnection.disconnect(); + this->cameraItem = cameraItem; + + activationCheckConnection.block(); + + if(!cameraItem){ + activationInSceneViewCheck.setChecked(false); + + } else { + auto currentCamera = SceneView::instance()->sceneWidget()->renderer()->currentCamera(); + activationInSceneViewCheck.setChecked(cameraItem->perspectiveCamera() == currentCamera); + + cameraConnection = + cameraItem->cameraTransform()->sigUpdated().connect( + [this](const SgUpdate&){ self->updateWidgetsWithCurrentCameraStates(); }); + + self->updateWidgetsWithCurrentCameraStates(); + } + + activationCheckConnection.unblock(); +} + + +void CameraConfigDialog::updateWidgetsWithCurrentCameraStates() +{ + impl->updateWidgetsWithCurrentCameraStates(); +} + + +void CameraConfigDialog::Impl::updateWidgetsWithCurrentCameraStates() +{ + widgetConnections.block(); + + nameEdit.setText(cameraItem->name().c_str()); + + if(cameraItem->cameraType() == CameraItem::Perspective){ + perspectiveRadio.setChecked(true); + } else { + orthographicRadio.setChecked(true); + } + + Isometry3 T = self->getCurrentCameraPositionToDisplay(); + + setVectorElementSpins(T.translation(), positionSpins); + setVectorElementSpins(Vector3(SgCamera::direction(T)), directionSpins); + setVectorElementSpins(Vector3(SgCamera::up(T)), upSpins); + + auto camera = cameraItem->currentCamera(); + nearClipSpin.setValue(camera->nearClipDistance()); + farClipSpin.setValue(camera->farClipDistance()); + + fovSpin.setValue(degree(cameraItem->perspectiveCamera()->fieldOfView())); + + interactiveViewpointChangeCheck.setChecked( + cameraItem->isInteractiveViewpointChangeEnabled()); + + widgetConnections.unblock(); +} + + +Isometry3 CameraConfigDialog::getCurrentCameraPositionToDisplay() +{ + return impl->cameraItem->cameraTransform()->T(); +} + + +void CameraConfigDialog::setCameraPositionToDisplayToCameraTransform(const Isometry3& T) +{ + auto transform = impl->cameraItem->cameraTransform(); + transform->setPosition(T); + transform->notifyUpdate(); +} + + +void CameraConfigDialog::Impl::setVectorElementSpins(const Vector3& v, LengthSpinBox spins[]) +{ + for(int i=0; i < 3; ++i){ + spins[i].setMeterValue(v[i]); + } +} + + +void CameraConfigDialog::Impl::setVectorElementSpins(const Vector3& v, DoubleSpinBox spins[]) +{ + for(int i=0; i < 3; ++i){ + spins[i].setValue(v[i]); + } +} + + +void CameraConfigDialog::Impl::onNameEditingFinished(const std::string& name) +{ + cameraItem->setName(name); +} + + +void CameraConfigDialog::Impl::alignWithBuiltinCamera() +{ + auto sceneWidget = SceneView::lastFocusSceneView()->sceneWidget(); + + SgCamera* camera; + SgCamera* builtinCamera; + if(perspectiveRadio.isChecked()){ + auto persCamera = cameraItem->perspectiveCamera(); + auto builtinPersCamera = sceneWidget->builtinPerspectiveCamera(); + persCamera->setFieldOfView(builtinPersCamera->fieldOfView()); + camera = persCamera; + builtinCamera = builtinPersCamera; + } else { + auto orthoCamera = cameraItem->orthographicCamera(); + auto builtinOrthoCamera = sceneWidget->builtinOrthographicCamera(); + orthoCamera->setHeight(builtinOrthoCamera->height()); + camera = orthoCamera; + builtinCamera = builtinOrthoCamera; + } + camera->setNearClipDistance(builtinCamera->nearClipDistance()); + camera->setFarClipDistance(builtinCamera->farClipDistance()); + + auto transform = cameraItem->cameraTransform(); + transform->setPosition(sceneWidget->builtinCameraTransform()->position()); + + camera->notifyUpdate(); +} + + +void CameraConfigDialog::Impl::onCameraTypeRadioChanged(int type) +{ + cameraItem->setCameraType(static_cast(type)); + updateWidgetsWithCurrentCameraStates(); +} + + +void CameraConfigDialog::Impl::onCameraPositionSpinValueChanged() +{ + cameraConnection.block(); + + Vector3 eye(positionSpins[0].meterValue(), positionSpins[1].meterValue(), positionSpins[2].meterValue()); + Vector3 dir(directionSpins[0].value(), directionSpins[1].value(), directionSpins[2].value()); + Vector3 up(upSpins[0].value(), upSpins[1].value(), upSpins[2].value()); + + if(dir.norm() > 0.0 && up.norm() > 0.0){ + Isometry3 T = SgCamera::positionLookingFor(eye, dir, up); + self->setCameraPositionToDisplayToCameraTransform(T); + } + + cameraConnection.unblock(); + + cameraItem->notifyUpdate(); +} + + +void CameraConfigDialog::Impl::onFieldOfViewSpinValueChanged(double fov) +{ + auto camera = cameraItem->perspectiveCamera(); + camera->setFieldOfView(radian(fov)); + camera->notifyUpdate(); + cameraItem->notifyUpdate(); +} + + +void CameraConfigDialog::Impl::onClipDistanceSpinValueChanged() +{ + auto persCamera = cameraItem->perspectiveCamera(); + persCamera->setNearClipDistance(nearClipSpin.value()); + persCamera->setFarClipDistance(farClipSpin.value()); + persCamera->notifyUpdate(); + + auto orthoCamera = cameraItem->orthographicCamera(); + orthoCamera->setNearClipDistance(nearClipSpin.value()); + orthoCamera->setFarClipDistance(farClipSpin.value()); + orthoCamera->notifyUpdate(); + + cameraItem->notifyUpdate(); +} + + +void CameraConfigDialog::Impl::onInteractiveViewpointChangeToggled(bool on) +{ + cameraItem->setInteractiveViewpointChangeEnabled(on); + cameraItem->notifyUpdate(); +} + + +void CameraConfigDialog::hideEvent(QHideEvent* event) +{ + impl->setCameraItem(nullptr); + Dialog::hideEvent(event); +} diff --git a/src/Base/CameraConfigDialog.h b/src/Base/CameraConfigDialog.h new file mode 100644 index 000000000..3f871fefa --- /dev/null +++ b/src/Base/CameraConfigDialog.h @@ -0,0 +1,45 @@ +#ifndef CNOID_BASE_CAMERA_CONFIG_DIALOG_H +#define CNOID_BASE_CAMERA_CONFIG_DIALOG_H + +#include +#include +#include "exportdecl.h" + +class QVBoxLayout; + +namespace cnoid { + +class Item; +class CameraItem; + +class CNOID_EXPORT CameraConfigDialog : public Dialog +{ +public: + CameraConfigDialog(); + virtual ~CameraConfigDialog(); + + static CameraConfigDialog* instance(); + + CameraItem* showToCreateCameraItem(Item* parentItem); + virtual void showToConfigureCameraItem(CameraItem* cameraItem); + +protected: + QVBoxLayout* alignVBox(); + QVBoxLayout* optionVBox1(); + QVBoxLayout* optionVBox2(); + CameraItem* cameraItem(); + virtual void updateWidgetsWithCurrentCameraStates(); + virtual Isometry3 getCurrentCameraPositionToDisplay(); + virtual void setCameraPositionToDisplayToCameraTransform(const Isometry3& T); + +protected: + virtual void hideEvent(QHideEvent* event) override; + +private: + class Impl; + Impl* impl; +}; + +} + +#endif diff --git a/src/Base/CameraItem.cpp b/src/Base/CameraItem.cpp new file mode 100644 index 000000000..47b400eeb --- /dev/null +++ b/src/Base/CameraItem.cpp @@ -0,0 +1,479 @@ +#include "CameraItem.h" +#include "CameraConfigDialog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gettext.h" + +using namespace std; +using namespace cnoid; + + +namespace cnoid { + +class CameraItem::Impl +{ +public: + CameraItem* self; + InteractiveCameraTransformPtr cameraTransform; + SgPerspectiveCameraPtr persCamera; + SgOrthographicCameraPtr orthoCamera; + SgCameraPtr currentCamera; + SgUpdate update; + Selection cameraType; + + Impl(CameraItem* self, InteractiveCameraTransform* cameraTransform, bool initCameraPosition); + Impl(CameraItem* self, const Impl& org, InteractiveCameraTransform* newCameraTransform); + void doPutProperties(PutPropertyFunction& putProperty); + bool setClipDistances(double nearDistance, double farDistance); + bool setFieldOfView(double fov); + bool setCameraType(int index); +}; + +} + + +void CameraItem::initializeClass(ExtensionManager* ext) +{ + ext->itemManager() + .registerClass(N_("CameraItem")) + .addCreationPanel(); + + ItemTreeView::customizeContextMenu( + [](CameraItem* item, MenuManager& menuManager, ItemFunctionDispatcher menuFunction){ + menuManager.addItem(_("Activate camera"))->sigTriggered().connect( + [item](){ item->activateCameraInSceneView(SceneView::lastFocusSceneView()); }); + menuManager.addItem(_("Apply to built-in camera"))->sigTriggered().connect( + [item](){ + item->activateSceneViewBuiltinCameraWithCameraItemConfiguration( + SceneView::lastFocusSceneView()); + }); + menuManager.addItem(_("Camera configuration"))->sigTriggered().connect( + [item](){ item->showDialogToConfigureCamera(); }); + menuManager.addSeparator(); + menuFunction.dispatchAs(item); + }); +} + + +CameraItem* CameraItem::showDialogToCreateCameraItem(Item* parentItem) +{ + return CameraConfigDialog::instance()->showToCreateCameraItem(parentItem); +} + + +void CameraItem::showDialogToConfigureCamera() +{ + CameraConfigDialog::instance()->showToConfigureCameraItem(this); +} + + +CameraItem::CameraItem() + : Item("Camera") +{ + impl = new Impl(this, new InteractiveCameraTransform, true); +} + + +CameraItem::CameraItem(const char* name, InteractiveCameraTransform* cameraTransform) + : Item(name) +{ + impl = new Impl(this, cameraTransform, true); +} + + +CameraItem::Impl::Impl(CameraItem* self, InteractiveCameraTransform* cameraTransform, bool initCameraPosition) + : self(self), + cameraType(NumCameraTypes, CNOID_GETTEXT_DOMAIN_NAME), + cameraTransform(cameraTransform) +{ + cameraType.setSymbol(Perspective, N_("Perspective")); + cameraType.setSymbol(Orthographic, N_("Orthographic")); + cameraType.select(Perspective); + + if(initCameraPosition){ + cameraTransform->setPosition( + SceneView::instance()->sceneWidget()->builtinCameraTransform()->position()); + } else { + cameraTransform->setInteractiveViewpointChangeLocked(true); + } + + persCamera = new SgPerspectiveCamera; + persCamera->setName(self->name()); + cameraTransform->addChild(persCamera); + currentCamera = persCamera; + + orthoCamera = new SgOrthographicCamera; + orthoCamera->setName(self->name()); +} + + +CameraItem::CameraItem(const CameraItem& org) + : Item(org) +{ + impl = new Impl(this, *org.impl, new InteractiveCameraTransform); +} + + +CameraItem::CameraItem(const CameraItem& org, InteractiveCameraTransform* newCameraTransform) + : Item(org) +{ + impl = new Impl(this, *org.impl, newCameraTransform); +} + + +CameraItem::Impl::Impl(CameraItem* self, const Impl& org, InteractiveCameraTransform* newCameraTransform) + : Impl(self, newCameraTransform, false) +{ + cameraType = org.cameraType; + + cameraTransform->setPosition(org.cameraTransform->position()); + cameraTransform->setInteractiveViewpointChangeLocked( + org.cameraTransform->isInteractiveViewpointChangeLocked()); +} + + +CameraItem::~CameraItem() +{ + delete impl; +} + + +bool CameraItem::setName(const std::string& name_) +{ + if(name_ != name()){ + impl->persCamera->setName(name_); + impl->orthoCamera->setName(name_); + Item::setName(name_); + impl->persCamera->notifyUpdate(impl->update); + impl->orthoCamera->notifyUpdate(impl->update); + } + return true; +} + + +Item* CameraItem::doCloneItem(CloneMap* /* cloneMap */) const +{ + return new CameraItem(*this); +} + + +void CameraItem::setInteractiveViewpointChangeEnabled(bool on) +{ + impl->cameraTransform->setInteractiveViewpointChangeLocked(!on); +} + + +bool CameraItem::isInteractiveViewpointChangeEnabled() const +{ + return !impl->cameraTransform->isInteractiveViewpointChangeLocked(); +} + + +void CameraItem::setCameraType(CameraType type) +{ + impl->setCameraType(type); +} + + +/** + \todo Improve the scene widget so that the current camera path described in a string list + can be kept even if the actual camera node is changed, and simplify the following implementation. +*/ +bool CameraItem::Impl::setCameraType(int index) +{ + if(cameraType.selectedIndex() == index){ + return true; + } + + cameraType.select(index); + + SgCamera* cameraToRemove; + if(cameraType.is(CameraItem::Perspective)){ + currentCamera = persCamera; + cameraToRemove = orthoCamera; + }else if(cameraType.is(CameraItem::Orthographic)){ + currentCamera = orthoCamera; + cameraToRemove = persCamera; + } + + vector renderers; + for(auto sceneView : SceneView::instances()){ + renderers.push_back(sceneView->sceneWidget()->renderer()); + } + + cameraTransform->addChild(currentCamera, update); + for(auto renderer : renderers){ + if(renderer->currentCamera() == cameraToRemove){ + renderer->extractPreprocessedNodes(); + renderer->setCurrentCamera(currentCamera); + } + } + cameraTransform->removeChild(cameraToRemove, update); + for(auto renderer : renderers){ + renderer->extractPreprocessedNodes(); + } + + return true; +} + + +CameraItem::CameraType CameraItem::cameraType() const +{ + return static_cast(impl->cameraType.which()); +} + + +SgPerspectiveCamera* CameraItem::perspectiveCamera() +{ + return impl->persCamera; +} + + +SgOrthographicCamera* CameraItem::orthographicCamera() +{ + return impl->orthoCamera; +} + + +SgCamera* CameraItem::currentCamera() +{ + return impl->currentCamera; +} + + +SgPosTransform* CameraItem::cameraTransform() +{ + return impl->cameraTransform; +} + + +SgNode* CameraItem::getScene() +{ + return impl->cameraTransform; +} + + +double CameraItem::fieldOfView() const +{ + return impl->persCamera->fieldOfView(); +} + + +bool CameraItem::setFieldOfView(double fov) +{ + return impl->setFieldOfView(fov); +} + + +bool CameraItem::Impl::setFieldOfView(double fov) +{ + if(fov > 0.0 && fov < PI){ + persCamera->setFieldOfView(fov); + persCamera->notifyUpdate(update); + return true; + } + return false; +} + + +double CameraItem::nearClipDistance() const +{ + return impl->persCamera->nearClipDistance(); +} + + +bool CameraItem::setNearClipDistance(double nearDistance) +{ + if(nearDistance > 0.0){ + impl->setClipDistances(nearDistance, farClipDistance()); + return true; + } + return false; +} + + +double CameraItem::farClipDistance() const +{ + return impl->persCamera->farClipDistance(); +} + + +bool CameraItem::setFarClipDistance(double farDistance) +{ + if(farDistance > 0.0){ + impl->setClipDistances(nearClipDistance(), farDistance); + return true; + } + return false; +} + + +bool CameraItem::setClipDistances(double nearDistance, double farDistance) +{ + if(nearDistance > 0.0 && farDistance > 0.0){ + impl->setClipDistances(nearDistance, farDistance); + return true; + } + return false; +} + + +bool CameraItem::Impl::setClipDistances(double nearDistance, double farDistance) +{ + if(persCamera->nearClipDistance() != nearDistance || persCamera->farClipDistance() != farDistance){ + persCamera->setNearClipDistance(nearDistance); + persCamera->setFarClipDistance(farDistance); + orthoCamera->setNearClipDistance(nearDistance); + orthoCamera->setFarClipDistance(farDistance); + persCamera->notifyUpdate(update); + orthoCamera->notifyUpdate(update); + } + return true; +} + + +void CameraItem::activateCameraInSceneView(SceneView* sceneView, bool on) +{ + auto sceneWidget = sceneView->sceneWidget(); + auto renderer = sceneWidget->renderer(); + + if(on && !isChecked()){ + setChecked(true); + renderer->extractPreprocessedNodes(); + } + + auto sceneViewCamera = renderer->currentCamera(); + if(on){ + if(impl->currentCamera != sceneViewCamera){ + renderer->setCurrentCamera(impl->currentCamera); + } + } else { + if(impl->currentCamera == sceneViewCamera){ + if(impl->currentCamera == impl->persCamera){ + renderer->setCurrentCamera(sceneWidget->builtinPerspectiveCamera()); + } else { + renderer->setCurrentCamera(sceneWidget->builtinOrthographicCamera()); + } + } + } +} + + +void CameraItem::activateSceneViewBuiltinCameraWithCameraItemConfiguration(SceneView* sceneView) +{ + auto sceneWidget = SceneView::instance()->sceneWidget(); + auto builtinCameraTransform = sceneWidget->builtinCameraTransform(); + builtinCameraTransform->setPosition(impl->cameraTransform->position()); + + SgCamera* builtinCamera = nullptr; + if(impl->currentCamera == impl->persCamera){ + auto builtinPersCamera = sceneWidget->builtinPerspectiveCamera(); + builtinPersCamera->setFieldOfView(impl->persCamera->fieldOfView()); + builtinCamera = builtinPersCamera; + } else if(impl->currentCamera == impl->orthoCamera){ + auto builtinOrthoCamera = sceneWidget->builtinOrthographicCamera(); + builtinOrthoCamera->setHeight(impl->orthoCamera->height()); + builtinCamera = builtinOrthoCamera; + } + + if(builtinCamera){ + builtinCamera->setNearClipDistance(impl->currentCamera->nearClipDistance()); + builtinCamera->setFarClipDistance(impl->currentCamera->farClipDistance()); + sceneWidget->renderer()->setCurrentCamera(builtinCamera); + builtinCamera->notifyUpdate(); + } +} + + +void CameraItem::onDoubleClicked() +{ + activateSceneViewBuiltinCameraWithCameraItemConfiguration(SceneView::lastFocusSceneView()); +} + + +void CameraItem::doPutProperties(PutPropertyFunction& putProperty) +{ + impl->doPutProperties(putProperty); +} + + +void CameraItem::Impl::doPutProperties(PutPropertyFunction& putProperty) +{ + putProperty(_("Camera type"), cameraType, + [&](int index){ return setCameraType(index); }); + putProperty(_("Field Of View"), degree(self->fieldOfView()), + [&](double fov){ return setFieldOfView(radian(fov)); } ); + putProperty(_("Near clip distance"), self->nearClipDistance(), + [&](double distance){ return self->setNearClipDistance(distance); }); + putProperty(_("Far clip distance"), self->farClipDistance(), + [&](double distance){ return self->setFarClipDistance(distance); } ); + putProperty(_("Interactive viewpoint change"), self->isInteractiveViewpointChangeEnabled(), + [&](bool on){ self->setInteractiveViewpointChangeEnabled(on); return true; }); +} + + +bool CameraItem::store(Archive& archive) +{ + archive.write("camera_type", impl->cameraType.selectedSymbol()); + + auto transform = impl->cameraTransform; + Isometry3 T = transform->T(); + write(archive, "translation", T.translation()); + writeDegreeAngleAxis(archive, "rotation", AngleAxis(T.linear())); + + archive.write("field_of_view", impl->persCamera->fieldOfView()); + archive.write("near_clip_distance", impl->persCamera->nearClipDistance()); + archive.write("far_clip_distance", impl->persCamera->farClipDistance()); + archive.write("interactive_viewpoint_change", isInteractiveViewpointChangeEnabled()); + + return true; +} + + +bool CameraItem::restore(const Archive& archive) +{ + string symbol; + if(archive.read({ "camera_type", "cameraType" }, symbol)){ + int index = impl->cameraType.index(symbol); + impl->setCameraType(index); + } + + auto transform = impl->cameraTransform; + Isometry3 T = Isometry3::Identity(); + Vector3 p; + if(read(archive, "translation", p)){ + T.translation() = p; + } + AngleAxis aa; + if(readDegreeAngleAxis(archive, "rotation", aa)){ + T.linear() = aa.toRotationMatrix(); + } + transform->setPosition(T); + + impl->setFieldOfView(archive.get({ "field_of_view", "fieldOfView" }, impl->persCamera->fieldOfView())); + + double nearDistance = + archive.get({ "near_clip_distance", "nearClipDistance" }, impl->persCamera->nearClipDistance()); + double farDistance = + archive.get({ "far_clip_distance", "farClipDistance" }, impl->persCamera->farClipDistance()); + impl->setClipDistances(nearDistance, farDistance); + + bool on; + if(archive.read("interactive_viewpoint_change", on)){ + setInteractiveViewpointChangeEnabled(on); + } + + transform->notifyUpdate(); + + return true; +} diff --git a/src/Base/CameraItem.h b/src/Base/CameraItem.h new file mode 100644 index 000000000..a6f7b27d1 --- /dev/null +++ b/src/Base/CameraItem.h @@ -0,0 +1,80 @@ +#ifndef CNOID_BASE_CAMERA_ITEM_H +#define CNOID_BASE_CAMERA_ITEM_H + +#include +#include +#include "exportdecl.h" + +namespace cnoid { + +class SgCamera; +class SgPerspectiveCamera; +class SgOrthographicCamera; +class SgPosTransform; +class InteractiveCameraTransform; +class SceneView; + +class CNOID_EXPORT CameraItem : public Item, public RenderableItem +{ +public: + static void initializeClass(ExtensionManager* ext); + static CameraItem* showDialogToCreateCameraItem(Item* parentItem); + + enum CameraType { + Perspective, + Orthographic, + NumCameraTypes, + }; + + CameraItem(); + virtual ~CameraItem(); + + virtual bool setName(const std::string& name) override; + + void setInteractiveViewpointChangeEnabled(bool on); + bool isInteractiveViewpointChangeEnabled() const; + void setCameraType(CameraType type); + CameraType cameraType() const; + SgPerspectiveCamera* perspectiveCamera(); + SgOrthographicCamera* orthographicCamera(); + SgCamera* currentCamera(); + SgPosTransform* cameraTransform(); + + double fieldOfView() const; + bool setFieldOfView(double fov); + + double nearClipDistance() const; + bool setNearClipDistance(double distance); + double farClipDistance() const; + bool setFarClipDistance(double distance); + bool setClipDistances(double nearDistance, double farDistance); + + virtual void showDialogToConfigureCamera(); + + void activateCameraInSceneView(SceneView* sceneView, bool on = true); + void activateSceneViewBuiltinCameraWithCameraItemConfiguration(SceneView* sceneView); + + // RenderableItem + virtual SgNode* getScene() override; + +protected: + CameraItem(const char* name, InteractiveCameraTransform* cameraTransform); + CameraItem(const CameraItem& org); + CameraItem(const CameraItem& org, InteractiveCameraTransform* newCameraTransform); + + virtual Item* doCloneItem(CloneMap* cloneMap) const override; + virtual void onDoubleClicked() override; + virtual void doPutProperties(PutPropertyFunction& putProperty) override; + virtual bool store(Archive& archive) override; + virtual bool restore(const Archive& archive) override; + +private: + class Impl; + Impl* impl; +}; + +typedef ref_ptr CameraItemPtr; + +} + +#endif From e0ffd8ea061b4becc6b07feb7b3ccde065181c65 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 26 Jul 2024 14:08:34 +0900 Subject: [PATCH 09/73] Add the isometric view button to SceneBar --- src/Base/Base.qrc | 1 + src/Base/SceneBar.cpp | 104 ++++++++++++++++++-------------- src/Base/icon/isometricview.svg | 60 ++++++++++++++++++ 3 files changed, 121 insertions(+), 44 deletions(-) create mode 100644 src/Base/icon/isometricview.svg diff --git a/src/Base/Base.qrc b/src/Base/Base.qrc index fd73447c2..b07be9cc3 100644 --- a/src/Base/Base.qrc +++ b/src/Base/Base.qrc @@ -36,6 +36,7 @@ icon/rightview.svg icon/topview.svg icon/bottomview.svg + icon/isometricview.svg icon/global.svg diff --git a/src/Base/SceneBar.cpp b/src/Base/SceneBar.cpp index 4d9374ada..3b76dfc79 100644 --- a/src/Base/SceneBar.cpp +++ b/src/Base/SceneBar.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "gettext.h" using namespace std; @@ -41,7 +42,8 @@ enum ElementId { TopViewButton = 72, BottomViewButton = 73, RightViewButton = 74, - LeftViewButton = 75 + LeftViewButton = 75, + IsometricViewButton = 76 }; } @@ -140,15 +142,15 @@ void SceneBar::Impl::initialize() editModeToggle = self->addToggleButton(":/Base/icon/sceneedit.svg", EditModeToggle); editModeToggle->setToolTip(_("Switch to the edit mode")); - editModeToggle->sigToggled().connect([&](bool on){ onEditModeButtonToggled(on); }); + editModeToggle->sigToggled().connect([this](bool on){ onEditModeButtonToggled(on); }); customModeButtonGroup.setExclusive(false); customModeButtonGroup.sigButtonToggled().connect( - [&](int mode, bool on){ onCustomModeButtonToggled(mode, on); }); + [this](int mode, bool on){ onCustomModeButtonToggled(mode, on); }); firstPersonModeToggle = self->addToggleButton(":/Base/icon/walkthrough.svg", FirstPersonModeToggle); firstPersonModeToggle->setToolTip(_("First-person viewpoint control mode")); - firstPersonModeToggle->sigToggled().connect([&](bool on){ onFirstPersonModeButtonToggled(on); }); + firstPersonModeToggle->sigToggled().connect([this](bool on){ onFirstPersonModeButtonToggled(on); }); cameraCombo = new ComboBox; @@ -167,13 +169,13 @@ void SceneBar::Impl::initialize() cameraCombo->setToolTip(_("Projection method / camera selection")); cameraCombo->sigCurrentIndexChanged().connect( - [&](int index){ onCameraComboCurrentIndexChanged(index); }); + [this](int index){ onCameraComboCurrentIndexChanged(index); }); self->addWidget(cameraCombo, CameraCombo); auto fittingButton = self->addButton(":/Base/icon/viewfitting.svg", FittingButton); fittingButton->setToolTip(_("Move the camera to look at the objects")); fittingButton->sigClicked().connect( - [&](){ + [this]{ auto sceneWidget = currentSceneView->sceneWidget(); sceneWidget->viewAll(); sceneWidget->setViewpointOperationMode(SceneWidget::ThirdPersonMode); @@ -181,7 +183,7 @@ void SceneBar::Impl::initialize() vertexToggle = self->addToggleButton(":/Base/icon/vertex.svg", VertexToggle); vertexToggle->setToolTip(_("Vertex rendering")); - vertexToggle->sigToggled().connect([&](bool){ onPolygonModeButtonToggled(); }); + vertexToggle->sigToggled().connect([this](bool){ onPolygonModeButtonToggled(); }); auto wireframeToggle = self->addToggleButton(":/Base/icon/wireframe.svg", WireframeToggle); wireframeToggle->setToolTip(_("Wireframe rendering")); @@ -197,38 +199,38 @@ void SceneBar::Impl::initialize() polygonModeGroup.addButton(solidPolygonToggle, 2); polygonModeGroup.sigButtonToggled().connect( - [&](int, bool on){ + [this](int, bool on){ if(on){ onPolygonModeButtonToggled(); } }); highlightToggle = self->addToggleButton(":/Base/icon/highlight.svg", HighlightToggle); highlightToggle->setToolTip(_("Highlight selected objects")); - highlightToggle->sigToggled().connect([&](bool on){ onHighlightingToggled(on); }); + highlightToggle->sigToggled().connect([this](bool on){ onHighlightingToggled(on); }); visualModelToggle = self->addToggleButton(":/Base/icon/visualshape.svg", VisualModelToggle); visualModelToggle->setToolTip(_("Show visual models")); visualModelToggle->setChecked(true); - visualModelToggle->sigToggled().connect([&](bool){ updateCollisionModelVisibility(); }); + visualModelToggle->sigToggled().connect([this](bool){ updateCollisionModelVisibility(); }); modelTypeFlipButton = self->addButton(":/Base/icon/shapeflip.svg", ModelTypeFlipButton); modelTypeFlipButton->setToolTip(_("Flip active model types")); - modelTypeFlipButton->sigClicked().connect([&](){ flipVisibleModels(); }); + modelTypeFlipButton->sigClicked().connect([this](){ flipVisibleModels(); }); collisionModelToggle = self->addToggleButton(":/Base/icon/collisionshape.svg", CollisionModelToggle); collisionModelToggle->setToolTip(_("Show the collision detection models")); - collisionModelToggle->sigToggled().connect([&](bool){ updateCollisionModelVisibility();}); + collisionModelToggle->sigToggled().connect([this](bool){ updateCollisionModelVisibility();}); collisionLineToggle = self->addToggleButton(":/Base/icon/collisionlines.svg", CollisionLineToggle); collisionLineToggle->setToolTip(_("Toggle the collision line visibility")); - collisionLineToggle->sigToggled().connect([&](bool on){ onCollisionLineButtonToggled(on); }); + collisionLineToggle->sigToggled().connect([this](bool on){ onCollisionLineButtonToggled(on); }); auto configButton = self->addButton(":/Base/icon/setup.svg", ConfigButton); configButton->setToolTip(_("Show the config dialog")); - configButton->sigClicked().connect([&](){ currentSceneView->sceneViewConfig()->showConfigDialog(); }); + configButton->sigClicked().connect([this]{ currentSceneView->sceneViewConfig()->showConfigDialog(); }); sceneViewFocusConnection = SceneView::sigLastFocusSceneViewChanged().connect( - [&](SceneView* view){ setCurrentSceneView(view); }); + [this](SceneView* view){ setCurrentSceneView(view); }); setCurrentSceneView(SceneView::instance()); @@ -543,28 +545,32 @@ void SceneBar::Impl::enableViewButtonSet() button = self->addButton(":/Base/icon/frontview.svg", FrontViewButton); button->setToolTip(_("Front view")); - button->sigClicked().connect([&](){ onViewButtonClicked(FrontViewButton); }); + button->sigClicked().connect([this]{ onViewButtonClicked(FrontViewButton); }); button = self->addButton(":/Base/icon/backview.svg", BackViewButton); button->setToolTip(_("Back view")); - button->sigClicked().connect([&](){ onViewButtonClicked(BackViewButton); }); + button->sigClicked().connect([this]{ onViewButtonClicked(BackViewButton); }); button = self->addButton(":/Base/icon/topview.svg", TopViewButton); button->setToolTip(_("Top view")); - button->sigClicked().connect([&](){ onViewButtonClicked(TopViewButton); }); + button->sigClicked().connect([this]{ onViewButtonClicked(TopViewButton); }); button = self->addButton(":/Base/icon/bottomview.svg", BottomViewButton); button->setToolTip(_("Bottom view")); - button->sigClicked().connect([&](){ onViewButtonClicked(BottomViewButton); }); + button->sigClicked().connect([this]{ onViewButtonClicked(BottomViewButton); }); button = self->addButton(":/Base/icon/rightview.svg", RightViewButton); button->setToolTip(_("Right view")); - button->sigClicked().connect([&](){ onViewButtonClicked(RightViewButton); }); + button->sigClicked().connect([this]{ onViewButtonClicked(RightViewButton); }); button = self->addButton(":/Base/icon/leftview.svg", LeftViewButton); button->setToolTip(_("Left view")); - button->sigClicked().connect([&](){ onViewButtonClicked(LeftViewButton); }); + button->sigClicked().connect([this]{ onViewButtonClicked(LeftViewButton); }); + button = self->addButton(":/Base/icon/isometricview.svg", IsometricViewButton); + button->setToolTip(_("Isometric view")); + button->sigClicked().connect([this]{ onViewButtonClicked(IsometricViewButton); }); + isViewButtonSetEnabled = true; } @@ -572,32 +578,42 @@ void SceneBar::Impl::enableViewButtonSet() void SceneBar::Impl::onViewButtonClicked(ElementId button) { if(currentSceneView){ + AngleAxis aa; + switch(button){ + case FrontViewButton: + aa = AngleAxis(M_PI_2, Vector3::UnitZ()) * AngleAxis(M_PI_2, Vector3::UnitX()); + break; + case BackViewButton: + aa = AngleAxis(-M_PI_2, Vector3::UnitZ()) * AngleAxis(M_PI_2, Vector3::UnitX()); + break; + case TopViewButton: + aa = AngleAxis(-M_PI_2, Vector3::UnitZ()); + break; + case BottomViewButton: + aa = AngleAxis(M_PI_2, Vector3::UnitZ()) * AngleAxis(M_PI, Vector3::UnitX()); + break; + case RightViewButton: + aa = AngleAxis(M_PI, Vector3::UnitZ()) * AngleAxis(M_PI_2, Vector3::UnitX()); + break; + case LeftViewButton: + aa = AngleAxis(M_PI_2, Vector3::UnitX()); + break; + case IsometricViewButton: + aa = + AngleAxis(M_PI_4, Vector3::UnitZ()) * AngleAxis(radian(-35.264), Vector3::UnitY()) * + AngleAxis(M_PI_2, Vector3::UnitZ()) * AngleAxis(M_PI_2, Vector3::UnitX()); + break; + default: + break; + } auto sceneWidget = currentSceneView->sceneWidget(); if(auto transform = sceneWidget->activeInteractiveCameraTransform()){ - switch(button){ - case FrontViewButton: - transform->setRotation(AngleAxis(M_PI_2, Vector3::UnitZ()) * AngleAxis(M_PI_2, Vector3::UnitX())); - break; - case BackViewButton: - transform->setRotation(AngleAxis(-M_PI_2, Vector3::UnitZ()) * AngleAxis(M_PI_2, Vector3::UnitX())); - break; - case TopViewButton: - transform->setRotation(AngleAxis(-M_PI_2, Vector3::UnitZ())); - break; - case BottomViewButton: - transform->setRotation(AngleAxis(M_PI_2, Vector3::UnitZ()) * AngleAxis(M_PI, Vector3::UnitX())); - break; - case RightViewButton: - transform->setRotation(AngleAxis(M_PI, Vector3::UnitZ()) * AngleAxis(M_PI_2, Vector3::UnitX())); - break; - case LeftViewButton: - transform->setRotation(AngleAxis(M_PI_2, Vector3::UnitX())); - break; - default: - break; - } - sceneWidget->viewAll(); + transform->setRotation(aa); + } else { + sceneWidget->renderer()->setCurrentCamera(sceneWidget->builtinOrthographicCamera()); + sceneWidget->builtinCameraTransform()->setRotation(aa); } + sceneWidget->viewAll(); } } diff --git a/src/Base/icon/isometricview.svg b/src/Base/icon/isometricview.svg new file mode 100644 index 000000000..5ed6b23a5 --- /dev/null +++ b/src/Base/icon/isometricview.svg @@ -0,0 +1,60 @@ + +image/svg+xml + + + + + From edf3ee8bb6dc96647c1146e7e576912fe127eb8b Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 23 Jul 2024 20:10:22 +0900 Subject: [PATCH 10/73] Update Japanese translations for the Base module --- src/Base/po/ja.po | 122 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 25 deletions(-) diff --git a/src/Base/po/ja.po b/src/Base/po/ja.po index 67fb7a794..d08cc10a4 100644 --- a/src/Base/po/ja.po +++ b/src/Base/po/ja.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Choreonoid\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-14 22:18+0900\n" +"POT-Creation-Date: 2024-07-26 11:55+0900\n" "PO-Revision-Date: 2021-10-25 12:00+0900\n" "Language: ja\n" "MIME-Version: 1.0\n" @@ -45,6 +45,84 @@ msgstr "" "アプリケーション設定ファイル \"{0}\" を読み込むことができません.\n" "{1}" +msgid "Name:" +msgstr "名前:" + +msgid "Align with the builtin camera" +msgstr "組み込みカメラに合わせる" + +msgid "Camera type:" +msgstr "カメラタイプ:" + +msgid "Perspective" +msgstr "透視投影" + +msgid "Orthographic" +msgstr "並行投影" + +msgid "Position:" +msgstr "位置:" + +msgid "Look-at:" +msgstr "視線方向:" + +msgid "Up vector:" +msgstr "上方向:" + +msgid "Field of View:" +msgstr "視野角:" + +msgid "[deg]" +msgstr "" + +msgid "Near Clip:" +msgstr "近方クリップ:" + +msgid "Far Clip:" +msgstr "遠方クリップ:" + +msgid "Interactive viewpoint change" +msgstr "インタラクティブな視点変更" + +msgid "Activate in the scene view" +msgstr "シーンビューで有効化" + +msgid "&OK" +msgstr "&OK" + +msgid "Camera Creation" +msgstr "カメラの作成" + +msgid "Camera" +msgstr "カメラ" + +msgid "Camera Configuration" +msgstr "カメラの設定" + +msgid "CameraItem" +msgstr "カメラアイテム" + +msgid "Activate camera" +msgstr "このカメラを使用" + +msgid "Apply to built-in camera" +msgstr "組み込みカメラに適用" + +msgid "Camera configuration" +msgstr "カメラの設定" + +msgid "Camera type" +msgstr "カメラタイプ" + +msgid "Field Of View" +msgstr "視野角" + +msgid "Near clip distance" +msgstr "近方クリップ距離" + +msgid "Far clip distance" +msgstr "近方クリップ距離" + msgid "CaptureBar" msgstr "キャプチャバー" @@ -144,9 +222,6 @@ msgstr "距離測定" msgid "Object %1" msgstr "対象%1" -msgid "Position:" -msgstr "位置:" - msgid "Pick" msgstr "ピック" @@ -186,9 +261,6 @@ msgstr "オーバーレイ" msgid "Create measurement item" msgstr "計測アイテムの作成" -msgid "Name:" -msgstr "名前" - msgid "&Measure" msgstr "測定" @@ -208,6 +280,12 @@ msgstr "距離測定アイテム \"{0}\" はプロジェクトから削除され msgid "The distance measurement cannot be started since the target items are not specified." msgstr "対象アイテムが指定されていないので距離測定を開始できません." +msgid "[m]" +msgstr "" + +msgid "[mm]" +msgstr "" + msgid "Distance Marker Color" msgstr "距離マーカの色" @@ -1219,6 +1297,9 @@ msgstr "パス" msgid "&Apply" msgstr "適用(&A)" +msgid "Loading {0} failed.\n" +msgstr "{0}の読み込みに失敗しました.\n" + msgid "{0}-plugin cannot be initialized because required plugin(s) {1} are not found.\n" msgstr "必要なプラグイン{1}が見つからないため,{0}プラグインの初期化ができません.\n" @@ -1620,6 +1701,9 @@ msgstr "右面ビュー" msgid "Left view" msgstr "左面ビュー" +msgid "Isometric view" +msgstr "等角投影ビュー" + msgid "Scene" msgstr "シーン" @@ -1689,15 +1773,9 @@ msgstr "テクスチャ" msgid "Fog" msgstr "フォグ" -msgid "Background color" -msgstr "背景色" - msgid "Background Color" msgstr "背景色" -msgid "Default color" -msgstr "デフォルト色" - msgid "Default Color" msgstr "デフォルト色" @@ -1728,9 +1806,6 @@ msgstr "シーンビュー" msgid "Configuration of {0}" msgstr "{0}の設定" -msgid "Camera" -msgstr "カメラ" - msgid "Lighting" msgstr "ライティング" @@ -1746,12 +1821,6 @@ msgstr "デバッグ" msgid "OpengGL image buffer for picking" msgstr "ピッキング用OpenGL画像バッファ" -msgid "Perspective" -msgstr "透視投影" - -msgid "Orthographic" -msgstr "並行投影" - msgid "OpenGL initialization failed." msgstr "OpenGLの初期化に失敗しました." @@ -1836,12 +1905,18 @@ msgstr "遠方" msgid "Vertical axis" msgstr "垂直軸" +msgid "Background color" +msgstr "背景色" + msgid "Span" msgstr "長さ" msgid "Interval" msgstr "間隔" +msgid "Default color" +msgstr "デフォルト色" + msgid "ScriptBar" msgstr "スクリプトバー" @@ -1988,9 +2063,6 @@ msgstr "進行中の更新に同期" msgid "Automatically expand the time range" msgstr "時間範囲の自動拡張" -msgid "&OK" -msgstr "&OK" - msgid "Stop animation" msgstr "アニメーションの停止" From 09f2c2d9df69c6642951d345a6e571be2ddd5a34 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 23 Jul 2024 22:31:32 +0900 Subject: [PATCH 11/73] Fix BodySyncCameraItem and BodySyncCameraConfigDialog to inherit CameraItem and CameraConfigDialog, respectively --- src/BodyPlugin/BodySyncCameraConfigDialog.cpp | 356 ++---------------- src/BodyPlugin/BodySyncCameraConfigDialog.h | 12 +- src/BodyPlugin/BodySyncCameraItem.cpp | 319 ++-------------- src/BodyPlugin/BodySyncCameraItem.h | 68 +--- 4 files changed, 83 insertions(+), 672 deletions(-) diff --git a/src/BodyPlugin/BodySyncCameraConfigDialog.cpp b/src/BodyPlugin/BodySyncCameraConfigDialog.cpp index b39790872..8e589aea5 100644 --- a/src/BodyPlugin/BodySyncCameraConfigDialog.cpp +++ b/src/BodyPlugin/BodySyncCameraConfigDialog.cpp @@ -30,40 +30,15 @@ class BodySyncCameraConfigDialog::Impl public: BodySyncCameraConfigDialog* self; BodySyncCameraItemPtr cameraItem; - LineEdit nameEdit; ButtonGroup coordinateRadioGroup; RadioButton globalRadio; RadioButton localRadio; - LengthSpinBox positionSpins[3]; - DoubleSpinBox directionSpins[3]; - DoubleSpinBox upSpins[3]; - DoubleSpinBox nearClipSpin; - DoubleSpinBox farClipSpin; - DoubleSpinBox fovSpin; CheckBox parallelTrackingCheck; - CheckBox interactiveViewpointChangeCheck; ConnectionSet widgetConnections; - CheckBox activationInSceneViewCheck; - Connection activationCheckConnection; - - ScopedConnection cameraConnection; - Impl(BodySyncCameraConfigDialog* self); - void showToConfigureCameraItem(BodySyncCameraItem* cameraItem); - void setCameraItem(BodySyncCameraItem* cameraItem); - void updateWidgetsWithCurrentCameraStates(); - void setVectorElementSpins(const Vector3& v, LengthSpinBox spins[]); - void setVectorElementSpins(const Vector3& v, DoubleSpinBox spins[]); - void onNameEditingFinished(const std::string& name); - void alignWithBuiltinCamera(); - void alignWithTargetOrigin(); - void onCameraPositionSpinValueChanged(); - void onFieldOfViewSpinValueChanged(double fov); - void onClipDistanceSpinValueChanged(); + void alignWithTargetOrigin(); void onParallelTrackingModeToggled(bool on); - void onInteractiveViewpointChangeToggled(bool on); - void onSceneViewActivationChecked(bool on); }; } @@ -80,42 +55,24 @@ BodySyncCameraConfigDialog* BodySyncCameraConfigDialog::instance() } + + + BodySyncCameraConfigDialog::BodySyncCameraConfigDialog() { impl = new Impl(this); } -BodySyncCameraConfigDialog::Impl::Impl(BodySyncCameraConfigDialog* self) - : self(self) +BodySyncCameraConfigDialog::Impl::Impl(BodySyncCameraConfigDialog* self_) + : self(self_) { - auto vbox = new QVBoxLayout; - self->setLayout(vbox); - - auto hbox = new QHBoxLayout; - hbox->addWidget(new QLabel(_("Name:"))); - widgetConnections.add( - nameEdit.sigEditingFinished().connect( - [&](){ onNameEditingFinished(nameEdit.text().toStdString()); })); - hbox->addWidget(&nameEdit); - vbox->addLayout(hbox); - - hbox = new QHBoxLayout; - auto alignVBox = new QVBoxLayout; - auto alignButton1 = new PushButton(_("Align with the builtin camera")); - alignButton1->sigClicked().connect( - [&](){ alignWithBuiltinCamera(); }); - alignVBox->addWidget(alignButton1); - auto alignButton2 = new PushButton(_("Align with the target origin")); - alignButton2->sigClicked().connect( + auto alignButton = new PushButton(_("Align with the target origin")); + alignButton->sigClicked().connect( [&](){ alignWithTargetOrigin(); }); - alignVBox->addWidget(alignButton2); - hbox->addStretch(); - hbox->addLayout(alignVBox); - hbox->addStretch(); - vbox->addLayout(hbox); + self->alignVBox()->addWidget(alignButton); - hbox = new QHBoxLayout; + auto hbox = new QHBoxLayout; hbox->addWidget(new QLabel(_("Coordinate System:"))); globalRadio.setText(_("Global")); hbox->addWidget(&globalRadio); @@ -123,108 +80,20 @@ BodySyncCameraConfigDialog::Impl::Impl(BodySyncCameraConfigDialog* self) localRadio.setChecked(true); hbox->addWidget(&localRadio); hbox->addStretch(); - vbox->addLayout(hbox); + self->optionVBox1()->addLayout(hbox); coordinateRadioGroup.addButton(&globalRadio, 0); coordinateRadioGroup.addButton(&localRadio, 1); coordinateRadioGroup.sigButtonToggled().connect( [this](int id, bool checked){ - if(checked) updateWidgetsWithCurrentCameraStates(); + if(checked) self->updateWidgetsWithCurrentCameraStates(); }); - auto grid = new QGridLayout; - grid->addWidget(new QLabel(_("Position:")), 0, 0); - grid->addWidget(new QLabel(_("Direction:")), 1, 0); - grid->addWidget(new QLabel(_("Up:")), 2, 0); - - DoubleSpinBox* spins[3][3]; - for(int i=0; i < 3; ++i){ - auto spin = &positionSpins[i]; - spin->setMeterRange(-9.999, 9.999); - spin->setMeterSingleStep(0.001); - spins[0][i] = spin; - spins[1][i] = &directionSpins[i]; - spins[2][i] = &upSpins[i]; - } - for(int i=1; i < 3; ++i){ - for(int j=0; j < 3; ++j){ - auto spin = spins[i][j]; - spin->setDecimals(3); - spin->setRange(-9.999, 9.999); - spin->setSingleStep(0.001); - } - } - const char* xyzLabels[] = { "X", "Y", "Z" }; - for(int i=0; i < 3; ++i){ - for(int j=0; j < 3; ++j){ - grid->addWidget(new QLabel(xyzLabels[j]), i, j * 2 + 1); - auto spin = spins[i][j]; - widgetConnections.add( - spin->sigValueChanged().connect( - [this](double){ onCameraPositionSpinValueChanged(); })); - grid->addWidget(spin, i, j * 2 + 2); - } - } - vbox->addLayout(grid); - - hbox = new QHBoxLayout; - hbox->addWidget(new QLabel(_("Field of View:"))); - fovSpin.setDecimals(0); - fovSpin.setRange(1.0, 179.0); - widgetConnections.add( - fovSpin.sigValueChanged().connect( - [this](double value){ onFieldOfViewSpinValueChanged(value); })); - hbox->addWidget(&fovSpin); - hbox->addWidget(new QLabel(_("[deg]"))); - hbox->addStretch(); - vbox->addLayout(hbox); - - hbox = new QHBoxLayout; - hbox->addWidget(new QLabel(_("Near Clip:"))); - nearClipSpin.setDecimals(3); - nearClipSpin.setRange(0.001, 9.999); - nearClipSpin.setSingleStep(0.001); - widgetConnections.add( - nearClipSpin.sigValueChanged().connect( - [this](double){ onClipDistanceSpinValueChanged(); })); - hbox->addWidget(&nearClipSpin); - - hbox->addWidget(new QLabel(_("Far Clip:"))); - farClipSpin.setDecimals(1); - farClipSpin.setRange(0.1, 999.9); - farClipSpin.setSingleStep(1.0); - widgetConnections.add( - farClipSpin.sigValueChanged().connect( - [this](double){ onClipDistanceSpinValueChanged(); })); - hbox->addWidget(&farClipSpin); - hbox->addStretch(); - vbox->addLayout(hbox); - parallelTrackingCheck.setText(_("Parallel tracking")); widgetConnections.add( parallelTrackingCheck.sigToggled().connect( [this](bool on){ onParallelTrackingModeToggled(on); })); - vbox->addWidget(¶llelTrackingCheck); - - interactiveViewpointChangeCheck.setText(_("Interactive viewpoint change")); - widgetConnections.add( - interactiveViewpointChangeCheck.sigToggled().connect( - [this](bool on){ onInteractiveViewpointChangeToggled(on); })); - vbox->addWidget(&interactiveViewpointChangeCheck); - - activationInSceneViewCheck.setText(_("Activate in the scene view")); - activationCheckConnection = - activationInSceneViewCheck.sigToggled().connect( - [this](bool on){ onSceneViewActivationChecked(on); }); - vbox->addWidget(&activationInSceneViewCheck); - - auto buttonBox = new QDialogButtonBox(self); - auto okButton = new PushButton(_("&OK")); - buttonBox->addButton(okButton, QDialogButtonBox::AcceptRole); - connect(buttonBox, &QDialogButtonBox::accepted, [this](){ this->self->accept(); }); - vbox->addWidget(buttonBox); - - self->setWindowPositionKeepingMode(true); + self->optionVBox2()->addWidget(¶llelTrackingCheck); } @@ -255,118 +124,57 @@ BodySyncCameraItem* BodySyncCameraConfigDialog::showToCreateCameraItem(BodyItem* bodyItem->addChildItem(cameraItem); - impl->showToConfigureCameraItem(cameraItem); + showToConfigureCameraItem(cameraItem); return cameraItem; } -void BodySyncCameraConfigDialog::showToConfigureCameraItem(BodySyncCameraItem* cameraItem) -{ - setWindowTitle(_("Camera Configuration")); - impl->showToConfigureCameraItem(cameraItem); -} - - -void BodySyncCameraConfigDialog::Impl::showToConfigureCameraItem(BodySyncCameraItem* cameraItem) -{ - setCameraItem(cameraItem); - self->show(); -} - - -void BodySyncCameraConfigDialog::Impl::setCameraItem(BodySyncCameraItem* cameraItem) +void BodySyncCameraConfigDialog::showToConfigureCameraItem(CameraItem* cameraItem) { - cameraConnection.disconnect(); - this->cameraItem = cameraItem; - - activationCheckConnection.block(); - - if(!cameraItem){ - activationInSceneViewCheck.setChecked(false); - - } else { - auto currentCamera = SceneView::instance()->sceneWidget()->renderer()->currentCamera(); - activationInSceneViewCheck.setChecked(cameraItem->perspectiveCamera() == currentCamera); - - cameraConnection = - cameraItem->cameraTransform()->sigUpdated().connect( - [this](const SgUpdate&){ updateWidgetsWithCurrentCameraStates(); }); - - updateWidgetsWithCurrentCameraStates(); + impl->cameraItem = dynamic_cast(cameraItem); + if(impl->cameraItem){ + CameraConfigDialog::showToConfigureCameraItem(cameraItem); } - - activationCheckConnection.unblock(); } -void BodySyncCameraConfigDialog::Impl::updateWidgetsWithCurrentCameraStates() +void BodySyncCameraConfigDialog::updateWidgetsWithCurrentCameraStates() { - widgetConnections.block(); - - nameEdit.setText(cameraItem->name().c_str()); - - Isometry3 T; - if(globalRadio.isChecked()){ - T = cameraItem->cameraTransform()->T(); - } else { - T = cameraItem->relativeCameraPosition(); - } - setVectorElementSpins(T.translation(), positionSpins); - setVectorElementSpins(Vector3(SgCamera::direction(T)), directionSpins); - setVectorElementSpins(Vector3(SgCamera::up(T)), upSpins); + impl->cameraItem->updateRelativeCameraPosition(); - auto camera = cameraItem->perspectiveCamera(); - nearClipSpin.setValue(camera->nearClipDistance()); - farClipSpin.setValue(camera->farClipDistance()); - fovSpin.setValue(degree(camera->fieldOfView())); - - parallelTrackingCheck.setChecked(cameraItem->isParallelTrackingMode()); - - interactiveViewpointChangeCheck.setChecked( - cameraItem->isInteractiveViewpointChangeEnabled()); + impl->widgetConnections.block(); + impl->parallelTrackingCheck.setChecked(impl->cameraItem->isParallelTrackingMode()); + impl->widgetConnections.unblock(); - widgetConnections.unblock(); + CameraConfigDialog::updateWidgetsWithCurrentCameraStates(); + } -void BodySyncCameraConfigDialog::Impl::setVectorElementSpins(const Vector3& v, LengthSpinBox spins[]) +Isometry3 BodySyncCameraConfigDialog::getCurrentCameraPositionToDisplay() { - for(int i=0; i < 3; ++i){ - spins[i].setMeterValue(v[i]); + Isometry3 T; + if(impl->globalRadio.isChecked()){ + T = impl->cameraItem->cameraTransform()->T(); + } else { + T = impl->cameraItem->relativeCameraPosition(); } + return T; } -void BodySyncCameraConfigDialog::Impl::setVectorElementSpins(const Vector3& v, DoubleSpinBox spins[]) +void BodySyncCameraConfigDialog::setCameraPositionToDisplayToCameraTransform(const Isometry3& T) { - for(int i=0; i < 3; ++i){ - spins[i].setValue(v[i]); + Isometry3 Tg; + if(impl->localRadio.isChecked()){ + Tg = impl->cameraItem->targetLinkPosition() * T; + } else { + Tg = T; } -} - - -void BodySyncCameraConfigDialog::Impl::onNameEditingFinished(const std::string& name) -{ - cameraItem->setName(name); -} - - -void BodySyncCameraConfigDialog::Impl::alignWithBuiltinCamera() -{ - auto sceneWidget = SceneView::instance()->sceneWidget(); - - auto builtin = sceneWidget->builtinPerspectiveCamera(); - auto camera = cameraItem->perspectiveCamera(); - camera->setNearClipDistance(builtin->nearClipDistance()); - camera->setFarClipDistance(builtin->farClipDistance()); - camera->setFieldOfView(builtin->fieldOfView()); - - auto transform = cameraItem->cameraTransform(); - transform->setPosition(sceneWidget->builtinCameraTransform()->position()); - - camera->notifyUpdate(); - globalRadio.setChecked(true); + auto transform = impl->cameraItem->cameraTransform(); + transform->setPosition(Tg); + transform->notifyUpdate(); } @@ -375,93 +183,11 @@ void BodySyncCameraConfigDialog::Impl::alignWithTargetOrigin() auto transform = cameraItem->cameraTransform(); transform->setPosition(cameraItem->targetLinkPosition()); transform->notifyUpdate(); - localRadio.setChecked(true); } - - -void BodySyncCameraConfigDialog::Impl::onCameraPositionSpinValueChanged() -{ - cameraConnection.block(); - Vector3 eye(positionSpins[0].meterValue(), positionSpins[1].meterValue(), positionSpins[2].meterValue()); - Vector3 dir(directionSpins[0].value(), directionSpins[1].value(), directionSpins[2].value()); - Vector3 up(upSpins[0].value(), upSpins[1].value(), upSpins[2].value()); - - if(dir.norm() > 0.0 && up.norm() > 0.0){ - Isometry3 T = SgCamera::positionLookingFor(eye, dir, up); - if(localRadio.isChecked()){ - T = cameraItem->targetLinkPosition() * T; - } - auto transform = cameraItem->cameraTransform(); - transform->setPosition(T); - transform->notifyUpdate(); - } - - cameraConnection.unblock(); - - cameraItem->notifyUpdate(); -} - - -void BodySyncCameraConfigDialog::Impl::onFieldOfViewSpinValueChanged(double fov) -{ - auto camera = cameraItem->perspectiveCamera(); - camera->setFieldOfView(radian(fov)); - camera->notifyUpdate(); - cameraItem->notifyUpdate(); -} - - -void BodySyncCameraConfigDialog::Impl::onClipDistanceSpinValueChanged() -{ - auto camera = cameraItem->perspectiveCamera(); - camera->setNearClipDistance(nearClipSpin.value()); - camera->setFarClipDistance(farClipSpin.value()); - camera->notifyUpdate(); - cameraItem->notifyUpdate(); -} - void BodySyncCameraConfigDialog::Impl::onParallelTrackingModeToggled(bool on) { cameraItem->setParallelTrackingMode(on); cameraItem->notifyUpdate(); } - - -void BodySyncCameraConfigDialog::Impl::onInteractiveViewpointChangeToggled(bool on) -{ - cameraItem->setInteractiveViewpointChangeEnabled(on); - cameraItem->notifyUpdate(); -} - - -void BodySyncCameraConfigDialog::Impl::onSceneViewActivationChecked(bool on) -{ - auto renderer = SceneView::instance()->sceneWidget()->renderer(); - - if(on && !cameraItem->isChecked()){ - cameraItem->setChecked(true); - renderer->extractPreprocessedNodes(); - } - - auto camera = cameraItem->perspectiveCamera(); - auto currentCamera = renderer->currentCamera(); - - if(on){ - if(camera != currentCamera){ - renderer->setCurrentCamera(camera); - } - } else { - if(camera == currentCamera){ - renderer->setCurrentCamera(0); - } - } -} - - -void BodySyncCameraConfigDialog::hideEvent(QHideEvent* event) -{ - impl->setCameraItem(nullptr); - Dialog::hideEvent(event); -} diff --git a/src/BodyPlugin/BodySyncCameraConfigDialog.h b/src/BodyPlugin/BodySyncCameraConfigDialog.h index 70516559f..ae9bf467e 100644 --- a/src/BodyPlugin/BodySyncCameraConfigDialog.h +++ b/src/BodyPlugin/BodySyncCameraConfigDialog.h @@ -1,7 +1,7 @@ #ifndef CNOID_BODY_PLUGIN_BODY_SYNC_CAMERA_CONFIG_DIALOG_H #define CNOID_BODY_PLUGIN_BODY_SYNC_CAMERA_CONFIG_DIALOG_H -#include +#include namespace cnoid { @@ -9,19 +9,21 @@ class BodyItem; class BodySyncCameraItem; class Link; -class BodySyncCameraConfigDialog : public Dialog +class BodySyncCameraConfigDialog : public CameraConfigDialog { public: BodySyncCameraConfigDialog(); - ~BodySyncCameraConfigDialog(); + virtual ~BodySyncCameraConfigDialog(); static BodySyncCameraConfigDialog* instance(); BodySyncCameraItem* showToCreateCameraItem(BodyItem* bodyItem, Link* link); - void showToConfigureCameraItem(BodySyncCameraItem* cameraItem); + virtual void showToConfigureCameraItem(CameraItem* cameraItem) override; protected: - virtual void hideEvent(QHideEvent* event) override; + virtual void updateWidgetsWithCurrentCameraStates() override; + virtual Isometry3 getCurrentCameraPositionToDisplay() override; + virtual void setCameraPositionToDisplayToCameraTransform(const Isometry3& T) override; private: class Impl; diff --git a/src/BodyPlugin/BodySyncCameraItem.cpp b/src/BodyPlugin/BodySyncCameraItem.cpp index 2fa09a2e8..9a8315615 100644 --- a/src/BodyPlugin/BodySyncCameraItem.cpp +++ b/src/BodyPlugin/BodySyncCameraItem.cpp @@ -1,22 +1,12 @@ -/** - \file - \author Shin'ichiro Nakaoka -*/ - #include "BodySyncCameraItem.h" #include "BodySyncCameraConfigDialog.h" #include #include #include #include -#include -#include #include -#include -#include #include #include -#include #include #include #include "gettext.h" @@ -156,13 +146,8 @@ class BodySyncCameraItem::Impl public: BodySyncCameraItem* self; BodySyncCameraTransformPtr cameraTransform; - SgPerspectiveCameraPtr persCamera; - SgOrthographicCameraPtr orthoCamera; - SgCameraPtr currentCamera; - SgUpdate update; - Selection cameraType; - Impl(BodySyncCameraItem* self, bool initCameraPosition); + Impl(BodySyncCameraItem* self); Impl(BodySyncCameraItem* self, const Impl& org); void doPutProperties(PutPropertyFunction& putProperty); bool setClipDistances(double nearDistance, double farDistance); @@ -176,17 +161,9 @@ class BodySyncCameraItem::Impl void BodySyncCameraItem::initializeClass(ExtensionManager* ext) { ext->itemManager() - .registerClass(N_("BodySyncCameraItem")) + .registerClass(N_("BodySyncCameraItem")) .addAlias("BodyTrackingCameraItem", "Body") .addCreationPanel(); - - ItemTreeView::customizeContextMenu( - [](BodySyncCameraItem* item, MenuManager& menuManager, ItemFunctionDispatcher menuFunction){ - menuManager.addItem(_("Camera configuration"))->sigTriggered().connect( - [item](){ item->showDialogToConfigureCamera(); }); - menuManager.addSeparator(); - menuFunction.dispatchAs(item); - }); } @@ -203,53 +180,29 @@ void BodySyncCameraItem::showDialogToConfigureCamera() BodySyncCameraItem::BodySyncCameraItem() - : Item("BodySyncCamera") + : CameraItem("BodySyncCamera", new BodySyncCameraTransform) { - impl = new Impl(this, true); + impl = new Impl(this); } BodySyncCameraItem::BodySyncCameraItem(const BodySyncCameraItem& org) - : Item(org) + : CameraItem(org, new BodySyncCameraTransform) { impl = new Impl(this, *org.impl); } -BodySyncCameraItem::Impl::Impl(BodySyncCameraItem* self, bool initCameraPosition) - : self(self), - cameraType(NumCameraTypes, CNOID_GETTEXT_DOMAIN_NAME) +BodySyncCameraItem::Impl::Impl(BodySyncCameraItem* self_) + : self(self_) { - cameraType.setSymbol(Perspective, N_("Perspective")); - cameraType.setSymbol(Orthographic, N_("Orthographic")); - cameraType.select(Perspective); - - cameraTransform = new BodySyncCameraTransform; - if(initCameraPosition){ - cameraTransform->setPosition( - SceneView::instance()->sceneWidget()->builtinCameraTransform()->position()); - } else { - cameraTransform->setInteractiveViewpointChangeLocked(true); - } - - persCamera = new SgPerspectiveCamera; - persCamera->setName(self->name()); - cameraTransform->addChild(persCamera); - currentCamera = persCamera; - - orthoCamera = new SgOrthographicCamera; - orthoCamera->setName(self->name()); + cameraTransform = static_cast(self->cameraTransform()); } BodySyncCameraItem::Impl::Impl(BodySyncCameraItem* self, const Impl& org) - : Impl(self, false) + : Impl(self) { - cameraType = org.cameraType; - - cameraTransform->setPosition(org.cameraTransform->position()); - cameraTransform->setInteractiveViewpointChangeLocked( - org.cameraTransform->isInteractiveViewpointChangeLocked()); cameraTransform->setParallelTrackingMode(org.cameraTransform->isParallelTrackingMode()); cameraTransform->targetLinkName = org.cameraTransform->targetLinkName; } @@ -261,19 +214,6 @@ BodySyncCameraItem::~BodySyncCameraItem() } -bool BodySyncCameraItem::setName(const std::string& name_) -{ - if(name_ != name()){ - impl->persCamera->setName(name_); - impl->orthoCamera->setName(name_); - Item::setName(name_); - impl->persCamera->notifyUpdate(impl->update); - impl->orthoCamera->notifyUpdate(impl->update); - } - return true; -} - - Item* BodySyncCameraItem::doCloneItem(CloneMap* /* cloneMap */) const { return new BodySyncCameraItem(*this); @@ -313,93 +253,9 @@ bool BodySyncCameraItem::isParallelTrackingMode() const } -void BodySyncCameraItem::setInteractiveViewpointChangeEnabled(bool on) -{ - impl->cameraTransform->setInteractiveViewpointChangeLocked(!on); -} - - -bool BodySyncCameraItem::isInteractiveViewpointChangeEnabled() const -{ - return !impl->cameraTransform->isInteractiveViewpointChangeLocked(); -} - - -void BodySyncCameraItem::setCameraType(CameraType type) +void BodySyncCameraItem::updateRelativeCameraPosition() { - impl->setCameraType(type); -} - - -/** - \todo Improve the scene widget so that the current camera path described in a string list - can be kept even if the actual camera node is changed, and simplify the following implementation. -*/ -bool BodySyncCameraItem::Impl::setCameraType(int index) -{ - if(cameraType.selectedIndex() == index){ - return true; - } - - cameraType.select(index); - - SgCamera* cameraToRemove; - if(cameraType.is(BodySyncCameraItem::Perspective)){ - currentCamera = persCamera; - cameraToRemove = orthoCamera; - }else if(cameraType.is(BodySyncCameraItem::Orthographic)){ - currentCamera = orthoCamera; - cameraToRemove = persCamera; - } - - vector renderers; - for(auto sceneView : SceneView::instances()){ - renderers.push_back(sceneView->sceneWidget()->renderer()); - } - - cameraTransform->addChild(currentCamera, update); - for(auto renderer : renderers){ - if(renderer->currentCamera() == cameraToRemove){ - renderer->extractPreprocessedNodes(); - renderer->setCurrentCamera(currentCamera); - } - } - cameraTransform->removeChild(cameraToRemove, update); - for(auto renderer : renderers){ - renderer->extractPreprocessedNodes(); - } - - return true; -} - - -BodySyncCameraItem::CameraType BodySyncCameraItem::cameraType() const -{ - return static_cast(impl->cameraType.which()); -} - - -SgPerspectiveCamera* BodySyncCameraItem::perspectiveCamera() -{ - return impl->persCamera; -} - - -SgOrthographicCamera* BodySyncCameraItem::orthographicCamera() -{ - return impl->orthoCamera; -} - - -SgCamera* BodySyncCameraItem::currentCamera() -{ - return impl->currentCamera; -} - - -SgPosTransform* BodySyncCameraItem::cameraTransform() -{ - return impl->cameraTransform; + return impl->cameraTransform->updateRelativePosition(); } @@ -409,99 +265,15 @@ Isometry3 BodySyncCameraItem::relativeCameraPosition() const } -SgNode* BodySyncCameraItem::getScene() -{ - return impl->cameraTransform; -} - - void BodySyncCameraItem::onTreePathChanged() { impl->cameraTransform->setBodyItem(findOwnerItem()); } -double BodySyncCameraItem::fieldOfView() const -{ - return impl->persCamera->fieldOfView(); -} - - -bool BodySyncCameraItem::setFieldOfView(double fov) -{ - return impl->setFieldOfView(fov); -} - - -bool BodySyncCameraItem::Impl::setFieldOfView(double fov) -{ - if(fov > 0.0 && fov < PI){ - persCamera->setFieldOfView(fov); - persCamera->notifyUpdate(update); - return true; - } - return false; -} - - -double BodySyncCameraItem::nearClipDistance() const -{ - return impl->persCamera->nearClipDistance(); -} - - -bool BodySyncCameraItem::setNearClipDistance(double nearDistance) -{ - if(nearDistance > 0.0){ - impl->setClipDistances(nearDistance, farClipDistance()); - return true; - } - return false; -} - - -double BodySyncCameraItem::farClipDistance() const -{ - return impl->persCamera->farClipDistance(); -} - - -bool BodySyncCameraItem::setFarClipDistance(double farDistance) -{ - if(farDistance > 0.0){ - impl->setClipDistances(nearClipDistance(), farDistance); - return true; - } - return false; -} - - -bool BodySyncCameraItem::setClipDistances(double nearDistance, double farDistance) -{ - if(nearDistance > 0.0 && farDistance > 0.0){ - impl->setClipDistances(nearDistance, farDistance); - return true; - } - return false; -} - - -bool BodySyncCameraItem::Impl::setClipDistances(double nearDistance, double farDistance) -{ - if(persCamera->nearClipDistance() != nearDistance || persCamera->farClipDistance() != farDistance){ - persCamera->setNearClipDistance(nearDistance); - persCamera->setFarClipDistance(farDistance); - orthoCamera->setNearClipDistance(nearDistance); - orthoCamera->setFarClipDistance(farDistance); - persCamera->notifyUpdate(update); - orthoCamera->notifyUpdate(update); - } - return true; -} - - void BodySyncCameraItem::doPutProperties(PutPropertyFunction& putProperty) { + CameraItem::doPutProperties(putProperty); impl->doPutProperties(putProperty); } @@ -510,38 +282,23 @@ void BodySyncCameraItem::Impl::doPutProperties(PutPropertyFunction& putProperty) { putProperty(_("Target link"), cameraTransform->targetLinkName, [&](const string& name){ cameraTransform->setTargetLink(name); return true; }); - putProperty(_("Camera type"), cameraType, - [&](int index){ return setCameraType(index); }); - putProperty(_("Field Of View"), degree(self->fieldOfView()), - [&](double fov){ return setFieldOfView(radian(fov)); } ); - putProperty(_("Near clip distance"), self->nearClipDistance(), - [&](double distance){ return self->setNearClipDistance(distance); }); - putProperty(_("Far clip distance"), self->farClipDistance(), - [&](double distance){ return self->setFarClipDistance(distance); } ); putProperty(_("Parallel tracking"), cameraTransform->isParallelTrackingMode(), [&](bool on){ self->setParallelTrackingMode(on); return true; }); - putProperty(_("Interactive viewpoint change"), self->isInteractiveViewpointChangeEnabled(), - [&](bool on){ self->setInteractiveViewpointChangeEnabled(on); return true; }); } bool BodySyncCameraItem::store(Archive& archive) { + if(!CameraItem::store(archive)){ + return false; + } + archive.write("target_link", impl->cameraTransform->targetLinkName, DOUBLE_QUOTED); archive.write("parallel_tracking", isParallelTrackingMode()); - archive.write("interactive_viewpoint_change", isInteractiveViewpointChangeEnabled()); - archive.write("camera_type", impl->cameraType.selectedSymbol()); - archive.write("near_clip_distance", impl->persCamera->nearClipDistance()); - archive.write("far_clip_distance", impl->persCamera->farClipDistance()); - archive.write("field_of_view", impl->persCamera->fieldOfView()); auto transform = impl->cameraTransform; - Isometry3 T = transform->T(); - write(archive, "translation", T.translation()); - writeDegreeAngleAxis(archive, "rotation", AngleAxis(T.linear())); - if(auto link = transform->targetLink){ - T = link->T().inverse() * T; + Isometry3 T = link->T().inverse() * transform->T(); write(archive, "local_translation", T.translation()); writeDegreeAngleAxis(archive, "local_rotation", AngleAxis(T.linear())); } @@ -552,6 +309,10 @@ bool BodySyncCameraItem::store(Archive& archive) bool BodySyncCameraItem::restore(const Archive& archive) { + if(!CameraItem::restore(archive)){ + return false; + } + auto transform = impl->cameraTransform; string symbol; @@ -574,48 +335,26 @@ bool BodySyncCameraItem::restore(const Archive& archive) if(doUpdate){ setParallelTrackingMode(on); } - if(archive.read("interactive_viewpoint_change", on)){ - setInteractiveViewpointChangeEnabled(on); - } - if(archive.read({ "camera_type", "cameraType" }, symbol)){ - int index = impl->cameraType.index(symbol); - impl->setCameraType(index); - } - double nearDistance = - archive.get({ "near_clip_distance", "nearClipDistance" }, impl->persCamera->nearClipDistance()); - double farDistance = - archive.get({ "far_clip_distance", "farClipDistance" }, impl->persCamera->farClipDistance()); - impl->setClipDistances(nearDistance, farDistance); - - impl->setFieldOfView(archive.get({ "field_of_view", "fieldOfView" }, impl->persCamera->fieldOfView())); - - bool isPositionReady = false; + + bool hasLocalPosition = false; Vector3 p; AngleAxis aa; Isometry3 T = Isometry3::Identity(); if(auto link = transform->targetLink){ if(read(archive, "local_translation", p)){ T.translation() = p; - isPositionReady = true; + hasLocalPosition = true; } if(readDegreeAngleAxis(archive, "local_rotation", aa)){ T.linear() = aa.toRotationMatrix(); - isPositionReady = true; + hasLocalPosition = true; } - if(isPositionReady){ + if(hasLocalPosition){ T = link->T() * T; + transform->setPosition(T); + transform->notifyUpdate(); } } - if(!isPositionReady){ - if(read(archive, "translation", p)){ - T.translation() = p; - } - if(readDegreeAngleAxis(archive, "rotation", aa)){ - T.linear() = aa.toRotationMatrix(); - } - } - transform->setPosition(T); - transform->notifyUpdate(); - + return true; } diff --git a/src/BodyPlugin/BodySyncCameraItem.h b/src/BodyPlugin/BodySyncCameraItem.h index 195e2fa7a..91d566ca6 100644 --- a/src/BodyPlugin/BodySyncCameraItem.h +++ b/src/BodyPlugin/BodySyncCameraItem.h @@ -1,83 +1,33 @@ -/*! - @file - @author Shin'ichiro Nakaoka -*/ - #ifndef CNOID_BODY_PLUGIN_BODY_SYNC_CAMERA_ITEM_H #define CNOID_BODY_PLUGIN_BODY_SYNC_CAMERA_ITEM_H -#include -#include +#include #include #include "exportdecl.h" namespace cnoid { -class SgCamera; -class SgPerspectiveCamera; -class SgOrthographicCamera; -class SgPosTransform; class BodyItem; class Link; -class CNOID_EXPORT BodySyncCameraItem : public Item, public RenderableItem +class CNOID_EXPORT BodySyncCameraItem : public CameraItem { public: static void initializeClass(ExtensionManager* ext); static BodySyncCameraItem* showDialogToCreateBodySyncCameraItem(BodyItem* bodyItem, Link* link); - enum CameraType { - Perspective, - Orthographic, - NumCameraTypes, - // deprecated - PERSPECTIVE = Perspective, - ORTHOGRAPHIC = Orthographic, - N_CAMERA_TYPE - }; - BodySyncCameraItem(); - ~BodySyncCameraItem(); - - virtual bool setName(const std::string& name) override; + virtual ~BodySyncCameraItem(); void setTargetLink(const std::string& name); const std::string& targetLinkName() const; Isometry3 targetLinkPosition() const; void setParallelTrackingMode(bool on); bool isParallelTrackingMode() const; - void setInteractiveViewpointChangeEnabled(bool on); - bool isInteractiveViewpointChangeEnabled() const; - void setCameraType(CameraType type); - CameraType cameraType() const; - SgPerspectiveCamera* perspectiveCamera(); - SgOrthographicCamera* orthographicCamera(); - SgCamera* currentCamera(); - SgPosTransform* cameraTransform(); + void updateRelativeCameraPosition(); Isometry3 relativeCameraPosition() const; - - double fieldOfView() const; - bool setFieldOfView(double fov); - - double nearClipDistance() const; - bool setNearClipDistance(double distance); - double farClipDistance() const; - bool setFarClipDistance(double distance); - bool setClipDistances(double nearDistance, double farDistance); - - void showDialogToConfigureCamera(); - - // RenderableItem - virtual SgNode* getScene() override; - - [[deprecated("Use setParallelTrackingMode.")]] - void setRotationSyncEnabled(bool on) { - setParallelTrackingMode(!on); - } - [[deprecated("Use isParallelTrackingMode.")]] - bool isRotationSyncEnabled() const { - return !isParallelTrackingMode(); - } + + virtual void showDialogToConfigureCamera() override; protected: BodySyncCameraItem(const BodySyncCameraItem& org); @@ -94,12 +44,6 @@ class CNOID_EXPORT BodySyncCameraItem : public Item, public RenderableItem typedef ref_ptr BodySyncCameraItemPtr; -// for the backward compatibility -[[deprecated]] -typedef BodySyncCameraItem BodyTrackingCameraItem; -[[deprecated]] -typedef ref_ptr BodyTrackingCameraItemPtr; - } #endif From bdf7f530fcdca26a77bc9c25e4a930cdbbdabcce Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 24 Jul 2024 12:37:46 +0900 Subject: [PATCH 12/73] Update Japanese translations for BodyPlugin --- src/BodyPlugin/po/ja.po | 62 +++-------------------------------------- 1 file changed, 4 insertions(+), 58 deletions(-) diff --git a/src/BodyPlugin/po/ja.po b/src/BodyPlugin/po/ja.po index b2940c91f..3147983e3 100644 --- a/src/BodyPlugin/po/ja.po +++ b/src/BodyPlugin/po/ja.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Choreonoid\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-28 14:22+0900\n" +"POT-Creation-Date: 2024-07-24 12:36+0900\n" "PO-Revision-Date: 2021-10-25 12:00+0900\n" "Language: ja\n" "MIME-Version: 1.0\n" @@ -702,87 +702,30 @@ msgstr "オン" msgid "BodySuperimposer" msgstr "ボディスーパーインポーザ" -msgid "Name:" -msgstr "名前:" - -msgid "Align with the builtin camera" -msgstr "組み込みカメラの位置に設定" - msgid "Align with the target origin" msgstr "ターゲット原点に設定" msgid "Coordinate System:" msgstr "座標系:" -msgid "Position:" -msgstr "位置:" - -msgid "Direction:" -msgstr "視線方向:" - -msgid "Up:" -msgstr "上方向:" - -msgid "Field of View:" -msgstr "視野角:" - -msgid "[deg]" -msgstr "" - -msgid "Near Clip:" -msgstr "近方クリップ:" - -msgid "Far Clip:" -msgstr "遠方クリップ:" - msgid "Parallel tracking" msgstr "平行トラッキング" -msgid "Interactive viewpoint change" -msgstr "インタラクティブな視点変更" - -msgid "Activate in the scene view" -msgstr "シーンビューで有効化" - -msgid "&OK" -msgstr "" - msgid "Camera Creation" msgstr "カメラの作成" msgid "{0} Camera" msgstr "{0}カメラ" -msgid "Camera Configuration" -msgstr "カメラの設定" - msgid "BodySyncCameraItem" msgstr "ボディ同期カメラ" msgid "Camera configuration" msgstr "カメラの設定" -msgid "Perspective" -msgstr "透視投影" - -msgid "Orthographic" -msgstr "並行投影" - msgid "Target link" msgstr "対象リンク" -msgid "Camera type" -msgstr "カメラ タイプ" - -msgid "Field Of View" -msgstr "視野角" - -msgid "Near clip distance" -msgstr "近方クリップ距離" - -msgid "Far clip distance" -msgstr "遠方クリップ距離" - msgid "CollisionDetectionController" msgstr "干渉検出コントローラ" @@ -1126,6 +1069,9 @@ msgstr "" msgid "angle" msgstr "角度" +msgid "[deg]" +msgstr "" + msgid "Penetration block depth" msgstr "貫通防止における許容深度" From bca82bdc7419119312cd59e27a49b914786c1991 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 9 Aug 2024 22:56:32 +0900 Subject: [PATCH 13/73] Fix a bug in outputting messages to MessageOut::cout and MessageOut::cerr --- src/Util/MessageOut.cpp | 67 +++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/src/Util/MessageOut.cpp b/src/Util/MessageOut.cpp index 5292b3197..33c5cde86 100644 --- a/src/Util/MessageOut.cpp +++ b/src/Util/MessageOut.cpp @@ -1,5 +1,6 @@ #include "MessageOut.h" -#include +#include +#include #include #include #include @@ -11,28 +12,17 @@ namespace { mutex sinkMutex; -class MessageOutStreamBuf : public std::stringbuf +class MessageOutStreamBuf : public std::basic_streambuf { public: - MessageOut& mout; - MessageOutStreamBuf(MessageOut& mout) - : mout(mout) { } - virtual int sync() override { - mout.put(str()); - return 0; - } -}; + MessageOutStreamBuf(MessageOut& mout, int messageType); + + virtual int_type overflow(int_type c) override; + virtual int sync() override; -class MessageOutErrorStreamBuf : public std::stringbuf -{ -public: MessageOut& mout; - MessageOutErrorStreamBuf(MessageOut& mout) - : mout(mout) { } - virtual int sync() override { - mout.putError(str()); - return 0; - } + int messageType; + vector buf; }; class Sink : public Referenced @@ -68,7 +58,7 @@ class MessageOut::Impl unique_ptr streamBuf; unique_ptr cout; - unique_ptr errorStreamBuf; + unique_ptr errorStreamBuf; unique_ptr cerr; Impl(MessageOut* self); @@ -77,6 +67,39 @@ class MessageOut::Impl } +MessageOutStreamBuf::MessageOutStreamBuf(MessageOut& mout, int messageType) + : mout(mout), + messageType(messageType) +{ + buf.resize(4096); + auto p = &buf.front(); + setp(p, p + buf.size()); +} + + +MessageOutStreamBuf::int_type MessageOutStreamBuf::overflow(int_type c) +{ + sync(); + + if(c != traits_type::eof()){ + buf[0] = c; + pbump(1); + return traits_type::not_eof(c); + } else { + return traits_type::eof(); + } +} + + +int MessageOutStreamBuf::sync() +{ + auto p = &buf.front(); + mout.put(string(p, pptr() - p), messageType); + setp(p, p + buf.size()); + return 0; +} + + MessageOut* MessageOut::master() { static MessageOutPtr instance = new MessageOut; @@ -164,7 +187,7 @@ std::ostream& MessageOut::cout() { lock_guard lock(sinkMutex); if(!impl->cout){ - impl->streamBuf = make_unique(*this); + impl->streamBuf = make_unique(*this, Normal); impl->cout = make_unique(impl->streamBuf.get()); } return *impl->cout; @@ -175,7 +198,7 @@ std::ostream& MessageOut::cerr() { lock_guard lock(sinkMutex); if(!impl->cout){ - impl->errorStreamBuf = make_unique(*this); + impl->errorStreamBuf = make_unique(*this, Error); impl->cerr = make_unique(impl->errorStreamBuf.get()); } return *impl->cerr; From e19df1451110ea7847e026eace76697acd03c487 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Sat, 27 Jul 2024 13:44:59 +0900 Subject: [PATCH 14/73] Fix a bug in setting URI information in StdSceneReader --- src/Util/StdSceneReader.cpp | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/Util/StdSceneReader.cpp b/src/Util/StdSceneReader.cpp index 1fcc973d9..e28c7ebad 100644 --- a/src/Util/StdSceneReader.cpp +++ b/src/Util/StdSceneReader.cpp @@ -1700,11 +1700,27 @@ StdSceneReader::Resource StdSceneReader::Impl::readResourceNode(Mapping* info) if(resource.scene){ resource.scene = readTransformParameters(info, resource.scene); - if(auto uriObject = resource.scene->findObject([](SgObject* object){ return object->hasUri(); })){ - uriObject->setUri(resource.uri, resource.file); - if(!resource.fragment.empty()){ - uriObject->setUriFragment(resource.fragment); - } + + SgObject* uriObject = resource.scene->findObject( + [&resource](SgObject* object){ + if(object->hasUri()){ + size_t pos = object->uri().rfind(resource.uri); + if(pos != string::npos){ + if(object->uri().size() - pos == resource.uri.size()){ + return true; + } + } + } + return false; + }); + + if(!uriObject){ + uriObject = resource.scene; + } + + uriObject->setUri(resource.uri, resource.file); + if(!resource.fragment.empty()){ + uriObject->setUriFragment(resource.fragment); } } } From a9900cf8fe25c695a1d30604a2471fbf05ff6a5b Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 9 Aug 2024 15:31:55 +0900 Subject: [PATCH 15/73] Fix VRMLSceneLoader to set the URI information --- src/Util/VRMLSceneLoader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Util/VRMLSceneLoader.cpp b/src/Util/VRMLSceneLoader.cpp index fab1d907f..2f4b00bac 100644 --- a/src/Util/VRMLSceneLoader.cpp +++ b/src/Util/VRMLSceneLoader.cpp @@ -105,5 +105,7 @@ SgNode* VRMLSceneLoader::Impl::load(const std::string& filename) } group.reset(); + node->setUriWithFilePathAndCurrentDirectory(filename); + return node.retn(); } From 866daf63c342823350b55d1f77145631e9d7df01 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 31 Jul 2024 07:10:37 +0900 Subject: [PATCH 16/73] Fix bugs in finding a sub string in AbstractSceneWriter, StdSceneWriter, ObjSceneLoader and HumanoidPoseFetchView --- src/PoseSeqPlugin/HumanoidPoseFetchView.cpp | 2 +- src/Util/AbstractSceneWriter.cpp | 4 ++-- src/Util/ObjSceneLoader.cpp | 2 +- src/Util/StdSceneWriter.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PoseSeqPlugin/HumanoidPoseFetchView.cpp b/src/PoseSeqPlugin/HumanoidPoseFetchView.cpp index eb8b8c8c9..4e38b0caa 100644 --- a/src/PoseSeqPlugin/HumanoidPoseFetchView.cpp +++ b/src/PoseSeqPlugin/HumanoidPoseFetchView.cpp @@ -1021,7 +1021,7 @@ void HumanoidPoseFetchView::Impl::setBodyPartLinks if(group->checkIfLink(i)){ if(auto link = body->link(group->linkIndex(i))){ if(!prefix.empty()){ - if(link->name().find_first_of(prefix) != 0){ + if(link->name().find(prefix) != 0){ continue; } } diff --git a/src/Util/AbstractSceneWriter.cpp b/src/Util/AbstractSceneWriter.cpp index aee3c2ff5..fae881de9 100644 --- a/src/Util/AbstractSceneWriter.cpp +++ b/src/Util/AbstractSceneWriter.cpp @@ -29,7 +29,7 @@ bool AbstractSceneWriter::findOrCopyImageFile(SgImage* image, const std::string& stdx::error_code ec; auto uri = image->uri(); - if(uri.find_first_of("file://") == 0){ + if(uri.find("file://") == 0){ uri = uri.substr(7); } filesystem::path filePath(fromUTF8(uri)); @@ -39,7 +39,7 @@ bool AbstractSceneWriter::findOrCopyImageFile(SgImage* image, const std::string& } else if(image->hasAbsoluteUri()){ auto& absUri = image->absoluteUri(); - if(absUri.find_first_of("file://") == 0){ + if(absUri.find("file://") == 0){ filesystem::path orgFilePath(fromUTF8(absUri.substr(7))); if(filesystem::exists(orgFilePath, ec)){ orgImageFileFound = true; diff --git a/src/Util/ObjSceneLoader.cpp b/src/Util/ObjSceneLoader.cpp index da06eaa43..4b417a167 100644 --- a/src/Util/ObjSceneLoader.cpp +++ b/src/Util/ObjSceneLoader.cpp @@ -648,7 +648,7 @@ bool ObjSceneLoader::Impl::loadMaterialTemplateLibrary(std::string filename) case 'm': if(subScanner.readStringAtCurrentPosition(token)){ - if(token.find_first_of("map_") == 0){ + if(token.find("map_") == 0){ readTexture(token.substr(4)); } else { isUnknownDirective = true; diff --git a/src/Util/StdSceneWriter.cpp b/src/Util/StdSceneWriter.cpp index a873baeb0..277965b8e 100644 --- a/src/Util/StdSceneWriter.cpp +++ b/src/Util/StdSceneWriter.cpp @@ -738,7 +738,7 @@ bool StdSceneWriter::Impl::replaceOriginalModelFile } else { // New reference if(objectOfUri->hasAbsoluteUri()){ auto& absUri = objectOfUri->absoluteUri(); - if(absUri.find_first_of("file://") == 0){ + if(absUri.find("file://") == 0){ filesystem::path orgFilePath(absUri.substr(7)); if(filesystem::equivalent(fullPath, orgFilePath, ec)){ os() << formatR(_("Model file \"{0}\" cannot be replaced with the same format file in the same directory"), From 0a048511f789a9b28624d7e07ad31a021816e115 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 9 Aug 2024 16:26:34 +0900 Subject: [PATCH 17/73] Fix a bug in reading ambient colors in ObjSceneLoader --- src/Util/ObjSceneLoader.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Util/ObjSceneLoader.cpp b/src/Util/ObjSceneLoader.cpp index 4b417a167..48a181cda 100644 --- a/src/Util/ObjSceneLoader.cpp +++ b/src/Util/ObjSceneLoader.cpp @@ -786,11 +786,14 @@ void ObjSceneLoader::Impl::updateAmbientIntensities() auto& info = kv.second; auto& material = info.material; if(material){ - float a = info.ambientColor.norm(); + float intensity = 1.0f; float d = material->diffuseColor().norm(); - float intensity = a / d; - if(intensity >= (1.0f - 1.0e-3)){ - intensity = 1.0f; + if(d > 0.0f){ + float a = info.ambientColor.norm(); + intensity = a / d; + if(intensity >= (1.0f - 1.0e-3)){ + intensity = 1.0f; + } } material->setAmbientIntensity(intensity); } From 7931c7368323f33453230f54df858b9a731c5daa Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 9 Aug 2024 19:01:04 +0900 Subject: [PATCH 18/73] Improve AbstractSceneWriter::findOrCopyImageFile to avoid conflicts in copied filenames --- src/Util/AbstractSceneWriter.cpp | 108 ++++++++++++++++++++++++------- src/Util/AbstractSceneWriter.h | 7 +- src/Util/ObjSceneWriter.cpp | 7 +- src/Util/StdSceneWriter.cpp | 20 +++--- 4 files changed, 105 insertions(+), 37 deletions(-) diff --git a/src/Util/AbstractSceneWriter.cpp b/src/Util/AbstractSceneWriter.cpp index fae881de9..b5287424f 100644 --- a/src/Util/AbstractSceneWriter.cpp +++ b/src/Util/AbstractSceneWriter.cpp @@ -3,16 +3,41 @@ #include "UTF8.h" #include "Format.h" #include +#include +#include #include "gettext.h" using namespace std; using namespace cnoid; namespace filesystem = stdx::filesystem; +namespace cnoid { -AbstractSceneWriter::~AbstractSceneWriter() +class AbstractSceneWriter::Impl +{ +public: + struct CopiedFileInfo { + string filename; + bool copied; + }; + + // Original file to copied file + unordered_map imageFileMap; + unordered_set copiedImageFiles; +}; + +} + + +AbstractSceneWriter::AbstractSceneWriter() { + impl = new Impl; +} + +AbstractSceneWriter::~AbstractSceneWriter() +{ + delete impl; } @@ -22,7 +47,14 @@ void AbstractSceneWriter::setMessageSink(std::ostream& os) } -bool AbstractSceneWriter::findOrCopyImageFile(SgImage* image, const std::string& outputBaseDir) +void AbstractSceneWriter::clearImageFileInformation() +{ + impl->imageFileMap.clear(); + impl->copiedImageFiles.clear(); +} + + +bool AbstractSceneWriter::findOrCopyImageFile(SgImage* image, const std::string& outputBaseDir, std::string& out_copiedFile) { bool foundOrCopied = false; bool orgImageFileFound = false; @@ -36,46 +68,72 @@ bool AbstractSceneWriter::findOrCopyImageFile(SgImage* image, const std::string& if(filePath.is_absolute()){ orgImageFileFound = filesystem::exists(filePath, ec); - + if(orgImageFileFound){ + out_copiedFile = uri; + foundOrCopied = true; + } } else if(image->hasAbsoluteUri()){ auto& absUri = image->absoluteUri(); if(absUri.find("file://") == 0){ filesystem::path orgFilePath(fromUTF8(absUri.substr(7))); - if(filesystem::exists(orgFilePath, ec)){ + auto found = impl->imageFileMap.find(orgFilePath.string()); + if(found != impl->imageFileMap.end()){ + auto& info = found->second; + out_copiedFile = toUTF8(info.filename); orgImageFileFound = true; + foundOrCopied = info.copied; + + } else if(filesystem::exists(orgFilePath, ec)){ + orgImageFileFound = true; + filesystem::path absPath; if(filePath.is_relative()){ - filePath = filesystem::path(fromUTF8(outputBaseDir)) / filePath; + absPath = filesystem::path(fromUTF8(outputBaseDir)) / filePath; + } else { + absPath = filePath; } - if(filesystem::equivalent(orgFilePath, filePath, ec)){ + auto stem = filePath.stem().string(); + auto ext = filePath.extension().string(); + int counter = 2; + while(true){ + auto inserted = impl->copiedImageFiles.insert(absPath.string()); + if(inserted.second){ + break; + } + filePath = filePath.parent_path() / formatC("{0}-{1}{2}", stem, counter, ext); + ++counter; + if(filePath.is_relative()){ + absPath = filesystem::path(fromUTF8(outputBaseDir)) / filePath; + } else { + absPath = filePath; + } + } + if(filesystem::equivalent(orgFilePath, absPath, ec)){ foundOrCopied = true; + out_copiedFile = toUTF8(filePath.string()); } else { - ec.clear(); - filesystem::create_directories(filePath.parent_path(), ec); + filesystem::create_directories(absPath.parent_path(), ec); if(!ec){ #if __cplusplus > 201402L filesystem::copy_file( - orgFilePath, filePath, filesystem::copy_options::update_existing, ec); + orgFilePath, absPath, filesystem::copy_options::overwrite_existing, ec); #else - bool doCopy = true; - if(filesystem::exists(filePath, ec)){ - if(filesystem::last_write_time(filePath, ec) >= filesystem::last_write_time(orgFilePath, ec)){ - doCopy = false; - } - } - if(doCopy){ - filesystem::copy_file( - orgFilePath, filePath, filesystem::copy_option::overwrite_if_exists, ec); - } + filesystem::copy_file( + orgFilePath, absPath, filesystem::copy_option::overwrite_if_exists, ec); #endif - if(!ec){ - foundOrCopied = true; - } } - if(ec){ - os() << formatR(_("Warning: Texture image file \"{0}\" cannot be copied: {1}"), - uri, ec.message()) << endl; + if(!ec){ + foundOrCopied = true; + out_copiedFile = toUTF8(filePath.string()); } } + if(ec){ + os() << formatR(_("Warning: Texture image file \"{0}\" cannot be copied: {1}"), + uri, ec.message()) << endl; + } + + auto& info = impl->imageFileMap[orgFilePath.string()]; + info.filename = filePath.string(); + info.copied = foundOrCopied; } } } diff --git a/src/Util/AbstractSceneWriter.h b/src/Util/AbstractSceneWriter.h index b8b22c85d..4402b961d 100644 --- a/src/Util/AbstractSceneWriter.h +++ b/src/Util/AbstractSceneWriter.h @@ -13,16 +13,21 @@ class SgImage; class CNOID_EXPORT AbstractSceneWriter { public: + AbstractSceneWriter(); virtual ~AbstractSceneWriter(); virtual void setMessageSink(std::ostream& os); virtual bool writeScene(const std::string& filename, SgNode* node) = 0; protected: - bool findOrCopyImageFile(SgImage* image, const std::string& outputBaseDir); + void clearImageFileInformation(); + bool findOrCopyImageFile(SgImage* image, const std::string& outputBaseDir, std::string& out_copiedFile); std::ostream& os(){ return *os_; } private: std::ostream* os_; + + class Impl; + Impl* impl; }; } diff --git a/src/Util/ObjSceneWriter.cpp b/src/Util/ObjSceneWriter.cpp index c98acaf6a..4a01af5cc 100644 --- a/src/Util/ObjSceneWriter.cpp +++ b/src/Util/ObjSceneWriter.cpp @@ -131,6 +131,8 @@ void ObjSceneWriter::Impl::clear() materialLabelSet.clear(); lastMaterialPair = MaterialPair(nullptr, nullptr); materialLabelIdCounter = 0; + + self->clearImageFileInformation(); } @@ -317,8 +319,9 @@ void ObjSceneWriter::Impl::writeMaterial(SgMaterial* material, SgTexture* textur if(texture){ auto image = texture->image(); if(image && image->hasUri()){ - if(self->findOrCopyImageFile(image, toUTF8(baseDirPath.generic_string()))){ - mfs << "map_Kd " << image->uri() << "\n"; + string copiedFile; + if(self->findOrCopyImageFile(image, toUTF8(baseDirPath.generic_string()), copiedFile)){ + mfs << "map_Kd " << copiedFile << "\n"; } } } diff --git a/src/Util/StdSceneWriter.cpp b/src/Util/StdSceneWriter.cpp index 277965b8e..3957b7c51 100644 --- a/src/Util/StdSceneWriter.cpp +++ b/src/Util/StdSceneWriter.cpp @@ -378,6 +378,7 @@ void StdSceneWriter::clear() impl->sceneToYamlNodeMap.clear(); impl->uriRewritingMap.clear(); impl->extModelFiles.clear(); + clearImageFileInformation(); } @@ -1224,18 +1225,18 @@ MappingPtr StdSceneWriter::Impl::writeTexture(SgTexture* texture) if(auto image = texture->image()){ if(image->hasUri()){ filesystem::path imageDirPath = outputBaseDirPath; + filesystem::path mainSceneNamePath; if(!mainSceneName.empty()){ - imageDirPath /= filesystem::path(fromUTF8(mainSceneName)); + mainSceneNamePath = filesystem::path(fromUTF8(mainSceneName)); + imageDirPath /= mainSceneNamePath; } - if(self->findOrCopyImageFile(image, toUTF8(imageDirPath.string()))){ - ensureUriSchemeProcessor(); - uriSchemeProcessor->detectScheme(image->uri()); - filesystem::path path(fromUTF8(uriSchemeProcessor->path())); - path = imageDirPath / path.filename(); - if(auto relPath = getRelativePath(path, outputBaseDirPath)){ - archive->write("uri", toUTF8(relPath->generic_string()), DOUBLE_QUOTED); + string copiedFile; + if(self->findOrCopyImageFile(image, toUTF8(imageDirPath.string()), copiedFile)){ + filesystem::path path(fromUTF8(copiedFile)); + if(path.is_relative() && !mainSceneName.empty()){ + path = mainSceneNamePath / path; } - isValid = true; + archive->write("uri", toUTF8(path.generic_string()), DOUBLE_QUOTED); if(texture->repeatS() == texture->repeatT()){ archive->write("repeat", texture->repeatS()); } else { @@ -1243,6 +1244,7 @@ MappingPtr StdSceneWriter::Impl::writeTexture(SgTexture* texture) repeat.append(texture->repeatS()); repeat.append(texture->repeatT()); } + isValid = true; } } } From a6f5d18968bb8967a5c684ee94272a35ca1f3417 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Sat, 10 Aug 2024 10:51:57 +0900 Subject: [PATCH 19/73] Fix the CopyModelFiles mode of StdSceneWriter to recursively copy files for sub nodes such as texture files --- src/Util/StdSceneWriter.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Util/StdSceneWriter.cpp b/src/Util/StdSceneWriter.cpp index 3957b7c51..ba1c73812 100644 --- a/src/Util/StdSceneWriter.cpp +++ b/src/Util/StdSceneWriter.cpp @@ -689,11 +689,9 @@ string StdSceneWriter::Impl::copyModelFiles(SgObject* sceneObject) } } - if(!relativeFilePathToCopiedFile.empty()){ - int n = sceneObject->numChildObjects(); - for(int i=0; i < n; ++i){ - copyModelFiles(sceneObject->childObject(i)); - } + int n = sceneObject->numChildObjects(); + for(int i=0; i < n; ++i){ + copyModelFiles(sceneObject->childObject(i)); } return relativeFilePathToCopiedFile; From 7c53bb4d814363cc58a76fb8bd7e43e849b5d7a7 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 26 Jul 2024 20:52:35 +0900 Subject: [PATCH 20/73] Implement a function to export the scene of selected renderable items as an OBJ mesh file --- include/cnoid/RenderableItemSceneExporter | 1 + src/Base/CMakeLists.txt | 2 + src/Base/MainMenu.cpp | 70 +++++++++++---------- src/Base/MainMenu.h | 1 + src/Base/RenderableItemSceneExporter.cpp | 75 +++++++++++++++++++++++ src/Base/RenderableItemSceneExporter.h | 17 +++++ 6 files changed, 135 insertions(+), 31 deletions(-) create mode 100644 include/cnoid/RenderableItemSceneExporter create mode 100644 src/Base/RenderableItemSceneExporter.cpp create mode 100644 src/Base/RenderableItemSceneExporter.h diff --git a/include/cnoid/RenderableItemSceneExporter b/include/cnoid/RenderableItemSceneExporter new file mode 100644 index 000000000..a0aec882a --- /dev/null +++ b/include/cnoid/RenderableItemSceneExporter @@ -0,0 +1 @@ +#include "src/Base/RenderableItemSceneExporter.h" diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index 1ab37bccb..eeb229096 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -25,6 +25,7 @@ set(sources RenderableItem.cpp RenderableItemUtil.cpp RenderableItemSceneStatistics.cpp + RenderableItemSceneExporter.cpp PolymorphicItemFunctionSet.cpp PutPropertyFunction.cpp RootItem.cpp @@ -228,6 +229,7 @@ set(headers LocatableItem.h RenderableItem.h RenderableItemUtil.h + RenderableItemSceneExporter.h ImageableItem.h TargetItemPicker.h UnifiedEditHistory.h diff --git a/src/Base/MainMenu.cpp b/src/Base/MainMenu.cpp index b584394e3..d38039d3d 100644 --- a/src/Base/MainMenu.cpp +++ b/src/Base/MainMenu.cpp @@ -16,6 +16,7 @@ #include "PathVariableEditor.h" #include "DistanceMeasurementDialog.h" #include "RenderableItemSceneStatistics.h" +#include "RenderableItemSceneExporter.h" #include "MovieRecorderDialog.h" #include "SceneWidget.h" #include "DescriptionDialog.h" @@ -110,7 +111,7 @@ void MainMenu::setMenuItems() // Add a menu item to show a dialog to load a plugin if the startup plugin loading is disabled // This is for the debug use mm.setPath(N_("Plugin")).addItem(_("Load Plugin")) - ->sigTriggered().connect([this, pluginManager](){ pluginManager->showDialogToLoadPlugin(); }); + ->sigTriggered().connect([this, pluginManager]{ pluginManager->showDialogToLoadPlugin(); }); mm.addSeparator(); } @@ -153,6 +154,7 @@ void MainMenu::setMenuItems() set_Tools_Menu(mm.currentMenu()); setActionAsShowDistanceMeasurementDialog(mm.addItem(_("Distance Measurement"))); setActionAsPutSceneStatistics(mm.addItem(_("Put Scene Statistics"))); + setActionAsExportSelectedRenderableItemScene(mm.addItem(_("Export Scene"))); setActionAsShowMovieRecorderDialog(mm.addItem(_("Movie Recorder"))); //------------------------ Filters ------------------------ @@ -172,13 +174,13 @@ void MainMenu::setMenuItems() auto vsyncItem = mm.addCheckItem(_("Vertical Sync")); glMenu->sigAboutToShow().connect( - [vsyncItem](){ vsyncItem->setChecked(SceneWidget::isVerticalSyncMode()); }); + [vsyncItem]{ vsyncItem->setChecked(SceneWidget::isVerticalSyncMode()); }); vsyncItem->sigToggled().connect( [](bool on){ SceneWidget::setVerticalSyncMode(on); }); auto lowMemoryItem = mm.addCheckItem(_("Low GPU Memory Consumption Mode")); glMenu->sigAboutToShow().connect( - [lowMemoryItem](){ lowMemoryItem->setChecked(SceneWidget::isLowMemoryConsumptionMode()); }); + [lowMemoryItem]{ lowMemoryItem->setChecked(SceneWidget::isLowMemoryConsumptionMode()); }); lowMemoryItem->sigToggled().connect( [](bool on){ SceneWidget::setLowMemoryConsumptionMode(on); }); @@ -252,7 +254,7 @@ Action* MainMenu::addMenuItem void MainMenu::setActionAsReloadSelectedItems(Action* action) { action->sigTriggered().connect( - [](){ + []{ for(auto& item : RootItem::instance()->selectedItems()){ item->reload(); } @@ -263,7 +265,7 @@ void MainMenu::setActionAsReloadSelectedItems(Action* action) void MainMenu::setActionAsSaveSelectedItems(Action* action) { action->sigTriggered().connect( - [](){ + []{ for(auto& item : RootItem::instance()->selectedItems()){ item->overwriteOrSaveWithDialog(true, ""); } @@ -274,7 +276,7 @@ void MainMenu::setActionAsSaveSelectedItems(Action* action) void MainMenu::setActionAsSaveSelectedItemsAs(Action* action) { action->sigTriggered().connect( - [](){ + []{ for(auto& item : RootItem::instance()->selectedItems()){ item->saveWithFileDialog(); } @@ -285,7 +287,7 @@ void MainMenu::setActionAsSaveSelectedItemsAs(Action* action) void MainMenu::setActionAsExportSelectedItems(Action* action) { action->sigTriggered().connect( - [](){ + []{ ItemFileDialog dialog; dialog.setExportMode(); for(auto& item : RootItem::instance()->selectedItems()){ @@ -306,82 +308,82 @@ void MainMenu::setActionAsExportSelectedItems(Action* action) void MainMenu::setActionAsOpenProject(Action* action) { action->sigTriggered().connect( - [](){ ProjectManager::instance()->showDialogToLoadProject(); }); + []{ ProjectManager::instance()->showDialogToLoadProject(); }); } void MainMenu::setActionAsSaveProject(Action* action) { action->sigTriggered().connect( - [](){ ProjectManager::instance()->overwriteCurrentProject(); }); + []{ ProjectManager::instance()->overwriteCurrentProject(); }); } void MainMenu::setActionAsSaveProjectAs(Action* action) { action->sigTriggered().connect( - [](){ ProjectManager::instance()->showDialogToSaveProject(); }); + []{ ProjectManager::instance()->showDialogToSaveProject(); }); } void MainMenu::setActionAsProjectLayoutToggle(Action* action) { qobject_cast(action->parent())->sigAboutToShow().connect( - [action](){ action->setChecked(ProjectManager::instance()->isLayoutInclusionMode()); }); + [action]{ action->setChecked(ProjectManager::instance()->isLayoutInclusionMode()); }); action->sigToggled().connect([](bool on){ ProjectManager::instance()->setLayoutInclusionMode(on); }); } void MainMenu::setActionAsShowPathVariableEditor(Action* action) { - action->sigTriggered().connect([](){ PathVariableEditor::instance()->show(); }); + action->sigTriggered().connect([]{ PathVariableEditor::instance()->show(); }); } void MainMenu::setActionAsExitApplication(Action* action) { - action->sigTriggered().connect([](){ MainWindow::instance()->close(); }); + action->sigTriggered().connect([]{ MainWindow::instance()->close(); }); } void MainMenu::setActionAsUndo(Action* action) { qobject_cast(action->parent())->sigAboutToShow().connect( - [action](){ action->setEnabled(UnifiedEditHistory::instance()->isUndoable()); }); - action->sigTriggered().connect([](){ UnifiedEditHistory::instance()->undo(); }); + [action]{ action->setEnabled(UnifiedEditHistory::instance()->isUndoable()); }); + action->sigTriggered().connect([]{ UnifiedEditHistory::instance()->undo(); }); } void MainMenu::setActionAsRedo(Action* action) { qobject_cast(action->parent())->sigAboutToShow().connect( - [action](){ action->setEnabled(UnifiedEditHistory::instance()->isRedoable()); }); - action->sigTriggered().connect([](){ UnifiedEditHistory::instance()->redo(); }); + [action]{ action->setEnabled(UnifiedEditHistory::instance()->isRedoable()); }); + action->sigTriggered().connect([]{ UnifiedEditHistory::instance()->redo(); }); } void MainMenu::setMenuAsToolBarVisibilityMenu(Menu* menu) { menu->sigAboutToShow().connect( - [menu](){ MainWindow::instance()->toolBarArea()->setVisibilityMenuItems(menu); }); + [menu]{ MainWindow::instance()->toolBarArea()->setVisibilityMenuItems(menu); }); } void MainMenu::setMenuAsViewVisibilityMenu(Menu* menu) { - menu->sigAboutToShow().connect([this, menu](){ onViewOperationMenuAboutToShow(menu, ViewVisibilityMenu); }); + menu->sigAboutToShow().connect([this, menu]{ onViewOperationMenuAboutToShow(menu, ViewVisibilityMenu); }); } void MainMenu::setMenuAsViewCreationMenu(Menu* menu) { - menu->sigAboutToShow().connect([this, menu](){ onViewOperationMenuAboutToShow(menu, ViewCreationMenu); }); + menu->sigAboutToShow().connect([this, menu]{ onViewOperationMenuAboutToShow(menu, ViewCreationMenu); }); } void MainMenu::setMenuAsViewDeletionMenu(Menu* menu, bool isItemToDeleteAllHiddenViewsEnabled) { - menu->sigAboutToShow().connect([this, menu](){ onViewOperationMenuAboutToShow(menu, ViewDeletionMenu); }); + menu->sigAboutToShow().connect([this, menu]{ onViewOperationMenuAboutToShow(menu, ViewDeletionMenu); }); this->isItemToDeleteAllHiddenViewsEnabled = isItemToDeleteAllHiddenViewsEnabled; } @@ -439,7 +441,7 @@ void MainMenu::onViewOperationMenuAboutToShow(Menu* menu, int viewMenuType) auto action = new Action(menu); action->setText(viewClass->translatedDefaultInstanceName()); action->sigTriggered().connect( - [viewClass](){ + [viewClass]{ if(auto view = viewClass->createViewWithDialog()){ view->mountOnMainWindow(true); } @@ -456,7 +458,7 @@ void MainMenu::onViewOperationMenuAboutToShow(Menu* menu, int viewMenuType) auto action = new Action(menu); action->setText(view->windowTitle()); action->sigTriggered().connect( - [view](){ ViewManager::deleteView(view); }); + [view]{ ViewManager::deleteView(view); }); menu->addAction(action); } } @@ -469,7 +471,7 @@ void MainMenu::onViewOperationMenuAboutToShow(Menu* menu, int viewMenuType) auto action = new Action(menu); action->setText(_("Delete All Unmounted Views")); action->sigTriggered().connect( - [](){ViewManager::deleteUnmountedViews(); }); + []{ViewManager::deleteUnmountedViews(); }); menu->addAction(action); } } @@ -478,7 +480,7 @@ void MainMenu::onViewOperationMenuAboutToShow(Menu* menu, int viewMenuType) void MainMenu::setActionAsViewTabToggle(Action* action) { qobject_cast(action->parent())->sigAboutToShow().connect( - [action](){ action->setChecked(MainWindow::instance()->viewArea()->viewTabsVisible()); }); + [action]{ action->setChecked(MainWindow::instance()->viewArea()->viewTabsVisible()); }); action->sigToggled().connect( [](bool on){ MainWindow::instance()->viewArea()->setViewTabsVisible(on); }); } @@ -487,7 +489,7 @@ void MainMenu::setActionAsViewTabToggle(Action* action) void MainMenu::setActionAsStatusBarToggle(Action* action) { qobject_cast(action->parent())->sigAboutToShow().connect( - [action](){ action->setChecked(InfoBar::instance()->isVisible()); }); + [action]{ action->setChecked(InfoBar::instance()->isVisible()); }); action->sigToggled().connect([](bool on){ InfoBar::instance()->setVisible(on); }); } @@ -509,31 +511,37 @@ void MainMenu::setActionAsFullScreenToggle(Action* action) void MainMenu::setActionAsResetMainWindowLayout(Action* action) { - action->sigTriggered().connect([](){ MainWindow::instance()->resetLayout(); }); + action->sigTriggered().connect([]{ MainWindow::instance()->resetLayout(); }); } void MainMenu::setActionAsShowDistanceMeasurementDialog(Action* action) { - action->sigTriggered().connect([](){ DistanceMeasurementDialog::instance()->show(); }); + action->sigTriggered().connect([]{ DistanceMeasurementDialog::instance()->show(); }); } void MainMenu::setActionAsPutSceneStatistics(Action* action) { - action->sigTriggered().connect([](){ putRenderableItemSceneStatistics(); }); + action->sigTriggered().connect([]{ putRenderableItemSceneStatistics(); }); +} + + +void MainMenu::setActionAsExportSelectedRenderableItemScene(Action* action) +{ + action->sigTriggered().connect([]{ showDialogToExportSelectedRenderableItemScene(); }); } void MainMenu::setActionAsShowMovieRecorderDialog(Action* action) { - action->sigTriggered().connect([](){ MovieRecorderDialog::instance()->show(); }); + action->sigTriggered().connect([]{ MovieRecorderDialog::instance()->show(); }); } void MainMenu::setActionAsShowDialogAboutChoreonoid(Action* action) { - action->sigTriggered().connect([](){ showDialogAboutChoreonoid(); }); + action->sigTriggered().connect([]{ showDialogAboutChoreonoid(); }); } diff --git a/src/Base/MainMenu.h b/src/Base/MainMenu.h index ec8824970..cf280606f 100644 --- a/src/Base/MainMenu.h +++ b/src/Base/MainMenu.h @@ -79,6 +79,7 @@ class CNOID_EXPORT MainMenu void setActionAsResetMainWindowLayout(Action* action); void setActionAsShowDistanceMeasurementDialog(Action* action); void setActionAsPutSceneStatistics(Action* action); + void setActionAsExportSelectedRenderableItemScene(Action* action); void setActionAsShowMovieRecorderDialog(Action* action); void setActionAsShowDialogAboutChoreonoid(Action* action); diff --git a/src/Base/RenderableItemSceneExporter.cpp b/src/Base/RenderableItemSceneExporter.cpp new file mode 100644 index 000000000..cec2b831e --- /dev/null +++ b/src/Base/RenderableItemSceneExporter.cpp @@ -0,0 +1,75 @@ +#include "RenderableItemSceneExporter.h" +#include "MainWindow.h" +#include "RootItem.h" +#include "RenderableItem.h" +#include "FileDialog.h" +#include +#include +#include +#include +#include "gettext.h" + +using namespace std; +using namespace cnoid; + + +void cnoid::showDialogToExportSelectedRenderableItemScene() +{ + FileDialog dialog(MainWindow::instance()); + dialog.setWindowTitle(_("Export the scene of selected items")); + dialog.setViewMode(QFileDialog::List); + dialog.setAcceptMode(QFileDialog::AcceptSave); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setLabelText(QFileDialog::Accept, _("Export")); + dialog.setLabelText(QFileDialog::Reject, _("Cancel")); + dialog.setNameFilter("OBJ file (*.obj)"); + dialog.updatePresetDirectories(); + if(dialog.exec() == QDialog::Accepted){ + auto mout = MessageOut::master(); + string filename = dialog.selectedFiles().value(0).toStdString(); + auto items = RootItem::instance()->selectedItems(); + if(items.empty()){ + mout->putErrorln(_("No selected items.")); + } else { + exportRenderableItemSceneAsObjFile(items, filename, mout); + } + } +} + + +bool cnoid::exportRenderableItemSceneAsObjFile +(const ItemList<>& items, const std::string& filename, MessageOut* mout) +{ + SgGroupPtr scene = new SgGroup; + vector sceneItems; + for(auto& item : items){ + if(auto renderableItem = dynamic_cast(item.get())){ + scene->addChild(renderableItem->getScene()); + sceneItems.push_back(item.get()); + } + } + if(scene->empty()){ + mout->putWarningln(_("Scene to export is empty.")); + return false; + } + + mout->put(formatR(_("Export the scene of the following items to \"{0}\":\n "), filename)); + for(int i=0; i < sceneItems.size(); ++i){ + mout->put(sceneItems[i]->displayName()); + if(i < sceneItems.size() - 1){ + mout->put(", "); + } + } + mout->putln(""); + + ObjSceneWriter sceneWriter; + sceneWriter.setMessageSink(mout->cout()); + bool result = sceneWriter.writeScene(filename, scene); + if(result){ + mout->putln(_("Completed!")); + } else { + mout->putErrorln(_("Failed.")); + } + + return result; +} diff --git a/src/Base/RenderableItemSceneExporter.h b/src/Base/RenderableItemSceneExporter.h new file mode 100644 index 000000000..c2ddbe4f3 --- /dev/null +++ b/src/Base/RenderableItemSceneExporter.h @@ -0,0 +1,17 @@ +#ifndef CNOID_BASE_RENDERABLE_ITEM_SCENE_EXPORTER_H +#define CNOID_BASE_RENDERABLE_ITEM_SCENE_EXPORTER_H + +#include "ItemList.h" +#include "exportdecl.h" + +namespace cnoid { + +class MessageOut; + +CNOID_EXPORT void showDialogToExportSelectedRenderableItemScene(); +CNOID_EXPORT bool exportRenderableItemSceneAsObjFile( + const ItemList<>& items, const std::string& filename, MessageOut* mout); + +} + +#endif From 816f0c671454ff6f16f8013800e26428ab9e6bd7 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 26 Jul 2024 22:50:57 +0900 Subject: [PATCH 21/73] Update Japanese translations for the Base module --- src/Base/po/ja.po | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Base/po/ja.po b/src/Base/po/ja.po index d08cc10a4..e706d8a3a 100644 --- a/src/Base/po/ja.po +++ b/src/Base/po/ja.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Choreonoid\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-26 11:55+0900\n" +"POT-Creation-Date: 2024-08-09 23:11+0900\n" "PO-Revision-Date: 2021-10-25 12:00+0900\n" "Language: ja\n" "MIME-Version: 1.0\n" @@ -1008,6 +1008,9 @@ msgstr "ツール" msgid "Put Scene Statistics" msgstr "シーン統計情報の表示" +msgid "Export Scene" +msgstr "シーンのエクスポート" + msgid "Movie Recorder" msgstr "動画レコーダ" @@ -1599,6 +1602,29 @@ msgstr "プロジェクトパック \"{0}\" はプロジェクトファイルを msgid "ReferencedObjectSeqItem" msgstr "参照オブジェクト時系列アイテム" +msgid "Export the scene of selected items" +msgstr "選択アイテムのシーンのエクスポート" + +msgid "Export" +msgstr "エクスポート" + +msgid "No selected items." +msgstr "アイテムが選択されていません." + +msgid "Scene to export is empty." +msgstr "エクスポートするシーンが空です." + +msgid "" +"Export the scene of the following items to \"{0}\":\n" +" " +msgstr "以下のアイテムのシーンを \"{0}\" にエクスポートします:\n " + +msgid "Completed!" +msgstr "完了!" + +msgid "Failed." +msgstr "失敗." + msgid "Scene statistics:" msgstr "シーン統計情報:" From 5f55a70d2af3c4b6f996a25a348a322e132453dc Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Sat, 10 Aug 2024 16:26:20 +0900 Subject: [PATCH 22/73] Improve HolderDevice to support multiple categories --- src/Body/AttachmentDevice.cpp | 20 ++++- src/Body/AttachmentDevice.h | 1 + src/Body/HolderDevice.cpp | 97 +++++++++++++++++++---- src/Body/HolderDevice.h | 9 +++ src/BodyPlugin/BodyItem.cpp | 2 +- src/BodyPlugin/KinematicSimulatorItem.cpp | 7 +- 6 files changed, 115 insertions(+), 21 deletions(-) diff --git a/src/Body/AttachmentDevice.cpp b/src/Body/AttachmentDevice.cpp index 01777e756..28a56b16c 100644 --- a/src/Body/AttachmentDevice.cpp +++ b/src/Body/AttachmentDevice.cpp @@ -134,8 +134,9 @@ std::string AttachmentDevice::category() const void AttachmentDevice::setCategory(const std::string& category) { - clearCategory(); - category_ = new string; + if(!category_){ + category_ = new string; + } *category_ = category; } @@ -149,6 +150,21 @@ void AttachmentDevice::clearCategory() } +bool AttachmentDevice::isAttachableTo(HolderDevice* holder) const +{ + if(body() == holder->body()){ + return false; + } + if(!holder->hasCategories()){ + return true; + } + if(!category_){ + return false; + } + return holder->hasCategory(*category_); +} + + int AttachmentDevice::stateSize() const { return 1; diff --git a/src/Body/AttachmentDevice.h b/src/Body/AttachmentDevice.h index 0d077ad97..8e25a13aa 100644 --- a/src/Body/AttachmentDevice.h +++ b/src/Body/AttachmentDevice.h @@ -35,6 +35,7 @@ class CNOID_EXPORT AttachmentDevice : public Device std::string category() const; void setCategory(const std::string& category); void clearCategory(); + bool isAttachableTo(HolderDevice* holder) const; bool readSpecifications(const Mapping* info); bool writeSpecifications(Mapping* info) const; diff --git a/src/Body/HolderDevice.cpp b/src/Body/HolderDevice.cpp index 772304090..df15ab3f4 100644 --- a/src/Body/HolderDevice.cpp +++ b/src/Body/HolderDevice.cpp @@ -13,7 +13,7 @@ namespace cnoid { class HolderDevice::NonState { public: - std::string category; + vector categories; int holdCondition; double maxHoldDistance; std::string holdTargetName; @@ -53,7 +53,7 @@ HolderDevice::HolderDevice(const HolderDevice& org, bool copyStateOnly, CloneMap HolderDevice::NonState::NonState(const NonState& org, CloneMap* cloneMap) - : category(org.category), + : categories(org.categories), holdTargetName(org.holdTargetName) { holdCondition = org.holdCondition; @@ -114,7 +114,7 @@ Referenced* HolderDevice::doClone(CloneMap* cloneMap) const void HolderDevice::copyHolderDeviceFrom(const HolderDevice* other) { - ns->category = other->ns->category; + ns->categories = other->ns->categories; ns->holdCondition = other->ns->holdCondition; ns->maxHoldDistance = other->ns->maxHoldDistance; ns->holdTargetName = other->ns->holdTargetName; @@ -152,10 +152,60 @@ void HolderDevice::on(bool on) } -std::string HolderDevice::category() const +std::vector HolderDevice::categories() const +{ + if(ns){ + return ns->categories; + } + return vector(); +} + + +bool HolderDevice::hasCategories() const +{ + return ns && !ns->categories.empty(); +} + + +bool HolderDevice::hasCategory(const char* category) const +{ + if(ns){ + for(auto& c : ns->categories){ + if(c == category){ + return true; + } + } + } + return false; +} + + +bool HolderDevice::hasCategory(const std::string& category) const +{ + return hasCategory(category.c_str()); +} + + +void HolderDevice::addCategory(const std::string& category) +{ + if(!category.empty() && ns){ + ns->categories.push_back(category); + } +} + + +void HolderDevice::clearCategories() { if(ns){ - return ns->category; + ns->categories.clear(); + } +} + + +std::string HolderDevice::category() const +{ + if(ns && !ns->categories.empty()){ + return ns->categories.front(); } return string(); } @@ -164,7 +214,8 @@ std::string HolderDevice::category() const void HolderDevice::setCategory(const std::string& category) { if(ns){ - ns->category = category; + ns->categories.clear(); + ns->categories.push_back(category); } } @@ -299,29 +350,45 @@ double* HolderDevice::writeState(double* out_buf) const bool HolderDevice::readDescription(const Mapping* info) { - if(!info->read("category", ns->category)){ - ns->category.clear(); + string symbol; + + clearCategories(); + if(auto& categories = *info->findListing("categories")){ + for(auto& category : categories){ + addCategory(category->toString()); + } + } else if(info->read("category", symbol)){ + addCategory(symbol); } - string condition; - if(info->read("hold_condition", condition)){ - if(condition == "distance"){ + + if(info->read("hold_condition", symbol)){ + if(symbol == "distance"){ ns->holdCondition = Distance; - } else if(condition == "collision"){ + } else if(symbol == "collision"){ ns->holdCondition = Collision; - } else if(condition == "name"){ + } else if(symbol == "name"){ ns->holdCondition = Name; } } info->read("max_hold_distance", ns->maxHoldDistance); info->read("hold_target_name", ns->holdTargetName); + return true; } bool HolderDevice::writeDescription(Mapping* info) const { - if(!ns->category.empty()){ - info->write("category", ns->category); + if(!ns->categories.empty()){ + if(ns->categories.size() == 1){ + // For backward compatibility + info->write("category", ns->categories.front()); + } else { + auto categories = info->openListing("categories"); + for(auto& category : ns->categories){ + categories->append(category); + } + } } string condition; switch(ns->holdCondition){ diff --git a/src/Body/HolderDevice.h b/src/Body/HolderDevice.h index 0c4fb675e..ab3954732 100644 --- a/src/Body/HolderDevice.h +++ b/src/Body/HolderDevice.h @@ -30,7 +30,16 @@ class CNOID_EXPORT HolderDevice : public Device virtual bool on() const override; virtual void on(bool on) override; + std::vector categories() const; + bool hasCategories() const; + bool hasCategory(const char* category) const; + bool hasCategory(const std::string& category) const; + void addCategory(const std::string& category); + void clearCategories(); + + [[deprecated("Use hasCategory or categories.")]] std::string category() const; + [[deprecated("Use addCategory.")]] void setCategory(const std::string& category); enum HoldCondition { Distance, Collision, Name }; diff --git a/src/BodyPlugin/BodyItem.cpp b/src/BodyPlugin/BodyItem.cpp index 407cf21fc..2f715f1ff 100644 --- a/src/BodyPlugin/BodyItem.cpp +++ b/src/BodyPlugin/BodyItem.cpp @@ -1523,7 +1523,7 @@ Link* BodyItem::Impl::attachToBodyItem(BodyItem* bodyItem) for(auto& attachment : body->devices()){ if(attachment->link()->isRoot()){ for(auto& holder : bodyItem->body()->devices()){ - if(attachment->category() == holder->category()){ + if(attachment->isAttachableTo(holder)){ holder->addAttachment(attachment); holder->on(true); attachment->on(true); diff --git a/src/BodyPlugin/KinematicSimulatorItem.cpp b/src/BodyPlugin/KinematicSimulatorItem.cpp index afa18d3ac..955233e2d 100644 --- a/src/BodyPlugin/KinematicSimulatorItem.cpp +++ b/src/BodyPlugin/KinematicSimulatorItem.cpp @@ -341,7 +341,7 @@ void KinematicSimulatorItem::Impl::activateHolder(HolderInfo* info) auto rootLink = body->rootLink(); AttachmentDevice* attachment = nullptr; for(auto& device : body->devices()){ - if(device->link() == rootLink && device->category() == holder->category()){ + if(device->link() == rootLink && device->isAttachableTo(holder)){ attachment = device; break; } @@ -422,10 +422,11 @@ void KinematicSimulatorItem::Impl::onHolderCollisionDetected void KinematicSimulatorItem::Impl::findAttachableBodiesByDistance (HolderDevice* holder, const Isometry3& T_holder, vector& out_bodies) { + auto holderBody = holder->body(); const double maxDistance = holder->maxHoldDistance(); for(auto& simBody : self->simulationBodies()){ - if(simBody->isActive()){ - Body* body = simBody->body(); + Body* body = simBody->body(); + if(body != holderBody && simBody->isActive()){ while(body){ auto rootLink = body->rootLink(); if(rootLink->isFreeJoint()){ From 510e41c9e984d82fd8fa2e4d65e056dc5590adae Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Sun, 11 Aug 2024 14:16:42 +0900 Subject: [PATCH 23/73] Fix KinematicBodyItemSet to emit KinematicBodySet::sigBodySetChanged when any associated body item is removed --- src/Body/KinematicBodySet.cpp | 7 ++++++- src/Body/KinematicBodySet.h | 4 +++- src/BodyPlugin/KinematicBodyItemSet.cpp | 14 ++++++++++++++ src/BodyPlugin/KinematicBodyItemSet.h | 7 ++++++- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/Body/KinematicBodySet.cpp b/src/Body/KinematicBodySet.cpp index 2bc0cae16..88ae97cb6 100644 --- a/src/Body/KinematicBodySet.cpp +++ b/src/Body/KinematicBodySet.cpp @@ -53,7 +53,7 @@ void KinematicBodySet::setBodyPart(int index, BodyKinematicsKit* kinematicsKit) } -void KinematicBodySet::clearBodyPart(int index) +void KinematicBodySet::removeBodyPart(int index) { if(index < static_cast(bodyParts_.size())){ auto& part = bodyParts_[index]; @@ -80,6 +80,11 @@ void KinematicBodySet::clearBodyPart(int index) void KinematicBodySet::clear() { + for(size_t i=0; i < bodyParts_.size(); ++i){ + if(bodyParts_[i]){ + removeBodyPart(i); + } + } bodyParts_.clear(); numValidBodyParts_ = 0; mainBodyPartIndex_ = -1; diff --git a/src/Body/KinematicBodySet.h b/src/Body/KinematicBodySet.h index e0e42cdd6..26760dfdf 100644 --- a/src/Body/KinematicBodySet.h +++ b/src/Body/KinematicBodySet.h @@ -17,7 +17,9 @@ class CNOID_EXPORT KinematicBodySet : public ClonableReferenced } virtual void setBodyPart(int index, BodyKinematicsKit* kinematicsKit); - void clearBodyPart(int index); + virtual void removeBodyPart(int index); + [[deprecated("Use removeBodyPart.")]] + void clearBodyPart(int index) { removeBodyPart(index); } void clear(); void setMainBodyPartIndex(int index) { mainBodyPartIndex_ = index; } int mainBodyPartIndex() const { return mainBodyPartIndex_; } diff --git a/src/BodyPlugin/KinematicBodyItemSet.cpp b/src/BodyPlugin/KinematicBodyItemSet.cpp index 9bf4a1aeb..761d417e6 100644 --- a/src/BodyPlugin/KinematicBodyItemSet.cpp +++ b/src/BodyPlugin/KinematicBodyItemSet.cpp @@ -27,13 +27,27 @@ Referenced* KinematicBodyItemSet::doClone(CloneMap* cloneMap) const void KinematicBodyItemSet::setBodyPart(int index, BodyKinematicsKit* kinematicsKit) { if(auto kit = dynamic_cast(kinematicsKit)){ + bodyItemConnectionMap[index] = + kit->bodyItem()->sigDisconnectedFromRoot().connect( + [this, index]{ + removeBodyPart(index); + notifyBodySetChange(); + }); KinematicBodySet::setBodyPart(index, kit); + } else { throw std::invalid_argument("Type mismatch in the KinematicBodyItemSet::setBodyPart function"); } } +void KinematicBodyItemSet::removeBodyPart(int index) +{ + bodyItemConnectionMap.erase(index); + KinematicBodySet::removeBodyPart(index); +} + + int KinematicBodyItemSet::indexOf(const BodyItem* item) const { int index = -1; diff --git a/src/BodyPlugin/KinematicBodyItemSet.h b/src/BodyPlugin/KinematicBodyItemSet.h index e0f954ebc..b6fa64dfa 100644 --- a/src/BodyPlugin/KinematicBodyItemSet.h +++ b/src/BodyPlugin/KinematicBodyItemSet.h @@ -3,6 +3,7 @@ #include "BodyItemKinematicsKit.h" #include +#include #include "exportdecl.h" namespace cnoid { @@ -15,9 +16,10 @@ class CNOID_EXPORT KinematicBodyItemSet : public KinematicBodySet KinematicBodyItemSet(); void setBodyItemPart(int index, BodyItemKinematicsKit* kinematicsKit) { - KinematicBodySet::setBodyPart(index, kinematicsKit); + setBodyPart(index, kinematicsKit); } virtual void setBodyPart(int index, BodyKinematicsKit* kinematicsKit) override; + virtual void removeBodyPart(int index) override; BodyItemKinematicsKit* bodyItemPart(int index){ return static_cast(bodyPart(index)); @@ -53,6 +55,9 @@ class CNOID_EXPORT KinematicBodyItemSet : public KinematicBodySet protected: KinematicBodyItemSet(const KinematicBodyItemSet& org, CloneMap* cloneMap); virtual Referenced* doClone(CloneMap* cloneMap) const override; + +private: + std::map bodyItemConnectionMap; }; typedef ref_ptr KinematicBodyItemSetPtr; From e740e34d4939d558bba350d41221487c7070a2d8 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 14 Aug 2024 00:03:13 +0900 Subject: [PATCH 24/73] Remove unnecessary headers from MovieRecorderDialog.cpp --- src/Base/MovieRecorderDialog.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Base/MovieRecorderDialog.cpp b/src/Base/MovieRecorderDialog.cpp index 74b0dd201..1b8e44e5d 100644 --- a/src/Base/MovieRecorderDialog.cpp +++ b/src/Base/MovieRecorderDialog.cpp @@ -6,11 +6,9 @@ #include "LineEdit.h" #include "CheckBox.h" #include "ComboBox.h" -#include "Dialog.h" #include "FileDialog.h" #include "Separator.h" #include -#include #include "gettext.h" using namespace std; From ea20e77f2bba6ffb46ae6d98dc2b7e774b80f622 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 14 Aug 2024 00:06:31 +0900 Subject: [PATCH 25/73] Remove an extraneous character from Link.cpp --- src/Body/Link.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Body/Link.cpp b/src/Body/Link.cpp index 992813295..e15d5f698 100644 --- a/src/Body/Link.cpp +++ b/src/Body/Link.cpp @@ -450,7 +450,7 @@ void Link::setMaterial(const std::string& name) bool Link::hasShape() const { - return !visualShape_->empty() || !collisionShape_->empty();\ + return !visualShape_->empty() || !collisionShape_->empty(); } From c99225e8225bccf82950bcf035fac3ffdd273875 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 12 Aug 2024 16:35:37 +0900 Subject: [PATCH 26/73] Add functions to SgObject, SgNode and SgMaterial - Add SgObject::traverseObjects - Add SgNode::traverseNodes - Add SgMaterial::copyMaterialPropertiesFrom --- src/Util/SceneDrawables.cpp | 18 +++++++++++------ src/Util/SceneDrawables.h | 2 ++ src/Util/SceneGraph.cpp | 39 +++++++++++++++++++++++++++++++++++++ src/Util/SceneGraph.h | 13 +++++++++++++ 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/Util/SceneDrawables.cpp b/src/Util/SceneDrawables.cpp index c9a34d1f7..ab626b186 100644 --- a/src/Util/SceneDrawables.cpp +++ b/src/Util/SceneDrawables.cpp @@ -40,12 +40,18 @@ SgMaterial::SgMaterial() SgMaterial::SgMaterial(const SgMaterial& org) : SgObject(org) { - ambientIntensity_ = org.ambientIntensity_; - diffuseColor_ = org.diffuseColor_; - emissiveColor_ = org.emissiveColor_; - specularColor_ = org.specularColor_; - specularExponent_ = org.specularExponent_; - transparency_ = org.transparency_; + copyMaterialPropertiesFrom(&org); +} + + +void SgMaterial::copyMaterialPropertiesFrom(const SgMaterial* other) +{ + ambientIntensity_ = other->ambientIntensity_; + diffuseColor_ = other->diffuseColor_; + emissiveColor_ = other->emissiveColor_; + specularColor_ = other->specularColor_; + specularExponent_ = other->specularExponent_; + transparency_ = other->transparency_; } diff --git a/src/Util/SceneDrawables.h b/src/Util/SceneDrawables.h index ab9aeaf89..45d221ab3 100644 --- a/src/Util/SceneDrawables.h +++ b/src/Util/SceneDrawables.h @@ -16,6 +16,8 @@ class CNOID_EXPORT SgMaterial : public SgObject SgMaterial(); SgMaterial(const SgMaterial& org); + void copyMaterialPropertiesFrom(const SgMaterial* other); + float ambientIntensity() const { return ambientIntensity_; } void setAmbientIntensity(float intensity) { ambientIntensity_ = intensity; } const Vector3f& diffuseColor() const { return diffuseColor_; } diff --git a/src/Util/SceneGraph.cpp b/src/Util/SceneGraph.cpp index fdc84c4c4..5dad266c5 100644 --- a/src/Util/SceneGraph.cpp +++ b/src/Util/SceneGraph.cpp @@ -99,6 +99,25 @@ SgObject* SgObject::findObject_(std::function& pred) } +bool SgObject::traverseObjects_(std::function& pred) +{ + auto status = pred(this); + if(status == Stop){ + return false; + } + if(status == Next){ + return true; + } + int n = numChildObjects(); + for(int i=0; i < n; ++i){ + if(!childObject(i)->traverseObjects_(pred)){ + return false; + } + } + return true; +} + + void SgObject::notifyUpperNodesOfUpdate(SgUpdate& update) { notifyUpperNodesOfUpdate(update, update.hasAction(SgUpdate::GeometryModified)); @@ -425,6 +444,26 @@ SgNodePath SgNode::findNode(const std::string& name, Affine3& out_T) } +bool SgNode::traverseNodes_(std::function& pred) +{ + auto status = pred(this); + if(status == Stop){ + return false; + } + if(status == Next){ + return true; + } + if(auto group = toGroupNode()){ + for(auto& child : *group){ + if(!child->traverseNodes_(pred)){ + return false; + } + } + } + return true; +} + + SgGroup::SgGroup() : SgNode(findClassId()) { diff --git a/src/Util/SceneGraph.h b/src/Util/SceneGraph.h index 52fc610c9..8b27971bf 100644 --- a/src/Util/SceneGraph.h +++ b/src/Util/SceneGraph.h @@ -79,6 +79,12 @@ class CNOID_EXPORT SgObject : public ClonableReferenced return findObject_(pred); } + enum TraverseStatus { Continue, Next, Stop }; + + bool traverseObjects(std::function pred) { + return traverseObjects_(pred); + } + SignalProxy sigUpdated() { return sigUpdated_; } @@ -178,6 +184,7 @@ class CNOID_EXPORT SgObject : public ClonableReferenced mutable std::unique_ptr uriInfo; SgObject* findObject_(std::function& pred); + bool traverseObjects_(std::function& pred); }; typedef ref_ptr SgObjectPtr; @@ -229,6 +236,10 @@ class CNOID_EXPORT SgNode : public SgObject void releaseDecorationReference() { --decorationRefCounter; } bool isDecoratedSomewhere() const { return decorationRefCounter > 0; } + bool traverseNodes(std::function pred) { + return traverseNodes_(pred); + } + protected: SgNode(int classId); virtual Referenced* doClone(CloneMap* cloneMap) const override; @@ -237,6 +248,8 @@ class CNOID_EXPORT SgNode : public SgObject int classId_; int decorationRefCounter; + bool traverseNodes_(std::function& pred); + //! \deprecated static int registerNodeType(const std::type_info& nodeType, const std::type_info& superType); }; From 60f0fb3e5d00ccdd4ce77e772f24a4d9fed6cbf3 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Thu, 15 Aug 2024 11:35:19 +0900 Subject: [PATCH 27/73] Modify the metadata type for the URI information of a scene graph object from string to Mapping --- src/Util/AbstractSceneLoader.cpp | 53 +++++++++++++++++++--- src/Util/AbstractSceneLoader.h | 7 +-- src/Util/ObjSceneLoader.cpp | 16 ++----- src/Util/SceneGraph.cpp | 11 ++--- src/Util/SceneGraph.h | 9 ++-- src/Util/StdSceneReader.cpp | 75 ++++++++++++++++++++------------ src/Util/StdSceneReader.h | 2 +- src/Util/StdSceneWriter.cpp | 10 ++--- 8 files changed, 116 insertions(+), 67 deletions(-) diff --git a/src/Util/AbstractSceneLoader.cpp b/src/Util/AbstractSceneLoader.cpp index eb0ebafbd..c9a53138a 100644 --- a/src/Util/AbstractSceneLoader.cpp +++ b/src/Util/AbstractSceneLoader.cpp @@ -1,16 +1,13 @@ -/** - \author Shin'ichiro Nakaoka -*/ - #include "AbstractSceneLoader.h" +#include "ValueTree.h" +using namespace std; using namespace cnoid; AbstractSceneLoader::AbstractSceneLoader() { - lengthUnitHint_ = Meter; - upperAxisHint_ = Z_Upper; + clearHintsForLoading(); } @@ -50,6 +47,33 @@ void AbstractSceneLoader::setUpperAxisHint(UpperAxisType hint) } +void AbstractSceneLoader::clearHintsForLoading() +{ + lengthUnitHint_ = Meter; + upperAxisHint_ = Z_Upper; +} + + +void AbstractSceneLoader::restoreLengthUnitAndUpperAxisHints(Mapping* metadata) +{ + if(metadata){ + string symbol; + if(metadata->read("length_unit", symbol)){ + if(symbol == "millimeter"){ + lengthUnitHint_ = Millimeter; + } else if(symbol == "inch"){ + lengthUnitHint_ = Inch; + } + } + if(metadata->read("upper_axis", symbol)){ + if(symbol == "Y"){ + upperAxisHint_ = Y_Upper; + } + } + } +} + + /** This function inserts a SgScaleTransform node and a SgPosTransform node to adjust the length unit and the upper direction axis. Each loader can use this function when all @@ -102,3 +126,20 @@ SgNode* AbstractSceneLoader::insertTransformNodeToAdjustUpperAxis(SgNode* node) } return node; } + + +void AbstractSceneLoader::storeLengthUnitAndUpperAxisHintsAsMetadata(SgObject* object) +{ + MappingPtr metadata = new Mapping; + if(lengthUnitHint_ == Millimeter){ + metadata->write("length_unit", "millimeter"); + } else if(lengthUnitHint_ == Inch){ + metadata->write("length_unit", "inch"); + } + if(upperAxisHint_ == Y_Upper){ + metadata->write("upper_axis", "Y"); + } + if(!metadata->empty()){ + object->setUriMetadata(metadata); + } +} diff --git a/src/Util/AbstractSceneLoader.h b/src/Util/AbstractSceneLoader.h index 5497efa83..bd0bf2477 100644 --- a/src/Util/AbstractSceneLoader.h +++ b/src/Util/AbstractSceneLoader.h @@ -1,6 +1,3 @@ -/** - @author Shin'ichiro Nakaoka -*/ #ifndef CNOID_UTIL_ABSTRACT_SCENE_LOADER_H #define CNOID_UTIL_ABSTRACT_SCENE_LOADER_H @@ -28,11 +25,15 @@ class CNOID_EXPORT AbstractSceneLoader virtual void setUpperAxisHint(UpperAxisType hint); UpperAxisType upperAxisHint() const { return upperAxisHint_; } + void clearHintsForLoading(); + void restoreLengthUnitAndUpperAxisHints(Mapping* metadata); + virtual SgNode* load(const std::string& filename) = 0; protected: SgNode* insertTransformNodesToAdjustLengthUnitAndUpperAxis(SgNode* node); SgNode* insertTransformNodeToAdjustUpperAxis(SgNode* node); + void storeLengthUnitAndUpperAxisHintsAsMetadata(SgObject* object); private: LengthUnitType lengthUnitHint_; diff --git a/src/Util/ObjSceneLoader.cpp b/src/Util/ObjSceneLoader.cpp index 48a181cda..dbf1e2242 100644 --- a/src/Util/ObjSceneLoader.cpp +++ b/src/Util/ObjSceneLoader.cpp @@ -4,6 +4,7 @@ #include "SceneLoader.h" #include "Triangulator.h" #include "ImageIO.h" +#include "ValueTree.h" #include "NullOut.h" #include "Format.h" #include @@ -217,26 +218,17 @@ SgNode* ObjSceneLoader::Impl::load(const string& filename) doCoordinateConversion = false; scale = 1.0f; - string metadata; auto lengthUnit = self->lengthUnitHint(); if(lengthUnit == AbstractSceneLoader::Millimeter){ scale = 1.0e-3f; doCoordinateConversion = true; - metadata = "millimeter"; } else if(lengthUnit == AbstractSceneLoader::Inch){ scale = 0.0254f; doCoordinateConversion = true; - metadata = "inch"; } upperAxis = self->upperAxisHint(); - if(upperAxis != Z_Upper){ + if(upperAxis == Y_Upper){ doCoordinateConversion = true; - if(upperAxis == Y_Upper){ - if(!metadata.empty()){ - metadata += " "; - } - metadata += "y_upper"; - } } try { @@ -248,9 +240,7 @@ SgNode* ObjSceneLoader::Impl::load(const string& filename) if(scene){ scene->setUriWithFilePathAndCurrentDirectory(filename); - if(!metadata.empty()){ - scene->setUriMetadataString(metadata); - } + self->storeLengthUnitAndUpperAxisHintsAsMetadata(scene); } scanner.close(); diff --git a/src/Util/SceneGraph.cpp b/src/Util/SceneGraph.cpp index 5dad266c5..139ffc6d9 100644 --- a/src/Util/SceneGraph.cpp +++ b/src/Util/SceneGraph.cpp @@ -1,6 +1,7 @@ #include "SceneGraph.h" #include "SceneNodeClassRegistry.h" #include "CloneMap.h" +#include "ValueTree.h" #include "UTF8.h" #include "Format.h" #include @@ -240,12 +241,12 @@ const std::string& SgObject::uriFragment() const } -const std::string& SgObject::uriMetadataString() const +Mapping* SgObject::uriMetadata() const { - if(!uriInfo){ - uriInfo.reset(new UriInfo); + if(uriInfo){ + return static_cast(uriInfo->metadata.get()); } - return uriInfo->metadata; + return nullptr; } @@ -319,7 +320,7 @@ void SgObject::setUriFragment(const std::string& fragment) } -void SgObject::setUriMetadataString(const std::string& data) +void SgObject::setUriMetadata(Mapping* data) { if(!uriInfo){ uriInfo.reset(new UriInfo); diff --git a/src/Util/SceneGraph.h b/src/Util/SceneGraph.h index 8b27971bf..cf0b59b7b 100644 --- a/src/Util/SceneGraph.h +++ b/src/Util/SceneGraph.h @@ -19,6 +19,7 @@ class SgNode; typedef ref_ptr SgNodePtr; class SgGroup; class SgTransform; +class Mapping; typedef std::vector SgNodePath; @@ -137,8 +138,8 @@ class CNOID_EXPORT SgObject : public ClonableReferenced const std::string& uriObjectName() const; bool hasUriFragment() const { return uriInfo && !uriInfo->fragment.empty(); } const std::string& uriFragment() const; - bool hasUriMetadataString() const { return uriInfo && !uriInfo->metadata.empty(); } - const std::string& uriMetadataString() const; + + Mapping* uriMetadata() const; void setUriWithFilePathAndBaseDirectory(const std::string& filePath, const std::string& baseDirectory); [[deprecated("Use setUriWithFilePathAndBaseDirectory.")]] void setUriByFilePathAndBaseDirectory(const std::string& filePath, const std::string& baseDirectory); @@ -148,7 +149,7 @@ class CNOID_EXPORT SgObject : public ClonableReferenced void setUri(const std::string& uri, const std::string& absoluteUri); void setUriObjectName(const std::string& name); void setUriFragment(const std::string& fragment); - void setUriMetadataString(const std::string& data); + void setUriMetadata(Mapping* data); void clearUri() { uriInfo.reset(); } bool isNode() const { return hasAttribute(Node); } @@ -178,7 +179,7 @@ class CNOID_EXPORT SgObject : public ClonableReferenced std::string absoluteUri; std::string objectName; std::string fragment; - std::string metadata; + ReferencedPtr metadata; // Actual type is MappingPtr }; mutable std::unique_ptr uriInfo; diff --git a/src/Util/StdSceneReader.cpp b/src/Util/StdSceneReader.cpp index e28c7ebad..bbe2ac02b 100644 --- a/src/Util/StdSceneReader.cpp +++ b/src/Util/StdSceneReader.cpp @@ -69,7 +69,7 @@ class StdSceneReader::Impl unique_ptr yamlReader; string directory; string file; - string metadata; + MappingPtr metadata; }; typedef ref_ptr ResourceInfoPtr; @@ -77,7 +77,6 @@ class StdSceneReader::Impl string baseDirectory; SceneLoader sceneLoader; - bool sceneLoaderConfigurationChanged; unique_ptr uriSchemeProcessor; typedef map ImagePathToSgImageMap; ImagePathToSgImageMap imagePathToSgImageMap; @@ -137,8 +136,9 @@ class StdSceneReader::Impl SgNode* readText(Mapping* info); SgNode* readResourceAsScene(Mapping* info); Resource readResourceNode(Mapping* info); + MappingPtr readOldFormatMetaDataString(const std::string& data); void extractNamedSceneNodes(Mapping* resourceNode, ResourceInfo* info, Resource& resource); - ResourceInfo* getOrCreateResourceInfo(Mapping* resourceNode, const string& uri, const string& metadata); + ResourceInfo* getOrCreateResourceInfo(Mapping* resourceNode, const string& uri, Mapping* metadata); stdx::filesystem::path findFileInPackage(const string& file); void adjustNodeCoordinate(SceneNodeInfo& info); void makeSceneNodeMap(ResourceInfo* info); @@ -213,7 +213,6 @@ StdSceneReader::Impl::Impl(StdSceneReader* self) } os_ = &nullout(); - sceneLoaderConfigurationChanged = false; imageIO.setUpsideDown(true); } @@ -1672,7 +1671,14 @@ StdSceneReader::Resource StdSceneReader::Impl::readResourceNode(Mapping* info) if(fragmentNode->isValid()){ resource.fragment = fragmentNode->toString(); } - info->read("metadata", resource.metadata); + auto metadataNode = info->find("metadata"); + if(metadataNode->isValid()){ + if(metadataNode->isMapping()){ + resource.metadata = metadataNode->toMapping(); + } else if(metadataNode->isString()){ + resource.metadata = readOldFormatMetaDataString(metadataNode->toString()); + } + } ResourceInfo* resourceInfo = getOrCreateResourceInfo(info, resource.uri, resource.metadata); if(resourceInfo){ @@ -1722,6 +1728,9 @@ StdSceneReader::Resource StdSceneReader::Impl::readResourceNode(Mapping* info) if(!resource.fragment.empty()){ uriObject->setUriFragment(resource.fragment); } + if(resource.metadata){ + uriObject->setUriMetadata(resource.metadata); + } } } @@ -1729,6 +1738,33 @@ StdSceneReader::Resource StdSceneReader::Impl::readResourceNode(Mapping* info) } +MappingPtr StdSceneReader::Impl::readOldFormatMetaDataString(const std::string& data) +{ + MappingPtr metadata; + if(!data.empty()){ + metadata = new Mapping; + size_t start; + size_t end = 0; + string symbol; + while((start = data.find_first_not_of(' ', end)) != std::string::npos) { + end = data.find(' ', start); + symbol = data.substr(start, end - start); + if(symbol == "millimeter"){ + metadata->write("length_unit", "millimeter"); + } else if(symbol == "inch"){ + metadata->write("length_unit", "inch"); + } else if(symbol == "y_upper"){ + metadata->write("upper_axis", "Y"); + } + } + if(metadata->empty()){ + metadata.reset(); + } + } + return metadata; +} + + void StdSceneReader::Impl::extractNamedSceneNodes (Mapping* resourceNode, ResourceInfo* info, Resource& resource) { @@ -1753,7 +1789,7 @@ void StdSceneReader::Impl::extractNamedSceneNodes StdSceneReader::Impl::ResourceInfo* -StdSceneReader::Impl::getOrCreateResourceInfo(Mapping* resourceNode, const string& uri, const string& metadata) +StdSceneReader::Impl::getOrCreateResourceInfo(Mapping* resourceNode, const string& uri, Mapping* metadata) { auto iter = resourceInfoMap.find(uri); @@ -1784,29 +1820,10 @@ StdSceneReader::Impl::getOrCreateResourceInfo(Mapping* resourceNode, const strin info->yamlReader = std::move(reader); } else { - if(sceneLoaderConfigurationChanged){ - sceneLoader.setLengthUnitHint(AbstractSceneLoader::Meter); - sceneLoader.setUpperAxisHint(AbstractSceneLoader::Z_Upper); - sceneLoaderConfigurationChanged = false; - } - if(!metadata.empty()){ - size_t start; - size_t end = 0; - string symbol; - while((start = metadata.find_first_not_of(' ', end)) != std::string::npos) { - end = metadata.find(' ', start); - symbol = metadata.substr(start, end - start); - if(symbol == "millimeter"){ - sceneLoader.setLengthUnitHint(AbstractSceneLoader::Millimeter); - sceneLoaderConfigurationChanged = true; - } else if(symbol == "inch"){ - sceneLoader.setLengthUnitHint(AbstractSceneLoader::Inch); - sceneLoaderConfigurationChanged = true; - } else if(symbol == "y_upper"){ - sceneLoader.setUpperAxisHint(AbstractSceneLoader::Y_Upper); - sceneLoaderConfigurationChanged = true; - } - } + sceneLoader.clearHintsForLoading(); + if(metadata){ + sceneLoader.restoreLengthUnitAndUpperAxisHints(metadata); + info->metadata = metadata; } SgNodePtr scene = sceneLoader.load(info->file); if(!scene){ diff --git a/src/Util/StdSceneReader.h b/src/Util/StdSceneReader.h index f51fa1740..8baaae71a 100644 --- a/src/Util/StdSceneReader.h +++ b/src/Util/StdSceneReader.h @@ -71,7 +71,7 @@ class CNOID_EXPORT StdSceneReader std::string file; std::string directory; std::string fragment; - std::string metadata; + MappingPtr metadata; }; Resource readResourceNode(Mapping* info); diff --git a/src/Util/StdSceneWriter.cpp b/src/Util/StdSceneWriter.cpp index ba1c73812..da92c40be 100644 --- a/src/Util/StdSceneWriter.cpp +++ b/src/Util/StdSceneWriter.cpp @@ -592,9 +592,8 @@ void StdSceneWriter::Impl::makeLinkToOriginalModelFile(Mapping* archive, SgObjec } archive->write("uri", uri, DOUBLE_QUOTED); - auto& metadata = sceneObject->uriMetadataString(); - if(!metadata.empty()){ - archive->write("metadata", metadata, DOUBLE_QUOTED); + if(auto metadata = sceneObject->uriMetadata()){ + archive->insert("metadata", metadata); } } @@ -610,9 +609,8 @@ void StdSceneWriter::Impl::copyModelFilesAndLinkToCopiedFile(Mapping* archive, S os() << formatR(_("Warning: Model file \"{0}\" cannot be copied."), sceneObject->uri()) << endl; } else { archive->write("uri", relativeFilePathToCopiedFile, DOUBLE_QUOTED); - auto& metadata = sceneObject->uriMetadataString(); - if(!metadata.empty()){ - archive->write("metadata", metadata, DOUBLE_QUOTED); + if(auto metadata = sceneObject->uriMetadata()){ + archive->insert("metadata", metadata); } } } From 7859b2888f84edeb32b9c0597dc0fa9b446ca5d7 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 14 Aug 2024 19:25:04 +0900 Subject: [PATCH 28/73] Improve STLSceneLoader to directly transform vertices and normals when the length unit is not meter or the upper axis is not Z --- src/Util/STLSceneLoader.cpp | 131 ++++++++++++++++++++++++------------ src/Util/STLSceneLoader.h | 3 +- 2 files changed, 90 insertions(+), 44 deletions(-) diff --git a/src/Util/STLSceneLoader.cpp b/src/Util/STLSceneLoader.cpp index b70340880..e5db1c810 100644 --- a/src/Util/STLSceneLoader.cpp +++ b/src/Util/STLSceneLoader.cpp @@ -46,6 +46,10 @@ class MeshLoader SgNormalArrayPtr normals; SgIndexArray* normalIndices; + bool isUpperAxisY; + bool doScaling; + float scale; + /** The following two variables are only used in BinaryMeshLoader. Defining them here instead of BinaryMeshLoader can improve the loading speed. @@ -70,12 +74,12 @@ class MeshLoader string errorMessage; - MeshLoader(size_t numTriangles); + MeshLoader(STLSceneLoader::Impl* loaderImpl, size_t numTriangles); MeshLoader(const MeshLoader& mainLoader); template - void addNormal(const Vector3f& normal, AddIndexFunction addIndex); + void addNormal(Vector3f& normal, AddIndexFunction addIndex); template - void addVertex(const Vector3f& vertex, AddIndexFunction addIndex); + void addVertex(Vector3f& vertex, AddIndexFunction addIndex); bool join(); int findElement( const Vector3f& element, const SgVectorArray& prevElements, int searchLength); @@ -96,11 +100,11 @@ class MeshLoader class BinaryMeshLoader : public MeshLoader { public: - BinaryMeshLoader(size_t numTriangles) : MeshLoader(numTriangles) { } + BinaryMeshLoader(STLSceneLoader::Impl* loaderImpl, size_t numTriangles) : MeshLoader(loaderImpl, numTriangles) { } BinaryMeshLoader(const BinaryMeshLoader& mainLoader) : MeshLoader(mainLoader) { } void initializeArrays(size_t triangleOffset, size_t numTriangles); - void addNormal(const Vector3f& normal); - void addVertex(const Vector3f& vertex); + void addNormal(Vector3f& normal); + void addVertex(Vector3f& vertex); void load(ifstream& ifs, size_t triangleOffset, size_t numTriangles); void loadConcurrently(const string& filename, size_t triangleOffset, size_t numTriangles); }; @@ -116,10 +120,10 @@ class AsciiMeshLoader : public MeshLoader string filename; bool isSuccessfullyLoaded; - AsciiMeshLoader(const string& filename, bool doOpen); + AsciiMeshLoader(STLSceneLoader::Impl* loaderImpl, const string& filename, bool doOpen); AsciiMeshLoader(const AsciiMeshLoader& mainLoader); - void addNormal(const Vector3f& normal); - void addVertex(const Vector3f& vertex); + void addNormal(Vector3f& normal); + void addVertex(Vector3f& vertex); bool seekToTriangleBorderPosition(pos_type position); bool load(); void loadConcurrently(); @@ -144,11 +148,15 @@ namespace cnoid { class STLSceneLoader::Impl { public: + STLSceneLoader* self; + bool isUpperAxisY; + bool doScaling; + float scale; size_t maxNumThreads; ostream* os_; ostream& os() { return *os_; } - Impl(); + Impl(STLSceneLoader* self); SgNode* load(const string& filename); SgMeshPtr loadBinaryFormat(const string& filename, ifstream& ifs, size_t numTriangles); SgMeshPtr loadBinaryFormatConcurrently( @@ -162,9 +170,7 @@ class STLSceneLoader::Impl } -namespace { - -MeshLoader::MeshLoader(size_t numTriangles) +MeshLoader::MeshLoader(STLSceneLoader::Impl* loaderImpl, size_t numTriangles) : sharedMesh(new SgMesh), numTriangles(numTriangles) { @@ -178,6 +184,10 @@ MeshLoader::MeshLoader(size_t numTriangles) sharedMesh->setNumTriangles(numTriangles); normalIndices->resize(numTriangles * 3); + + isUpperAxisY = loaderImpl->isUpperAxisY; + doScaling = loaderImpl->doScaling; + scale = loaderImpl->scale; } @@ -190,6 +200,10 @@ MeshLoader::MeshLoader(const MeshLoader& mainLoader) triangleVertices = nullptr; normals = new SgNormalArray; normalIndices = nullptr; + + isUpperAxisY = mainLoader.isUpperAxisY; + doScaling = mainLoader.doScaling; + scale = mainLoader.scale; } @@ -214,8 +228,18 @@ static inline bool isApprox(const Vector3f& v1, const Vector3f& v2) template -void MeshLoader::addNormal(const Vector3f& normal, AddIndexFunction addIndex) +void MeshLoader::addNormal(Vector3f& normal, AddIndexFunction addIndex) { + if(isUpperAxisY){ + float y = normal.y(); + normal.y() = normal.x(); + normal.x() = normal.z(); + normal.z() = y; + } + if(doScaling){ + normal *= scale; + } + bool found = false; int index = normals->size() - 1; @@ -232,15 +256,25 @@ void MeshLoader::addNormal(const Vector3f& normal, AddIndexFunction addIndex) if(!found){ index = normals->size(); - normals->push_back(normal); + normals->emplace_back(normal); } addIndex(index); } template -void MeshLoader::addVertex(const Vector3f& vertex, AddIndexFunction addIndex) +void MeshLoader::addVertex(Vector3f& vertex, AddIndexFunction addIndex) { + if(isUpperAxisY){ + float y = vertex.y(); + vertex.y() = vertex.x(); + vertex.x() = vertex.z(); + vertex.z() = y; + } + if(doScaling){ + vertex *= scale; + } + bool found = false; int index = vertices->size() - 1; @@ -259,7 +293,7 @@ void MeshLoader::addVertex(const Vector3f& vertex, AddIndexFunction addIndex) addIndex(index); } else { addIndex(vertices->size()); - vertices->push_back(vertex); + vertices->emplace_back(vertex); bbox.expandBy(vertex); } } @@ -433,16 +467,15 @@ SgMeshPtr MeshLoader::completeMesh(bool doShrink) return sharedMesh; } -} - STLSceneLoader::STLSceneLoader() { - impl = new Impl; + impl = new Impl(this); } -STLSceneLoader::Impl::Impl() +STLSceneLoader::Impl::Impl(STLSceneLoader* self) + : self(self) { maxNumThreads = std::max((unsigned)1, thread::hardware_concurrency()); @@ -464,7 +497,7 @@ void STLSceneLoader::setMessageSink(std::ostream& os) SgNode* STLSceneLoader::load(const std::string& filename) { - return insertTransformNodesToAdjustLengthUnitAndUpperAxis(impl->load(filename)); + return impl->load(filename); } @@ -492,6 +525,21 @@ SgNode* STLSceneLoader::Impl::load(const string& filename) } } + isUpperAxisY = false; + doScaling = false; + scale = 1.0f; + + if(self->upperAxisHint() == Y_Upper){ + isUpperAxisY = true; + } + if(self->lengthUnitHint() == Millimeter){ + doScaling = true; + scale = 1.0e-3f; + } else if(self->lengthUnitHint() == Inch){ + doScaling = true; + scale = 0.0254f; + } + SgMeshPtr mesh; if(isBinary){ mesh = loadBinaryFormat(filename, ifs, numTriangles); @@ -506,6 +554,7 @@ SgNode* STLSceneLoader::Impl::load(const string& filename) } mesh->setUriWithFilePathAndCurrentDirectory(filename); + self->storeLengthUnitAndUpperAxisHintsAsMetadata(mesh); auto shape = new SgShape; shape->setMesh(mesh); @@ -524,7 +573,7 @@ SgMeshPtr STLSceneLoader::Impl::loadBinaryFormat(const string& filename, ifstrea return nullptr; } - BinaryMeshLoader mainLoader(numTriangles); + BinaryMeshLoader mainLoader(this, numTriangles); size_t numThreads = std::min(maxNumThreads, std::max(size_t(1), numTriangles / NumTrianglesPerThread)); @@ -569,8 +618,6 @@ SgMeshPtr STLSceneLoader::Impl::loadBinaryFormatConcurrently } -namespace { - void BinaryMeshLoader::initializeArrays(size_t triangleOffset, size_t numTriangles) { this->triangleOffset = triangleOffset; @@ -586,7 +633,7 @@ void BinaryMeshLoader::initializeArrays(size_t triangleOffset, size_t numTriangl } -void BinaryMeshLoader::addNormal(const Vector3f& normal) +void BinaryMeshLoader::addNormal(Vector3f& normal) { MeshLoader::addNormal( normal, @@ -598,7 +645,7 @@ void BinaryMeshLoader::addNormal(const Vector3f& normal) } -void BinaryMeshLoader::addVertex(const Vector3f& vertex) +void BinaryMeshLoader::addVertex(Vector3f& vertex) { MeshLoader::addVertex( vertex, @@ -628,10 +675,14 @@ void BinaryMeshLoader::load(ifstream& ifs, size_t triangleOffset, size_t numTria char data[datasize]; for(size_t i = 0; i < numTriangles; ++i){ ifs.read(data, datasize); - addNormal(Vector3f(reinterpret_cast(data))); - addVertex(Vector3f(reinterpret_cast(&data[12]))); - addVertex(Vector3f(reinterpret_cast(&data[24]))); - addVertex(Vector3f(reinterpret_cast(&data[36]))); + Vector3f normal(reinterpret_cast(data)); + addNormal(normal); + Vector3f v0(reinterpret_cast(&data[12])); + addVertex(v0); + Vector3f v1(reinterpret_cast(&data[24])); + addVertex(v1); + Vector3f v2(reinterpret_cast(&data[36])); + addVertex(v2); } } @@ -645,8 +696,6 @@ void BinaryMeshLoader::loadConcurrently(const string& filename, size_t triangleO }); } -} - SgMeshPtr STLSceneLoader::Impl::loadAsciiFormat(const string& filename, pos_type fileSize) { @@ -661,14 +710,14 @@ SgMeshPtr STLSceneLoader::Impl::loadAsciiFormat(const string& filename, pos_type SgMeshPtr mesh; bool doOpen = (numThreads == 1); - AsciiMeshLoader mainLoader(filename, doOpen); + AsciiMeshLoader mainLoader(this, filename, doOpen); if(numThreads == 1){ if(mainLoader.load()){ mesh = mainLoader.completeMesh(true); } } else { - mesh =loadAsciiFormatConcurrently(filename, mainLoader, fileSize, numThreads); + mesh = loadAsciiFormatConcurrently(filename, mainLoader, fileSize, numThreads); } return mesh; @@ -723,10 +772,8 @@ SgMeshPtr STLSceneLoader::Impl::loadAsciiFormatConcurrently } -namespace { - -AsciiMeshLoader::AsciiMeshLoader(const string& filename, bool doOpen) - : MeshLoader(0), +AsciiMeshLoader::AsciiMeshLoader(STLSceneLoader::Impl* loaderImpl, const string& filename, bool doOpen) + : MeshLoader(loaderImpl, 0), filename(filename) { if(doOpen){ @@ -756,7 +803,7 @@ bool AsciiMeshLoader::seekToTriangleBorderPosition(pos_type position) } -void AsciiMeshLoader::addNormal(const Vector3f& normal) +void AsciiMeshLoader::addNormal(Vector3f& normal) { MeshLoader::addNormal( normal, @@ -768,7 +815,7 @@ void AsciiMeshLoader::addNormal(const Vector3f& normal) } -void AsciiMeshLoader::addVertex(const Vector3f& vertex) +void AsciiMeshLoader::addVertex(Vector3f& vertex) { MeshLoader::addVertex( vertex, @@ -870,8 +917,6 @@ void AsciiMeshLoader::initializeIntegration(MeshLoader* prevLoader) } } -} - SgMeshPtr STLSceneLoader::Impl::integrateSubLoaderMeshes (MeshLoader& mainLoader, vector loaders) diff --git a/src/Util/STLSceneLoader.h b/src/Util/STLSceneLoader.h index a96f18a18..6477dddb9 100644 --- a/src/Util/STLSceneLoader.h +++ b/src/Util/STLSceneLoader.h @@ -14,8 +14,9 @@ class CNOID_EXPORT STLSceneLoader : public AbstractSceneLoader virtual void setMessageSink(std::ostream& os) override; virtual SgNode* load(const std::string& filename) override; -private: class Impl; + +private: Impl* impl; }; From afe54a68086c450675abebede183c92bafe48a8c Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 13 Aug 2024 14:40:40 +0900 Subject: [PATCH 29/73] Move the makeNameFilter function from ItemFileDialog to FileDialog --- src/Base/FileDialog.cpp | 21 +++++++++++++++++++++ src/Base/FileDialog.h | 2 ++ src/Base/ItemFileDialog.cpp | 22 ---------------------- src/Base/ItemFileDialog.h | 3 --- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/Base/FileDialog.cpp b/src/Base/FileDialog.cpp index a6d933b6c..660cad43a 100644 --- a/src/Base/FileDialog.cpp +++ b/src/Base/FileDialog.cpp @@ -239,6 +239,27 @@ void FileDialog::selectNameFilter(int index) } +QString FileDialog::makeNameFilter(const std::string& caption, const std::vector& extensions) +{ + QString filter(caption.c_str()); + + if(extensions.empty()){ + filter += " (*)"; + } else { + QString prefix = " ("; + for(auto& ext : extensions){ + filter += prefix; + filter += "*."; + filter += ext.c_str(); + prefix = " "; + } + filter += ")"; + } + + return filter; +} + + SignalProxy FileDialog::sigAboutToFinish() { return impl->sigAboutToFinish; diff --git a/src/Base/FileDialog.h b/src/Base/FileDialog.h index 91f29e11e..2ac5aa46c 100644 --- a/src/Base/FileDialog.h +++ b/src/Base/FileDialog.h @@ -62,6 +62,8 @@ class CNOID_EXPORT FileDialog : public QDialog // Util functions void selectNameFilter(int index); + static QString makeNameFilter(const std::string& caption, const std::vector& extensions); + private: class Impl; Impl* impl; diff --git a/src/Base/ItemFileDialog.cpp b/src/Base/ItemFileDialog.cpp index 28b2de1ef..34b61b30c 100644 --- a/src/Base/ItemFileDialog.cpp +++ b/src/Base/ItemFileDialog.cpp @@ -462,25 +462,3 @@ bool ItemFileDialog::Impl::onFileDialogAboutToFinish(int result) return finished; } - - -QString ItemFileDialog::makeNameFilter -(const std::string& caption, const std::vector& extensions) -{ - QString filter(caption.c_str()); - - if(extensions.empty()){ - filter += " (*)"; - } else { - QString prefix = " ("; - for(auto& ext : extensions){ - filter += prefix; - filter += "*."; - filter += ext.c_str(); - prefix = " "; - } - filter += ")"; - } - - return filter; -} diff --git a/src/Base/ItemFileDialog.h b/src/Base/ItemFileDialog.h index cdc41c4d7..b8074c201 100644 --- a/src/Base/ItemFileDialog.h +++ b/src/Base/ItemFileDialog.h @@ -31,9 +31,6 @@ class CNOID_EXPORT ItemFileDialog : public FileDialog void setExportMode(bool on = true); bool saveItem(Item* item); - static QString makeNameFilter( - const std::string& caption, const std::vector& extensions); - private: void setRegisteredFileIOsFor_(const std::type_info& type); From f0f569ea3a4608193cda342d4628d7e3c7d2c183 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Thu, 15 Aug 2024 16:50:34 +0900 Subject: [PATCH 30/73] Add the doSetCurrentDirectory argument to FileDialog::updatePresetDirectories --- src/Base/CaptureBar.cpp | 2 +- src/Base/FileDialog.cpp | 40 +++++++++++++----------- src/Base/FileDialog.h | 2 +- src/Base/ItemFileDialog.cpp | 4 +-- src/Base/ItemManager.cpp | 4 +-- src/Base/ItemPropertyWidget.cpp | 2 +- src/Base/MovieRecorderDialog.cpp | 2 +- src/Base/ProjectManager.cpp | 4 +-- src/Base/RenderableItemSceneExporter.cpp | 2 +- src/BodyPlugin/BodyLibraryView.cpp | 2 +- src/BodyPlugin/WorldLogFileItem.cpp | 2 +- 11 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/Base/CaptureBar.cpp b/src/Base/CaptureBar.cpp index 849439c0d..19b0f7ff2 100644 --- a/src/Base/CaptureBar.cpp +++ b/src/Base/CaptureBar.cpp @@ -219,7 +219,7 @@ void CaptureBar::save(QWidget* widget, std::functionget("directory", QDir::currentPath().toStdString())); diff --git a/src/Base/FileDialog.cpp b/src/Base/FileDialog.cpp index 660cad43a..517a8fedd 100644 --- a/src/Base/FileDialog.cpp +++ b/src/Base/FileDialog.cpp @@ -45,7 +45,7 @@ class FileDialog::Impl : public QFileDialog Signal sigAboutToFinish; Impl(FileDialog* self); - void updatePresetDirectories(); + void updatePresetDirectories(bool doSetCurrentDirectory); void onFilterSelected(const QString& selected); void onFinished(int result); void storeRecentDirectories(); @@ -110,13 +110,13 @@ FileDialog::~FileDialog() } -void FileDialog::updatePresetDirectories() +void FileDialog::updatePresetDirectories(bool doSetCurrentDirectory) { - impl->updatePresetDirectories(); + impl->updatePresetDirectories(doSetCurrentDirectory); } -void FileDialog::Impl::updatePresetDirectories() +void FileDialog::Impl::updatePresetDirectories(bool doSetCurrentDirectory) { QList urls; @@ -160,26 +160,28 @@ void FileDialog::Impl::updatePresetDirectories() setHistory(qhistory); } - bool directoryDetermined = false; - if(!isBeforeChoosingAnyFile){ - auto qhistory = history(); - if(!qhistory.empty()){ - setDirectory(qhistory.last()); - directoryDetermined = true; + if(doSetCurrentDirectory){ + bool directoryDetermined = false; + if(!isBeforeChoosingAnyFile){ + auto qhistory = history(); + if(!qhistory.empty()){ + setDirectory(qhistory.last()); + directoryDetermined = true; + } } - } - if(!directoryDetermined){ - auto projectDir = ProjectManager::instance()->currentProjectDirectory(); - if(!projectDir.empty()){ - setDirectory(projectDir.c_str()); - } else { + if(!directoryDetermined){ + auto projectDir = ProjectManager::instance()->currentProjectDirectory(); + if(!projectDir.empty()){ + setDirectory(projectDir.c_str()); + } else { #ifdef Q_OS_WIN32 - setDirectory(QDir::homePath() + "/Documents"); + setDirectory(QDir::homePath() + "/Documents"); #else - setDirectory(QDir::current()); + setDirectory(QDir::current()); #endif + } } - } + } } diff --git a/src/Base/FileDialog.h b/src/Base/FileDialog.h index 2ac5aa46c..cf644a58c 100644 --- a/src/Base/FileDialog.h +++ b/src/Base/FileDialog.h @@ -27,7 +27,7 @@ class CNOID_EXPORT FileDialog : public QDialog QDialog::setWindowTitle(title); } - void updatePresetDirectories(); + void updatePresetDirectories(bool doSetCurrentDirectory = true); bool selectFilePath(const std::string& filePath); void insertOptionPanel(QWidget* panel); diff --git a/src/Base/ItemFileDialog.cpp b/src/Base/ItemFileDialog.cpp index 34b61b30c..52208e096 100644 --- a/src/Base/ItemFileDialog.cpp +++ b/src/Base/ItemFileDialog.cpp @@ -149,7 +149,7 @@ ItemList ItemFileDialog::Impl::loadItems(Item* parentItem, bool doAddition self->setLabelText(QFileDialog::Accept, _("Import")); } - self->updatePresetDirectories(); + self->updatePresetDirectories(true); if(self->exec() == QDialog::Accepted){ @@ -247,7 +247,7 @@ bool ItemFileDialog::Impl::saveItem(Item* item) self->setLabelText(QFileDialog::Accept, _("Save")); self->setFileMode(QFileDialog::AnyFile); - self->updatePresetDirectories(); + self->updatePresetDirectories(true); bool selected = false; filesystem::path filePath(fromUTF8(item->filePath())); diff --git a/src/Base/ItemManager.cpp b/src/Base/ItemManager.cpp index 6cd6feb04..5c825974d 100644 --- a/src/Base/ItemManager.cpp +++ b/src/Base/ItemManager.cpp @@ -1157,7 +1157,7 @@ string getOpenFileName(const string& caption, const string& extensions) dialog.setWindowTitle(caption.c_str()); dialog.setNameFilter(makeNameFilterString(caption, extensions)); dialog.setFileMode(QFileDialog::ExistingFile); - dialog.updatePresetDirectories(); + dialog.updatePresetDirectories(true); if(dialog.exec() == QDialog::Accepted){ filename = dialog.selectedFiles().value(0).toStdString(); } @@ -1172,7 +1172,7 @@ vector getOpenFileNames(const string& caption, const string& extensions) dialog.setWindowTitle(caption.c_str()); dialog.setNameFilter(makeNameFilterString(caption, extensions)); dialog.setFileMode(QFileDialog::ExistingFiles); - dialog.updatePresetDirectories(); + dialog.updatePresetDirectories(true); if(dialog.exec() == QDialog::Accepted){ for(auto& file : dialog.selectedFiles()){ filenames.push_back(file.toStdString()); diff --git a/src/Base/ItemPropertyWidget.cpp b/src/Base/ItemPropertyWidget.cpp index 772dff3d5..626d794e1 100644 --- a/src/Base/ItemPropertyWidget.cpp +++ b/src/Base/ItemPropertyWidget.cpp @@ -565,7 +565,7 @@ void CustomizedItemDelegate::openFileDialog(FilePathProperty value, FilePathEdit } dialog.setLabelText(QFileDialog::Reject, _("Cancel")); - dialog.updatePresetDirectories(); + dialog.updatePresetDirectories(true); filesystem::path directory; if(!value.baseDirectory().empty()){ diff --git a/src/Base/MovieRecorderDialog.cpp b/src/Base/MovieRecorderDialog.cpp index 1b8e44e5d..7e346f8e2 100644 --- a/src/Base/MovieRecorderDialog.cpp +++ b/src/Base/MovieRecorderDialog.cpp @@ -553,7 +553,7 @@ void MovieRecorderDialog::showDirectorySelectionDialog() dialog.setViewMode(QFileDialog::List); dialog.setFileMode(QFileDialog::Directory); dialog.setOption(QFileDialog::ShowDirsOnly); - dialog.updatePresetDirectories(); + dialog.updatePresetDirectories(true); dialog.setDirectory(directoryEntry->text()); if(dialog.exec()){ diff --git a/src/Base/ProjectManager.cpp b/src/Base/ProjectManager.cpp index 89d630dd5..3d8bc3512 100644 --- a/src/Base/ProjectManager.cpp +++ b/src/Base/ProjectManager.cpp @@ -805,7 +805,7 @@ bool ProjectManager::showDialogToLoadProject() filters << _("Any files (*)"); dialog.setNameFilters(filters); - dialog.updatePresetDirectories(); + dialog.updatePresetDirectories(true); bool loaded = false; if(dialog.exec()){ @@ -827,7 +827,7 @@ bool ProjectManager::showDialogToSaveProject() dialog = new SaveDialog(impl); } - dialog->updatePresetDirectories(); + dialog->updatePresetDirectories(true); if(!dialog->selectFilePath(impl->currentProjectFile)){ dialog->selectFile(impl->currentProjectName); diff --git a/src/Base/RenderableItemSceneExporter.cpp b/src/Base/RenderableItemSceneExporter.cpp index cec2b831e..0be3980f1 100644 --- a/src/Base/RenderableItemSceneExporter.cpp +++ b/src/Base/RenderableItemSceneExporter.cpp @@ -23,7 +23,7 @@ void cnoid::showDialogToExportSelectedRenderableItemScene() dialog.setLabelText(QFileDialog::Accept, _("Export")); dialog.setLabelText(QFileDialog::Reject, _("Cancel")); dialog.setNameFilter("OBJ file (*.obj)"); - dialog.updatePresetDirectories(); + dialog.updatePresetDirectories(true); if(dialog.exec() == QDialog::Accepted){ auto mout = MessageOut::master(); string filename = dialog.selectedFiles().value(0).toStdString(); diff --git a/src/BodyPlugin/BodyLibraryView.cpp b/src/BodyPlugin/BodyLibraryView.cpp index cdbd50e65..1dfe8b1ee 100644 --- a/src/BodyPlugin/BodyLibraryView.cpp +++ b/src/BodyPlugin/BodyLibraryView.cpp @@ -1257,7 +1257,7 @@ bool BodyLibraryView::Impl::setBodyThumbnailWithDialog(LibraryItem* item) dialog.setViewMode(QFileDialog::List); dialog.setFileMode(QFileDialog::ExistingFile); dialog.setLabelText(QFileDialog::Accept, _("Select")); - dialog.updatePresetDirectories(); + dialog.updatePresetDirectories(true); fs::path filePath(fromUTF8(item->file)); bool isBodyCopiedInLibraryDirectory = checkIfInternalFilePath(filePath); diff --git a/src/BodyPlugin/WorldLogFileItem.cpp b/src/BodyPlugin/WorldLogFileItem.cpp index 94ab40af0..dbfcb2554 100644 --- a/src/BodyPlugin/WorldLogFileItem.cpp +++ b/src/BodyPlugin/WorldLogFileItem.cpp @@ -1271,7 +1271,7 @@ void WorldLogFileItem::Impl::openDialogToSelectDirectoryToSavePlaybackArchive() dialog.setFileMode(QFileDialog::AnyFile); dialog.setLabelText(QFileDialog::Accept, _("Save")); dialog.setLabelText(QFileDialog::Reject, _("Cancel")); - dialog.updatePresetDirectories(); + dialog.updatePresetDirectories(true); QStringList filters; filters << _("Project files (*.cnoid)"); From d75a7842f3a7ee3ab35b5cfbfca03a315ff787f0 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 16 Aug 2024 11:06:48 +0900 Subject: [PATCH 31/73] Fix to use the system instance of FilePathVariableProcessor to enable all the path variables in exporting a SceneItem or a BodyItem --- src/Base/SceneItemFileIO.cpp | 2 ++ src/BodyPlugin/BodyItemFileIO.cpp | 5 +++++ src/Util/FilePathVariableProcessor.cpp | 3 +-- src/Util/StdSceneWriter.cpp | 21 ++++++++++++--------- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/Base/SceneItemFileIO.cpp b/src/Base/SceneItemFileIO.cpp index 1e2c0f459..f35be38a4 100644 --- a/src/Base/SceneItemFileIO.cpp +++ b/src/Base/SceneItemFileIO.cpp @@ -3,6 +3,7 @@ #include "ItemManager.h" #include #include +#include #include "gettext.h" using namespace std; @@ -69,6 +70,7 @@ StdSceneWriter* SceneItemStdSceneFileExporter::ensureSceneWriter() if(!sceneWriter_){ sceneWriter_.reset(new StdSceneWriter); sceneWriter_->setMessageSink(os()); + sceneWriter_->setFilePathVariableProcessor(FilePathVariableProcessor::systemInstance()); } return sceneWriter_.get(); } diff --git a/src/BodyPlugin/BodyItemFileIO.cpp b/src/BodyPlugin/BodyItemFileIO.cpp index 548276808..e5700c2c9 100644 --- a/src/BodyPlugin/BodyItemFileIO.cpp +++ b/src/BodyPlugin/BodyItemFileIO.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -215,6 +216,8 @@ StdBodyWriter* BodyItemBodyFileIO::ensureBodyWriter() bodyWriter_ = new StdBodyWriter; bodyWriter_->setMessageSink(os()); bodyWriter_->setOriginalShapeExtModelFileUriRewritingEnabled(true); + bodyWriter_->sceneWriter()->setFilePathVariableProcessor( + FilePathVariableProcessor::systemInstance()); } return bodyWriter_; } @@ -408,6 +411,8 @@ StdSceneWriter* StdSceneFileExporter::ensureSceneWriter() sceneWriter.reset(new StdSceneWriter); sceneWriter->setMessageSink(os()); sceneWriter->setIndentWidth(1); + sceneWriter->setFilePathVariableProcessor( + FilePathVariableProcessor::systemInstance()); } return sceneWriter.get(); } diff --git a/src/Util/FilePathVariableProcessor.cpp b/src/Util/FilePathVariableProcessor.cpp index bbb30ec6c..80e719efd 100644 --- a/src/Util/FilePathVariableProcessor.cpp +++ b/src/Util/FilePathVariableProcessor.cpp @@ -73,7 +73,6 @@ FilePathVariableProcessor* FilePathVariableProcessor::systemInstance() if(!instance){ instance = new FilePathVariableProcessor; - instance->setSubstitutionWithSystemPathVariableEnabled(true); } return instance; @@ -89,7 +88,7 @@ FilePathVariableProcessor::FilePathVariableProcessor() FilePathVariableProcessor::Impl::Impl() { isProjectDirDifferentFromBaseDir = false; - isSubstitutionWithSystemPathVariableEnabled = false; + isSubstitutionWithSystemPathVariableEnabled = true; topDirPath = executableTopDirPath(); topDirString = executableTopDir(); diff --git a/src/Util/StdSceneWriter.cpp b/src/Util/StdSceneWriter.cpp index da92c40be..538efdd67 100644 --- a/src/Util/StdSceneWriter.cpp +++ b/src/Util/StdSceneWriter.cpp @@ -43,6 +43,7 @@ class StdSceneWriter::Impl bool isMeshEnabled; SgMaterialPtr defaultMaterial; unique_ptr uriSchemeProcessor; + FilePathVariableProcessorPtr filePathVariableProcessor; unique_ptr yamlWriter; unique_ptr subSceneWriter; unique_ptr objSceneWriter; @@ -70,7 +71,7 @@ class StdSceneWriter::Impl StdSceneWriter* getOrCreateSubSceneWriter(); ObjSceneWriter* getOrCreateObjSceneWriter(); void setOutputBaseDirectory(const std::string& directory); - void ensureUriSchemeProcessor(FilePathVariableProcessor* fpvp = nullptr); + void ensureUriSchemeProcessor(); bool writeScene(const std::string& filename, SgNode* node, const std::vector* pnodes); void rewriteOriginalSceneExtModelFileUris(); pair findOrCreateMapping(SgObject* object); @@ -183,6 +184,7 @@ void StdSceneWriter::Impl::copyConfigurations(const Impl* org) outputBaseDirPath = org->outputBaseDirPath; originalBaseDirPath = org->originalBaseDirPath; os_ = org->os_; + filePathVariableProcessor = org->filePathVariableProcessor; if(org->yamlWriter){ getOrCreateYamlWriter()->setIndentWidth(org->yamlWriter->indentWidth()); } @@ -265,26 +267,27 @@ void StdSceneWriter::Impl::setOutputBaseDirectory(const std::string& directory) } -void StdSceneWriter::Impl::ensureUriSchemeProcessor(FilePathVariableProcessor* fpvp) +void StdSceneWriter::Impl::ensureUriSchemeProcessor() { if(!uriSchemeProcessor){ uriSchemeProcessor = make_unique(); - if(!fpvp){ - fpvp = new FilePathVariableProcessor; - fpvp->setBaseDirPath(outputBaseDirPath); + if(!filePathVariableProcessor){ + filePathVariableProcessor = new FilePathVariableProcessor; + filePathVariableProcessor->setBaseDirPath(outputBaseDirPath); } - } - if(fpvp){ - uriSchemeProcessor->setFilePathVariableProcessor(fpvp); + uriSchemeProcessor->setFilePathVariableProcessor(filePathVariableProcessor); } } void StdSceneWriter::setFilePathVariableProcessor(FilePathVariableProcessor* fpvp) { - impl->ensureUriSchemeProcessor(fpvp); + impl->filePathVariableProcessor = fpvp; impl->outputBaseDirectory = fpvp->baseDirectory(); impl->outputBaseDirPath = fpvp->baseDirPath(); + if(impl->uriSchemeProcessor){ + impl->uriSchemeProcessor->setFilePathVariableProcessor(fpvp); + } } From dae38e9245a4b3b86bc708afe0e3dfb37ba7bd00 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 16 Aug 2024 18:18:27 +0900 Subject: [PATCH 32/73] Fix a bug in copying model files in StdSceneWriter --- src/Util/StdSceneWriter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Util/StdSceneWriter.cpp b/src/Util/StdSceneWriter.cpp index 538efdd67..22bbd4bbc 100644 --- a/src/Util/StdSceneWriter.cpp +++ b/src/Util/StdSceneWriter.cpp @@ -636,8 +636,7 @@ string StdSceneWriter::Impl::copyModelFiles(SgObject* sceneObject) findPathInDirectory(originalBaseDirPath, srcFilePath, relativeFilePath); } if(relativeFilePath.empty()){ - uriSchemeProcessor->detectScheme(sceneObject->uri()); - filesystem::path uriPath = fromUTF8(uriSchemeProcessor->path()); + filesystem::path uriPath = fromUTF8(uriSchemeProcessor->getFilePath(sceneObject->uri())); uriPath = uriPath.lexically_normal(); if(uriPath.has_root_path()){ uriPath = uriPath.relative_path(); From 5e6cb2ad2a0547d0e18b482a56fb2fab88e526da Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 13 Aug 2024 12:35:01 +0900 Subject: [PATCH 33/73] Add GeneralSceneFileLoadDialog --- include/cnoid/GeneralSceneFileLoadDialog | 1 + src/Base/CMakeLists.txt | 2 + src/Base/GeneralSceneFileLoadDialog.cpp | 230 +++++++++++++++++++++++ src/Base/GeneralSceneFileLoadDialog.h | 64 +++++++ 4 files changed, 297 insertions(+) create mode 100644 include/cnoid/GeneralSceneFileLoadDialog create mode 100644 src/Base/GeneralSceneFileLoadDialog.cpp create mode 100644 src/Base/GeneralSceneFileLoadDialog.h diff --git a/include/cnoid/GeneralSceneFileLoadDialog b/include/cnoid/GeneralSceneFileLoadDialog new file mode 100644 index 000000000..505d29bf1 --- /dev/null +++ b/include/cnoid/GeneralSceneFileLoadDialog @@ -0,0 +1 @@ +#include "src/Base/GeneralSceneFileLoadDialog.h" diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index eeb229096..6271793c9 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -131,6 +131,7 @@ set(sources SceneItemFileIO.cpp SceneGeometryMeasurementTracker.cpp GeneralSceneFileImporterBase.cpp + GeneralSceneFileLoadDialog.cpp CameraItem.cpp CameraConfigDialog.cpp LightingItem.cpp @@ -289,6 +290,7 @@ set(headers SceneItem.h SceneItemFileIO.h GeneralSceneFileImporterBase.h + GeneralSceneFileLoadDialog.h CameraItem.h CameraConfigDialog.h LightingItem.h diff --git a/src/Base/GeneralSceneFileLoadDialog.cpp b/src/Base/GeneralSceneFileLoadDialog.cpp new file mode 100644 index 000000000..3e36a9d2d --- /dev/null +++ b/src/Base/GeneralSceneFileLoadDialog.cpp @@ -0,0 +1,230 @@ +#include "GeneralSceneFileLoadDialog.h" +#include +#include +#include +#include +#include +#include +#include +#include "gettext.h" + +using namespace std; +using namespace cnoid; + +namespace { + +SceneLoader::LengthUnitType defaultLengthUnitHint = SceneLoader::Meter; + +} + +namespace cnoid { + +class GeneralSceneFileLoadDialog::OptionSet::Panel : public QWidget +{ +public: + ComboBox unitCombo; + ComboBox axisCombo; + + Panel(OptionSet* optionSet); +}; + +} + + +void GeneralSceneFileLoadDialog::setDefaultLengthUnitHint(SceneLoader::LengthUnitType hint) +{ + defaultLengthUnitHint = hint; +} + + +GeneralSceneFileLoadDialog::GeneralSceneFileLoadDialog() +{ + initialize(); +} + + +GeneralSceneFileLoadDialog::GeneralSceneFileLoadDialog(QWidget* parent, Qt::WindowFlags f) + : FileDialog(parent, f) +{ + initialize(); +} + + +void GeneralSceneFileLoadDialog::initialize() +{ + setWindowTitle(_("Load a scene file")); + fileTypeCaption_ = _("Scene file"); + setViewMode(QFileDialog::List); + setFileMode(QFileDialog::ExistingFile); + setLabelText(QFileDialog::Accept, _("Load")); + setLabelText(QFileDialog::Reject, _("Cancel")); + + insertOptionPanel(optionSet.panel()); +} + + +void GeneralSceneFileLoadDialog::setFileTypeCaption(const std::string& caption) +{ + fileTypeCaption_ = caption; +} + + +int GeneralSceneFileLoadDialog::exec() +{ + loadedScene_.reset(); + setNameFilter(makeNameFilter(fileTypeCaption_, SceneLoader::availableFileExtensions())); + auto mout = MessageOut::master(); + + int result = FileDialog::exec(); + if(result == QDialog::Accepted){ + if(!sceneLoader){ + sceneLoader.reset(new SceneLoader); + sceneLoader->setMessageSink(mout->cout()); + } + string filename = selectedFiles().at(0).toStdString(); + + sceneLoader->setLengthUnitHint(optionSet.lengthUnitHint()); + sceneLoader->setUpperAxisHint(optionSet.upperAxisHint()); + + mout->put(formatR(_("Loading the file \"{0}\" ..."), filename)); + loadedScene_ = sceneLoader->load(filename); + if(loadedScene_){ + mout->putln(_(" OK!")); + } else { + mout->putErrorln(_(" Failed.")); + } + } + + return result; +} + + +void GeneralSceneFileLoadDialog::clearLoadedScene() +{ + loadedScene_.reset(); +} + + +GeneralSceneFileLoadDialog::OptionSet::OptionSet() +{ + resetOptions(); + panel_ = nullptr; +} + + +GeneralSceneFileLoadDialog::OptionSet::~OptionSet() +{ + if(panel_){ + delete panel_; + panel_ = nullptr; + } +} + + +void GeneralSceneFileLoadDialog::OptionSet::resetOptions() +{ + lengthUnitHint_ = defaultLengthUnitHint; + upperAxisHint_ = SceneLoader::Z_Upper; +} + + +void GeneralSceneFileLoadDialog::OptionSet::setLengthUnitHint(AbstractSceneLoader::LengthUnitType hint) +{ + if(panel_){ + auto& combo = panel_->unitCombo; + combo.setCurrentIndex(combo.findData(hint)); + } else { + lengthUnitHint_ = hint; + } +} + + +void GeneralSceneFileLoadDialog::OptionSet::setUpperAxisHint(SceneLoader::UpperAxisType hint) +{ + if(panel_){ + auto& combo = panel_->axisCombo; + combo.setCurrentIndex(combo.findData(hint)); + } else { + upperAxisHint_ = hint; + } +} + + +void GeneralSceneFileLoadDialog::OptionSet::storeOptions(Mapping* archive) +{ + if(lengthUnitHint_ != SceneLoader::Meter){ + archive->write( + "length_unit_hint", + (lengthUnitHint_ == SceneLoader::Millimeter) ? "millimeter" : "inch"); + } + + if(upperAxisHint_ != SceneLoader::Z_Upper){ + archive->write("upper_axis_hint", "Y"); + } +} + + +bool GeneralSceneFileLoadDialog::OptionSet::restoreOptions(const Mapping* archive) +{ + string symbol; + + lengthUnitHint_ = SceneLoader::Meter; + if(archive->read({ "length_unit_hint", "meshLengthUnitHint" }, symbol)){ + if(symbol == "millimeter"){ + setLengthUnitHint(SceneLoader::Millimeter); + } else if(symbol == "inch"){ + setLengthUnitHint(SceneLoader::Inch); + } + } + + upperAxisHint_ = SceneLoader::Z_Upper; + if(archive->read({ "upper_axis_hint", "meshUpperAxisHint" }, symbol)){ + if(symbol == "Y"){ + setUpperAxisHint(SceneLoader::Y_Upper); + } + } + + return true; +} + + +QWidget* GeneralSceneFileLoadDialog::OptionSet::panel() +{ + if(!panel_){ + panel_ = new Panel(this); + } + return panel_; +} + + +GeneralSceneFileLoadDialog::OptionSet::Panel::Panel(OptionSet* optionSet) +{ + auto hbox = new QHBoxLayout; + hbox->setContentsMargins(0, 0, 0, 0); + setLayout(hbox); + + hbox->addWidget(new QLabel(_("[ import hints ]"))); + + hbox->addWidget(new QLabel(_("Unit:"))); + unitCombo.addItem(_("Meter"), SceneLoader::Meter); + unitCombo.addItem(_("Millimeter"), SceneLoader::Millimeter); + unitCombo.addItem(_("Inch"), SceneLoader::Inch); + unitCombo.setCurrentIndex(unitCombo.findData(optionSet->lengthUnitHint())); + unitCombo.sigCurrentIndexChanged().connect( + [this, optionSet](int index){ + optionSet->lengthUnitHint_ = + static_cast(unitCombo.itemData(index).toInt()); + }); + hbox->addWidget(&unitCombo); + + hbox->addWidget(new QLabel(_("Upper axis:"))); + axisCombo.addItem("Z", SceneLoader::Z_Upper); + axisCombo.addItem("Y", SceneLoader::Y_Upper); + axisCombo.setCurrentIndex(axisCombo.findData(optionSet->upperAxisHint())); + axisCombo.sigCurrentIndexChanged().connect( + [this, optionSet](int index){ + optionSet->upperAxisHint_ = + static_cast(unitCombo.itemData(index).toInt()); + }); + hbox->addWidget(&axisCombo); +} diff --git a/src/Base/GeneralSceneFileLoadDialog.h b/src/Base/GeneralSceneFileLoadDialog.h new file mode 100644 index 000000000..c675766fb --- /dev/null +++ b/src/Base/GeneralSceneFileLoadDialog.h @@ -0,0 +1,64 @@ +#ifndef CNOID_BASE_GENERAL_SCENE_FILE_LOAD_DIALOG_H +#define CNOID_BASE_GENERAL_SCENE_FILE_LOAD_DIALOG_H + +#include "FileDialog.h" +#include +#include +#include +#include "exportdecl.h" + +namespace cnoid { + +class Mapping; + +class CNOID_EXPORT GeneralSceneFileLoadDialog : public FileDialog +{ +public: + // For the application customization + static void setDefaultLengthUnitHint(SceneLoader::LengthUnitType hint); + + GeneralSceneFileLoadDialog(); + GeneralSceneFileLoadDialog(QWidget* parent, Qt::WindowFlags f = Qt::WindowFlags()); + void setFileTypeCaption(const std::string& caption); + virtual int exec() override; + SgNode* loadedScene() const { return loadedScene_; } + void clearLoadedScene(); + + class OptionSet + { + public: + OptionSet(); + virtual ~OptionSet(); + void resetOptions(); + + void setLengthUnitHint(SceneLoader::LengthUnitType hint); + SceneLoader::LengthUnitType lengthUnitHint() const { return lengthUnitHint_; } + + void setUpperAxisHint(SceneLoader::UpperAxisType hint); + SceneLoader::UpperAxisType upperAxisHint() const { return upperAxisHint_; } + + void storeOptions(Mapping* archive); + bool restoreOptions(const Mapping* archive); + + QWidget* panel(); + + private: + SceneLoader::LengthUnitType lengthUnitHint_; + SceneLoader::UpperAxisType upperAxisHint_; + + class Panel; + Panel* panel_; + }; + +private: + std::string fileTypeCaption_; + SgNodePtr loadedScene_; + std::unique_ptr sceneLoader; + OptionSet optionSet; + + void initialize(); +}; + +} + +#endif From d77c8af7c8eb6cc0afeca286e1274d0442767dba Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 16 Aug 2024 19:06:06 +0900 Subject: [PATCH 34/73] Fix the implementation of GeneralSceneFileImporterBase to use GeneralSceneFileLoadDialog::OptionSet --- src/Base/GeneralSceneFileImporterBase.cpp | 121 ++-------------------- src/Base/GeneralSceneFileImporterBase.h | 1 - 2 files changed, 11 insertions(+), 111 deletions(-) diff --git a/src/Base/GeneralSceneFileImporterBase.cpp b/src/Base/GeneralSceneFileImporterBase.cpp index b86dfaebf..5cea605bb 100644 --- a/src/Base/GeneralSceneFileImporterBase.cpp +++ b/src/Base/GeneralSceneFileImporterBase.cpp @@ -1,13 +1,9 @@ #include "GeneralSceneFileImporterBase.h" +#include "GeneralSceneFileLoadDialog.h" #include -#include -#include -#include #include #include #include -#include -#include #include "gettext.h" using namespace std; @@ -23,18 +19,9 @@ class GeneralSceneFileImporterBase::Impl static int sharedImplCounter; unique_ptr sceneLoader; - QWidget* optionPanel; + GeneralSceneFileLoadDialog::OptionSet optionSet; - Selection lengthUnitHint; - ComboBox* unitCombo; - - Selection upperAxisHint; - ComboBox* axisCombo; - - Impl(); - ~Impl(); SgNode* loadScene(GeneralSceneFileImporterBase* self, const std::string& filename); - void createOptionPanel(); }; GeneralSceneFileImporterBase::Impl* GeneralSceneFileImporterBase::Impl::sharedImpl = nullptr; @@ -68,23 +55,6 @@ GeneralSceneFileImporterBase::GeneralSceneFileImporterBase() } -GeneralSceneFileImporterBase::Impl::Impl() - : lengthUnitHint(SceneLoader::NumLengthUnitTypes), - upperAxisHint(SceneLoader::NumUpperAxisTypes, CNOID_GETTEXT_DOMAIN_NAME) -{ - lengthUnitHint.setSymbol(SceneLoader::Meter, "meter"); - lengthUnitHint.setSymbol(SceneLoader::Millimeter, "millimeter"); - lengthUnitHint.setSymbol(SceneLoader::Inch, "inch"); - - upperAxisHint.setSymbol(SceneLoader::Z_Upper, "Z"); - upperAxisHint.setSymbol(SceneLoader::Y_Upper, "Y"); - - optionPanel = nullptr; - unitCombo = nullptr; - axisCombo = nullptr; -} - - GeneralSceneFileImporterBase::~GeneralSceneFileImporterBase() { if(--Impl::sharedImplCounter == 0){ @@ -94,14 +64,6 @@ GeneralSceneFileImporterBase::~GeneralSceneFileImporterBase() } -GeneralSceneFileImporterBase::Impl::~Impl() -{ - if(optionPanel){ - delete optionPanel; - } -} - - SgNode* GeneralSceneFileImporterBase::loadScene(const std::string& filename) { return impl->loadScene(this, filename); @@ -115,8 +77,8 @@ SgNode* GeneralSceneFileImporterBase::Impl::loadScene(GeneralSceneFileImporterBa sceneLoader->setMessageSink(self->os()); } - sceneLoader->setLengthUnitHint(static_cast(lengthUnitHint.which())); - sceneLoader->setUpperAxisHint(static_cast(upperAxisHint.which())); + sceneLoader->setLengthUnitHint(optionSet.lengthUnitHint()); + sceneLoader->setUpperAxisHint(optionSet.upperAxisHint()); bool isSupported; SgNode* scene = sceneLoader->load(filename, isSupported); @@ -147,41 +109,28 @@ bool GeneralSceneFileImporterBase::saveScene(SgNode* /* scene */, const std::str void GeneralSceneFileImporterBase::resetOptions() { - impl->lengthUnitHint.select(SceneLoader::Meter); - impl->upperAxisHint.select(SceneLoader::Z_Upper); + impl->optionSet.resetOptions(); } void GeneralSceneFileImporterBase::storeOptions(Mapping* archive) { - if(!impl->lengthUnitHint.is(SceneLoader::Meter)){ - archive->write("meshLengthUnitHint", impl->lengthUnitHint.selectedSymbol()); - } - if(!impl->upperAxisHint.is(SceneLoader::Z_Upper)){ - archive->write("meshUpperAxisHint", impl->upperAxisHint.selectedSymbol()); - } + impl->optionSet.storeOptions(archive); } bool GeneralSceneFileImporterBase::restoreOptions(const Mapping* archive) { - string value; - if(archive->read("meshLengthUnitHint", value)){ - impl->lengthUnitHint.select(value); - } - if(archive->read("meshUpperAxisHint", value)){ - impl->upperAxisHint.select(value); - } - return true; + return impl->optionSet.restoreOptions(archive); } void GeneralSceneFileImporterBase::setCurrentLengthUnitHint(LengthUnitType unitType) { switch(unitType){ - case Meter: impl->lengthUnitHint.select(SceneLoader::Meter); break; - case Millimeter: impl->lengthUnitHint.select(SceneLoader::Millimeter); break; - case Inch: impl->lengthUnitHint.select(SceneLoader::Inch); break; + case Meter: impl->optionSet.setLengthUnitHint(SceneLoader::Meter); break; + case Millimeter: impl->optionSet.setLengthUnitHint(SceneLoader::Millimeter); break; + case Inch: impl->optionSet.setLengthUnitHint(SceneLoader::Inch); break; default: break; } } @@ -189,53 +138,5 @@ void GeneralSceneFileImporterBase::setCurrentLengthUnitHint(LengthUnitType unitT QWidget* GeneralSceneFileImporterBase::getOptionPanelForLoading() { - if(!impl->optionPanel){ - impl->createOptionPanel(); - } - - impl->unitCombo->blockSignals(true); - impl->unitCombo->setCurrentIndex(impl->lengthUnitHint.which()); - impl->unitCombo->blockSignals(false); - - impl->axisCombo->blockSignals(true); - impl->axisCombo->setCurrentIndex(impl->upperAxisHint.which()); - impl->axisCombo->blockSignals(false); - - return impl->optionPanel; -} - - -void GeneralSceneFileImporterBase::Impl::createOptionPanel() -{ - optionPanel = new QWidget; - auto hbox = new QHBoxLayout; - hbox->setContentsMargins(0, 0, 0, 0); - optionPanel->setLayout(hbox); - - hbox->addWidget(new QLabel(_("[ Mesh import hints ]"))); - - hbox->addWidget(new QLabel(_("Unit:"))); - unitCombo = new ComboBox; - unitCombo->addItem(_("Meter")); - unitCombo->addItem(_("Millimeter")); - unitCombo->addItem(_("Inch")); - unitCombo->sigCurrentIndexChanged().connect( - [this](int index){ lengthUnitHint.select(index); }); - hbox->addWidget(unitCombo); - - hbox->addWidget(new QLabel(_("Upper axis:"))); - axisCombo = new ComboBox; - for(int i=0; i < SceneLoader::NumUpperAxisTypes; ++i){ - axisCombo->addItem(upperAxisHint.label(i)); - } - axisCombo->sigCurrentIndexChanged().connect( - [this](int index){ upperAxisHint.select(index); }); - hbox->addWidget(axisCombo); -} - - -void GeneralSceneFileImporterBase::fetchOptionPanelForLoading() -{ - impl->lengthUnitHint.select(impl->unitCombo->currentIndex()); - impl->upperAxisHint.select(impl->axisCombo->currentIndex()); + return impl->optionSet.panel(); } diff --git a/src/Base/GeneralSceneFileImporterBase.h b/src/Base/GeneralSceneFileImporterBase.h index d0f0a8ce1..04fd5d85b 100644 --- a/src/Base/GeneralSceneFileImporterBase.h +++ b/src/Base/GeneralSceneFileImporterBase.h @@ -31,7 +31,6 @@ class CNOID_EXPORT GeneralSceneFileImporterBase : public ItemFileIO virtual void storeOptions(Mapping* archive) override; virtual bool restoreOptions(const Mapping* archive) override; virtual QWidget* getOptionPanelForLoading() override; - virtual void fetchOptionPanelForLoading() override; private: class Impl; From 829cf19e35f7b5bd6710c735f7e0c89833f80cd2 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 14 Aug 2024 15:15:47 +0900 Subject: [PATCH 35/73] Update Japanese translations for the Base module --- src/Base/po/ja.po | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Base/po/ja.po b/src/Base/po/ja.po index e706d8a3a..1bef978d6 100644 --- a/src/Base/po/ja.po +++ b/src/Base/po/ja.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Choreonoid\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-09 23:11+0900\n" +"POT-Creation-Date: 2024-08-17 16:07+0900\n" "PO-Revision-Date: 2021-10-25 12:00+0900\n" "Language: ja\n" "MIME-Version: 1.0\n" @@ -355,8 +355,26 @@ msgstr "フォルダアイテム" msgid "The file format of \"{}\" is not supported.\n" msgstr "ファイルフォーマット \"{}\" はサポートされていません.\n" -msgid "[ Mesh import hints ]" -msgstr "[ メッシュインポートヒント ]" +msgid "Load a scene file" +msgstr "シーンファイルの読み込み" + +msgid "Scene file" +msgstr "シーンファイル" + +msgid "Load" +msgstr "読み込み" + +msgid "Loading the file \"{0}\" ..." +msgstr "ファイル \"{0}\" を読み込み中…" + +msgid " OK!" +msgstr "" + +msgid " Failed." +msgstr " 失敗." + +msgid "[ import hints ]" +msgstr "[ インポートヒント ]" msgid "Unit:" msgstr "単位:" @@ -531,9 +549,6 @@ msgstr "{0}の読み込み" msgid "Import {0}" msgstr "{0}のインポート" -msgid "Load" -msgstr "読み込み" - msgid "Import" msgstr "インポート" @@ -1617,7 +1632,9 @@ msgstr "エクスポートするシーンが空です." msgid "" "Export the scene of the following items to \"{0}\":\n" " " -msgstr "以下のアイテムのシーンを \"{0}\" にエクスポートします:\n " +msgstr "" +"以下のアイテムのシーンを \"{0}\" にエクスポートします:\n" +" " msgid "Completed!" msgstr "完了!" From 3a7d267b094b4674539f1fd75e01030b0d826900 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Sat, 17 Aug 2024 12:59:14 +0900 Subject: [PATCH 36/73] Add the function for setting the default length unit hint of GeneralSceneFileLoadDialog to AppCustomizationUtil --- src/Base/AppCustomizationUtil.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Base/AppCustomizationUtil.h b/src/Base/AppCustomizationUtil.h index 0908603b0..3e9193f7a 100644 --- a/src/Base/AppCustomizationUtil.h +++ b/src/Base/AppCustomizationUtil.h @@ -10,6 +10,7 @@ #include "FileDialog.h" #include "TimeBar.h" #include "DisplayValueFormat.h" +#include "GeneralSceneFileLoadDialog.h" #include namespace cnoid { @@ -116,6 +117,11 @@ class AppCustomizationUtil TimeBar::setNegativeTimeEnabled(on); } + static void setGeneralSceneFileLoadDialogDefaultLengthUnitHint(SceneLoader::LengthUnitType hint) + { + GeneralSceneFileLoadDialog::setDefaultLengthUnitHint(hint); + } + void setLengthUnit(DisplayValueFormat::LengthUnit unit) { displayValueFormat->setLengthUnit(unit); From be16c3e6c213b79530e88e4ce537197fcdb8b97d Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Thu, 15 Aug 2024 16:38:05 +0900 Subject: [PATCH 37/73] Add the getContentHash function to Mapping and Listing --- src/Util/ValueTree.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/Util/ValueTree.h | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/src/Util/ValueTree.cpp b/src/Util/ValueTree.cpp index d387fcbbd..61437783c 100644 --- a/src/Util/ValueTree.cpp +++ b/src/Util/ValueTree.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "gettext.h" #ifdef _WIN32 @@ -42,6 +43,10 @@ ListingPtr invalidListing; constexpr double PI = 3.141592653589793238462643383279502884; constexpr double TO_RADIAN = PI / 180.0; +void hash_combine(std::size_t& seed, std::size_t hash) { + seed ^= hash + 0x9e3779b9 + (seed<<6) + (seed>>2); +} + } ValueNode::Initializer ValueNode::initializer; @@ -1081,6 +1086,24 @@ void Mapping::writePath(const std::string &key, const std::string& value) } +size_t Mapping::getContentHash() const +{ + size_t seed = 0; + std::hash hasher; + for(auto& kv : *this){ + auto& node = kv.second; + if(node->isScalar()){ + hash_combine(seed, hasher(node->toString())); + } else if(node->isMapping()){ + hash_combine(seed, node->toMapping()->getContentHash()); + } else if(node->isListing()){ + hash_combine(seed, node->toListing()->getContentHash()); + } + } + return seed; +} + + Listing::Listing() { typeBits = LISTING; @@ -1270,3 +1293,20 @@ void Listing::write(int i, const std::string& value, StringStyle stringStyle) { values[i] = new ScalarNode(value, stringStyle); } + + +size_t Listing::getContentHash() const +{ + size_t seed = 0; + std::hash hasher; + for(auto& node : *this){ + if(node->isScalar()){ + hash_combine(seed, hasher(node->toString())); + } else if(node->isMapping()){ + hash_combine(seed, node->toMapping()->getContentHash()); + } else if(node->isListing()){ + hash_combine(seed, node->toListing()->getContentHash()); + } + } + return seed; +} diff --git a/src/Util/ValueTree.h b/src/Util/ValueTree.h index 596a7b3c7..575aec2a3 100644 --- a/src/Util/ValueTree.h +++ b/src/Util/ValueTree.h @@ -444,6 +444,8 @@ class CNOID_EXPORT Mapping : public ValueNode StringStyle keyStringStyle() const { return keyStringStyle_; } + size_t getContentHash() const; + #ifdef CNOID_BACKWARD_COMPATIBILITY Listing* findSequence(const std::string& key) const { return findListing(key); } Listing* openSequence(const std::string& key) { return openListing(key); } @@ -600,6 +602,8 @@ class CNOID_EXPORT Listing : public ValueNode const_iterator begin() const { return values.begin(); } const_iterator end() const { return values.end(); }; + size_t getContentHash() const; + private: Listing(int line, int column); From 6a01cd033b44c6e3bceec219dc661f9634eb1f29 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Thu, 15 Aug 2024 16:45:28 +0900 Subject: [PATCH 38/73] Improve StdSceneReader to prevent conflicts between resources shareing the same URI but having different metadata --- src/Util/StdSceneReader.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Util/StdSceneReader.cpp b/src/Util/StdSceneReader.cpp index bbe2ac02b..16fdbabb1 100644 --- a/src/Util/StdSceneReader.cpp +++ b/src/Util/StdSceneReader.cpp @@ -73,12 +73,12 @@ class StdSceneReader::Impl }; typedef ref_ptr ResourceInfoPtr; - map resourceInfoMap; + unordered_map resourceInfoMap; string baseDirectory; SceneLoader sceneLoader; unique_ptr uriSchemeProcessor; - typedef map ImagePathToSgImageMap; + typedef unordered_map ImagePathToSgImageMap; ImagePathToSgImageMap imagePathToSgImageMap; typedef SgNode* (Impl::*NodeFunction)(Mapping* info); @@ -1791,7 +1791,14 @@ void StdSceneReader::Impl::extractNamedSceneNodes StdSceneReader::Impl::ResourceInfo* StdSceneReader::Impl::getOrCreateResourceInfo(Mapping* resourceNode, const string& uri, Mapping* metadata) { - auto iter = resourceInfoMap.find(uri); + string uriWithMetadata; + if(!metadata){ + uriWithMetadata = uri; + } else { + uriWithMetadata = formatC("{0}?metadata={1:0x}", uri, metadata->getContentHash()); + } + + auto iter = resourceInfoMap.find(uriWithMetadata); if(iter != resourceInfoMap.end()){ return iter->second; @@ -1835,7 +1842,7 @@ StdSceneReader::Impl::getOrCreateResourceInfo(Mapping* resourceNode, const strin info->directory = toUTF8(filePath.parent_path().string()); - resourceInfoMap[uri] = info; + resourceInfoMap[uriWithMetadata] = info; return info; } From c3babc36e66ab0535473c4e3a55410a31c75c481 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 12 Aug 2024 11:46:49 +0900 Subject: [PATCH 39/73] Improve LinkOverwriteItem to support the ShapeOffset and ShapeColor elements --- src/BodyPlugin/LinkOverwriteItem.cpp | 689 ++++++++++++++++++++++----- src/BodyPlugin/LinkOverwriteItem.h | 55 ++- 2 files changed, 606 insertions(+), 138 deletions(-) diff --git a/src/BodyPlugin/LinkOverwriteItem.cpp b/src/BodyPlugin/LinkOverwriteItem.cpp index 090aa9f64..c53f5f996 100644 --- a/src/BodyPlugin/LinkOverwriteItem.cpp +++ b/src/BodyPlugin/LinkOverwriteItem.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include "gettext.h" using namespace std; @@ -57,7 +59,7 @@ class LinkOverwriteItem::Impl { public: LinkOverwriteItem* self; - int targetElementSet; + int overwriteElementSet; LinkPtr targetLink; LinkPtr referenceLink; LinkPtr additionalLink; @@ -65,6 +67,24 @@ class LinkOverwriteItem::Impl LinkPtr originalLinkClone; bool isRootLink; + Isometry3 shapeOffset; + SgPosTransformPtr shapeOffsetTransform; + SgPosTransformPtr collisionShapeOffsetTransform; + Vector3f shapeColor; + + struct MaterialInfo + { + SgMaterialPtr orgMaterialClone; + bool isUpdated; + }; + unordered_map materialMap; + unordered_set noMaterialShapes; + SgMaterialPtr materialForNoMaterialShapes; + + SgNodePtr visualShape; + SgNodePtr collisionShape; + SgUpdate sgUpdate; + PositionDraggerPtr originMarker; OffsetLocationPtr offsetLocation; int locationTargetType; @@ -77,11 +97,19 @@ class LinkOverwriteItem::Impl Impl(LinkOverwriteItem* self, const Impl& org, CloneMap* cloneMap); bool updateOverwriting(BodyItem* bodyItem); void overwriteExistingLink(Link* existingLink); - void copyTargetElements(Link* srcLink, Link* destLink, int elementSet); + void copyOverwriteLinkElements(Link* srcLink, Link* destLink); + void overwriteShapeElements(Link* link); + void cancelOverwritingShapeElements(Link* link); + void overwriteShapeOffset(Link* link, bool doNotify); + void cancelOverwritingShapeOffset(Link* link, bool doNotify); + void overwriteShapeColor(Link* link, bool doNotify); + void cancelOverwritingShapeColor(Link* link, bool doNotify); + void restoreOriginalShapeMaterials(Link* link, bool doNotify); + void restoreOverwritingShapeMaterials(Link* link, bool doNotify); + void notifyMaterialUpdates(int noMaterialShapeAction); bool addNewLink(Body* body); void releaseOverwriteTarget(); void cancelOverwriting(); - SgPosTransform* getShapeOffsetTransform(Link* link); bool restoreShapeWrittenInOldFormat(const Archive& archive, ValueNode* shapeArchive); void setReferenceLinkToRestoreShapeWritteinInOldFormat(Link* orgLink, SgNode* newShape); SgPosTransform* extractOrInsertOffsetTransform(vector& nodePaths); @@ -119,8 +147,10 @@ LinkOverwriteItem::LinkOverwriteItem() LinkOverwriteItem::Impl::Impl(LinkOverwriteItem* self) : self(self) { - targetElementSet = NoElement; + overwriteElementSet = NoElement; isRootLink = false; + shapeOffset.setIdentity(); + shapeColor.setOnes(); locationTargetType = LinkOffsetLocation; } @@ -134,7 +164,7 @@ LinkOverwriteItem::LinkOverwriteItem(const LinkOverwriteItem& org, CloneMap* clo LinkOverwriteItem::Impl::Impl(LinkOverwriteItem* self, const Impl& org, CloneMap* cloneMap) : self(self), - targetElementSet(org.targetElementSet), + overwriteElementSet(org.overwriteElementSet), additionalLinkParentName(org.additionalLinkParentName) { if(org.targetLink && cloneMap && self->bodyItem()){ @@ -146,11 +176,18 @@ LinkOverwriteItem::Impl::Impl(LinkOverwriteItem* self, const Impl& org, CloneMap if(org.additionalLink){ additionalLink = CloneMap::getClone(org.additionalLink, cloneMap); } - if(org.originalLinkClone){ - originalLinkClone = CloneMap::getClone(org.originalLinkClone, cloneMap); - } isRootLink = org.isRootLink; locationTargetType = org.locationTargetType; + + shapeOffset = org.shapeOffset; + shapeColor = org.shapeColor; + + if(org.visualShape){ + visualShape = CloneMap::getClone(org.visualShape, cloneMap); + } + if(org.collisionShape){ + collisionShape = CloneMap::getClone(org.collisionShape, cloneMap); + } } @@ -210,21 +247,33 @@ bool LinkOverwriteItem::setName(const std::string& name) } -void LinkOverwriteItem::setTargetElementSet(int elementSet) +void LinkOverwriteItem::setOverwriteElementSet(int elementSet) { - impl->targetElementSet = elementSet; + impl->overwriteElementSet = elementSet; } -void LinkOverwriteItem::addTargetElement(int element) +void LinkOverwriteItem::addOverwriteElement(int element) +{ + impl->overwriteElementSet |= element; +} + + +void LinkOverwriteItem::addOverwriteElementSet(int elementSet) +{ + impl->overwriteElementSet |= elementSet; +} + + +int LinkOverwriteItem::overwriteElementSet() const { - impl->targetElementSet |= element; + return impl->overwriteElementSet; } -int LinkOverwriteItem::targetElementSet() const +bool LinkOverwriteItem::hasOverwriteElement(int element) const { - return impl->targetElementSet; + return impl->overwriteElementSet & element; } @@ -280,6 +329,110 @@ Link* LinkOverwriteItem::additionalLink() } +void LinkOverwriteItem::setShapeOffset(const Isometry3& T, bool doOverwrite) +{ + impl->shapeOffset = T; + impl->overwriteElementSet |= ShapeOffset; + if(doOverwrite && impl->targetLink){ + impl->overwriteShapeOffset(impl->targetLink, true); + if(auto bodyItem_ = bodyItem()){ + bodyItem_->notifyModelUpdate(BodyItem::ShapeUpdate); + } + } +} + + +const Isometry3& LinkOverwriteItem::shapeOffset() const +{ + return impl->shapeOffset; +} + + +void LinkOverwriteItem::setShapeColor(const Vector3f& color, bool doOverwrite) +{ + impl->shapeColor = color; + impl->overwriteElementSet |= ShapeColor; + if(doOverwrite && impl->targetLink){ + impl->overwriteShapeColor(impl->targetLink, true); + if(auto bodyItem_ = bodyItem()){ + bodyItem_->notifyModelUpdate(BodyItem::ShapeUpdate); + } + } +} + + +void LinkOverwriteItem::resetShapeColor(bool doNotify) +{ + impl->cancelOverwritingShapeColor(impl->targetLink, doNotify); + if(doNotify){ + if(auto bodyItem_ = bodyItem()){ + bodyItem_->notifyModelUpdate(BodyItem::ShapeUpdate); + } + } +} + + +const Vector3f& LinkOverwriteItem::shapeColor() const +{ + return impl->shapeColor; +} + + +void LinkOverwriteItem::setShape(SgNode* shape) +{ + setVisualShape(shape); + setCollisionShape(shape); +} + + +void LinkOverwriteItem::setVisualShape(SgNode* shape) +{ + impl->overwriteElementSet |= Shape; + impl->visualShape = shape; +} + + +void LinkOverwriteItem::setCollisionShape(SgNode* shape) +{ + impl->overwriteElementSet |= Shape; + impl->collisionShape = shape; +} + + +SgNode* LinkOverwriteItem::visualShape() +{ + return impl->visualShape; +} + + +SgNode* LinkOverwriteItem::collisionShape() +{ + return impl->collisionShape; +} + + +std::string LinkOverwriteItem::findOriginalShapeFile() const +{ + string filename; + + if(impl->targetLink){ + auto pred = [](SgObject* object){ return object->hasUri(); }; + SgObject* uriObject = impl->targetLink->visualShape()->findObject(pred); + if(!uriObject){ + uriObject = impl->targetLink->collisionShape()->findObject(pred); + } + if(uriObject){ + filename = uriObject->localFileAbsolutePath(); + if(filename.empty()){ + filename = uriObject->localFilePath(); + } + } + } + + return filename; +} + + Link* LinkOverwriteItem::sourceLink() { return impl->referenceLink ? impl->referenceLink : impl->additionalLink; @@ -328,7 +481,15 @@ bool LinkOverwriteItem::Impl::updateOverwriting(BodyItem* bodyItem) auto body = bodyItem->body(); Link* newTargetLink = nullptr; - if(!targetLink){ + if(targetLink){ + if(referenceLink){ + overwriteExistingLink(targetLink); + updated = true; + } else if(additionalLink){ + overwriteShapeElements(targetLink); + updated = true; + } + } else { if(referenceLink){ if(isRootLink){ newTargetLink = body->rootLink(); @@ -349,6 +510,7 @@ bool LinkOverwriteItem::Impl::updateOverwriting(BodyItem* bodyItem) updated = true; } else if(additionalLink){ updated = addNewLink(body); + overwriteShapeElements(newTargetLink); } if(updated){ targetLink = newTargetLink; @@ -357,20 +519,13 @@ bool LinkOverwriteItem::Impl::updateOverwriting(BodyItem* bodyItem) } } } - } else { - if(referenceLink){ - overwriteExistingLink(targetLink); - updated = true; - } else if(additionalLink){ - updated = true; - } } if(updated){ bool isKinematicStateChangeNotificationRequested = false; if((additionalLink && newTargetLink) || - (targetElementSet & (JointType | JointId | JointName))){ + (overwriteElementSet & (JointType | JointId | JointName))){ body->updateLinkTree(); if(bodyItem->isBeingRestored()){ bodyItem->requestNonRootLinkStatesRestorationOnSubTreeRestored(); @@ -383,7 +538,7 @@ bool LinkOverwriteItem::Impl::updateOverwriting(BodyItem* bodyItem) BodyItem::DeviceSetUpdate | BodyItem::ShapeUpdate); if(!isKinematicStateChangeNotificationRequested){ - if(targetElementSet & (OffsetPosition | JointType | JointAxis)){ + if(overwriteElementSet & (OffsetPosition | JointType | JointAxis)){ bodyItem->notifyKinematicStateChange(true); } } @@ -398,8 +553,8 @@ bool LinkOverwriteItem::Impl::updateOverwriting(BodyItem* bodyItem) } if(offsetLocation){ - if(((targetElementSet & OffsetPosition) && (locationTargetType == LinkOffsetLocation)) || - ((targetElementSet & Shape) && (locationTargetType == ShapeOffsetLocation))){ + if(((overwriteElementSet & OffsetPosition) && (locationTargetType == LinkOffsetLocation)) || + ((overwriteElementSet & ShapeOffset) && (locationTargetType == ShapeOffsetLocation))){ offsetLocation->sigLocationChanged_(); } } @@ -416,59 +571,277 @@ void LinkOverwriteItem::Impl::overwriteExistingLink(Link* existingLink) if(!originalLinkClone){ originalLinkClone = existingLink->clone(); } - copyTargetElements(referenceLink, existingLink, targetElementSet); + copyOverwriteLinkElements(referenceLink, existingLink); + overwriteShapeElements(existingLink); } -void LinkOverwriteItem::Impl::copyTargetElements(Link* srcLink, Link* destLink, int elementSet) +void LinkOverwriteItem::Impl::copyOverwriteLinkElements(Link* srcLink, Link* destLink) { if(isRootLink){ destLink->setName(srcLink->name()); } - if(elementSet & OffsetPosition){ + if(overwriteElementSet & OffsetPosition){ destLink->setOffsetPosition(srcLink->offsetPosition()); } - if(elementSet & JointType){ + if(overwriteElementSet & JointType){ destLink->setJointType(srcLink->jointType()); } - if(elementSet & JointAxis){ + if(overwriteElementSet & JointAxis){ destLink->setJointAxis(srcLink->jointAxis()); } - if(elementSet & JointId){ + if(overwriteElementSet & JointId){ destLink->setJointId(srcLink->jointId()); } - if(elementSet & JointName){ + if(overwriteElementSet & JointName){ destLink->setJointName(srcLink->jointName()); } - if(elementSet & JointRange){ + if(overwriteElementSet & JointRange){ destLink->setJointRange(srcLink->q_lower(), srcLink->q_upper()); } - if(elementSet & JointVelocityRange){ + if(overwriteElementSet & JointVelocityRange){ destLink->setJointVelocityRange(srcLink->dq_lower(), srcLink->dq_upper()); } - if(elementSet & JointEffortRange){ + if(overwriteElementSet & JointEffortRange){ destLink->setJointEffortRange(srcLink->u_lower(), srcLink->u_upper()); } - if(elementSet & Mass){ + if(overwriteElementSet & Mass){ destLink->setMass(srcLink->mass()); } - if(elementSet & Inertia){ + if(overwriteElementSet & Inertia){ destLink->setInertia(srcLink->I()); } - if(elementSet & CenterOfMass){ + if(overwriteElementSet & CenterOfMass){ destLink->setCenterOfMass(srcLink->centerOfMass()); } - if(elementSet & Material){ + if(overwriteElementSet & Material){ destLink->setMaterial(srcLink->materialId()); } - if(elementSet & Shape){ - SgUpdate update; - destLink->clearShapeNodes(update); - for(auto& node : *srcLink->visualShape()){ - destLink->addVisualShapeNode(node, update); +} + + +void LinkOverwriteItem::Impl::overwriteShapeElements(Link* link) +{ + if(overwriteElementSet & Shape){ + link->clearShapeNodes(sgUpdate); + link->addVisualShapeNode(visualShape, sgUpdate); + link->addCollisionShapeNode(collisionShape, sgUpdate); + shapeOffsetTransform.reset(); + collisionShapeOffsetTransform.reset(); + } + overwriteShapeOffset(link, true); + overwriteShapeColor(link, true); +} + + +void LinkOverwriteItem::Impl::cancelOverwritingShapeElements(Link* link) +{ + cancelOverwritingShapeOffset(link, true); + cancelOverwritingShapeColor(link, true); + + if(overwriteElementSet & Shape){ + if(originalLinkClone){ + link->clearShapeNodes(sgUpdate); + for(auto& node : *originalLinkClone->visualShape()){ + link->addVisualShapeNode(node, sgUpdate); + } + for(auto& node : *originalLinkClone->collisionShape()){ + link->addCollisionShapeNode(node, sgUpdate); + } + } + } +} + + +void LinkOverwriteItem::Impl::overwriteShapeOffset(Link* link, bool doNotify) +{ + if(overwriteElementSet & ShapeOffset){ + if(shapeOffsetTransform || collisionShapeOffsetTransform){ + if(shapeOffsetTransform){ + shapeOffsetTransform->setPosition(shapeOffset); + if(doNotify){ + shapeOffsetTransform->notifyUpdate(sgUpdate.withAction(SgUpdate::Modified)); + } + } + if(collisionShapeOffsetTransform && collisionShapeOffsetTransform != shapeOffsetTransform){ + collisionShapeOffsetTransform->setPosition(shapeOffset); + if(doNotify){ + collisionShapeOffsetTransform->notifyUpdate(sgUpdate.withAction(SgUpdate::Modified)); + } + } + } else { + bool hasDedicatedCollisionShape = link->hasDedicatedCollisionShape(); + auto visualShape = link->visualShape(); + if(!visualShape->empty()){ + shapeOffsetTransform = new SgPosTransform(shapeOffset); + visualShape->moveChildrenTo(shapeOffsetTransform); + visualShape->addChild(shapeOffsetTransform); + if(doNotify){ + visualShape->notifyUpdate(sgUpdate.withAction(SgUpdate::Added | SgUpdate::Removed)); + } + } + auto collisionShape = link->collisionShape(); + if(!hasDedicatedCollisionShape){ + if(shapeOffsetTransform){ + collisionShape->clearChildren(); + collisionShape->addChild(shapeOffsetTransform); + collisionShapeOffsetTransform = shapeOffsetTransform; + if(doNotify){ + collisionShape->notifyUpdate(sgUpdate.withAction(SgUpdate::Added | SgUpdate::Removed)); + } + } + } else if(!collisionShape->empty()){ + collisionShapeOffsetTransform = new SgPosTransform(shapeOffset); + collisionShape->moveChildrenTo(collisionShapeOffsetTransform); + collisionShape->addChild(collisionShapeOffsetTransform); + if(doNotify){ + collisionShape->notifyUpdate(sgUpdate.withAction(SgUpdate::Added | SgUpdate::Removed)); + } + } + } + } else if(shapeOffsetTransform || collisionShapeOffsetTransform){ + cancelOverwritingShapeOffset(link, doNotify); + } +} + + +void LinkOverwriteItem::Impl::cancelOverwritingShapeOffset(Link* link, bool doNotify) +{ + if(shapeOffsetTransform){ + auto shape = link->visualShape(); + shape->contains(shapeOffsetTransform); + shape->removeChild(shapeOffsetTransform); + shapeOffsetTransform->copyChildrenTo(shape); + shapeOffsetTransform.reset(); + if(doNotify){ + shape->notifyUpdate(sgUpdate.withAction(SgUpdate::Added | SgUpdate::Removed)); + } + } + if(collisionShapeOffsetTransform){ + auto shape = link->collisionShape(); + shape->contains(collisionShapeOffsetTransform); + shape->removeChild(collisionShapeOffsetTransform); + collisionShapeOffsetTransform->moveChildrenTo(shape); + collisionShapeOffsetTransform.reset(); + if(doNotify){ + shape->notifyUpdate(sgUpdate.withAction(SgUpdate::Added | SgUpdate::Removed)); + } + } +} + + +void LinkOverwriteItem::Impl::overwriteShapeColor(Link* link, bool doNotify) +{ + if(overwriteElementSet & ShapeColor){ + for(auto& kv : materialMap){ + kv.second.isUpdated = false; + } + if(!materialForNoMaterialShapes){ + materialForNoMaterialShapes = new SgMaterial; + } + materialForNoMaterialShapes->setDiffuseColor(shapeColor); + bool materialForNoMaterialShapesAdded = false; + + link->shape()->traverseNodes( + [this, &materialForNoMaterialShapesAdded](SgNode* node) -> SgObject::TraverseStatus { + if(auto shape = dynamic_cast(node)){ + if(noMaterialShapes.find(shape) == noMaterialShapes.end()){ + if(auto material = shape->material()){ + auto& info = materialMap[material]; + if(!info.isUpdated){ + if(!info.orgMaterialClone){ + info.orgMaterialClone = static_cast(material->clone()); + } + material->setDiffuseColor(shapeColor); + if(!material->emissiveColor().isZero()){ + material->setEmissiveColor(shapeColor); + } + info.isUpdated = true; + } + } else { + shape->setMaterial(materialForNoMaterialShapes); + noMaterialShapes.insert(shape); + materialForNoMaterialShapesAdded = true; + } + } + } + return SgObject::Continue; + }); + + if(doNotify){ + sgUpdate.setAction(SgUpdate::Modified); + for(auto& kv : materialMap){ + kv.first->notifyUpdate(sgUpdate); + } + if(materialForNoMaterialShapesAdded){ + sgUpdate.addAction(SgUpdate::Added); + materialForNoMaterialShapes->notifyUpdate(sgUpdate); + } + } + + } else if(!materialMap.empty() || materialForNoMaterialShapes){ + cancelOverwritingShapeColor(link, doNotify); + } +} + + +void LinkOverwriteItem::Impl::cancelOverwritingShapeColor(Link* link, bool doNotify) +{ + restoreOriginalShapeMaterials(link, doNotify); + materialMap.clear(); + noMaterialShapes.clear(); + materialForNoMaterialShapes.reset(); + overwriteElementSet &= ~ShapeColor; +} + + +void LinkOverwriteItem::Impl::restoreOriginalShapeMaterials(Link* link, bool doNotify) +{ + for(auto& kv : materialMap){ + auto& material = kv.first; + auto& info = kv.second; + if(info.orgMaterialClone){ + material->copyMaterialPropertiesFrom(info.orgMaterialClone); } - for(auto& node : *srcLink->collisionShape()){ - destLink->addCollisionShapeNode(node, update); + } + for(auto& shape : noMaterialShapes){ + shape->setMaterial(nullptr); + } + if(doNotify){ + notifyMaterialUpdates(SgUpdate::Removed); + } +} + + +void LinkOverwriteItem::Impl::restoreOverwritingShapeMaterials(Link* link, bool doNotify) +{ + for(auto& kv : materialMap){ + auto& material = kv.first; + material->setDiffuseColor(shapeColor); + if(!material->emissiveColor().isZero()){ + material->setEmissiveColor(shapeColor); + } + } + for(auto& shape : noMaterialShapes){ + shape->setMaterial(materialForNoMaterialShapes); + } + if(doNotify){ + notifyMaterialUpdates(SgUpdate::Added); + } +} + + +void LinkOverwriteItem::Impl::notifyMaterialUpdates(int noMaterialShapeAction) +{ + sgUpdate.setAction(SgUpdate::Modified); + for(auto& kv : materialMap){ + auto& material = kv.first; + material->notifyUpdate(sgUpdate); + } + if(!noMaterialShapes.empty()){ + sgUpdate.addAction(noMaterialShapeAction); + for(auto& shape : noMaterialShapes){ + shape->notifyUpdate(sgUpdate); } } } @@ -522,6 +895,11 @@ void LinkOverwriteItem::Impl::releaseOverwriteTarget() additionalLink.reset(); originalLinkClone.reset(); isRootLink = false; + shapeOffsetTransform.reset(); + collisionShapeOffsetTransform.reset(); + materialMap.clear(); + noMaterialShapes.clear(); + materialForNoMaterialShapes.reset(); } @@ -531,12 +909,17 @@ void LinkOverwriteItem::Impl::cancelOverwriting() if(targetLink){ if(auto body = targetLink->body()){ - if(originalLinkClone){ - copyTargetElements(originalLinkClone, targetLink, targetElementSet); - updated = true; - } else if(auto parent = targetLink->parent()){ - parent->removeChild(targetLink); + if(referenceLink){ + if(originalLinkClone){ + copyOverwriteLinkElements(originalLinkClone, targetLink); + } + cancelOverwritingShapeElements(targetLink); updated = true; + } else if(additionalLink){ + if(auto parent = targetLink->parent()){ + parent->removeChild(targetLink); + updated = true; + } } if(updated){ body->updateLinkTree(); @@ -555,26 +938,6 @@ void LinkOverwriteItem::Impl::cancelOverwriting() } -SgPosTransform* LinkOverwriteItem::Impl::getShapeOffsetTransform(Link* link) -{ - if(link){ - auto shape = link->shape(); - if(shape->numChildren() == 1){ - if(auto transform = dynamic_cast(shape->child(0))){ - return transform; - } - } - auto collisionShape = link->collisionShape(); - if(collisionShape->numChildren() == 1){ - if(auto transform = dynamic_cast(collisionShape->child(0))){ - return transform; - } - } - } - return nullptr; -} - - LocationProxyPtr LinkOverwriteItem::getLocationProxy() { if(!impl->offsetLocation){ @@ -651,7 +1014,8 @@ bool LinkOverwriteItem::Impl::store(Archive& archive) archive.write("is_root", true); } - if(self->isAddingLink()){ + bool isAddingLink = self->isAddingLink(); + if(isAddingLink){ archive.write("is_additional", true); if(auto parentLink = link->parent()){ archive.write("parent", parentLink->name(), DOUBLE_QUOTED); @@ -662,7 +1026,7 @@ bool LinkOverwriteItem::Impl::store(Archive& archive) archive.setFloatingNumberFormat("%.9g"); - if(targetElementSet & OffsetPosition){ + if(overwriteElementSet & OffsetPosition){ // The "translation" value is always written so that the restore function can // know that the OffsetPosition is an element to overwrite. write(archive, "translation", link->offsetTranslation()); @@ -671,29 +1035,41 @@ bool LinkOverwriteItem::Impl::store(Archive& archive) writeDegreeAngleAxis(archive, "rotation", aa); } } - if(targetElementSet & JointType){ + if(overwriteElementSet & JointType){ archive.write("joint_type", link->jointTypeSymbol()); } - if(targetElementSet & JointAxis){ + if(overwriteElementSet & JointAxis){ write(archive, "joint_axis", link->jointAxis()); } - if(targetElementSet & JointId){ + if(overwriteElementSet & JointId){ archive.write("joint_id", link->jointId()); } - if(targetElementSet & JointName){ + if(overwriteElementSet & JointName){ archive.write("joint_name", link->jointName(), DOUBLE_QUOTED); } - if(targetElementSet & JointRange){ + if(overwriteElementSet & JointRange){ StdBodyWriter::writeJointDisplacementRange(&archive, link, true); } - if(targetElementSet & JointVelocityRange){ + if(overwriteElementSet & JointVelocityRange){ StdBodyWriter::writeJointVelocityRange(&archive, link, true); } - if(targetElementSet & JointEffortRange){ + if(overwriteElementSet & JointEffortRange){ StdBodyWriter::writeJointEffortRange(&archive, link, true); } - if(targetElementSet & Shape){ + if(overwriteElementSet & ShapeOffset){ + write(archive, "shape_translation", shapeOffset.translation()); + AngleAxis aa(shapeOffset.linear()); + if(aa.angle() != 0.0){ + writeDegreeAngleAxis(archive, "shape_rotation", aa); + } + } + + if(overwriteElementSet & ShapeColor){ + write(archive, "shape_color", shapeColor); + } + + if(overwriteElementSet & Shape){ if(!sceneWriter){ sceneWriter = sharedSceneWriter.lock(); if(!sceneWriter){ @@ -705,11 +1081,11 @@ bool LinkOverwriteItem::Impl::store(Archive& archive) } sceneWriter->setFilePathVariableProcessor(archive.filePathVariableProcessor()); - auto visualShape = link->visualShape(); - auto collisionShape = link->collisionShape(); - bool hasDedicatedCollisionShape = link->hasDedicatedCollisionShape(); - - if(!visualShape->empty()){ + if(overwriteElementSet & ShapeColor){ + restoreOriginalShapeMaterials(link, false); + } + bool hasDedicatedCollisionShape = (visualShape != collisionShape); + if(visualShape){ auto visualShapeArchive = sceneWriter->writeScene(visualShape); if(!hasDedicatedCollisionShape){ archive.insert("shape", visualShapeArchive); @@ -717,13 +1093,16 @@ bool LinkOverwriteItem::Impl::store(Archive& archive) archive.insert("visual_shape", visualShapeArchive); } } - if(!collisionShape->empty() && hasDedicatedCollisionShape){ + if(collisionShape && hasDedicatedCollisionShape){ if(auto collisionShapeArchive = sceneWriter->writeScene(collisionShape)){ archive.insert("collision_shape", collisionShapeArchive); } } + if(overwriteElementSet & ShapeColor){ + restoreOverwritingShapeMaterials(link, false); + } } - + return true; } @@ -765,7 +1144,7 @@ bool LinkOverwriteItem::Impl::restore(const Archive& archive) LinkPtr link = new Link; link->setName(self->name()); - int elementSet = NoElement; + overwriteElementSet = NoElement; if(!archive.get("is_additional", false)){ self->setReferenceLink(link, archive.get("is_root", false)); @@ -781,7 +1160,7 @@ bool LinkOverwriteItem::Impl::restore(const Archive& archive) if(readDegreeAngleAxis(archive, "rotation", aa)){ link->setOffsetRotation(aa); } - elementSet |= OffsetPosition; + overwriteElementSet |= OffsetPosition; } string symbol; if(archive.read("joint_type", symbol)){ @@ -796,17 +1175,17 @@ bool LinkOverwriteItem::Impl::restore(const Archive& archive) } else { archive.throwException(formatR(_("Illegal jointType value \"{0}\""), symbol)); } - elementSet |= JointType; + overwriteElementSet |= JointType; } Vector3 a; if(read(archive, "joint_axis", a)){ link->setJointAxis(a); - elementSet |= JointAxis; + overwriteElementSet |= JointAxis; } int id; if(archive.read("joint_id", id)){ link->setJointId(id); - elementSet |= JointId; + overwriteElementSet |= JointId; } if(archive.read("joint_name", symbol)){ if(symbol.empty()){ @@ -814,45 +1193,56 @@ bool LinkOverwriteItem::Impl::restore(const Archive& archive) } else { link->setJointName(symbol); } - elementSet |= JointName; + overwriteElementSet |= JointName; } if(StdBodyLoader::readJointDisplacementRange(&archive, link)){ - elementSet |= JointRange; + overwriteElementSet |= JointRange; } if(StdBodyLoader::readJointVelocityRange(&archive, link)){ - elementSet |= JointVelocityRange; + overwriteElementSet |= JointVelocityRange; } if(StdBodyLoader::readJointEffortRange(&archive, link)){ - elementSet |= JointEffortRange; + overwriteElementSet |= JointEffortRange; + } + + if(read(archive, "shape_translation", p)){ + Isometry3 T; + T.translation() = p; + AngleAxis aa; + if(readDegreeAngleAxis(archive, "shape_rotation", aa)){ + T.linear() = aa.toRotationMatrix(); + } else { + T.linear().setIdentity(); + } + self->setShapeOffset(T); + } + + Vector3f c; + if(read(archive, "shape_color", c)){ + shapeColor = c; + overwriteElementSet |= ShapeColor; } auto shapeArchive = archive.find("shape"); if(shapeArchive->isValid()){ if(auto shape = ensureSceneReader(archive)->readScene(shapeArchive)){ - link->addShapeNode(shape); - elementSet |= Shape; + self->setShape(shape); } } auto visualShapeArchive = archive.find("visual_shape"); if(visualShapeArchive->isValid()){ if(auto visualShape = ensureSceneReader(archive)->readScene(visualShapeArchive)){ - link->addVisualShapeNode(visualShape); - elementSet |= Shape; + self->setVisualShape(visualShape); } } auto collisionShapeArchive = archive.find("collision_shape"); if(collisionShapeArchive->isValid()){ if(auto collisionShape = ensureSceneReader(archive)->readScene(collisionShapeArchive)){ - link->addCollisionShapeNode(collisionShape); - elementSet |= Shape; + self->setCollisionShape(collisionShape); } } - if(elementSet){ - self->setTargetElementSet(elementSet); - } - - return elementSet != NoElement; + return true; } @@ -876,17 +1266,38 @@ bool LinkOverwriteItem::Impl::restoreShapeWrittenInOldFormat(const Archive& arch } +bool checkHintsInMetadata(SgObject* object, bool& out_isNotMeter, bool& out_isYUpperAxis) +{ + auto metadata = object->uriMetadata(); + if(!metadata){ + return false; + } + string symbol; + if(metadata->read("length_unit", symbol)){ + if(symbol != "meter"){ + out_isNotMeter = true; + } + } + if(metadata->read("upper_axis", symbol)){ + if(symbol == "Y"){ + out_isYUpperAxis = true; + } + } + return true; +} + + void LinkOverwriteItem::Impl::setReferenceLinkToRestoreShapeWritteinInOldFormat(Link* orgLink, SgNode* newShape) { - SgPosTransformPtr shapeOffset = nullptr; + SgPosTransformPtr shapeOffsetNode = nullptr; vector shapeNodePaths; SceneNodeExtractor nodeExtractor; if(newShape){ - shapeOffset = dynamic_cast(newShape); - if(!shapeOffset){ - shapeOffset = new SgPosTransform; - shapeOffset->addChild(newShape); + shapeOffsetNode = dynamic_cast(newShape); + if(!shapeOffsetNode){ + shapeOffsetNode = new SgPosTransform; + shapeOffsetNode->addChild(newShape); } shapeNodePaths = nodeExtractor.extractNodes(newShape, true); } @@ -895,21 +1306,30 @@ void LinkOverwriteItem::Impl::setReferenceLinkToRestoreShapeWritteinInOldFormat( SgObject::setNonNodeCloning(cloneMap, false); SgNodePtr shapeClone = cloneMap.getClone(orgLink->shape()); vector existingShapeNodePaths = nodeExtractor.extractNodes(shapeClone, false); + bool doRemoveScalingForLengthUnitConversion = false; + bool doRemoveRotationForUpperAxisConversion = false; if(existingShapeNodePaths.empty()){ if(!newShape){ - shapeOffset = new SgPosTransform; + shapeOffsetNode = new SgPosTransform; } } else { if(!newShape){ - shapeOffset = extractOrInsertOffsetTransform(existingShapeNodePaths); + shapeOffsetNode = extractOrInsertOffsetTransform(existingShapeNodePaths); } else { int n = std::min(shapeNodePaths.size(), existingShapeNodePaths.size()); for(int i=0; i < n; ++i){ auto shapeNode = static_cast(shapeNodePaths[i].back().get()); auto existingShapeNode = static_cast(existingShapeNodePaths[i].back().get()); if(!shapeNode->mesh()){ - shapeNode->setMesh(existingShapeNode->mesh()); + auto existingMesh = existingShapeNode->mesh(); + shapeNode->setMesh(existingMesh); + + if(!checkHintsInMetadata( + existingShapeNode, doRemoveScalingForLengthUnitConversion, doRemoveRotationForUpperAxisConversion)){ + checkHintsInMetadata( + existingMesh, doRemoveScalingForLengthUnitConversion, doRemoveRotationForUpperAxisConversion); + } } if(!shapeNode->material()){ shapeNode->setMaterial(existingShapeNode->material()); @@ -918,12 +1338,30 @@ void LinkOverwriteItem::Impl::setReferenceLinkToRestoreShapeWritteinInOldFormat( } } + Isometry3 T = shapeOffsetNode->position(); + if(doRemoveRotationForUpperAxisConversion){ + Matrix3 R; + R << 0, 0, 1, + 1, 0, 0, + 0, 1, 0; + T.linear() = T.linear() * R.transpose(); + } + if(!T.matrix().isIdentity()){ + self->setShapeOffset(T); + } + if(!shapeOffsetNode->empty()){ + SgNode* node = shapeOffsetNode->child(0); + if(doRemoveScalingForLengthUnitConversion){ + if(auto scale = dynamic_cast(node)){ + node = scale->child(0); + } + } + self->setShape(node); + } + LinkPtr link = new Link; link->setName(orgLink->name()); - link->addShapeNode(shapeOffset, true); - self->setReferenceLink(link); - self->setTargetElementSet(Shape); } @@ -987,9 +1425,7 @@ Isometry3 OffsetLocation::getLocation() const if(isLinkOffsetLocation()){ return impl->targetLink->offsetPosition(); } else if(isShapeOffsetLocation()){ - if(auto transform = impl->getShapeOffsetTransform(impl->targetLink)){ - return transform->T(); - } + return impl->shapeOffset; } } return Isometry3::Identity(); @@ -1004,11 +1440,8 @@ bool OffsetLocation::setLocation(const Isometry3& T) sourceLink->setOffsetPosition(T); updated = true; } else if(isShapeOffsetLocation()){ - if(auto transform = impl->getShapeOffsetTransform(sourceLink)){ - transform->setPosition(T); - transform->notifyUpdate(); - updated = true; - } + impl->self->setShapeOffset(T, true); + updated = true; } } if(updated){ diff --git a/src/BodyPlugin/LinkOverwriteItem.h b/src/BodyPlugin/LinkOverwriteItem.h index a731be997..a33f3bab5 100644 --- a/src/BodyPlugin/LinkOverwriteItem.h +++ b/src/BodyPlugin/LinkOverwriteItem.h @@ -39,27 +39,64 @@ class CNOID_EXPORT LinkOverwriteItem : public BodyElementOverwriteItem, Inertia = 1 << 9, CenterOfMass = 1 << 10, Material = 1 << 11, - Shape = 1 << 12, - AllElements = + ShapeOffset = 1 << 12, + ShapeColor = 1 << 13, + Shape = 1 << 14, + AllNonShapeElements = OffsetPosition | JointType | JointAxis | JointId | JointName | JointRange | - JointVelocityRange | JointEffortRange | Mass | Inertia | CenterOfMass | - Material | Shape, + JointVelocityRange | JointEffortRange | Mass | Inertia | CenterOfMass | Material }; - void setTargetElementSet(int elementSet); - void addTargetElement(int element); - int targetElementSet() const; - + void setOverwriteElementSet(int elementSet); + void addOverwriteElement(int element); + void addOverwriteElementSet(int elementSet); + int overwriteElementSet() const; + bool hasOverwriteElement(int element) const; + + [[deprecated("Use setOverwriteElementSet.")]] + void setTargetElementSet(int elementSet) { setOverwriteElementSet(elementSet); } + [[deprecated("Use addOverwriteElement.")]] + void addTargetElement(int element) { addOverwriteElement(element); } + [[deprecated("Use overwriteElementSet.")]] + int targetElementSet() const { return overwriteElementSet(); } + + /** + When a LinkOverwriteItem overwrites an existing link, the information of the link elements to be overwritten is + stored in a reference link, which is a separate object from the existing link. + Note that if the overwritten elements are only shape elements, the reference link is not necessary. + */ bool setReferenceLink(Link* referenceLink, bool isRootLink = false); Link* referenceLink(); bool isRootLink() const; Link* originalLinkClone(); + /** + When a LinkOverwriteItem creates a new link, the new link is stored as an "additional link". + In this case, the LinkOverwriteItem does not have the reference link. + */ bool setAdditionalLink(Link* additionalLink, const std::string& parentLinkName = std::string()); Link* additionalLink(); + void setShapeOffset(const Isometry3& T, bool doOverwrite = false); + const Isometry3& shapeOffset() const; + void setShapeColor(const Vector3f& color, bool doOverwrite = false); + const Vector3f& shapeColor() const; + void resetShapeColor(bool doNotify = false); + + void setShape(SgNode* shape); + void setVisualShape(SgNode* shape); + void setCollisionShape(SgNode* shape); + SgNode* visualShape(); + SgNode* collisionShape(); + + std::string findOriginalShapeFile() const; + + /** + The source link is either the reference link or additional link. + */ Link* sourceLink(); + Link* targetLink(); bool isOverwriting() const; @@ -69,8 +106,6 @@ class CNOID_EXPORT LinkOverwriteItem : public BodyElementOverwriteItem, bool updateOverwriting(); virtual void releaseOverwriteTarget() override; - SgPosTransform* shapeOffsetTransform(); - // LocatableItem function virtual LocationProxyPtr getLocationProxy() override; From 3a0f0d9eb19ade386c727b8d7e18f99f143dfe63 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 19 Aug 2024 15:59:53 +0900 Subject: [PATCH 40/73] Fix Japanese translations for the Base module --- src/Base/po/ja.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Base/po/ja.po b/src/Base/po/ja.po index 1bef978d6..23713ccfb 100644 --- a/src/Base/po/ja.po +++ b/src/Base/po/ja.po @@ -58,7 +58,7 @@ msgid "Perspective" msgstr "透視投影" msgid "Orthographic" -msgstr "並行投影" +msgstr "平行投影" msgid "Position:" msgstr "位置:" From 5de65144310d7e9c48804e9d0ff0231e5a1e1bab Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 21 Aug 2024 18:00:44 +0900 Subject: [PATCH 41/73] Fix the Python wrappers for the signal types defined in TimeBar --- src/Base/pybind11/PyToolBars.cpp | 3 --- src/Util/pybind11/PySignal.cpp | 13 ++++++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Base/pybind11/PyToolBars.cpp b/src/Base/pybind11/PyToolBars.cpp index 3392d928c..361c2329e 100644 --- a/src/Base/pybind11/PyToolBars.cpp +++ b/src/Base/pybind11/PyToolBars.cpp @@ -135,8 +135,5 @@ void exportPyToolBars(py::module m) .def("getPlaybackSpeedScale", &TimeBar::playbackSpeedRatio) .def("getPlaybackFrameRate", &TimeBar::playbackFrameRate) ; - - PySignal(m, "SigPlaybackInitialized"); - PySignal(m, "SigTimeChanged"); } } diff --git a/src/Util/pybind11/PySignal.cpp b/src/Util/pybind11/PySignal.cpp index 07eb49b19..fee5cab22 100644 --- a/src/Util/pybind11/PySignal.cpp +++ b/src/Util/pybind11/PySignal.cpp @@ -13,11 +13,14 @@ namespace cnoid { void exportPySignalTypes(py::module& m) { - PySignal(m, "VoidSignal"); - PySignal(m,"BoolSignal"); - PySignal(m, "IntSignal"); - PySignal(m, "DoubleSignal"); - PySignal(m, "StringSignal"); + PySignal(m, "VoidVoidSignal"); + PySignal(m,"VoidBoolSignal"); + PySignal(m, "VoidIntSignal"); + PySignal(m, "VoidDoubleSignal"); + PySignal(m, "BoolDoubleSignal"); + PySignal(m, "VoidDoubleBoolSignal"); + PySignal(m, "DoubleDoubleBoolSignal"); + PySignal(m, "VoidStringSignal"); py::class_(m, "Connection") .def(py::init<>()) From ca585a16b09d68bc0ed62606979fb740457e0c62 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 28 Aug 2024 13:32:29 +0900 Subject: [PATCH 42/73] Fix SmokeDevice and RainSnowDevice to be public classes --- src/SceneEffectsPlugin/RainSnowDevice.cpp | 5 ----- src/SceneEffectsPlugin/RainSnowDevice.h | 8 ++------ src/SceneEffectsPlugin/SmokeDevice.cpp | 5 ----- src/SceneEffectsPlugin/SmokeDevice.h | 8 ++------ 4 files changed, 4 insertions(+), 22 deletions(-) diff --git a/src/SceneEffectsPlugin/RainSnowDevice.cpp b/src/SceneEffectsPlugin/RainSnowDevice.cpp index 55e9006f7..b2d8fc048 100644 --- a/src/SceneEffectsPlugin/RainSnowDevice.cpp +++ b/src/SceneEffectsPlugin/RainSnowDevice.cpp @@ -1,8 +1,3 @@ -/** - @file - @author Shin'ichiro Nakaoka -*/ - #include "RainSnowDevice.h" #include "SceneRainSnow.h" #include "SceneEffectDeviceTypeRegistration.h" diff --git a/src/SceneEffectsPlugin/RainSnowDevice.h b/src/SceneEffectsPlugin/RainSnowDevice.h index 7a2925cc3..c6cac0c51 100644 --- a/src/SceneEffectsPlugin/RainSnowDevice.h +++ b/src/SceneEffectsPlugin/RainSnowDevice.h @@ -1,17 +1,13 @@ -/** - @file - @author Shin'ichiro Nakaoka -*/ - #ifndef CNOID_SCENE_EFFECTS_PLUGIN_RAIN_SNOW_DEVICE_H #define CNOID_SCENE_EFFECTS_PLUGIN_RAIN_SNOW_DEVICE_H #include "ParticleSystem.h" #include +#include "exportdecl.h" namespace cnoid { -class RainSnowDevice : public Device +class CNOID_EXPORT RainSnowDevice : public Device { public: void copyStateFrom(const RainSnowDevice& other); diff --git a/src/SceneEffectsPlugin/SmokeDevice.cpp b/src/SceneEffectsPlugin/SmokeDevice.cpp index e495dcb9b..663a65101 100644 --- a/src/SceneEffectsPlugin/SmokeDevice.cpp +++ b/src/SceneEffectsPlugin/SmokeDevice.cpp @@ -1,8 +1,3 @@ -/** - @file - @author Shin'ichiro Nakaoka -*/ - #include "SmokeDevice.h" #include "SceneSmoke.h" #include "SceneEffectDeviceTypeRegistration.h" diff --git a/src/SceneEffectsPlugin/SmokeDevice.h b/src/SceneEffectsPlugin/SmokeDevice.h index 304b76d42..96dec8342 100644 --- a/src/SceneEffectsPlugin/SmokeDevice.h +++ b/src/SceneEffectsPlugin/SmokeDevice.h @@ -1,17 +1,13 @@ -/** - @file - @author Shin'ichiro Nakaoka -*/ - #ifndef CNOID_SCENE_EFFECTS_PLUGIN_SMOKE_DEVICE_H #define CNOID_SCENE_EFFECTS_PLUGIN_SMOKE_DEVICE_H #include "ParticleSystem.h" #include +#include "exportdecl.h" namespace cnoid { -class SmokeDevice : public Device +class CNOID_EXPORT SmokeDevice : public Device { public: SmokeDevice(); From c41c68af1baf4141d3257f414b44b7f375a5e0db Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Thu, 29 Aug 2024 13:13:58 +0900 Subject: [PATCH 43/73] Modify the default background color of GLSceneRenderer --- src/GLSceneRenderer/GLSceneRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GLSceneRenderer/GLSceneRenderer.cpp b/src/GLSceneRenderer/GLSceneRenderer.cpp index 0eebc7f73..0b1c23171 100644 --- a/src/GLSceneRenderer/GLSceneRenderer.cpp +++ b/src/GLSceneRenderer/GLSceneRenderer.cpp @@ -86,7 +86,7 @@ GLSceneRenderer::Impl::Impl(GLSceneRenderer* self, SgGroup* sceneRoot) vp.h = invaid; self->aspectRatio_ = 1.0f; self->devicePixelRatio_ = 1.0f; - backgroundColor << 0.1f, 0.1f, 0.3f; // dark blue + backgroundColor << 0.0f, 0.0f, 0.0f; // black defaultColor << 1.0f, 1.0f, 1.0f; os_ = &nullout(); From c5a5f736fb156a17a76680b0f3908fe28622af59 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Thu, 29 Aug 2024 13:14:27 +0900 Subject: [PATCH 44/73] Add properties to GLVisionSimulatorItem - Add the background color property - Add the world light property to turn the world light on/off --- src/BodyPlugin/GLVisionSimulatorItem.cpp | 54 +++++++++++++++++++++--- src/BodyPlugin/GLVisionSimulatorItem.h | 3 ++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/BodyPlugin/GLVisionSimulatorItem.cpp b/src/BodyPlugin/GLVisionSimulatorItem.cpp index ba6c0728e..739353764 100644 --- a/src/BodyPlugin/GLVisionSimulatorItem.cpp +++ b/src/BodyPlugin/GLVisionSimulatorItem.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -263,9 +264,11 @@ class GLVisionSimulatorItem::Impl vector sensorNames; string sensorNameListString; Selection threadMode; + Vector3f backgroundColor; bool isBestEffortModeProperty; bool shootAllSceneObjects; bool isHeadLightEnabled; + bool isWorldLightEnabled; bool areAdditionalLightsEnabled; double maxFrameRate; double maxLatency; @@ -317,16 +320,20 @@ GLVisionSimulatorItem::Impl::Impl(GLVisionSimulatorItem* self) threadMode(GLVisionSimulatorItem::N_THREAD_MODES, CNOID_GETTEXT_DOMAIN_NAME) { simulatorItem = nullptr; - maxFrameRate = 1000.0; - maxLatency = 1.0; + + isVisionDataRecordingEnabled = false; + rangeSensorPrecisionRatio = 2.0; depthError = 0.0; - isVisionDataRecordingEnabled = false; + backgroundColor << 0.0f, 0.0f, 0.0f; isBestEffortModeProperty = true; + shootAllSceneObjects = true; isHeadLightEnabled = true; + isWorldLightEnabled = true; areAdditionalLightsEnabled = true; - shootAllSceneObjects = true; + maxFrameRate = 1000.0; + maxLatency = 1.0; threadMode.setSymbol(GLVisionSimulatorItem::SINGLE_THREAD_MODE, N_("Single")); threadMode.setSymbol(GLVisionSimulatorItem::SENSOR_THREAD_MODE, N_("Sensor")); @@ -353,14 +360,18 @@ GLVisionSimulatorItem::Impl::Impl(GLVisionSimulatorItem* self, const Impl& org) simulatorItem = nullptr; isVisionDataRecordingEnabled = org.isVisionDataRecordingEnabled; + rangeSensorPrecisionRatio = org.rangeSensorPrecisionRatio; depthError = org.depthError; + bodyNameListString = getNameListString(bodyNames); sensorNameListString = getNameListString(sensorNames); threadMode = org.threadMode; + backgroundColor = org.backgroundColor; isBestEffortModeProperty = org.isBestEffortModeProperty; shootAllSceneObjects = org.shootAllSceneObjects; isHeadLightEnabled = org.isHeadLightEnabled; + isWorldLightEnabled = org.isWorldLightEnabled; areAdditionalLightsEnabled = org.areAdditionalLightsEnabled; maxFrameRate = org.maxFrameRate; maxLatency = org.maxLatency; @@ -445,6 +456,12 @@ void GLVisionSimulatorItem::setRangeSensorPrecisionRatio(double r) } +void GLVisionSimulatorItem::setBackgroundColor(const Vector3f& c) +{ + impl->backgroundColor = c; +} + + void GLVisionSimulatorItem::setAllSceneObjectsEnabled(bool on) { impl->setProperty(impl->shootAllSceneObjects, on); @@ -457,6 +474,12 @@ void GLVisionSimulatorItem::setHeadLightEnabled(bool on) } +void GLVisionSimulatorItem::setWorldLightEnabled(bool on) +{ + impl->setProperty(impl->isWorldLightEnabled, on); +} + + void GLVisionSimulatorItem::setAdditionalLightsEnabled(bool on) { impl->setProperty(impl->areAdditionalLightsEnabled, on); @@ -1002,11 +1025,13 @@ bool SensorScreenRenderer::initializeGL(SgCamera* sceneCamera) flagToUpdatePreprocessedNodeTree = true; renderer->extractPreprocessedNodes(); renderer->setCurrentCamera(sceneCamera); + renderer->setBackgroundColor(simImpl->backgroundColor); if(rangeSensorForRendering){ renderer->setLightingMode(GLSceneRenderer::NoLighting); } else { - if(screenId != FRONT_SCREEN){ + renderer->headLight()->on(simImpl->isHeadLightEnabled); + if(simImpl->isHeadLightEnabled && screenId != FRONT_SCREEN){ SgDirectionalLight* headLight = dynamic_cast(renderer->headLight()); if(headLight){ switch(screenId){ @@ -1028,7 +1053,8 @@ bool SensorScreenRenderer::initializeGL(SgCamera* sceneCamera) } } } - renderer->headLight()->on(simImpl->isHeadLightEnabled); + + renderer->worldLight()->on(simImpl->isWorldLightEnabled); renderer->enableAdditionalLights(simImpl->areAdditionalLightsEnabled); } @@ -1898,7 +1924,19 @@ void GLVisionSimulatorItem::Impl::doPutProperties(PutPropertyFunction& putProper putProperty(_("Precision ratio of range sensors"), rangeSensorPrecisionRatio, changeProperty(rangeSensorPrecisionRatio)); putProperty.reset()(_("Depth error"), depthError, changeProperty(depthError)); + + putProperty(_("Background color"), str(backgroundColor), + [this](const string& value){ + Vector3f c; + if(toVector3(value, c)){ + backgroundColor = c; + return true; + } + return false; + }); + putProperty(_("Head light"), isHeadLightEnabled, changeProperty(isHeadLightEnabled)); + putProperty(_("World light"), isWorldLightEnabled, changeProperty(isWorldLightEnabled)); putProperty(_("Additional lights"), areAdditionalLightsEnabled, changeProperty(areAdditionalLightsEnabled)); putProperty(_("Anti-aliasing"), isAntiAliasingEnabled, changeProperty(isAntiAliasingEnabled)); } @@ -1923,7 +1961,9 @@ bool GLVisionSimulatorItem::Impl::store(Archive& archive) archive.write("all_scene_objects", shootAllSceneObjects); archive.write("range_sensor_precision_ratio", rangeSensorPrecisionRatio); archive.write("depth_error", depthError); + write(archive, "background_color", backgroundColor); archive.write("enable_head_light", isHeadLightEnabled); + archive.write("enable_world_light", isWorldLightEnabled); archive.write("enable_additional_lights", areAdditionalLightsEnabled); archive.write("antialiasing", isAntiAliasingEnabled); return true; @@ -1951,7 +1991,9 @@ bool GLVisionSimulatorItem::Impl::restore(const Archive& archive) archive.read({ "all_scene_objects", "allSceneObjects" }, shootAllSceneObjects); archive.read({ "range_sensor_precision_ratio", "rangeSensorPrecisionRatio" }, rangeSensorPrecisionRatio); archive.read({ "depth_error", "depthError" }, depthError); + read(archive, "background_color", backgroundColor); archive.read({ "enable_head_light", "enableHeadLight" }, isHeadLightEnabled); + archive.read("enable_world_light", isWorldLightEnabled); archive.read({ "enable_additional_lights", "enableAdditionalLights" }, areAdditionalLightsEnabled); archive.read({ "antialiasing", "antiAliasing" }, isAntiAliasingEnabled); diff --git a/src/BodyPlugin/GLVisionSimulatorItem.h b/src/BodyPlugin/GLVisionSimulatorItem.h index 52e781194..7bf18c2a0 100644 --- a/src/BodyPlugin/GLVisionSimulatorItem.h +++ b/src/BodyPlugin/GLVisionSimulatorItem.h @@ -2,6 +2,7 @@ #define CNOID_BODY_PLUGIN_GL_VISION_SIMULATOR_ITEM_H #include "SubSimulatorItem.h" +#include #include "exportdecl.h" namespace cnoid { @@ -25,8 +26,10 @@ class CNOID_EXPORT GLVisionSimulatorItem : public SubSimulatorItem void setThreadMode(int mode); void setBestEffortMode(bool on); void setRangeSensorPrecisionRatio(double r); + void setBackgroundColor(const Vector3f& c); void setAllSceneObjectsEnabled(bool on); void setHeadLightEnabled(bool on); + void setWorldLightEnabled(bool on); void setAdditionalLightsEnabled(bool on); virtual bool initializeSimulation(SimulatorItem* simulatorItem) override; From 27ea6ac23d7c819a293c147124f09be9f62228e6 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Thu, 29 Aug 2024 13:09:45 +0900 Subject: [PATCH 45/73] Update Japanese translations for BodyPlugin --- src/BodyPlugin/po/ja.po | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/BodyPlugin/po/ja.po b/src/BodyPlugin/po/ja.po index 3147983e3..855965157 100644 --- a/src/BodyPlugin/po/ja.po +++ b/src/BodyPlugin/po/ja.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Choreonoid\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-24 12:36+0900\n" +"POT-Creation-Date: 2024-08-29 12:03+0900\n" "PO-Revision-Date: 2021-10-25 12:00+0900\n" "Language: ja\n" "MIME-Version: 1.0\n" @@ -720,9 +720,6 @@ msgstr "{0}カメラ" msgid "BodySyncCameraItem" msgstr "ボディ同期カメラ" -msgid "Camera configuration" -msgstr "カメラの設定" - msgid "Target link" msgstr "対象リンク" @@ -828,9 +825,15 @@ msgstr "レンジセンサ精度係数" msgid "Depth error" msgstr "深度エラー" +msgid "Background color" +msgstr "背景色" + msgid "Head light" msgstr "ヘッドライト" +msgid "World light" +msgstr "ワールドライト" + msgid "Additional lights" msgstr "追加のライト" From d9d36d04b374e84fe9552391e73ea8574f6873d1 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 2 Sep 2024 15:27:25 +0900 Subject: [PATCH 46/73] Fix a bug in copying the initial state in BodyItem::doAssign when reloading the model file with an increased number of joints --- src/BodyPlugin/BodyItem.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/BodyPlugin/BodyItem.cpp b/src/BodyPlugin/BodyItem.cpp index 2f715f1ff..5a104c80f 100644 --- a/src/BodyPlugin/BodyItem.cpp +++ b/src/BodyPlugin/BodyItem.cpp @@ -403,15 +403,7 @@ bool BodyItem::Impl::doAssign(const Item* srcItem) setCurrentBaseLink(baseLink, false, false); } } - // copy the current kinematic state Body* srcBody = srcBodyItem->body(); - for(int i=0; i < srcBody->numLinks(); ++i){ - Link* srcLink = srcBody->link(i); - Link* link = body->link(srcLink->name()); - if(link){ - link->q() = srcLink->q(); - } - } if(baseLink){ baseLink->p() = srcBaseLink->p(); baseLink->R() = srcBaseLink->R(); @@ -420,9 +412,20 @@ bool BodyItem::Impl::doAssign(const Item* srcItem) body->rootLink()->R() = srcBody->rootLink()->R(); } - initialState = srcImpl->initialState; + // copy the current kinematic state + int numSrcLinks = srcBody->numLinks(); + for(int i=0; i < numSrcLinks; ++i){ + Link* srcLink = srcBody->link(i); + Link* link = body->link(srcLink->name()); + if(link){ + link->q() = srcLink->q(); + } + } + + self->calcForwardKinematics(); + self->storeKinematicState(initialState); - self->notifyKinematicStateChange(true); + self->notifyKinematicStateChange(); return true; } From 720f1a9d0460a34509717cd017b29c85d51be1c5 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 2 Sep 2024 15:54:55 +0900 Subject: [PATCH 47/73] Add a floor model with fence --- share/model/misc/fencedfloor.body | 45 +++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 share/model/misc/fencedfloor.body diff --git a/share/model/misc/fencedfloor.body b/share/model/misc/fencedfloor.body new file mode 100644 index 000000000..e12168cc9 --- /dev/null +++ b/share/model/misc/fencedfloor.body @@ -0,0 +1,45 @@ +format: ChoreonoidBody +formatVersion: 2.0 +name: FencedFloor +links: + - + name: Floor + jointType: fixed + material: Ground + elements: + Shape: + translation: [ 0, 0, -0.1 ] + geometry: { type: Box, size: [ 10.0, 10.0, 0.2 ] } + appearance: { material: { diffuseColor: [ 0, 0, 1 ] }} + - + name: Fence1 + parent: Floor + translation: [ 4.95, 0, 0.2 ] + jointType: fixed + elements: + Shape: &Fence1 + geometry: { type: Box, size: [ 0.1, 10.0, 0.4 ] } + appearance: &App1 { material: { diffuseColor: [ 0.7, 0.7, 0.7 ] }} + - + name: Fence2 + parent: Floor + translation: [ -4.95, 0, 0.2 ] + jointType: fixed + elements: + Shape: *Fence1 + - + name: Fence3 + parent: Floor + translation: [ 0, 4.95, 0.2 ] + jointType: fixed + elements: + Shape: &Fence2 + geometry: { type: Box, size: [ 9.8, 0.1, 0.4 ] } + appearance: *App1 + - + name: Fence4 + parent: Floor + translation: [ 0, -4.95, 0.2 ] + jointType: fixed + elements: + Shape: *Fence2 From 5db54ed99e0691a9119d2d5a30760ebcdf6e0a13 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 3 Sep 2024 11:34:19 +0900 Subject: [PATCH 48/73] Modify the default recording mode of SimulatorItem to the tail recording mode to prevent unintended memory exhaustion due to a long-running simulation --- src/BodyPlugin/SimulatorItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BodyPlugin/SimulatorItem.cpp b/src/BodyPlugin/SimulatorItem.cpp index c5c11f2bc..2c88aea14 100644 --- a/src/BodyPlugin/SimulatorItem.cpp +++ b/src/BodyPlugin/SimulatorItem.cpp @@ -1235,7 +1235,7 @@ SimulatorItem::Impl::Impl(SimulatorItem* self) recordingMode.setSymbol(FullRecording, N_("full")); recordingMode.setSymbol(TailRecording, N_("tail")); recordingMode.setSymbol(NoRecording, N_("off")); - recordingMode.select(FullRecording); + recordingMode.select(TailRecording); timeRangeMode.setSymbol(UnlimitedTime, N_("Unlimited")); timeRangeMode.setSymbol(SpecifiedTime, N_("Specified time")); @@ -1247,7 +1247,7 @@ SimulatorItem::Impl::Impl(SimulatorItem* self) realtimeSyncMode.setSymbol(ConservativeRealtimeSync, N_("On (Conservative)")); realtimeSyncMode.select(CompensatoryRealtimeSync); - timeLength = 180.0; // 3 min. + timeLength = 300.0; // 5 min. useControllerThreadsProperty = true; isActiveControlTimeRangeMode = false; isAllLinkPositionOutputMode = true; From 163d1e43978f0c08e3c14f96a3ae9a5dd15f4f12 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 3 Sep 2024 11:56:20 +0900 Subject: [PATCH 49/73] Fix ItemTreeView and ItemTreeWidget to disable name editing for sub items and attached items --- src/Base/ItemTreeView.cpp | 8 ++++++-- src/Base/ItemTreeWidget.cpp | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Base/ItemTreeView.cpp b/src/Base/ItemTreeView.cpp index 15e1650c7..b33994ac7 100644 --- a/src/Base/ItemTreeView.cpp +++ b/src/Base/ItemTreeView.cpp @@ -141,8 +141,12 @@ void ItemTreeView::Impl::onContextMenuRequested(Item* item, MenuManager& menu) clearSelection->setEnabled(false); } else { - rename->sigTriggered().connect( - [this, item](){ itemTreeWidget->editItemName(item); }); + if(item->isSubItem() || item->hasAttribute(Item::Attached)){ + rename->setEnabled(false); + } else { + rename->sigTriggered().connect( + [this, item](){ itemTreeWidget->editItemName(item); }); + } if(itemTreeWidget->checkCuttable(item)){ cut->sigTriggered().connect( diff --git a/src/Base/ItemTreeWidget.cpp b/src/Base/ItemTreeWidget.cpp index 236127a93..6606cb9a2 100644 --- a/src/Base/ItemTreeWidget.cpp +++ b/src/Base/ItemTreeWidget.cpp @@ -196,7 +196,7 @@ ItemTreeWidget::ItwItem::ItwItem(Item* item, ItemTreeWidget::Impl* widgetImpl) if(widgetImpl->isCheckColumnShown){ flags |= Qt::ItemIsUserCheckable; } - if(!item->hasAttribute(Item::Attached)){ + if(!item->isSubItem() && !item->hasAttribute(Item::Attached)){ flags |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled; } setFlags(flags); From 104e96a28f1c788d5a934ee75098d650be3b25e5 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 3 Sep 2024 16:03:03 +0900 Subject: [PATCH 50/73] Fix Item::addChildItem and Item::addSubItem to check if the target item already exists as a child of this item --- src/Base/Item.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Base/Item.cpp b/src/Base/Item.cpp index 03d15b3b7..c7f3042dd 100644 --- a/src/Base/Item.cpp +++ b/src/Base/Item.cpp @@ -655,7 +655,11 @@ Item* Item::localRootItem() const bool Item::addChildItem(Item* item, bool isManualOperation) { - return impl->doInsertChildItem(item, nullptr, isManualOperation); + if(item->parentItem() == this){ + return true; // Already inserted + } else { + return impl->doInsertChildItem(item, nullptr, isManualOperation); + } } @@ -674,7 +678,12 @@ bool Item::insertChildItem(Item* item, Item* nextItem, bool isManualOperation) bool Item::addSubItem(Item* item) { item->setAttribute(SubItem); - return impl->doInsertChildItem(item, nullptr, false); + + if(item->parentItem() == this){ + return true; // Already inserted + } else { + return impl->doInsertChildItem(item, nullptr, false); + } } From dda4bebd007ab5c70f927da0275455c98b0287ad Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 3 Sep 2024 16:05:28 +0900 Subject: [PATCH 51/73] Fix the code to update sub visualizer items in SensorVisualizerItem --- src/BodyPlugin/SensorVisualizerItem.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/BodyPlugin/SensorVisualizerItem.cpp b/src/BodyPlugin/SensorVisualizerItem.cpp index bbdd60c01..b00410326 100644 --- a/src/BodyPlugin/SensorVisualizerItem.cpp +++ b/src/BodyPlugin/SensorVisualizerItem.cpp @@ -408,7 +408,9 @@ void SensorVisualizerItem::Impl::addSensorVisualizerItem(Body* body) } if(item->bodyItem != bodyItem){ item->setBodyItem(bodyItem); - self->addSubItem(item); + if(item->parentItem() != self){ + self->addSubItem(item); + } } } } @@ -432,7 +434,9 @@ void SensorVisualizerItem::Impl::addVisionSensorVisualizerItem(Body* body) } if(item->bodyItem != bodyItem){ item->setBodyItem(bodyItem, sensor); - self->addSubItem(item); + if(item->parentItem() != self){ + self->addSubItem(item); + } } } } From 2311b9cf7d4a4cc9a95b254976d22fff3b117fc4 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 3 Sep 2024 17:34:52 +0900 Subject: [PATCH 52/73] Fix SensorVisualizerItem to update each sub item name when the corresponding sensor name is changed in loading a project --- src/BodyPlugin/SensorVisualizerItem.cpp | 25 ++++++------------------- src/BodyPlugin/SensorVisualizerItem.h | 5 ----- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/BodyPlugin/SensorVisualizerItem.cpp b/src/BodyPlugin/SensorVisualizerItem.cpp index b00410326..990b4243c 100644 --- a/src/BodyPlugin/SensorVisualizerItem.cpp +++ b/src/BodyPlugin/SensorVisualizerItem.cpp @@ -1,8 +1,3 @@ -/*! - @file - @author Shin'ichiro Nakaoka -*/ - #include "SensorVisualizerItem.h" #include "BodyItem.h" #include @@ -775,13 +770,11 @@ SignalProxy CameraImageVisualizerItem::sigImageUpdated() void CameraImageVisualizerItem::setBodyItem(BodyItem* bodyItem, Camera* camera) { - if(name().empty()){ - string name = camera->name(); - if(dynamic_cast(camera)){ - name += "-Image"; - } - setName(name); + string cameraName = camera->name(); + if(dynamic_cast(camera)){ + cameraName += "-Image"; } + setName(cameraName); this->camera = camera; @@ -829,11 +822,8 @@ Item* PointCloudVisualizerItem::doCloneItem(CloneMap* /* cloneMap */) const void PointCloudVisualizerItem::setBodyItem(BodyItem* bodyItem, RangeCamera* rangeCamera) { - if(name().empty()){ - setName(rangeCamera->name()); - } + setName(rangeCamera->name()); this->rangeCamera = rangeCamera; - SubSensorVisualizerItem::setBodyItem(bodyItem); } @@ -921,11 +911,8 @@ RangeSensorVisualizerItem::RangeSensorVisualizerItem() void RangeSensorVisualizerItem::setBodyItem(BodyItem* bodyItem, RangeSensor* rangeSensor) { - if(name().empty()){ - setName(rangeSensor->name()); - } + setName(rangeSensor->name()); this->rangeSensor = rangeSensor; - SubSensorVisualizerItem::setBodyItem(bodyItem); } diff --git a/src/BodyPlugin/SensorVisualizerItem.h b/src/BodyPlugin/SensorVisualizerItem.h index 030e46235..a118ca65d 100644 --- a/src/BodyPlugin/SensorVisualizerItem.h +++ b/src/BodyPlugin/SensorVisualizerItem.h @@ -1,8 +1,3 @@ -/*! - @file - @author Shin'ichiro Nakaoka -*/ - #ifndef CNOID_BODY_PLUGIN_SENSOR_VISUALIZER_ITEM_H #define CNOID_BODY_PLUGIN_SENSOR_VISUALIZER_ITEM_H From 8fa835a3d594c92fb59c32540b7ba1cab1027526 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 3 Sep 2024 18:32:20 +0900 Subject: [PATCH 53/73] Improve ItemTreeWidget to keep the expansion state of an item when the item is moved in the item tree --- src/Base/ItemTreeWidget.cpp | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Base/ItemTreeWidget.cpp b/src/Base/ItemTreeWidget.cpp index 6606cb9a2..8b6517dac 100644 --- a/src/Base/ItemTreeWidget.cpp +++ b/src/Base/ItemTreeWidget.cpp @@ -115,7 +115,7 @@ class ItemTreeWidget::Impl : public TreeWidget ItwItem* findNextItwItemInSubTree(Item* item, bool doTraverse); bool isItemUnderTreeWidgetInternalOperation(Item* item); void onSubTreeAddedOrMoved(Item* item); - void onSubTreeRemoved(Item* item); + void onSubTreeRemoved(Item* item, bool isMoving); void onItemAssigned(Item* assigned, const Item* srcItem); void getItemsIter(ItwItem* itwItem, ItemList<>& itemList); @@ -438,7 +438,7 @@ void ItemTreeWidget::Impl::initialize() projectRootItemConnections.add( projectRootItem->sigSubTreeRemoved().connect( - [this](Item* item, bool){ onSubTreeRemoved(item); })); + [this](Item* item, bool isMoving){ onSubTreeRemoved(item, isMoving); })); projectRootItemConnections.add( projectRootItem->sigItemAssigned().connect( @@ -937,10 +937,19 @@ void ItemTreeWidget::Impl::insertItem(QTreeWidgetItem* parentTwItem, Item* item, { auto itwItem = findItwItem(item); + bool doExpand = false; + if(itwItem){ - parentTwItem = itwItem; + if(itwItem->parent()){ + parentTwItem = itwItem; + } else { // Item is moving + doExpand = itwItem->isExpandedBeforeRemoving; + delete itwItem; + itwItem = nullptr; + } + } - } else { + if(!itwItem){ if(!findOrCreateLocalRootItem(false)){ return; } @@ -985,6 +994,10 @@ void ItemTreeWidget::Impl::insertItem(QTreeWidgetItem* parentTwItem, Item* item, insertItem(parentTwItem, child, isTopLevelItemCandidate); } } + + if(itwItem && doExpand){ + itwItem->setExpanded(true); + } } @@ -1074,7 +1087,7 @@ void ItemTreeWidget::Impl::onSubTreeAddedOrMoved(Item* item) } -void ItemTreeWidget::Impl::onSubTreeRemoved(Item* item) +void ItemTreeWidget::Impl::onSubTreeRemoved(Item* item, bool isMoving) { if(isItemUnderTreeWidgetInternalOperation(item) || !localRootItem){ return; @@ -1083,15 +1096,18 @@ void ItemTreeWidget::Impl::onSubTreeRemoved(Item* item) isChangingTreeWidgetTreeStructure++; if(auto itwItem = findItwItem(item)){ + itwItem->isExpandedBeforeRemoving = itwItem->isExpanded(); if(auto parentTwItem = itwItem->parent()){ parentTwItem->removeChild(itwItem); } else { takeTopLevelItem(indexOfTopLevelItem(itwItem)); } - delete itwItem; + if(!isMoving){ + delete itwItem; + } } else { for(auto child = item->childItem(); child; child = child->nextItem()){ - onSubTreeRemoved(child); + onSubTreeRemoved(child, isMoving); } } From a17a5a8661827d0354523b319529e698fce0a1d9 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 4 Sep 2024 11:50:44 +0900 Subject: [PATCH 54/73] Fix JointDisplacementWidgetSet to avoid a crash due to a bug of QDial --- src/BodyPlugin/JointDisplacementWidgetSet.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BodyPlugin/JointDisplacementWidgetSet.cpp b/src/BodyPlugin/JointDisplacementWidgetSet.cpp index a72b70ec3..20f460a37 100644 --- a/src/BodyPlugin/JointDisplacementWidgetSet.cpp +++ b/src/BodyPlugin/JointDisplacementWidgetSet.cpp @@ -784,6 +784,7 @@ void JointIndicator::initialize(Link* joint) spin.setDecimals(0); spin.setRange(0.0, 0.0); spin.setEnabled(false); + dial.setValue(0); dial.setRange(0, 0); dial.setWrapping(false); dial.setNotchesVisible(false); From 2b9d4e83ab6475860bd34fef685eb425f0df3f21 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 4 Sep 2024 15:51:57 +0900 Subject: [PATCH 55/73] Support for AGX Dynamics 2.38 --- src/AGXDynamicsPlugin/AGXObjectFactory.cpp | 8 ++++++++ src/AGXDynamicsPlugin/AGXScene.cpp | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/AGXDynamicsPlugin/AGXObjectFactory.cpp b/src/AGXDynamicsPlugin/AGXObjectFactory.cpp index 58f555695..22bf5bd85 100644 --- a/src/AGXDynamicsPlugin/AGXObjectFactory.cpp +++ b/src/AGXDynamicsPlugin/AGXObjectFactory.cpp @@ -49,7 +49,11 @@ agxSDK::SimulationRef AGXObjectFactory::createSimulation(const AGXSimulationDesc sim->getSpace()->setContactReductionThreshold(desc.contactReductionThreshhold); sim->getDynamicsSystem()->setEnableContactWarmstarting(desc.enableContactWarmstarting); sim->getMergeSplitHandler()->setEnable(desc.enableAMOR); + +#if AGX_MAJOR_VERSION < 38 sim->getDynamicsSystem()->getAutoSleep()->setEnable(desc.enableAutoSleep); +#endif + return sim; } @@ -107,7 +111,11 @@ LinkRigidBodyRef AGXObjectFactory::createLinkRigidBody(const AGXRigidBodyDesc& d rigid->setPosition(desc.p); rigid->setRotation(desc.R); rigid->setName(desc.name); + +#if AGX_MAJOR_VERSION < 38 rigid->getAutoSleepProperties().setEnable(desc.enableAutoSleep); +#endif + return rigid; } diff --git a/src/AGXDynamicsPlugin/AGXScene.cpp b/src/AGXDynamicsPlugin/AGXScene.cpp index cf213fd6c..72f981442 100644 --- a/src/AGXDynamicsPlugin/AGXScene.cpp +++ b/src/AGXDynamicsPlugin/AGXScene.cpp @@ -132,12 +132,18 @@ void AGXScene::setGravity(const agx::Vec3 & g) bool AGXScene::getEnableAutoSleep() const { +#if AGX_MAJOR_VERSION >= 38 + return false; +#else return getSimulation()->getDynamicsSystem()->getAutoSleep()->getEnable(); +#endif } void AGXScene::setEnableAutoSleep(const bool & bOn) { +#if AGX_MAJOR_VERSION < 38 getSimulation()->getDynamicsSystem()->getAutoSleep()->setEnable(bOn); +#endif } bool AGXScene::saveSceneToAGXFile() @@ -151,4 +157,4 @@ agxSDK::SimulationRef AGXScene::getSimulation() const return _agxSimulation; } -} \ No newline at end of file +} From 280b10598617e965b1b7c1586b89dd9c90e80b93 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Fri, 6 Sep 2024 23:23:58 +0900 Subject: [PATCH 56/73] Refactor the API of LocatableItem --- src/Base/CoordinateFrameItem.cpp | 16 ++--- src/Base/LocatableItem.cpp | 35 +++++---- src/Base/LocatableItem.h | 23 ++++-- src/Base/LocationView.cpp | 4 +- src/Base/PointSetItem.cpp | 4 +- src/Base/PositionTagGroupItem.cpp | 33 ++++----- src/Base/SceneItem.cpp | 4 +- src/BodyPlugin/BodyItem.cpp | 72 ++++++------------- src/BodyPlugin/DeviceOverwriteItem.cpp | 13 +--- src/BodyPlugin/LinkOverwriteItem.cpp | 14 ++-- .../RegionIntrusionDetectorItem.cpp | 9 +-- src/MocapPlugin/SkeletonMotionItem.cpp | 4 +- 12 files changed, 92 insertions(+), 139 deletions(-) diff --git a/src/Base/CoordinateFrameItem.cpp b/src/Base/CoordinateFrameItem.cpp index 0c6f9d2f7..ea3868cd1 100644 --- a/src/Base/CoordinateFrameItem.cpp +++ b/src/Base/CoordinateFrameItem.cpp @@ -21,8 +21,7 @@ class FrameLocation : public LocationProxy FrameLocation(CoordinateFrameItem::Impl* impl); void updateLocationType(); - virtual Item* getCorrespondingItem() override; - virtual LocationProxyPtr getParentLocationProxy() const override; + virtual LocationProxyPtr getParentLocationProxy() override; virtual std::string getName() const override; virtual Isometry3 getLocation() const override; virtual bool isLocked() const override; @@ -378,11 +377,10 @@ void CoordinateFrameItem::setLocationLocked(bool on) FrameLocation::FrameLocation(CoordinateFrameItem::Impl* impl) - : LocationProxy(InvalidLocation), + : LocationProxy(impl->self, InvalidLocation), impl(impl) { - impl->self->sigNameChanged().connect( - [&](const std::string& /* oldName */){ notifyAttributeChange(); }); + setNameDependencyOnItemName(); } @@ -410,13 +408,7 @@ void FrameLocation::updateLocationType() } -Item* FrameLocation::getCorrespondingItem() -{ - return impl->self; -} - - -LocationProxyPtr FrameLocation::getParentLocationProxy() const +LocationProxyPtr FrameLocation::getParentLocationProxy() { if(impl->frame->isLocal()){ if(impl->frameListItem){ diff --git a/src/Base/LocatableItem.cpp b/src/Base/LocatableItem.cpp index 2d87f1dab..76b92df4b 100644 --- a/src/Base/LocatableItem.cpp +++ b/src/Base/LocatableItem.cpp @@ -11,8 +11,9 @@ Signal sigEditRequest; } -LocationProxy::LocationProxy(LocationType type) - : locationType_(type) +LocationProxy::LocationProxy(Item* locatableItem, LocationType type) + : locatableItemRef(locatableItem), + locationType_(type) { isLocked_ = false; } @@ -24,13 +25,23 @@ LocationProxy::~LocationProxy() } +void LocationProxy::setNameDependencyOnItemName() +{ + if(auto item = locatableItem()){ + if(!itemNameConnection_.connected()){ + itemNameConnection_ = item->sigNameChanged().connect( + [this](const std::string&){ notifyAttributeChange(); }); + } + } +} + + std::string LocationProxy::getName() const { auto self = const_cast(this); - if(auto item = self->getCorrespondingItem()){ + if(auto item = self->locatableItem()){ if(!itemNameConnection_.connected()){ - self->itemNameConnection_ = item->sigNameChanged().connect( - [self](const std::string&){ self->notifyAttributeChange(); }); + self->setNameDependencyOnItemName(); } return item->displayName(); } @@ -59,7 +70,7 @@ void LocationProxy::setLocked(bool on) } -bool LocationProxy::isDoingContinuousUpdate() const +bool LocationProxy::isContinuousUpdateState() const { return false; } @@ -77,15 +88,9 @@ void LocationProxy::finishLocationEditing() } -Item* LocationProxy::getCorrespondingItem() +LocationProxyPtr LocationProxy::getParentLocationProxy() { - return nullptr; -} - - -LocationProxyPtr LocationProxy::getParentLocationProxy() const -{ - if(auto item = const_cast(this)->getCorrespondingItem()){ + if(auto item = locatableItem()){ if(auto parentLocatableItem = item->findOwnerItem()){ return parentLocatableItem->getLocationProxy(); } @@ -107,7 +112,7 @@ Isometry3 LocationProxy::getGlobalLocationOf(const Isometry3 T) const return T; case ParentRelativeLocation: case OffsetLocation: - if(auto parent = getParentLocationProxy()){ + if(auto parent = const_cast(this)->getParentLocationProxy()){ return parent->getGlobalLocation() * T; } else { return T; diff --git a/src/Base/LocatableItem.h b/src/Base/LocatableItem.h index 8c3ef6043..658c386ec 100644 --- a/src/Base/LocatableItem.h +++ b/src/Base/LocatableItem.h @@ -15,6 +15,10 @@ typedef ref_ptr LocationProxyPtr; class CNOID_EXPORT LocationProxy : public Referenced { public: + virtual ~LocationProxy(); + + Item* locatableItem() { return locatableItemRef.lock(); } + enum LocationType { InvalidLocation, GlobalLocation, @@ -23,11 +27,9 @@ class CNOID_EXPORT LocationProxy : public Referenced // this maeks the global coordinate unavailable in the user interface OffsetLocation }; - - virtual ~LocationProxy(); - LocationType locationType() const { return locationType_; } void setLocationType(LocationType type) { locationType_ = type; } + virtual std::string getName() const; /** @@ -40,11 +42,10 @@ class CNOID_EXPORT LocationProxy : public Referenced virtual Isometry3 getLocation() const = 0; virtual bool isLocked() const; virtual void setLocked(bool on); - virtual bool isDoingContinuousUpdate() const; + virtual bool isContinuousUpdateState() const; virtual bool setLocation(const Isometry3& T); virtual void finishLocationEditing(); - virtual Item* getCorrespondingItem(); - virtual LocationProxyPtr getParentLocationProxy() const; + virtual LocationProxyPtr getParentLocationProxy(); virtual void expire(); virtual SignalProxy sigLocationChanged() = 0; virtual SignalProxy sigAttributeChanged(); @@ -57,10 +58,18 @@ class CNOID_EXPORT LocationProxy : public Referenced static SignalProxy sigEditRequest(); + [[deprecated("Use isContinuousUpdateState.")]] + bool isDoingContinuousUpdate() const { return isContinuousUpdateState(); } + + [[deprecated("Use locatableItem.")]] + Item* getCorrespondingItem() { return locatableItem(); } + protected: - LocationProxy(LocationType type); + LocationProxy(Item* locatableItem, LocationType type); + void setNameDependencyOnItemName(); private: + weak_ref_ptr locatableItemRef; LocationType locationType_; bool isLocked_; Signal sigAttributeChanged_; diff --git a/src/Base/LocationView.cpp b/src/Base/LocationView.cpp index dd2cec714..1dca198b5 100644 --- a/src/Base/LocationView.cpp +++ b/src/Base/LocationView.cpp @@ -610,7 +610,7 @@ void LocationView::Impl::setCurrentLocationCategory(int categoryIndex) bool blocked = locked; if(!blocked){ for(auto& info : locationInfos){ - if(info->location->isDoingContinuousUpdate()){ + if(info->location->isContinuousUpdateState()){ blocked = true; break; } @@ -762,7 +762,7 @@ void LocationView::Impl::updateBaseCoordinateSystems() Item* targetItem = locationInfo->item; if(!targetItem){ - targetItem = location->getCorrespondingItem(); + targetItem = location->locatableItem(); } for(int i=0; i < n; ++i){ diff --git a/src/Base/PointSetItem.cpp b/src/Base/PointSetItem.cpp index 87d49fdf8..af747938f 100644 --- a/src/Base/PointSetItem.cpp +++ b/src/Base/PointSetItem.cpp @@ -999,10 +999,10 @@ LocationProxyPtr PointSetItem::getLocationProxy() PointSetLocation::PointSetLocation(PointSetItem* item) - : LocationProxy(GlobalLocation), + : LocationProxy(item, GlobalLocation), item(item) { - + setNameDependencyOnItemName(); } diff --git a/src/Base/PositionTagGroupItem.cpp b/src/Base/PositionTagGroupItem.cpp index 754b8b7ed..e16520d4a 100644 --- a/src/Base/PositionTagGroupItem.cpp +++ b/src/Base/PositionTagGroupItem.cpp @@ -114,12 +114,11 @@ class TagGroupLocationProxy : public LocationProxy TagGroupLocationProxy(PositionTagGroupItem::Impl* impl); virtual std::string getName() const override; - virtual Item* getCorrespondingItem() override; virtual Isometry3 getLocation() const override; virtual bool setLocation(const Isometry3& T) override; virtual void finishLocationEditing() override; virtual SignalProxy sigLocationChanged() override; - virtual LocationProxyPtr getParentLocationProxy() const override; + virtual LocationProxyPtr getParentLocationProxy() override; }; typedef ref_ptr TagGroupLocationProxyPtr; @@ -141,7 +140,7 @@ class TagLocationProxy : public LocationProxy virtual bool setLocation(const Isometry3& T) override; virtual void finishLocationEditing() override; virtual SignalProxy sigLocationChanged() override; - virtual LocationProxyPtr getParentLocationProxy() const override; + virtual LocationProxyPtr getParentLocationProxy() override; }; typedef ref_ptr TagLocationProxyPtr; @@ -156,7 +155,7 @@ class TagParentLocationProxy : public LocationProxy virtual std::string getName() const override; virtual Isometry3 getLocation() const override; virtual SignalProxy sigLocationChanged() override; - virtual LocationProxyPtr getParentLocationProxy() const override; + virtual LocationProxyPtr getParentLocationProxy() override; }; typedef ref_ptr TagParentLocationProxyPtr; @@ -1461,10 +1460,10 @@ bool SceneTagGroup::onContextMenuRequest(SceneWidgetEvent* event) TagGroupLocationProxy::TagGroupLocationProxy(PositionTagGroupItem::Impl* impl) - : LocationProxy(ParentRelativeLocation), + : LocationProxy(impl->self, ParentRelativeLocation), impl(impl) { - + setNameDependencyOnItemName(); } @@ -1474,12 +1473,6 @@ std::string TagGroupLocationProxy::getName() const } -Item* TagGroupLocationProxy::getCorrespondingItem() -{ - return impl->self; -} - - Isometry3 TagGroupLocationProxy::getLocation() const { return impl->T_offset; @@ -1505,17 +1498,19 @@ SignalProxy TagGroupLocationProxy::sigLocationChanged() } -LocationProxyPtr TagGroupLocationProxy::getParentLocationProxy() const +LocationProxyPtr TagGroupLocationProxy::getParentLocationProxy() { return impl->groupParentLocation; } TagLocationProxy::TagLocationProxy(PositionTagGroupItem::Impl* impl, int tagIndex) - : LocationProxy(ParentRelativeLocation), + : LocationProxy(impl->self, ParentRelativeLocation), impl(impl), tagIndex(tagIndex) { + setNameDependencyOnItemName(); + connection.reset( impl->tagGroup->sigTagPositionUpdated().connect( [&](int index){ @@ -1579,23 +1574,23 @@ SignalProxy TagLocationProxy::sigLocationChanged() } -LocationProxyPtr TagLocationProxy::getParentLocationProxy() const +LocationProxyPtr TagLocationProxy::getParentLocationProxy() { return impl->tagParentLocation; } TagParentLocationProxy::TagParentLocationProxy(PositionTagGroupItem::Impl* impl) - : LocationProxy(ParentRelativeLocation), + : LocationProxy(impl->self, ParentRelativeLocation), impl(impl) { - + setNameDependencyOnItemName(); } std::string TagParentLocationProxy::getName() const { - return formatR(_("{0}: Origin"), impl->self->name()); + return formatR(_("{0}: Origin"), impl->self->displayName()); } @@ -1611,7 +1606,7 @@ SignalProxy TagParentLocationProxy::sigLocationChanged() } -LocationProxyPtr TagParentLocationProxy::getParentLocationProxy() const +LocationProxyPtr TagParentLocationProxy::getParentLocationProxy() { if(impl->groupParentLocation){ return impl->groupParentLocation; diff --git a/src/Base/SceneItem.cpp b/src/Base/SceneItem.cpp index f8735b0f7..d66d9ceca 100644 --- a/src/Base/SceneItem.cpp +++ b/src/Base/SceneItem.cpp @@ -298,10 +298,10 @@ LocationProxyPtr SceneItem::getLocationProxy() SceneItem::Location::Location(SceneItem* item) - : LocationProxy(GlobalLocation), + : LocationProxy(item, GlobalLocation), item(item) { - + setNameDependencyOnItemName(); } diff --git a/src/BodyPlugin/BodyItem.cpp b/src/BodyPlugin/BodyItem.cpp index 5a104c80f..c355161a9 100644 --- a/src/BodyPlugin/BodyItem.cpp +++ b/src/BodyPlugin/BodyItem.cpp @@ -55,28 +55,23 @@ class BodyLocation : public LocationProxy virtual Isometry3 getLocation() const override; virtual bool isLocked() const override; virtual void setLocked(bool on) override; - virtual bool isDoingContinuousUpdate() const override; + virtual bool isContinuousUpdateState() const override; virtual bool setLocation(const Isometry3& T) override; virtual void finishLocationEditing() override; - virtual Item* getCorrespondingItem() override; - virtual LocationProxyPtr getParentLocationProxy() const override; + virtual LocationProxyPtr getParentLocationProxy() override; virtual SignalProxy sigLocationChanged() override; }; class LinkLocation : public LocationProxy { public: - weak_ref_ptr refBodyItem; weak_ref_ptr refLink; - LinkLocation(); LinkLocation(BodyItem* bodyItem, Link* link); - void setTarget(BodyItem* bodyItem, Link* link); virtual std::string getName() const override; virtual Isometry3 getLocation() const override; virtual bool isLocked() const override; - virtual Item* getCorrespondingItem() override; - virtual LocationProxyPtr getParentLocationProxy() const override; + virtual LocationProxyPtr getParentLocationProxy() override; virtual SignalProxy sigLocationChanged() override; }; @@ -1168,7 +1163,7 @@ LocationProxyPtr BodyItem::createLinkLocationProxy(Link* link) BodyLocation::BodyLocation(BodyItem::Impl* impl) - : LocationProxy(impl->attachmentToParent ? OffsetLocation : GlobalLocation), + : LocationProxy(impl->self, impl->attachmentToParent ? OffsetLocation : GlobalLocation), impl(impl) { @@ -1214,7 +1209,7 @@ void BodyLocation::setLocked(bool on) } -bool BodyLocation::isDoingContinuousUpdate() const +bool BodyLocation::isContinuousUpdateState() const { return impl->self->isDoingContinuousKinematicUpdate(); } @@ -1246,24 +1241,22 @@ void BodyLocation::finishLocationEditing() } -Item* BodyLocation::getCorrespondingItem() -{ - return impl->self; -} - - -LocationProxyPtr BodyLocation::getParentLocationProxy() const +LocationProxyPtr BodyLocation::getParentLocationProxy() { if(impl->parentBodyItem){ - if(impl->attachmentToParent){ + if(!impl->attachmentToParent){ + return impl->parentBodyItem->getLocationProxy(); + } else { + auto parentLink = impl->body->parentBodyLink(); + if(impl->parentLinkLocation){ + if(impl->parentLinkLocation->refLink.lock() != parentLink){ + impl->parentLinkLocation.reset(); + } + } if(!impl->parentLinkLocation){ - impl->parentLinkLocation = new LinkLocation; + impl->parentLinkLocation = new LinkLocation(impl->parentBodyItem, parentLink); } - auto parentLink = impl->body->parentBodyLink(); - impl->parentLinkLocation->setTarget(impl->parentBodyItem, parentLink); return impl->parentLinkLocation; - } else { - return impl->parentBodyItem->getLocationProxy(); } } return nullptr; @@ -1276,26 +1269,11 @@ SignalProxy BodyLocation::sigLocationChanged() } -LinkLocation::LinkLocation() - : LocationProxy(GlobalLocation) -{ - -} - - LinkLocation::LinkLocation(BodyItem* bodyItem, Link* link) - : LocationProxy(GlobalLocation), - refBodyItem(bodyItem), + : LocationProxy(bodyItem, GlobalLocation), refLink(link) { - -} - - -void LinkLocation::setTarget(BodyItem* bodyItem, Link* link) -{ - refBodyItem = bodyItem; - refLink = link; + setNameDependencyOnItemName(); } @@ -1323,16 +1301,10 @@ bool LinkLocation::isLocked() const } -Item* LinkLocation::getCorrespondingItem() -{ - return refBodyItem.lock(); -} - - -LocationProxyPtr LinkLocation::getParentLocationProxy() const +LocationProxyPtr LinkLocation::getParentLocationProxy() { - if(auto body = refBodyItem.lock()){ - body->getLocationProxy(); + if(auto bodyItem = static_cast(locatableItem())){ + bodyItem->getLocationProxy(); } return nullptr; } @@ -1340,7 +1312,7 @@ LocationProxyPtr LinkLocation::getParentLocationProxy() const SignalProxy LinkLocation::sigLocationChanged() { - if(auto bodyItem = refBodyItem.lock()){ + if(auto bodyItem = static_cast(locatableItem())){ return bodyItem->sigKinematicStateChanged(); } else { static Signal dummySignal; diff --git a/src/BodyPlugin/DeviceOverwriteItem.cpp b/src/BodyPlugin/DeviceOverwriteItem.cpp index 05be57beb..02767f095 100644 --- a/src/BodyPlugin/DeviceOverwriteItem.cpp +++ b/src/BodyPlugin/DeviceOverwriteItem.cpp @@ -40,8 +40,7 @@ class DeviceLocation : public LocationProxy DeviceLocation(DeviceOverwriteItem::Impl* impl); virtual Isometry3 getLocation() const override; virtual bool setLocation(const Isometry3& T) override; - virtual Item* getCorrespondingItem() override; - virtual LocationProxyPtr getParentLocationProxy() const override; + virtual LocationProxyPtr getParentLocationProxy() override; virtual SignalProxy sigLocationChanged() override; }; @@ -462,7 +461,7 @@ LocationProxyPtr DeviceOverwriteItem::getLocationProxy() DeviceLocation::DeviceLocation(DeviceOverwriteItem::Impl* impl) - : LocationProxy(OffsetLocation), + : LocationProxy(impl->self, OffsetLocation), impl(impl) { setLocked(true); @@ -489,13 +488,7 @@ bool DeviceLocation::setLocation(const Isometry3& T) } -Item* DeviceLocation::getCorrespondingItem() -{ - return impl->self; -} - - -LocationProxyPtr DeviceLocation::getParentLocationProxy() const +LocationProxyPtr DeviceLocation::getParentLocationProxy() { if(!impl->linkLocation){ if(impl->device){ diff --git a/src/BodyPlugin/LinkOverwriteItem.cpp b/src/BodyPlugin/LinkOverwriteItem.cpp index c53f5f996..22997a33c 100644 --- a/src/BodyPlugin/LinkOverwriteItem.cpp +++ b/src/BodyPlugin/LinkOverwriteItem.cpp @@ -44,8 +44,7 @@ class OffsetLocation : public LocationProxy virtual std::string getName() const override; virtual Isometry3 getLocation() const override; virtual bool setLocation(const Isometry3& T) override; - virtual Item* getCorrespondingItem() override; - virtual LocationProxyPtr getParentLocationProxy() const override; + virtual LocationProxyPtr getParentLocationProxy() override; virtual SignalProxy sigLocationChanged() override; }; @@ -1390,10 +1389,11 @@ SgPosTransform* LinkOverwriteItem::Impl::extractOrInsertOffsetTransform(vectorself, LocationProxy::OffsetLocation), impl(impl) { setLocked(true); + setNameDependencyOnItemName(); } @@ -1451,13 +1451,7 @@ bool OffsetLocation::setLocation(const Isometry3& T) } -Item* OffsetLocation::getCorrespondingItem() -{ - return impl->self; -} - - -LocationProxyPtr OffsetLocation::getParentLocationProxy() const +LocationProxyPtr OffsetLocation::getParentLocationProxy() { if(impl->targetLink){ if(isLinkOffsetLocation()){ diff --git a/src/BodyPlugin/RegionIntrusionDetectorItem.cpp b/src/BodyPlugin/RegionIntrusionDetectorItem.cpp index 475df4d63..fe14c5761 100644 --- a/src/BodyPlugin/RegionIntrusionDetectorItem.cpp +++ b/src/BodyPlugin/RegionIntrusionDetectorItem.cpp @@ -24,7 +24,6 @@ class RegionLocation : public LocationProxy Signal sigLocationChanged_; RegionLocation(RegionIntrusionDetectorItem::Impl* impl); - virtual Item* getCorrespondingItem() override; virtual Isometry3 getLocation() const override; virtual bool setLocation(const Isometry3& T) override; virtual SignalProxy sigLocationChanged() override; @@ -261,19 +260,13 @@ LocationProxyPtr RegionIntrusionDetectorItem::getLocationProxy() RegionLocation::RegionLocation(RegionIntrusionDetectorItem::Impl* impl) - : LocationProxy(GlobalLocation), + : LocationProxy(impl->self, GlobalLocation), impl(impl) { } -Item* RegionLocation::getCorrespondingItem() -{ - return impl->self; -} - - Isometry3 RegionLocation::getLocation() const { return impl->regionOffset; diff --git a/src/MocapPlugin/SkeletonMotionItem.cpp b/src/MocapPlugin/SkeletonMotionItem.cpp index 45490ddca..c0ad81ef2 100644 --- a/src/MocapPlugin/SkeletonMotionItem.cpp +++ b/src/MocapPlugin/SkeletonMotionItem.cpp @@ -492,10 +492,10 @@ void SceneBone::setPosition(const Vector3f& p0, const Vector3f& p1) SkeletonMotionItem::Location::Location(SkeletonMotionItem* item) - : LocationProxy(GlobalLocation), + : LocationProxy(item, GlobalLocation), item(item) { - + setNameDependencyOnItemName(); } std::string SkeletonMotionItem::Location::getName() const From fd893ff58e16d09c9ba3494a5f6d09b1839e08e3 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Sat, 7 Sep 2024 11:41:00 +0900 Subject: [PATCH 57/73] Move the definition of continuous update state from BodyItem to Item --- src/Base/Item.cpp | 67 +++++++++++++++++++ src/Base/Item.h | 21 ++++++ src/Base/LocatableItem.cpp | 9 +++ src/Base/LocatableItem.h | 1 + src/BodyPlugin/BodyItem.cpp | 48 ------------- src/BodyPlugin/BodyItem.h | 29 ++++---- src/BodyPlugin/JointDisplacementWidgetSet.cpp | 10 +-- src/BodyPlugin/LinkPositionWidget.cpp | 6 +- src/BodyPlugin/OperableSceneBody.cpp | 8 +-- src/BodyPlugin/SimulatorItem.cpp | 8 +-- 10 files changed, 130 insertions(+), 77 deletions(-) diff --git a/src/Base/Item.cpp b/src/Base/Item.cpp index c7f3042dd..fc4ae6a87 100644 --- a/src/Base/Item.cpp +++ b/src/Base/Item.cpp @@ -86,6 +86,7 @@ class Item::Impl Signal sigAnyCheckToggled; Signal sigLogicalSumOfAllChecksToggled; map> checkIdToSignalMap; + Signal sigContinuousUpdateStateChanged; // for file overwriting management, mainly accessed by ItemManager::Impl std::string filePath; @@ -133,6 +134,7 @@ class Item::Impl void traverse(Item* item, const std::function& callback); void removeAddon(ItemAddon* addon, bool isMoving); ItemAddon* createAddon(const std::type_info& type); + void notifyContinuousUpdateStateChangeRecursively(bool on); static void clearItemReplacementMaps(); }; @@ -197,6 +199,7 @@ void Item::Impl::initialize() self->lastChild_ = nullptr; self->numChildren_ = 0; self->attributes_ = 0; + self->continuousUpdateCounter = 0; self->isSelected_ = false; fileModificationTime = 0; @@ -1529,6 +1532,70 @@ std::vector Item::addons() const } +Item::ContinuousUpdateEntry Item::startContinuousUpdate() +{ + return new ContinuousUpdateRef(this); +} + + +bool Item::isContinuousUpdateStateSubTree() const +{ + if(isContinuousUpdateState()){ + return true; + } + if(parent_){ + return parent_->isContinuousUpdateStateSubTree(); + } + return false; +} + + +SignalProxy Item::sigContinuousUpdateStateChanged() +{ + return impl->sigContinuousUpdateStateChanged; +} + + +void Item::Impl::notifyContinuousUpdateStateChangeRecursively(bool on) +{ + for(auto child = self->childItem(); child; child = child->nextItem()){ + if(!child->isContinuousUpdateState()){ + child->impl->sigContinuousUpdateStateChanged(on); + child->impl->notifyContinuousUpdateStateChangeRecursively(on); + } + } +} + + +Item::ContinuousUpdateRef::ContinuousUpdateRef(Item* item) + : itemRef(item) +{ + if(item->continuousUpdateCounter == 0){ + bool hasOnInUpperNodes = item->isContinuousUpdateStateSubTree(); + ++item->continuousUpdateCounter; + item->impl->sigContinuousUpdateStateChanged(true); + if(!hasOnInUpperNodes){ + item->impl->notifyContinuousUpdateStateChangeRecursively(true); + } + } +} + + +Item::ContinuousUpdateRef::~ContinuousUpdateRef() +{ + if(auto item = itemRef.lock()){ + if(item->continuousUpdateCounter == 1){ + bool hasOnInUpperNodes = item->isContinuousUpdateStateSubTree(); + --item->continuousUpdateCounter; + item->impl->sigContinuousUpdateStateChanged(false); + if(!hasOnInUpperNodes){ + item->impl->notifyContinuousUpdateStateChangeRecursively(false); + } + } + } +} + + bool Item::load(const std::string& filename, const std::string& format, const Mapping* options) { return ItemManager::loadItem(this, filename, parentItem(), format, options); diff --git a/src/Base/Item.h b/src/Base/Item.h index 28b4db3e1..b416bfdaa 100644 --- a/src/Base/Item.h +++ b/src/Base/Item.h @@ -465,6 +465,26 @@ class CNOID_EXPORT Item : public ClonableReferenced std::vector addons(); std::vector addons() const; + class ContinuousUpdateRef : public Referenced + { + private: + ContinuousUpdateRef(Item* item); + ~ContinuousUpdateRef(); + weak_ref_ptr itemRef; + friend class Item; + }; + typedef ref_ptr ContinuousUpdateEntry; + + ContinuousUpdateEntry startContinuousUpdate(); + bool isContinuousUpdateState() const { return continuousUpdateCounter > 0; } + bool isContinuousUpdateStateSubTree() const; + + /** + \note The sigUpdated signal is not emitted when the continuous update state is changed + becasue the state is not a permenent one. + */ + SignalProxy sigContinuousUpdateStateChanged(); + /** This function loads the data of the item from a file by using a registered FileIO object. To make this function available, a FileIO object must be registered to an ItemManager @@ -617,6 +637,7 @@ class CNOID_EXPORT Item : public ClonableReferenced Item* lastChild_; int numChildren_; unsigned int attributes_; + int continuousUpdateCounter; std::string name_; bool isSelected_; diff --git a/src/Base/LocatableItem.cpp b/src/Base/LocatableItem.cpp index 76b92df4b..d3ee8640f 100644 --- a/src/Base/LocatableItem.cpp +++ b/src/Base/LocatableItem.cpp @@ -72,6 +72,15 @@ void LocationProxy::setLocked(bool on) bool LocationProxy::isContinuousUpdateState() const { + auto self = const_cast(this); + if(auto item = self->locatableItem()){ + if(!self->continuousUpdateStateConnection_.connected()){ + self->continuousUpdateStateConnection_ = + item->sigContinuousUpdateStateChanged().connect( + [self](bool){ self->notifyAttributeChange(); }); + } + return item->isContinuousUpdateState(); + } return false; } diff --git a/src/Base/LocatableItem.h b/src/Base/LocatableItem.h index 658c386ec..2671bf206 100644 --- a/src/Base/LocatableItem.h +++ b/src/Base/LocatableItem.h @@ -75,6 +75,7 @@ class CNOID_EXPORT LocationProxy : public Referenced Signal sigAttributeChanged_; Signal sigExpired_; ScopedConnection itemNameConnection_; + ScopedConnection continuousUpdateStateConnection_; }; class CNOID_EXPORT LocatableItem diff --git a/src/BodyPlugin/BodyItem.cpp b/src/BodyPlugin/BodyItem.cpp index c355161a9..53c2e081d 100644 --- a/src/BodyPlugin/BodyItem.cpp +++ b/src/BodyPlugin/BodyItem.cpp @@ -55,7 +55,6 @@ class BodyLocation : public LocationProxy virtual Isometry3 getLocation() const override; virtual bool isLocked() const override; virtual void setLocked(bool on) override; - virtual bool isContinuousUpdateState() const override; virtual bool setLocation(const Isometry3& T) override; virtual void finishLocationEditing() override; virtual LocationProxyPtr getParentLocationProxy() override; @@ -159,8 +158,6 @@ class BodyItem::Impl float transparency; Signal sigModelUpdated; - Signal sigContinuousKinematicUpdateStateChanged; - LeggedBodyHelperPtr legged; static unique_ptr renderableItemUtil; @@ -244,7 +241,6 @@ BodyItem::BodyItem() impl = new Impl(this); impl->init(false); - continuousKinematicUpdateCounter = 0; isAttachedToParentBody_ = false; isVisibleLinkSelectionMode_ = false; } @@ -285,7 +281,6 @@ BodyItem::BodyItem(const BodyItem& org, CloneMap* cloneMap) impl = new Impl(this, *org.impl, cloneMap); impl->init(true); - continuousKinematicUpdateCounter = 0; isAttachedToParentBody_ = false; isVisibleLinkSelectionMode_ = org.isVisibleLinkSelectionMode_; @@ -1209,12 +1204,6 @@ void BodyLocation::setLocked(bool on) } -bool BodyLocation::isContinuousUpdateState() const -{ - return impl->self->isDoingContinuousKinematicUpdate(); -} - - bool BodyLocation::setLocation(const Isometry3& T) { auto rootLink = impl->body->rootLink(); @@ -1547,43 +1536,6 @@ void BodyItem::Impl::onParentBodyKinematicStateChanged() } -BodyItem::ContinuousKinematicUpdateEntry BodyItem::startContinuousKinematicUpdate() -{ - return new ContinuousKinematicUpdateRef(this); -} - - -SignalProxy BodyItem::sigContinuousKinematicUpdateStateChanged() -{ - return impl->sigContinuousKinematicUpdateStateChanged; -} - - -BodyItem::ContinuousKinematicUpdateRef::ContinuousKinematicUpdateRef(BodyItem* item) - : bodyItemRef(item) -{ - if(++item->continuousKinematicUpdateCounter == 1){ - item->impl->sigContinuousKinematicUpdateStateChanged(true); - if(auto& bodyLocation = item->impl->bodyLocation){ - bodyLocation->notifyAttributeChange(); - } - } -} - - -BodyItem::ContinuousKinematicUpdateRef::~ContinuousKinematicUpdateRef() -{ - if(auto item = bodyItemRef.lock()){ - if(--item->continuousKinematicUpdateCounter == 0){ - item->impl->sigContinuousKinematicUpdateStateChanged(false); - if(auto& bodyLocation = item->impl->bodyLocation){ - bodyLocation->notifyAttributeChange(); - } - } - } -} - - MyCompositeBodyIK::MyCompositeBodyIK(BodyItem::Impl* bodyItemImpl) : bodyItemImpl(bodyItemImpl), attachment(bodyItemImpl->attachmentToParent) diff --git a/src/BodyPlugin/BodyItem.h b/src/BodyPlugin/BodyItem.h index bdfe6d6b3..086ec984b 100644 --- a/src/BodyPlugin/BodyItem.h +++ b/src/BodyPlugin/BodyItem.h @@ -188,23 +188,27 @@ class CNOID_EXPORT BodyItem : public Item, public LocatableItem, public Renderab void setLocationLocked(bool on); LocationProxyPtr createLinkLocationProxy(Link* link); - class ContinuousKinematicUpdateRef : public Referenced - { - private: - ContinuousKinematicUpdateRef(BodyItem* item); - ~ContinuousKinematicUpdateRef(); - weak_ref_ptr bodyItemRef; - friend class BodyItem; - }; - typedef ref_ptr ContinuousKinematicUpdateEntry; + [[deprecated]] + typedef ContinuousUpdateEntry ContinuousKinematicUpdateEntry; + + [[deprecated]] + ContinuousKinematicUpdateEntry startContinuousKinematicUpdate() { + return Item::startContinuousUpdate(); + } - ContinuousKinematicUpdateEntry startContinuousKinematicUpdate(); - bool isDoingContinuousKinematicUpdate() const { return continuousKinematicUpdateCounter > 0; } + [[deprecated]] + bool isDoingContinuousKinematicUpdate() const { + return Item::isContinuousUpdateState(); + } + /** \note The sigUpdated signal is not emitted when the corresponding state changed becasue this is not a permenent state. */ - SignalProxy sigContinuousKinematicUpdateStateChanged(); + [[deprecated]] + SignalProxy sigContinuousKinematicUpdateStateChanged(){ + return Item::sigContinuousUpdateStateChanged(); + } // RenderableItem function virtual SgNode* getScene() override; @@ -252,7 +256,6 @@ class CNOID_EXPORT BodyItem : public Item, public LocatableItem, public Renderab private: Impl* impl; - int continuousKinematicUpdateCounter; bool isAttachedToParentBody_; bool isVisibleLinkSelectionMode_; std::vector collisions_; diff --git a/src/BodyPlugin/JointDisplacementWidgetSet.cpp b/src/BodyPlugin/JointDisplacementWidgetSet.cpp index 20f460a37..fdf60e393 100644 --- a/src/BodyPlugin/JointDisplacementWidgetSet.cpp +++ b/src/BodyPlugin/JointDisplacementWidgetSet.cpp @@ -100,7 +100,7 @@ class JointDisplacementWidgetSet::Impl : public QObject ScopedConnection linkSelectionChangeConnection; ScopedConnection kinematicStateChangeConnection; - ScopedConnection continuousKinematicUpdateStateChangeConnection; + ScopedConnection continuousUpdateStateChangeConnection; ScopedConnection modelUpdateConnection; DisplayValueFormat* dvFormat; @@ -383,7 +383,7 @@ void JointDisplacementWidgetSet::Impl::setBodyItem(BodyItem* bodyItem) linkedJointHandler.reset(); kinematicStateChangeConnection.disconnect(); - continuousKinematicUpdateStateChangeConnection.disconnect(); + continuousUpdateStateChangeConnection.disconnect(); modelUpdateConnection.disconnect(); if(bodyItem){ @@ -392,11 +392,11 @@ void JointDisplacementWidgetSet::Impl::setBodyItem(BodyItem* bodyItem) kinematicStateChangeConnection = bodyItem->sigKinematicStateChanged().connect(updateJointDisplacementsLater); - continuousKinematicUpdateStateChangeConnection = - bodyItem->sigContinuousKinematicUpdateStateChanged().connect( + continuousUpdateStateChangeConnection = + bodyItem->sigContinuousUpdateStateChanged().connect( [this](bool on){ setUserInputEnabled(!on); }); - setUserInputEnabled(!bodyItem->isDoingContinuousKinematicUpdate()); + setUserInputEnabled(!bodyItem->isContinuousUpdateState()); modelUpdateConnection = bodyItem->sigModelUpdated().connect( diff --git a/src/BodyPlugin/LinkPositionWidget.cpp b/src/BodyPlugin/LinkPositionWidget.cpp index a43748c5e..c5bc08af9 100644 --- a/src/BodyPlugin/LinkPositionWidget.cpp +++ b/src/BodyPlugin/LinkPositionWidget.cpp @@ -526,10 +526,10 @@ void LinkPositionWidget::Impl::setTargetBodyAndLink(BodyItem* bodyItem, Link* li [this](){ updateTargetLink(targetLink); })); targetConnections.add( - bodyItem->sigContinuousKinematicUpdateStateChanged().connect( + bodyItem->sigContinuousUpdateStateChanged().connect( [this](bool on){ setUserInputEnabled(!on); })); - setUserInputEnabled(!bodyItem->isDoingContinuousKinematicUpdate()); + setUserInputEnabled(!bodyItem->isContinuousUpdateState()); } } @@ -893,7 +893,7 @@ void LinkPositionWidget::Impl::showConfigurationDialog() if(!configurationDialog){ configurationDialog = new JointSpaceConfigurationDialog(this); if(targetBodyItem){ - configurationDialog->setUserInputEnabled(!targetBodyItem->isDoingContinuousKinematicUpdate()); + configurationDialog->setUserInputEnabled(!targetBodyItem->isContinuousUpdateState()); } } diff --git a/src/BodyPlugin/OperableSceneBody.cpp b/src/BodyPlugin/OperableSceneBody.cpp index fca99f201..b1ac362be 100644 --- a/src/BodyPlugin/OperableSceneBody.cpp +++ b/src/BodyPlugin/OperableSceneBody.cpp @@ -541,7 +541,7 @@ void OperableSceneBody::Impl::onSceneGraphConnection(bool on) [this](){ onBodyItemUpdated(); })); connections.add( - bodyItem->sigContinuousKinematicUpdateStateChanged().connect( + bodyItem->sigContinuousUpdateStateChanged().connect( [this](bool){ onBodyItemUpdated(); })); connections.add( @@ -563,7 +563,7 @@ void OperableSceneBody::Impl::onSceneGraphConnection(bool on) void OperableSceneBody::Impl::onBodyItemUpdated() { - bool isUserInputBlocked = bodyItem->isDoingContinuousKinematicUpdate() || bodyItem->isLocationLocked(); + bool isUserInputBlocked = bodyItem->isContinuousUpdateState() || bodyItem->isLocationLocked(); if(isUserInputBlocked){ if(sceneLinkForPositionDragger){ detachPositionDragger(); @@ -1359,7 +1359,7 @@ bool OperableSceneBody::Impl::onButtonPressEvent(SceneWidgetEvent* event) PointedType pointedType = findPointedObject(event->nodePath()); if(pointedType == PT_ZMP && event->button() == Qt::LeftButton){ - if(!bodyItem->isDoingContinuousKinematicUpdate()){ + if(!bodyItem->isContinuousUpdateState()){ startZmpTranslation(event); return true; } @@ -1408,7 +1408,7 @@ bool OperableSceneBody::Impl::onButtonPressEvent(SceneWidgetEvent* event) if(event->button() == Qt::LeftButton){ updateMarkersAndManipulators(true); - if(!bodyItem->isDoingContinuousKinematicUpdate()){ + if(!bodyItem->isContinuousUpdateState()){ if(operationType == LinkOperationType::FK){ startFK(event); } else if(operationType == LinkOperationType::IK){ diff --git a/src/BodyPlugin/SimulatorItem.cpp b/src/BodyPlugin/SimulatorItem.cpp index 2c88aea14..14cad7c0f 100644 --- a/src/BodyPlugin/SimulatorItem.cpp +++ b/src/BodyPlugin/SimulatorItem.cpp @@ -155,7 +155,7 @@ class SimulationLogEngine : public TimeSyncItemEngine TimeSyncItemEngineManager* manager; vector subEngines;; CollisionSeqEnginePtr collisionSeqEngine; - vector bodyItemEntries; + vector bodyItemEntries; bool doKeepPlayback; SimulationLogEngine(SimulatorItem::Impl* itemImpl); @@ -181,7 +181,7 @@ class SimulationBody::Impl SimulationBody* self; BodyPtr body_; BodyItemPtr bodyItem; - BodyItem::ContinuousKinematicUpdateEntry continuousKinematicUpdateEntry; + Item::ContinuousUpdateEntry continuousUpdateEntry; vector controllerInfos; SimulatorItem::Impl* simImpl; @@ -1977,7 +1977,7 @@ bool SimulatorItem::Impl::initializeSimulation(bool doReset) // For blocking manual user operations for modifying body kinematic state using the builtin GUIs for(auto& simBody : simBodiesWithBody){ auto simpl = simBody->impl; - simpl->continuousKinematicUpdateEntry = simpl->bodyItem->startContinuousKinematicUpdate(); + simpl->continuousUpdateEntry = simpl->bodyItem->startContinuousUpdate(); } if(isSceneViewEditModeBlockedDuringSimulation){ SceneView::blockEditModeForAllViews(self); @@ -3014,7 +3014,7 @@ void SimulationLogEngine::setupBodyItems(bool doStartPlayback) bodyItem->notifyKinematicStateUpdate(false); } if(doStartPlayback){ - bodyItemEntries.push_back(bodyItem->startContinuousKinematicUpdate()); + bodyItemEntries.push_back(bodyItem->startContinuousUpdate()); } } } From 011188cbaaaea0ce6ee190d60d455aa47bc51e27 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Sat, 7 Sep 2024 12:35:04 +0900 Subject: [PATCH 58/73] Improve SimulatorItem to set all the associated items to the continuous update state during its simulation --- src/BodyPlugin/SimulatorItem.cpp | 101 +++++++++++++++++-------------- 1 file changed, 55 insertions(+), 46 deletions(-) diff --git a/src/BodyPlugin/SimulatorItem.cpp b/src/BodyPlugin/SimulatorItem.cpp index 14cad7c0f..a92772419 100644 --- a/src/BodyPlugin/SimulatorItem.cpp +++ b/src/BodyPlugin/SimulatorItem.cpp @@ -98,7 +98,8 @@ struct FunctionSet class ControllerInfo : public Referenced, public ControllerIO { public: - ControllerItemPtr controller; + ControllerItemPtr controllerItem; + vector continuousUpdateEntries; SimulationBody::Impl* simBodyImpl; Body* body_; SimulatorItem::Impl* simImpl; @@ -181,7 +182,7 @@ class SimulationBody::Impl SimulationBody* self; BodyPtr body_; BodyItemPtr bodyItem; - Item::ContinuousUpdateEntry continuousUpdateEntry; + vector continuousUpdateEntries; vector controllerInfos; SimulatorItem::Impl* simImpl; @@ -242,6 +243,7 @@ class SimulatorItem::Impl : public QThread vector simBodiesWithBody; vector activeSimBodies; vector loggedControllerInfos; + vector continuousUpdateEntries; BodyItemToSimBodyMap simBodyMap; @@ -505,35 +507,35 @@ SimulatorItem* SimulatorItem::findActiveSimulatorItemFor(Item* item) } -ControllerInfo::ControllerInfo(ControllerItem* controller, SimulationBody::Impl* simBodyImpl) - : controller(controller), +ControllerInfo::ControllerInfo(ControllerItem* controllerItem, SimulationBody::Impl* simBodyImpl) + : controllerItem(controllerItem), simBodyImpl(simBodyImpl), body_(simBodyImpl->body_), simImpl(simBodyImpl->simImpl), isLogEnabled_(false), isSimulationFromInitialState_(simImpl->isSimulationFromInitialState) { - if(controller){ + if(controllerItem){ // ControllerInfo cannot directly set a simulator item to the controller item // because ControllerItem::setSimulatorItem is a private function. - simImpl->setSimulatorItemToControllerItem(controller); + simImpl->setSimulatorItemToControllerItem(controllerItem); } } ControllerInfo::~ControllerInfo() { - if(controller){ + if(controllerItem){ // ControllerInfo cannot directly reset a simulator item for the controller item // because ControllerItem::setSimulatorItem is a private function. - simImpl->resetSimulatorItemForControllerItem(controller); + simImpl->resetSimulatorItemForControllerItem(controllerItem); } } std::string ControllerInfo::controllerName() const { - return controller ? controller->name() : string(); + return controllerItem ? controllerItem->name() : string(); } @@ -585,8 +587,8 @@ bool ControllerInfo::enableLog() logBuf->setFrameRate(simImpl->worldFrameRate); logBufFrameOffset = 0; - string logName = simImpl->self->name() + "-" + controller->name(); - logItem = controller->findChildItem(logName); + string logName = simImpl->self->name() + "-" + controllerItem->name(); + logItem = controllerItem->findChildItem(logName); if(logItem){ logItem->resetSeq(); if(!logItem->isTemporary()){ @@ -594,11 +596,12 @@ bool ControllerInfo::enableLog() logItem->notifyUpdate(); } } else { - logItem = controller->createLogItem(); + logItem = controllerItem->createLogItem(); logItem->setTemporary(); logItem->setName(logName); - controller->addChildItem(logItem); + controllerItem->addChildItem(logItem); } + continuousUpdateEntries.push_back(logItem->startContinuousUpdate()); log = logItem->seq(); log->setNumFrames(0); log->setFrameRate(simImpl->worldFrameRate); @@ -661,13 +664,13 @@ void ControllerInfo::flushLog() bool ControllerInfo::isNoDelayMode() const { - return controller->isNoDelayMode(); + return controllerItem->isNoDelayMode(); } bool ControllerInfo::setNoDelayMode(bool on) { - controller->setNoDelayMode(on); + controllerItem->setNoDelayMode(on); return on; } @@ -723,7 +726,7 @@ int SimulationBody::numControllers() const ControllerItem* SimulationBody::controller(int index) const { if(index < static_cast(impl->controllerInfos.size())){ - return impl->controllerInfos[index]->controller; + return impl->controllerInfos[index]->controllerItem; } return nullptr; } @@ -739,6 +742,7 @@ bool SimulationBody::Impl::initialize(SimulatorItem* simulatorItem, BodyItem* bo { simImpl = simulatorItem->impl; this->bodyItem = bodyItem; + continuousUpdateEntries.push_back(bodyItem->startContinuousUpdate()); deviceStateConnections.disconnect(); controllerInfos.clear(); recordItemPrefix = simImpl->self->name() + "-" + bodyItem->name(); @@ -765,6 +769,7 @@ bool SimulationBody::Impl::initialize(SimulatorItem::Impl* simImpl, ControllerIt ControllerInfoPtr info = new ControllerInfo(controllerItem, this); if(controllerItem->initialize(info)){ + info->continuousUpdateEntries.push_back(controllerItem->startContinuousUpdate()); controllerInfos.push_back(info); initialized = true; } @@ -781,13 +786,13 @@ void SimulationBody::Impl::extractAssociatedItems() parentOfRecordItems = bodyItem; } else if(controllerInfos.size() == 1){ - parentOfRecordItems = controllerInfos.front()->controller; + parentOfRecordItems = controllerInfos.front()->controllerItem; } else { // find the common owner of all the controllers int minDepth = std::numeric_limits::max(); for(size_t i=0; i < controllerInfos.size(); ++i){ - Item* owner = controllerInfos[i]->controller->parentItem(); + Item* owner = controllerInfos[i]->controllerItem->parentItem(); int depth = 0; Item* item = owner; while(item && item != bodyItem){ @@ -948,6 +953,7 @@ void SimulationBody::Impl::initializeRecordItems() doAddMotionItem = true; } + continuousUpdateEntries.push_back(motionItem->startContinuousUpdate()); motion = motionItem->motion(); motion->setNumFrames(0); motion->setOffsetTime(0.0); @@ -1589,6 +1595,7 @@ void SimulatorItem::Impl::clearSimulation() simBodiesWithBody.clear(); activeSimBodies.clear(); loggedControllerInfos.clear(); + continuousUpdateEntries.clear(); simBodyMap.clear(); preDynamicsFunctions.clear(); @@ -1773,10 +1780,10 @@ bool SimulatorItem::Impl::initializeSimulation(bool doReset) } bodyItem->notifyKinematicStateChange(); - } else if(auto controller = dynamic_cast(targetItem.get())){ + } else if(auto controllerItem = dynamic_cast(targetItem.get())){ // ControllerItem which is not associated with a body SimulationBodyPtr simBody = new SimulationBody(nullptr); - if(simBody->impl->initialize(this, controller)){ + if(simBody->impl->initialize(this, controllerItem)){ allSimBodies.push_back(simBody); } } else if(auto script = dynamic_cast(targetItem.get())){ @@ -1815,6 +1822,7 @@ bool SimulatorItem::Impl::initializeSimulation(bool doReset) mv->putln(formatR(_("SubSimulatorItem \"{}\" is disabled."), item->displayName())); } if(initialized){ + continuousUpdateEntries.push_back(item->startContinuousUpdate()); ++p; } else { p = subSimulatorItems.erase(p); @@ -1871,6 +1879,8 @@ bool SimulatorItem::Impl::initializeSimulation(bool doReset) collisionSeq->setNumFrames(1); CollisionSeq::Frame frame0 = collisionSeq->frame(0); frame0[0] = std::make_shared(); + + continuousUpdateEntries.push_back(collisionSeqItem->startContinuousUpdate()); } for(auto& simBody : allSimBodies){ @@ -1880,23 +1890,24 @@ bool SimulatorItem::Impl::initializeSimulation(bool doReset) auto iter = controllerInfos.begin(); while(iter != controllerInfos.end()){ auto& info = *iter; - ControllerItem* controller = info->controller; + ControllerItem* controllerItem = info->controllerItem; bool ready = false; if(body){ - ready = controller->start(); + ready = controllerItem->start(); if(!ready){ mv->putln(formatR(_("{0} for {1} failed to start."), - controller->displayName(), simBodyImpl->bodyItem->displayName()), + controllerItem->displayName(), simBodyImpl->bodyItem->displayName()), MessageView::Warning); } } else { - ready = controller->start(); + ready = controllerItem->start(); if(!ready){ - mv->putln(formatR(_("{} failed to start."), controller->displayName()), + mv->putln(formatR(_("{} failed to start."), controllerItem->displayName()), MessageView::Warning); } } if(ready){ + info->continuousUpdateEntries.push_back(controllerItem->startContinuousUpdate()); activeControllerInfos.push_back(info); ++iter; } else { @@ -1963,8 +1974,12 @@ bool SimulatorItem::Impl::initializeSimulation(bool doReset) } logTimeStep = 1.0 / r; } + continuousUpdateEntries.push_back(worldLogFileItem->startContinuousUpdate()); } + continuousUpdateEntries.push_back(worldItem->startContinuousUpdate()); + continuousUpdateEntries.push_back(self->startContinuousUpdate()); + logEngine->startOngoingTimeUpdate(0.0); flushRecords(); start(); @@ -1974,11 +1989,6 @@ bool SimulatorItem::Impl::initializeSimulation(bool doReset) sigSimulationStarted(); - // For blocking manual user operations for modifying body kinematic state using the builtin GUIs - for(auto& simBody : simBodiesWithBody){ - auto simpl = simBody->impl; - simpl->continuousUpdateEntry = simpl->bodyItem->startContinuousUpdate(); - } if(isSceneViewEditModeBlockedDuringSimulation){ SceneView::blockEditModeForAllViews(self); } @@ -2172,21 +2182,21 @@ bool SimulatorItem::Impl::stepSimulationMain() if(!useControllerThreads){ for(auto& info : activeControllerInfos){ - auto& controller = info->controller; - controller->input(); - doContinue |= controller->control(); - if(controller->isNoDelayMode()){ - controller->output(); + auto& controllerItem = info->controllerItem; + controllerItem->input(); + doContinue |= controllerItem->control(); + if(controllerItem->isNoDelayMode()){ + controllerItem->output(); } } } else { bool hasNoDelayModeControllers = false; for(auto& info : activeControllerInfos){ - auto& controller = info->controller; - if(controller->isNoDelayMode()){ + auto& controllerItem = info->controllerItem; + if(controllerItem->isNoDelayMode()){ hasNoDelayModeControllers = true; } - info->controller->input(); + info->controllerItem->input(); { std::lock_guard lock(info->controlMutex); info->isControlRequested = true; @@ -2197,11 +2207,11 @@ bool SimulatorItem::Impl::stepSimulationMain() // Todo: Process the controller that finishes control earlier first to // reduce the total elapsed time before finishing all the output functions. for(auto& info : activeControllerInfos){ - if(info->controller->isNoDelayMode()){ + if(info->controllerItem->isNoDelayMode()){ if(info->waitForControlInThreadToFinish()){ doContinue = true; } - info->controller->output(); + info->controllerItem->output(); } } } @@ -2217,7 +2227,7 @@ bool SimulatorItem::Impl::stepSimulationMain() if(useControllerThreads){ for(auto& info : activeControllerInfos){ - if(!info->controller->isNoDelayMode()){ + if(!info->controllerItem->isNoDelayMode()){ if(info->waitForControlInThreadToFinish()){ doContinue = true; } @@ -2228,8 +2238,8 @@ bool SimulatorItem::Impl::stepSimulationMain() postDynamicsFunctions.call(); for(auto& info : activeControllerInfos){ - if(!info->controller->isNoDelayMode()){ - info->controller->output(); + if(!info->controllerItem->isNoDelayMode()){ + info->controllerItem->output(); } } @@ -2269,7 +2279,7 @@ void ControllerInfo::concurrentControlLoop() } } - bool doContinue = controller->control(); + bool doContinue = controllerItem->control(); { std::lock_guard lock(controlMutex); @@ -2457,8 +2467,7 @@ void SimulatorItem::Impl::onSimulationLoopStopped(bool isForced) for(auto& simBody : allSimBodies){ for(auto& info : simBody->impl->controllerInfos){ - auto& controller = info->controller; - controller->stop(); + info->controllerItem->stop(); } } self->finalizeSimulation(); From c063adffe93e2c76a490ff05480958104550cf84 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Sat, 7 Sep 2024 14:05:29 +0900 Subject: [PATCH 59/73] Improve ItemPropertyWidget to block property editing when the target item is continuous update state --- src/Base/ItemPropertyWidget.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Base/ItemPropertyWidget.cpp b/src/Base/ItemPropertyWidget.cpp index 626d794e1..bc3fe990b 100644 --- a/src/Base/ItemPropertyWidget.cpp +++ b/src/Base/ItemPropertyWidget.cpp @@ -134,6 +134,7 @@ class ItemPropertyWidget::Impl : public PutPropertyFunction ItemPtr currentItem; ScopedConnectionSet itemConnections; PolymorphicItemFunctionSet propertyFunctions; + bool isEditable; double minValue; double maxValue; @@ -152,6 +153,7 @@ class ItemPropertyWidget::Impl : public PutPropertyFunction void updateProperties(bool isItemChanged = false); void addProperty(const std::string& name, PropertyItem* propertyItem); void onTargetItemSpecified(Item* item); + void setEditable(bool on); void zoomFontSize(int pointSizeDiff); // PutPropertyFunction's virtual functions @@ -209,7 +211,11 @@ PropertyItem::PropertyItem(ItemPropertyWidget::Impl* view, ValueVariant value, F value(value), func(func) { - setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable); + int flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + if(view->isEditable){ + flags |= Qt::ItemIsEditable; + } + setFlags(static_cast(flags)); hasValidFunction = true; } @@ -711,17 +717,26 @@ void ItemPropertyWidget::Impl::setCurrentItem(Item* item) { if(item != currentItem){ itemConnections.disconnect(); + isEditable = false; + if(item){ itemConnections.add( item->sigUpdated().connect( - [this](){ updateProperties(); })); + [this]{ updateProperties(); })); itemConnections.add( item->sigNameChanged().connect( [this](const std::string& /* oldName */){ updateProperties(); })); itemConnections.add( item->sigDisconnectedFromRoot().connect( - [this](){ setCurrentItem(nullptr); })); + [this]{ setCurrentItem(nullptr); })); + itemConnections.add( + item->sigContinuousUpdateStateChanged().connect( + [this](bool on){ setEditable(!on); })); + + isEditable = !item->isContinuousUpdateState(); + } + currentItem = item; updateProperties(true); } @@ -904,6 +919,13 @@ void ItemPropertyWidget::Impl::operator() } +void ItemPropertyWidget::Impl::setEditable(bool on) +{ + isEditable = on; + updateProperties(false); +} + + void ItemPropertyWidget::keyPressEvent(QKeyEvent* event) { if(event->modifiers() & Qt::ControlModifier){ From 876a53f3cf780bd8a97fc9bd997c337fd7979c3e Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 9 Sep 2024 21:20:02 +0900 Subject: [PATCH 60/73] Fix ItemTreeWidget to block user inputs for items with the continuous update state and its sub tree --- src/Base/ItemTreeWidget.cpp | 56 +++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/Base/ItemTreeWidget.cpp b/src/Base/ItemTreeWidget.cpp index 8b6517dac..9b3dcc2d3 100644 --- a/src/Base/ItemTreeWidget.cpp +++ b/src/Base/ItemTreeWidget.cpp @@ -169,6 +169,8 @@ class ItemTreeWidget::ItwItem : public QTreeWidgetItem ScopedConnection itemSelectionConnection; ScopedConnection itemCheckConnection; ScopedConnection displayUpdateConnection; + ScopedConnection continuousUpdateStateConnection; + bool isNameEditable; bool isExpandedBeforeRemoving; bool isTemporaryAttributeDisplay; @@ -180,6 +182,7 @@ class ItemTreeWidget::ItwItem : public QTreeWidgetItem ItwItem(Item* item, ItemTreeWidget::Impl* widgetImpl); virtual ~ItwItem(); + void updateEditFlags(); virtual void setData(int column, int role, const QVariant& value) override; }; @@ -192,15 +195,21 @@ ItemTreeWidget::ItwItem::ItwItem(Item* item, ItemTreeWidget::Impl* widgetImpl) { widgetImpl->itemToItwItemMap[item] = this; - Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled; + isNameEditable = true; + bool isContinuousUpdateStateSubTree = item->isContinuousUpdateStateSubTree(); + + Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; if(widgetImpl->isCheckColumnShown){ flags |= Qt::ItemIsUserCheckable; } - if(!item->isSubItem() && !item->hasAttribute(Item::Attached)){ - flags |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled; - } setFlags(flags); + updateEditFlags(); + + continuousUpdateStateConnection = + item->sigContinuousUpdateStateChanged().connect( + [this](bool){ updateEditFlags(); }); + setToolTip(0, QString()); setText(0, item->displayName().c_str()); @@ -250,6 +259,24 @@ ItemTreeWidget::ItwItem::~ItwItem() } +void ItemTreeWidget::ItwItem::updateEditFlags() +{ + Qt::ItemFlags flags_ = flags() & ~(Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); + bool isContinuousUpdateStateSubTree = item->isContinuousUpdateStateSubTree(); + + if(!isContinuousUpdateStateSubTree){ + flags_ |= Qt::ItemIsDropEnabled; + } + if(!item->isSubItem() && !item->hasAttribute(Item::Attached) && !isContinuousUpdateStateSubTree){ + if(isNameEditable){ + flags_ |= Qt::ItemIsEditable; + } + flags_ |= Qt::ItemIsDragEnabled; + } + setFlags(flags_); +} + + void ItemTreeWidget::ItwItem::setData(int column, int role, const QVariant& value) { if(column == 0){ @@ -341,10 +368,9 @@ void ItemTreeWidget::Display::setStatusTip(const std::string& statusTip) void ItemTreeWidget::Display::setNameEditable(bool on) { - if(on){ - itwItem->setFlags(itwItem->flags() | Qt::ItemIsEditable); - } else { - itwItem->setFlags(itwItem->flags() & ~Qt::ItemIsEditable); + if(on != itwItem->isNameEditable){ + itwItem->isNameEditable = on; + itwItem->updateEditFlags(); } } @@ -1879,7 +1905,19 @@ void ItemTreeWidget::Impl::keyPressEvent(QKeyEvent* event) case Qt::Key_R: unifiedEditHistory->flushNewRecordBuffer(); for(auto& item : getSelectedItems()){ - item->reload(); + if(!item->isContinuousUpdateStateSubTree()){ + item->reload(); + } else { + if(item->isContinuousUpdateState()){ + showWarningDialog( + formatR(_("Item \"{0}\" cannot be reloaded currently, as it is being continuously updated."), + item->displayName())); + } else { + showWarningDialog( + formatR(_("Item \"{0}\" cannot be reloaded currently, as it is a part of a sub-tree being continuously updated."), + item->displayName())); + } + } } break; From ac243ac0825f640b6e17953a3bec2be48ab999e6 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 9 Sep 2024 21:24:06 +0900 Subject: [PATCH 61/73] Fix item context menus to disable menu items that should not be executed in the continuous update state --- src/Base/ItemTreeView.cpp | 25 +++++++++++++++++-------- src/BodyPlugin/BodyMotionItem.cpp | 15 +++++++++++---- src/BodyPlugin/SimulatorItem.cpp | 30 ++++++++++++++++++++++-------- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/Base/ItemTreeView.cpp b/src/Base/ItemTreeView.cpp index b33994ac7..0db26b65a 100644 --- a/src/Base/ItemTreeView.cpp +++ b/src/Base/ItemTreeView.cpp @@ -129,15 +129,19 @@ void ItemTreeView::Impl::onContextMenuRequested(Item* item, MenuManager& menu) auto selectAll = menu.addItem(_("Select all")); auto clearSelection = menu.addItem(_("Clear selection")); - if(!item){ + bool isContinuousUpdateStateSubTree = item->isContinuousUpdateStateSubTree(); + + if(!item || isContinuousUpdateStateSubTree){ rename->setEnabled(false); cut->setEnabled(false); copy1->setEnabled(false); copy2->setEnabled(false); + paste->setEnabled(false); check->setEnabled(false); uncheck->setEnabled(false); toggleCheck->setEnabled(false); reload->setEnabled(false); + saveAs->setEnabled(false); clearSelection->setEnabled(false); } else { @@ -163,12 +167,6 @@ void ItemTreeView::Impl::onContextMenuRequested(Item* item, MenuManager& menu) copy1->setEnabled(false); copy2->setEnabled(false); } - check->sigTriggered().connect( - [this](){ itemTreeWidget->setSelectedItemsChecked(true); }); - uncheck->sigTriggered().connect( - [this](){ itemTreeWidget->setSelectedItemsChecked(false); }); - toggleCheck->sigTriggered().connect( - [this](){ itemTreeWidget->toggleSelectedItemChecks(); }); if(!item->hasAttribute(Item::Reloadable)){ reload->setEnabled(false); @@ -191,7 +189,18 @@ void ItemTreeView::Impl::onContextMenuRequested(Item* item, MenuManager& menu) [this](){ itemTreeWidget->clearSelection(); }); } - if(itemTreeWidget->checkPastable(item)){ + if(item){ + clearSelection->setEnabled(true); + check->sigTriggered().connect( + [this](){ itemTreeWidget->setSelectedItemsChecked(true); }); + uncheck->sigTriggered().connect( + [this](){ itemTreeWidget->setSelectedItemsChecked(false); }); + toggleCheck->sigTriggered().connect( + [this](){ itemTreeWidget->toggleSelectedItemChecks(); }); + } + + if(itemTreeWidget->checkPastable(item) && !(item && isContinuousUpdateStateSubTree)){ + paste->setEnabled(true); paste->sigTriggered().connect( [this](){ itemTreeWidget->pasteItems(); }); } else { diff --git a/src/BodyPlugin/BodyMotionItem.cpp b/src/BodyPlugin/BodyMotionItem.cpp index ab25738d7..e558f29e9 100644 --- a/src/BodyPlugin/BodyMotionItem.cpp +++ b/src/BodyPlugin/BodyMotionItem.cpp @@ -184,10 +184,17 @@ void BodyMotionItem::initializeClass(ExtensionManager* ext) ItemTreeView::customizeContextMenu( [](BodyMotionItem* item, MenuManager& menuManager, ItemFunctionDispatcher menuFunction){ menuManager.setPath("/").setPath(_("Data conversion")); - menuManager.addItem(_("Generate old-format position data items"))->sigTriggered().connect( - [item](){ item->motion()->updateLinkPosSeqAndJointPosSeqWithBodyStateSeq(); }); - menuManager.addItem(_("Restore position data from old-format data items"))->sigTriggered().connect( - [item](){ item->motion()->updateBodyStateSeqWithLinkPosSeqAndJointPosSeq(); }); + auto generate = menuManager.addItem(_("Generate old-format position data items")); + auto restore = menuManager.addItem(_("Restore position data from old-format data items")); + if(item->isContinuousUpdateStateSubTree()){ + generate->setEnabled(false); + restore->setEnabled(false); + } else { + generate->sigTriggered().connect( + [item]{ item->motion()->updateLinkPosSeqAndJointPosSeqWithBodyStateSeq(); }); + restore->sigTriggered().connect( + [item](){ item->motion()->updateBodyStateSeqWithLinkPosSeqAndJointPosSeq(); }); + } menuManager.setPath("/"); menuManager.addSeparator(); menuFunction.dispatchAs(item); diff --git a/src/BodyPlugin/SimulatorItem.cpp b/src/BodyPlugin/SimulatorItem.cpp index a92772419..e66092f94 100644 --- a/src/BodyPlugin/SimulatorItem.cpp +++ b/src/BodyPlugin/SimulatorItem.cpp @@ -479,14 +479,27 @@ void SimulatorItem::initializeClass(ExtensionManager* ext) ItemTreeView::customizeContextMenu( [](SimulatorItem* item, MenuManager& menuManager, ItemFunctionDispatcher menuFunction){ menuManager.setPath("/").setPath(_("Simulation")); - menuManager.addItem(_("Start"))->sigTriggered().connect( - [item](){ item->startSimulation(); }); - menuManager.addItem(_("Pause"))->sigTriggered().connect( - [item](){ item->pauseSimulation(); }); - menuManager.addItem(_("Resume"))->sigTriggered().connect( - [item](){ item->restartSimulation(); }); - menuManager.addItem(_("Finish"))->sigTriggered().connect( - [item](){ item->stopSimulation(true); }); + auto start = menuManager.addItem(_("Start")); + auto pause = menuManager.addItem(_("Pause")); + auto resume = menuManager.addItem(_("Resume")); + auto finish = menuManager.addItem(_("Finish")); + + if(item->isRunning()){ + start->setEnabled(false); + pause->sigTriggered().connect([item]{ item->pauseSimulation(); }); + finish->sigTriggered().connect([item]{ item->stopSimulation(true); }); + } else { + start->sigTriggered().connect([item]{ item->startSimulation(); }); + pause->setEnabled(false); + finish->setEnabled(false); + } + if(item->isPausing()){ + pause->setEnabled(false); + resume->sigTriggered().connect([item]{ item->restartSimulation(); }); + } else { + resume->setEnabled(false); + } + menuManager.setPath("/"); menuManager.addSeparator(); menuFunction.dispatchAs(item); @@ -2444,6 +2457,7 @@ void SimulatorItem::Impl::stopSimulation(bool isForced, bool doSync) } isForcedToStopSimulation = isForced; stopRequested = true; + pauseRequested = false; if(doSync){ wait(); From 91336a43ec3c0616a841ba71611a4f1eddac5d67 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 10 Sep 2024 11:03:41 +0900 Subject: [PATCH 62/73] Improve SmokeDevice and SceneSmoke to specify a tint color --- share/model/misc/smoke.body | 2 +- src/SceneEffectsPlugin/ParticleSystem.cpp | 8 ++++++++ src/SceneEffectsPlugin/ParticleSystem.h | 4 ++++ src/SceneEffectsPlugin/SceneSmoke.cpp | 15 +++++++++------ src/SceneEffectsPlugin/SceneSmoke.h | 4 ---- src/SceneEffectsPlugin/SmokeDevice.cpp | 9 +++++++-- src/SceneEffectsPlugin/shader/Particles.frag | 3 ++- 7 files changed, 31 insertions(+), 14 deletions(-) diff --git a/share/model/misc/smoke.body b/share/model/misc/smoke.body index aecd3b137..bc579cb12 100644 --- a/share/model/misc/smoke.body +++ b/share/model/misc/smoke.body @@ -8,4 +8,4 @@ links: name: Base jointType: fixed elements: - SmokeDevice: { } + SmokeDevice: { tint_color: [ 1.0, 1.0, 1.0 ] } diff --git a/src/SceneEffectsPlugin/ParticleSystem.cpp b/src/SceneEffectsPlugin/ParticleSystem.cpp index 69dcedf35..dfce13de0 100644 --- a/src/SceneEffectsPlugin/ParticleSystem.cpp +++ b/src/SceneEffectsPlugin/ParticleSystem.cpp @@ -16,6 +16,7 @@ ParticleSystem::ParticleSystem() initialSpeedVariation_ = 0.1f; emissionRange_ = static_cast(PI / 3.0); acceleration_.setZero(); + tintColor_.setOnes(); } @@ -30,6 +31,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem& org) initialSpeedVariation_ = org.initialSpeedVariation_; emissionRange_ = org.emissionRange_; acceleration_ = org.acceleration_; + tintColor_ = org.tintColor_; } @@ -49,6 +51,9 @@ void ParticleSystem::readParameters(const Mapping* info) info->read({ "initial_speed_variation", "initialSpeedVariation" }, initialSpeedVariation_); info->readAngle({ "emission_range", "emissionRange" }, emissionRange_); read(info, "acceleration", acceleration_); + if(!read(info, "tint_color", tintColor_)){ + tintColor_.setOnes(); + } } @@ -62,5 +67,8 @@ void ParticleSystem::writeParameters(Mapping* info) const info->write("initial_speed_variation", initialSpeedVariation_); info->write("emission_range", degree(emissionRange_)); write(info, "acceleration", acceleration_); + if(!tintColor_.isApprox(Vector3f::Ones())){ + write(info, "tint_color", tintColor_); + } } diff --git a/src/SceneEffectsPlugin/ParticleSystem.h b/src/SceneEffectsPlugin/ParticleSystem.h index 698a482c1..fc185fe9d 100644 --- a/src/SceneEffectsPlugin/ParticleSystem.h +++ b/src/SceneEffectsPlugin/ParticleSystem.h @@ -41,6 +41,9 @@ class ParticleSystem const Vector3f& acceleration() const { return acceleration_; } void setAcceleration(const Vector3f& a){ acceleration_ = a; } + const Vector3f& tintColor() const { return tintColor_; } + void setTintColor(const Vector3f& c){ tintColor_ = c; } + void readParameters(const Mapping* info); void writeParameters(Mapping* info) const; @@ -54,6 +57,7 @@ class ParticleSystem float initialSpeedVariation_; float emissionRange_; Vector3f acceleration_; + Vector3f tintColor_; }; } diff --git a/src/SceneEffectsPlugin/SceneSmoke.cpp b/src/SceneEffectsPlugin/SceneSmoke.cpp index 9639161c7..632f41335 100644 --- a/src/SceneEffectsPlugin/SceneSmoke.cpp +++ b/src/SceneEffectsPlugin/SceneSmoke.cpp @@ -1,8 +1,3 @@ -/** - @file - @author Shin'ichiro Nakaoka -*/ - #include "SceneEffectsPlugin.h" #include "SceneSmoke.h" #include "ParticlesProgram.h" @@ -25,11 +20,13 @@ class SmokeProgram : public ParticlesProgram GLint lifeTimeLocation; GLint accelLocation; + GLint tintColorLocation; // Variables to detect changes causing the buffer update int numParticles; float lifeTime; float emissionRange; + Vector3f tintColor; GLuint initVelBuffer; GLuint offsetTimeBuffer; @@ -79,7 +76,7 @@ SmokeProgram::SmokeProgram(GLSLSceneRenderer* renderer) ":/SceneEffectsPlugin/shader/Smoke.vert", ":/SceneEffectsPlugin/shader/Particles.frag") { - + tintColor.setOnes(); } @@ -92,6 +89,7 @@ bool SmokeProgram::initializeRendering(SceneParticles* particles) auto& glsl = glslProgram(); lifeTimeLocation = glsl.getUniformLocation("lifeTime"); accelLocation = glsl.getUniformLocation("accel"); + tintColorLocation = glsl.getUniformLocation("tintColor"); glGenBuffers(1, &initVelBuffer); glGenBuffers(1, &offsetTimeBuffer); @@ -177,6 +175,11 @@ void SmokeProgram::render(SceneSmoke* smoke) Vector3f accel = globalAttitude().transpose() * ps.acceleration(); glUniform3fv(accelLocation, 1, accel.data()); + if(!tintColor.isApprox(ps.tintColor())){ + tintColor = ps.tintColor(); + glUniform3fv(tintColorLocation, 1, tintColor.data()); + } + /* GLint blendSrc, blendDst; glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrc); diff --git a/src/SceneEffectsPlugin/SceneSmoke.h b/src/SceneEffectsPlugin/SceneSmoke.h index abe690a82..8010bccf2 100644 --- a/src/SceneEffectsPlugin/SceneSmoke.h +++ b/src/SceneEffectsPlugin/SceneSmoke.h @@ -1,7 +1,3 @@ -/** - @author Shin'ichiro Nakaoka -*/ - #ifndef CNOID_SCENE_EFFECTS_PLUGIN_SCENE_SMOKE_H #define CNOID_SCENE_EFFECTS_PLUGIN_SCENE_SMOKE_H diff --git a/src/SceneEffectsPlugin/SmokeDevice.cpp b/src/SceneEffectsPlugin/SmokeDevice.cpp index 663a65101..5087c745d 100644 --- a/src/SceneEffectsPlugin/SmokeDevice.cpp +++ b/src/SceneEffectsPlugin/SmokeDevice.cpp @@ -10,7 +10,7 @@ using namespace cnoid; namespace { -SceneEffectDeviceTypeRegistration snowDeviceRegistration("SmokeDevice");; +SceneEffectDeviceTypeRegistration smokeDeviceRegistration("SmokeDevice");; } @@ -95,7 +95,7 @@ void SmokeDevice::on(bool on) int SmokeDevice::stateSize() const { - return 11; + return 14; } @@ -114,6 +114,8 @@ const double* SmokeDevice::readState(const double* buf) ps.setEmissionRange(buf[i++]); ps.setAcceleration(Vector3f(buf[i], buf[i+1], buf[i+2])); i += 3; + ps.setTintColor(Vector3f(buf[i], buf[i+1], buf[i+2])); + i += 3; return buf + i; } @@ -135,6 +137,9 @@ double* SmokeDevice::writeState(double* out_buf) const out_buf[i++] = ps.acceleration()[0]; out_buf[i++] = ps.acceleration()[1]; out_buf[i++] = ps.acceleration()[2]; + out_buf[i++] = ps.tintColor()[0]; + out_buf[i++] = ps.tintColor()[1]; + out_buf[i++] = ps.tintColor()[2]; return out_buf + i; } diff --git a/src/SceneEffectsPlugin/shader/Particles.frag b/src/SceneEffectsPlugin/shader/Particles.frag index 262e63d54..c7e21f27d 100644 --- a/src/SceneEffectsPlugin/shader/Particles.frag +++ b/src/SceneEffectsPlugin/shader/Particles.frag @@ -26,6 +26,7 @@ struct LightInfo { uniform LightInfo lights[10]; +uniform vec3 tintColor = vec3(1.0, 1.0, 1.0); uniform vec3 fogColor; uniform float maxFogDist; uniform float minFogDist; @@ -72,7 +73,7 @@ void main() { vec4 texColor = texture(particleTex, gl_PointCoord); - vec3 color = texColor.xyz; + vec3 color = texColor.xyz * tintColor; vec3 c = vec3(0.0); for(int i=0; i < numLights; ++i){ c += calcLightingColor(color, lights[i]); From 3238fb05af3c356017357e3c810dd67b4ed77366 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 10 Sep 2024 11:37:51 +0900 Subject: [PATCH 63/73] Update Japanese translations for the Base module --- src/Base/po/ja.po | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Base/po/ja.po b/src/Base/po/ja.po index 23713ccfb..ca4e9265e 100644 --- a/src/Base/po/ja.po +++ b/src/Base/po/ja.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: Choreonoid\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-17 16:07+0900\n" +"POT-Creation-Date: 2024-09-10 11:33+0900\n" "PO-Revision-Date: 2021-10-25 12:00+0900\n" "Language: ja\n" "MIME-Version: 1.0\n" @@ -798,6 +798,16 @@ msgstr "コピーされたアイテムを \"{0}\" にペーストできません msgid "Paste items in {0}" msgstr "複数のアイテムを{0}上で貼り付け" +msgid "Item \"{0}\" cannot be reloaded currently, as it is being continuously updated." +msgstr "" +"アイテム \"{0}\" は継続的に更新中のため、今は再読込することができません." + +msgid "" +"Item \"{0}\" cannot be reloaded currently, as it is a part of a sub-tree being continuously " +"updated." +msgstr "" +"アイテム \"{0}\" は継続的に更新中のサブツリーの一部であるため、今は再読込することができません." + msgid "Drop items in {0}" msgstr "複数のアイテムを{0}上でドロップ" From 9c45294c745ada8bca08c3b443fb5e72521dd0f5 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 10 Sep 2024 13:54:31 +0900 Subject: [PATCH 64/73] Make the ParticleSystem class and related headers public --- include/cnoid/ParticleSystem | 1 + include/cnoid/RainSnowDevice | 1 + include/cnoid/SmokeDevice | 1 + src/SceneEffectsPlugin/ParticleSystem.h | 3 ++- 4 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 include/cnoid/ParticleSystem create mode 100644 include/cnoid/RainSnowDevice create mode 100644 include/cnoid/SmokeDevice diff --git a/include/cnoid/ParticleSystem b/include/cnoid/ParticleSystem new file mode 100644 index 000000000..829192efe --- /dev/null +++ b/include/cnoid/ParticleSystem @@ -0,0 +1 @@ +#include "src/SceneEffectsPlugin/ParticleSystem.h" diff --git a/include/cnoid/RainSnowDevice b/include/cnoid/RainSnowDevice new file mode 100644 index 000000000..b62fb78ca --- /dev/null +++ b/include/cnoid/RainSnowDevice @@ -0,0 +1 @@ +#include "src/SceneEffectsPlugin/RainSnowDevice.h" diff --git a/include/cnoid/SmokeDevice b/include/cnoid/SmokeDevice new file mode 100644 index 000000000..a197ed5e4 --- /dev/null +++ b/include/cnoid/SmokeDevice @@ -0,0 +1 @@ +#include "src/SceneEffectsPlugin/SmokeDevice.h" diff --git a/src/SceneEffectsPlugin/ParticleSystem.h b/src/SceneEffectsPlugin/ParticleSystem.h index fc185fe9d..ff6844e2f 100644 --- a/src/SceneEffectsPlugin/ParticleSystem.h +++ b/src/SceneEffectsPlugin/ParticleSystem.h @@ -2,12 +2,13 @@ #define CNOID_SCENE_EFFECTS_PLUGIN_PARTICLE_SYSTEMS_H #include +#include "exportdecl.h" namespace cnoid { class Mapping; -class ParticleSystem +class CNOID_EXPORT ParticleSystem { public: ParticleSystem(); From ed5998c0e34a35c106d65dcaed5d9e8ecf41e631 Mon Sep 17 00:00:00 2001 From: Taiki Ishigaki Date: Sun, 1 Sep 2024 21:36:08 +0900 Subject: [PATCH 65/73] fix readGeometryTag in Sphere type --- src/URDFBodyLoader/URDFBodyLoader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/URDFBodyLoader/URDFBodyLoader.cpp b/src/URDFBodyLoader/URDFBodyLoader.cpp index f7ac58301..f42fc3096 100644 --- a/src/URDFBodyLoader/URDFBodyLoader.cpp +++ b/src/URDFBodyLoader/URDFBodyLoader.cpp @@ -681,6 +681,7 @@ bool URDFBodyLoader::Impl::readGeometryTag(const xml_node& geometryNode, ShapeDe description.length = geometryNode.child(CYLINDER).attribute(LENGTH).as_double(); } else if (!geometryNode.child(SPHERE).empty()) { + description.shapeType = ShapeDescription::Sphere; if (geometryNode.child(SPHERE).attribute(RADIUS).empty()) { os() << "Error: sphere radius is not defined"; return false; From 7f65768fe2684a814e60a8850e09c0052f881d50 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 10 Sep 2024 22:31:38 +0900 Subject: [PATCH 66/73] Fix to prevent a compile warning in Visual C++ --- src/BodyPlugin/BodyItem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BodyPlugin/BodyItem.h b/src/BodyPlugin/BodyItem.h index 086ec984b..fce2091dc 100644 --- a/src/BodyPlugin/BodyItem.h +++ b/src/BodyPlugin/BodyItem.h @@ -192,7 +192,7 @@ class CNOID_EXPORT BodyItem : public Item, public LocatableItem, public Renderab typedef ContinuousUpdateEntry ContinuousKinematicUpdateEntry; [[deprecated]] - ContinuousKinematicUpdateEntry startContinuousKinematicUpdate() { + ContinuousUpdateEntry startContinuousKinematicUpdate() { return Item::startContinuousUpdate(); } From c6fa1a344d2ee76c642b1ffbcd204cd6275d8e34 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 16 Sep 2024 12:31:29 +0900 Subject: [PATCH 67/73] Fix the reference type of LocatableItem in LocationProxy to increase its robustness --- src/Base/LocatableItem.cpp | 32 ++++++++++++++++++-------------- src/Base/LocatableItem.h | 9 +++++---- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/Base/LocatableItem.cpp b/src/Base/LocatableItem.cpp index d3ee8640f..ec8ff0577 100644 --- a/src/Base/LocatableItem.cpp +++ b/src/Base/LocatableItem.cpp @@ -12,9 +12,13 @@ Signal sigEditRequest; LocationProxy::LocationProxy(Item* locatableItem, LocationType type) - : locatableItemRef(locatableItem), + : locatableItem_(locatableItem), locationType_(type) { + if(locatableItem){ + itemConnection = locatableItem->sigDisconnectedFromRoot().connect( + [this]{ locatableItem_ = nullptr; }); + } isLocked_ = false; } @@ -27,9 +31,9 @@ LocationProxy::~LocationProxy() void LocationProxy::setNameDependencyOnItemName() { - if(auto item = locatableItem()){ - if(!itemNameConnection_.connected()){ - itemNameConnection_ = item->sigNameChanged().connect( + if(locatableItem_){ + if(!itemNameConnection.connected()){ + itemNameConnection = locatableItem_->sigNameChanged().connect( [this](const std::string&){ notifyAttributeChange(); }); } } @@ -39,11 +43,11 @@ void LocationProxy::setNameDependencyOnItemName() std::string LocationProxy::getName() const { auto self = const_cast(this); - if(auto item = self->locatableItem()){ - if(!itemNameConnection_.connected()){ + if(locatableItem_){ + if(!itemNameConnection.connected()){ self->setNameDependencyOnItemName(); } - return item->displayName(); + return locatableItem_->displayName(); } return std::string(); } @@ -73,13 +77,13 @@ void LocationProxy::setLocked(bool on) bool LocationProxy::isContinuousUpdateState() const { auto self = const_cast(this); - if(auto item = self->locatableItem()){ - if(!self->continuousUpdateStateConnection_.connected()){ - self->continuousUpdateStateConnection_ = - item->sigContinuousUpdateStateChanged().connect( + if(locatableItem_){ + if(!self->continuousUpdateStateConnection.connected()){ + self->continuousUpdateStateConnection = + locatableItem_->sigContinuousUpdateStateChanged().connect( [self](bool){ self->notifyAttributeChange(); }); } - return item->isContinuousUpdateState(); + return locatableItem_->isContinuousUpdateState(); } return false; } @@ -99,8 +103,8 @@ void LocationProxy::finishLocationEditing() LocationProxyPtr LocationProxy::getParentLocationProxy() { - if(auto item = locatableItem()){ - if(auto parentLocatableItem = item->findOwnerItem()){ + if(locatableItem_){ + if(auto parentLocatableItem = locatableItem_->findOwnerItem()){ return parentLocatableItem->getLocationProxy(); } } diff --git a/src/Base/LocatableItem.h b/src/Base/LocatableItem.h index 2671bf206..40d4d96ed 100644 --- a/src/Base/LocatableItem.h +++ b/src/Base/LocatableItem.h @@ -17,7 +17,7 @@ class CNOID_EXPORT LocationProxy : public Referenced public: virtual ~LocationProxy(); - Item* locatableItem() { return locatableItemRef.lock(); } + Item* locatableItem() { return locatableItem_; } enum LocationType { InvalidLocation, @@ -69,13 +69,14 @@ class CNOID_EXPORT LocationProxy : public Referenced void setNameDependencyOnItemName(); private: - weak_ref_ptr locatableItemRef; + Item* locatableItem_; LocationType locationType_; bool isLocked_; Signal sigAttributeChanged_; Signal sigExpired_; - ScopedConnection itemNameConnection_; - ScopedConnection continuousUpdateStateConnection_; + ScopedConnection itemConnection; + ScopedConnection itemNameConnection; + ScopedConnection continuousUpdateStateConnection; }; class CNOID_EXPORT LocatableItem From 3b0c4ccfecef0638f8a52a46fce89cfab146cee8 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 16 Sep 2024 18:23:32 +0900 Subject: [PATCH 68/73] Fix YAMLReader not to set the flow-style for empty mappings --- src/Util/YAMLReader.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Util/YAMLReader.cpp b/src/Util/YAMLReader.cpp index a6367efed..efb12ef64 100644 --- a/src/Util/YAMLReader.cpp +++ b/src/Util/YAMLReader.cpp @@ -409,6 +409,12 @@ void YAMLReaderImpl::onMappingEnd(yaml_event_t& event) cout << "YAMLReaderImpl::onMappingEnd()" << endl; } + if(auto mapping = nodeStack.top().node->toMapping()){ + if(mapping->empty()){ + mapping->setFlowStyle(false); + } + } + popNode(event); } From 062bd241da9c70d364f488df8bed5ad3954c2f8e Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Mon, 16 Sep 2024 18:25:21 +0900 Subject: [PATCH 69/73] Fix to delete objects managed by the Base module when the application finishes --- src/Base/App.cpp | 3 ++- src/Base/ExtensionManager.cpp | 6 ++++++ src/Base/ExtensionManager.h | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Base/App.cpp b/src/Base/App.cpp index 1e746ca9e..da031affe 100644 --- a/src/Base/App.cpp +++ b/src/Base/App.cpp @@ -497,9 +497,9 @@ App::~App() App::Impl::~Impl() { - AppConfig::flush(); delete qapplication; delete pluginManager; + AppConfig::flush(); } @@ -588,6 +588,7 @@ int App::Impl::exec() RootItem::instance()->clearChildren(); pluginManager->finalizePlugins(); + ext->deleteManagedObjects(); delete mainWindow; mainWindow = nullptr; diff --git a/src/Base/ExtensionManager.cpp b/src/Base/ExtensionManager.cpp index e751dfbae..2531362ea 100644 --- a/src/Base/ExtensionManager.cpp +++ b/src/Base/ExtensionManager.cpp @@ -235,6 +235,12 @@ void ExtensionManager::Impl::deleteManagedObjects() } +void ExtensionManager::deleteManagedObjects() +{ + impl->deleteManagedObjects(); +} + + void ExtensionManager::setProjectArchiver( const std::string& name, std::function storeFunction, diff --git a/src/Base/ExtensionManager.h b/src/Base/ExtensionManager.h index dc7d6f82b..766c3afbe 100644 --- a/src/Base/ExtensionManager.h +++ b/src/Base/ExtensionManager.h @@ -56,6 +56,8 @@ class CNOID_EXPORT ExtensionManager return pointer; } + void deleteManagedObjects(); + void setProjectArchiver( const std::string& name, std::function storeFunction, From 5f2a011b4e52abf92892facae15ee42237921f59 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Tue, 17 Sep 2024 11:11:16 +0900 Subject: [PATCH 70/73] Fix StdSceneWriter to update the output base directory correctly --- src/Util/StdSceneWriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Util/StdSceneWriter.cpp b/src/Util/StdSceneWriter.cpp index 22bbd4bbc..0a6b1fb1b 100644 --- a/src/Util/StdSceneWriter.cpp +++ b/src/Util/StdSceneWriter.cpp @@ -261,8 +261,8 @@ void StdSceneWriter::Impl::setOutputBaseDirectory(const std::string& directory) { outputBaseDirectory = directory; outputBaseDirPath = fromUTF8(directory); - if(uriSchemeProcessor){ - uriSchemeProcessor->filePathVariableProcessor()->setBaseDirectory(directory); + if(filePathVariableProcessor){ + filePathVariableProcessor->setBaseDirectory(directory); } } From 6817db053b81ac940b4de27eee5f942996d793d5 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 18 Sep 2024 12:39:39 +0900 Subject: [PATCH 71/73] Improve the API of the MessageOut class Add the notify and flush functions. --- src/Base/MessageView.cpp | 16 ++++++-- src/Util/MessageOut.cpp | 83 +++++++++++++++++++++++++++++++++++----- src/Util/MessageOut.h | 33 +++++++++++----- 3 files changed, 108 insertions(+), 24 deletions(-) diff --git a/src/Base/MessageView.cpp b/src/Base/MessageView.cpp index 5a81939ff..6f6894ace 100644 --- a/src/Base/MessageView.cpp +++ b/src/Base/MessageView.cpp @@ -286,15 +286,19 @@ MessageView::Impl::Impl(MessageView* self) : MessageOut::master()->addSink( [this](const std::string& message, int type){ - put(message, type, false, false, true, false); - }); + put(message, type, false, false, false, false); + }, + [](const std::string& message, int /* type */){ + InfoBar::instance()->notify(message); + }, + [this]{ flush(); }); MessageOut::interactive()->addSink( [this](const std::string& message, int type){ switch(type){ case MessageOut::Normal: case MessageOut::Highlighted: - put(message, type, false, false, true, false); + put(message, type, false, false, false, false); break; case MessageOut::Warning: showWarningDialog(message); @@ -305,7 +309,11 @@ MessageView::Impl::Impl(MessageView* self) : default: break; } - }); + }, + [](const std::string& message, int /* type */){ + InfoBar::instance()->notify(message); + }, + [this]{ flush(); }); } diff --git a/src/Util/MessageOut.cpp b/src/Util/MessageOut.cpp index 33c5cde86..a82861119 100644 --- a/src/Util/MessageOut.cpp +++ b/src/Util/MessageOut.cpp @@ -28,10 +28,14 @@ class MessageOutStreamBuf : public std::basic_streambuf class Sink : public Referenced { public: - std::function function; - - Sink(const std::function& func) - : function(func) { } + std::function messageFunc; + std::function notifyFunc; + std::function flushFunc; + + Sink(const std::function& messageFunc, + const std::function& notifyFunc, + const std::function& flushFunc) + : messageFunc(messageFunc), notifyFunc(notifyFunc), flushFunc(flushFunc) { } }; typedef ref_ptr SinkPtr; @@ -56,10 +60,12 @@ class MessageOut::Impl bool isPendingMode; bool hasErrors; - unique_ptr streamBuf; + ostream* direct_cout; unique_ptr cout; - unique_ptr errorStreamBuf; + unique_ptr streamBuf; + ostream* direct_cerr; unique_ptr cerr; + unique_ptr errorStreamBuf; Impl(MessageOut* self); }; @@ -95,6 +101,7 @@ int MessageOutStreamBuf::sync() { auto p = &buf.front(); mout.put(string(p, pptr() - p), messageType); + mout.flush(); setp(p, p + buf.size()); return 0; } @@ -120,11 +127,37 @@ MessageOut::MessageOut() } +MessageOut::MessageOut +(std::function messageFunc, + std::function notifyFunc, + std::function flushFunc) +{ + impl = new Impl(this); + addSink(messageFunc, notifyFunc, flushFunc); +} + + +MessageOut::MessageOut(std::ostream& sink) +{ + impl = new Impl(this); + + addSink( + [&sink](const std::string& message, int /* type */){ sink << message; }, + [](const std::string& /* message */, int /* type */){ }, + [&sink]{ sink.flush(); }); + + impl->direct_cout = &sink; + impl->direct_cerr = &sink; +} + + MessageOut::Impl::Impl(MessageOut* self) : self(self) { isPendingMode = false; hasErrors = false; + direct_cout = nullptr; + direct_cerr = nullptr; } @@ -141,10 +174,13 @@ void MessageOut::clearSinks() } -MessageOut::SinkHandle MessageOut::addSink(std::function func) +MessageOut::SinkHandle MessageOut::addSink +(std::function messageFunc, + std::function notifyFunc, + std::function flushFunc) { lock_guard lock(sinkMutex); - impl->sinks.push_back(new Sink(func)); + impl->sinks.push_back(new Sink(messageFunc, notifyFunc, flushFunc)); return impl->sinks.back(); } @@ -169,7 +205,7 @@ void MessageOut::put(const std::string& message, int type) } if(!impl->isPendingMode){ for(auto& sink : impl->sinks){ - sink->function(message, type); + sink->messageFunc(message, type); } } else { impl->pendingMessages.emplace_back(message, type); @@ -180,12 +216,35 @@ void MessageOut::put(const std::string& message, int type) void MessageOut::putln(const std::string& message, int type) { put(message + "\n", type); + flush(); +} + + +void MessageOut::notify(const std::string& message, int type) +{ + putln(message, type); + for(auto& sink : impl->sinks){ + sink->notifyFunc(message, type); + } +} + + +void MessageOut::flush() +{ + if(!impl->isPendingMode){ + for(auto& sink : impl->sinks){ + sink->flushFunc(); + } + } } std::ostream& MessageOut::cout() { lock_guard lock(sinkMutex); + if(impl->direct_cout){ + return *impl->direct_cout; + } if(!impl->cout){ impl->streamBuf = make_unique(*this, Normal); impl->cout = make_unique(impl->streamBuf.get()); @@ -197,6 +256,9 @@ std::ostream& MessageOut::cout() std::ostream& MessageOut::cerr() { lock_guard lock(sinkMutex); + if(impl->direct_cerr){ + return *impl->direct_cerr; + } if(!impl->cout){ impl->errorStreamBuf = make_unique(*this, Error); impl->cerr = make_unique(impl->errorStreamBuf.get()); @@ -223,7 +285,8 @@ void MessageOut::flushPendingMessages() lock_guard lock(sinkMutex); for(auto& message : impl->pendingMessages){ for(auto& sink : impl->sinks){ - sink->function(message.text, message.type); + sink->messageFunc(message.text, message.type); + sink->flushFunc(); } } impl->pendingMessages.clear(); diff --git a/src/Util/MessageOut.h b/src/Util/MessageOut.h index 269fb0214..68b97bcd2 100644 --- a/src/Util/MessageOut.h +++ b/src/Util/MessageOut.h @@ -14,7 +14,11 @@ class CNOID_EXPORT MessageOut : public Referenced static MessageOut* interactive(); MessageOut(); - MessageOut(std::function sink); + MessageOut( + std::function messageFunc, + std::function notifyFunc, + std::function flushFunc); + MessageOut(std::ostream& sink); MessageOut(MessageOut* parent); ~MessageOut(); @@ -23,42 +27,51 @@ class CNOID_EXPORT MessageOut : public Referenced typedef ReferencedPtr SinkHandle; void clearSinks(); - SinkHandle addSink(std::function sink); + SinkHandle addSink( + std::function messageFunc, + std::function notifyFunc, + std::function flushFunc); int numSinks() const; SinkHandle sinkHandle(int index); void removeSink(SinkHandle sink); - void put(const std::string& message, int type); - void putln(const std::string& message, int type); + void put(const std::string& message, int type = Normal); + void putln(const std::string& message, int type = Normal); + void notify(const std::string& message, int type = Normal); - void put(const std::string& message){ - put(message, Normal); - } - void putln(const std::string& message){ - putln(message, Normal); - } void putHighlighted(const std::string& message){ put(message, Highlighted); } void putHighlightedln(const std::string& message){ putln(message, Highlighted); } + void notifyHighlighted(const std::string& message){ + notify(message, Highlighted); + } void putWarning(const std::string& message){ put(message, Warning); } void putWarningln(const std::string& message){ putln(message, Warning); } + void notifyWarning(const std::string& message){ + notify(message, Warning); + } void putError(const std::string& message){ put(message, Error); } void putErrorln(const std::string& message){ putln(message, Error); } + void notifyError(const std::string& message){ + notify(message, Error); + } std::ostream& cout(); std::ostream& cerr(); + void flush(); + void setPendingMode(bool on); void flushPendingMessages(); From 96f6d8233888f6bb7e7d6560d23033d0f75d23ed Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Wed, 18 Sep 2024 14:36:19 +0900 Subject: [PATCH 72/73] Refactor some code on MessageOut --- src/Base/PluginManager.cpp | 42 +++++++++++++++----- src/ManipulatorPlugin/MprPosition.cpp | 8 ++-- src/ManipulatorPlugin/MprProgramItemBase.cpp | 14 +++---- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/Base/PluginManager.cpp b/src/Base/PluginManager.cpp index 9c28b7485..303786e09 100644 --- a/src/Base/PluginManager.cpp +++ b/src/Base/PluginManager.cpp @@ -381,9 +381,11 @@ void PluginManager::Impl::loadScannedPluginFiles(bool doActivation) if(numNotLoaded > 0){ for(auto& plugin : allPluginInfos){ if(plugin->status == PluginManager::NOT_LOADED){ - mout->putErrorln(formatR(_("Loading {0} failed.\n"), plugin->name)); + mout->putError(formatR(_("Loading {0} failed.\n"), plugin->name)); if(!plugin->lastErrorMessage.empty()){ mout->putErrorln(plugin->lastErrorMessage); + } else { + mout->flush(); } plugin->status = PluginManager::INVALID; } @@ -428,8 +430,8 @@ void PluginManager::Impl::loadScannedPluginFiles(bool doActivation) lacks += info->requisites[j]; } } - mout->putError( - formatR(_("{0}-plugin cannot be initialized because required plugin(s) {1} are not found.\n"), + mout->putErrorln( + formatR(_("{0}-plugin cannot be initialized because required plugin(s) {1} are not found."), info->name, lacks)); } } @@ -452,13 +454,16 @@ bool PluginManager::loadPlugin(int index) bool PluginManager::Impl::loadPlugin(int index, bool isLoadingMultiplePlugins) { PluginInfoPtr& info = allPluginInfos[index]; + bool hasMessages = false; if(info->status == PluginManager::ACTIVE){ mout->put(formatR(_("Plugin file \"{}\" has already been activated.\n"), info->pathString)); + hasMessages = true; } else if(info->status == PluginManager::NOT_LOADED){ if(false){ mout->put(formatR(_("Detecting plugin file \"{}\".\n"), info->pathString)); + hasMessages = true; } info->dll.setFileName(info->pathString.c_str()); @@ -494,8 +499,9 @@ bool PluginManager::Impl::loadPlugin(int index, bool isLoadingMultiplePlugins) if(!symbol){ info->status = PluginManager::INVALID; info->lastErrorMessage = _("The plugin entry function \"getChoreonoidPlugin\" is not found.\n"); - info->lastErrorMessage += info->dll.errorString().toStdString(); - mout->putErrorln(info->lastErrorMessage); + info->lastErrorMessage += info->dll.errorString().toStdString() + "\n"; + mout->putError(info->lastErrorMessage); + hasMessages = true; } else { Plugin::PluginEntry getCnoidPluginFunc = (Plugin::PluginEntry)(symbol); @@ -505,6 +511,7 @@ bool PluginManager::Impl::loadPlugin(int index, bool isLoadingMultiplePlugins) if(!plugin){ info->status = PluginManager::INVALID; mout->putError(_("The plugin object cannot be created.\n")); + hasMessages = true; } else { info->status = PluginManager::LOADED; @@ -517,6 +524,7 @@ bool PluginManager::Impl::loadPlugin(int index, bool isLoadingMultiplePlugins) _("The internal version of the {0} plugin is different from the system internal version.\n" "The plugin file \"{1}\" should be removed or updated to avoid a problem.\n"), info->name, info->pathString)); + hasMessages = true; } const int numRequisites = plugin->numRequisites(); @@ -547,9 +555,10 @@ bool PluginManager::Impl::loadPlugin(int index, bool isLoadingMultiplePlugins) PluginInfoPtr& another = p->second; another->status = PluginManager::CONFLICT; info->lastErrorMessage = - formatR(_("Plugin file \"{0}\" conflicts with \"{1}\"."), + formatR(_("Plugin file \"{0}\" conflicts with \"{1}\".\n"), info->pathString, another->pathString); - mout->putErrorln(info->lastErrorMessage); + mout->putError(info->lastErrorMessage); + hasMessages = true; } } @@ -557,6 +566,11 @@ bool PluginManager::Impl::loadPlugin(int index, bool isLoadingMultiplePlugins) info->lastErrorMessage.clear(); } else { mout->putError(_("Loading the plugin failed.\n")); + hasMessages = true; + } + + if(hasMessages){ + mout->flush(); } return (info->status == PluginManager::LOADED); @@ -566,11 +580,13 @@ bool PluginManager::Impl::loadPlugin(int index, bool isLoadingMultiplePlugins) bool PluginManager::Impl::activatePlugin(int index) { string errorMessage; + bool hasMessages = false; PluginInfoPtr info = allPluginInfos[index]; if(info->status == PluginManager::ACTIVE){ mout->putWarning(formatR(_("Plugin file \"{}\" has already been activated.\n"), info->pathString)); + hasMessages = true; } else if(info->status == PluginManager::LOADED){ @@ -648,12 +664,18 @@ bool PluginManager::Impl::activatePlugin(int index) } mout->put(formatR(_("{}-plugin has been activated.\n"), info->name)); + hasMessages = true; } } } if(!errorMessage.empty()){ mout->putErrorln(formatR(_("Loading the plugin failed.\n{0}"), errorMessage)); + hasMessages = true; + } + + if(hasMessages){ + mout->flush(); } return (info->status == PluginManager::ACTIVE); @@ -727,8 +749,8 @@ bool PluginManager::Impl::finalizePlugin(PluginInfoPtr info) if(allDependentsFinalized){ info->plugin->isActive_ = false; if(!info->plugin->finalize()){ - MessageOut::master()->putError( - formatR(_("{0}-plugin cannot be finalized.\n"), info->name)); + mout->putErrorln( + formatR(_("{0}-plugin cannot be finalized."), info->name)); } else { bool isUnloadable = info->plugin->isUnloadable(); info->status = PluginManager::FINALIZED; @@ -765,7 +787,7 @@ void PluginManager::Impl::unloadPluginsActually() if(info->dll.unload()){ info->status = PluginManager::UNLOADED; nameToPluginInfoMap.erase(info->name); - mout->put(formatR(_("Plugin DLL \"{}\" has been unloaded.\n"), info->pathString)); + mout->putln(formatR(_("Plugin DLL \"{}\" has been unloaded."), info->pathString)); if(info->doReloading){ info->status = PluginManager::NOT_LOADED; info->doReloading = false; diff --git a/src/ManipulatorPlugin/MprPosition.cpp b/src/ManipulatorPlugin/MprPosition.cpp index 3316c9c48..03c9fa24d 100644 --- a/src/ManipulatorPlugin/MprPosition.cpp +++ b/src/ManipulatorPlugin/MprPosition.cpp @@ -30,7 +30,7 @@ bool checkJointDisplacementRanges(JointTraverse& traverse, MessageOut* mout) if(joint->hasActualJoint()){ if(joint->q() < joint->q_lower() || joint->q() > joint->q_upper()){ if(mout){ - mout->putError( + mout->putErrorln( formatR(_("The joint displacement of {0} is out of its movable range."), joint->jointName())); } @@ -418,7 +418,7 @@ bool MprIkPosition::fetch(BodyKinematicsKit* kinematicsKit, MessageOut* mout) int state = configuration->getCurrentNearSingularPointState(); if(state > 0){ if(mout){ - mout->putError( + mout->putErrorln( formatR(_("The current manipulator position is not valid: {0}."), configuration->getNearSingularPointFactorString(state))); } @@ -683,9 +683,9 @@ bool MprCompositePosition::fetch(KinematicBodySet* bodySet, MessageOut* mout) if(numFetchedElements != numPositionElements){ if(id().isValid()){ - mout->putWarning(formatR(_("Could not fetch all the elements of position {0}."), id().label())); + mout->putWarningln(formatR(_("Could not fetch all the elements of position {0}."), id().label())); } else { - mout->putWarning(_("Could not fetch all the elements of the position.")); + mout->putWarningln(_("Could not fetch all the elements of the position.")); } } } diff --git a/src/ManipulatorPlugin/MprProgramItemBase.cpp b/src/ManipulatorPlugin/MprProgramItemBase.cpp index fe75a62d8..1d5925583 100644 --- a/src/ManipulatorPlugin/MprProgramItemBase.cpp +++ b/src/ManipulatorPlugin/MprProgramItemBase.cpp @@ -47,7 +47,7 @@ class MprProgramItemBase::Impl MprPosition* findPositionOrShowWarning(MprPositionStatement* statement, MessageOut* mout); BodyItemKinematicsKit* findKinematicsKit(); bool moveTo(MprPosition* position, bool doUpdateAll, MessageOut* mout); - bool superimposePosition(MprPosition* position, MessageOut* mout); + bool superimposePosition(MprPosition* position); bool touchupPosition(MprPosition* position, MessageOut* mout); }; @@ -245,7 +245,7 @@ MprPosition* MprProgramItemBase::Impl::findPositionOrShowWarning(MprPositionStat { MprPosition* position = statement->position(); if(!position && mout){ - mout->putError( + mout->putErrorln( formatR(_("Position {0} is not found in {1}."), statement->positionLabel(), self->name()).c_str()); } @@ -343,7 +343,7 @@ bool MprProgramItemBase::Impl::moveTo(MprPosition* position, bool doUpdateAll, M } if(!errorMessage.empty() && mout){ - mout->putError(errorMessage); + mout->putErrorln(errorMessage); } return updated; @@ -353,15 +353,15 @@ bool MprProgramItemBase::Impl::moveTo(MprPosition* position, bool doUpdateAll, M bool MprProgramItemBase::superimposePosition(MprPositionStatement* statement, MessageOut* mout) { if(auto position = impl->findPositionOrShowWarning(statement, mout)){ - return impl->superimposePosition(position, mout); + return impl->superimposePosition(position); } return false; } -bool MprProgramItemBase::superimposePosition(MprPosition* position, MessageOut* mout) +bool MprProgramItemBase::superimposePosition(MprPosition* position, MessageOut* /* mout */) { - return impl->superimposePosition(position, mout); + return impl->superimposePosition(position); } @@ -369,7 +369,7 @@ bool MprProgramItemBase::superimposePosition(MprPosition* position, MessageOut* \todo Simplify the following implementation by using an independent BodySuperimposerAddons for each body item and updating the positions of all the boides simultaneously. */ -bool MprProgramItemBase::Impl::superimposePosition(MprPosition* position, MessageOut* mout) +bool MprProgramItemBase::Impl::superimposePosition(MprPosition* position) { if(!targetBodyItemSet){ return false; From d5cf0764b4b5af9aab16b23ca58576efed99b6e3 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Nakaoka Date: Thu, 19 Sep 2024 09:20:32 +0900 Subject: [PATCH 73/73] Fix ItemTreeView to avoid a crash when its empty space is right-clicked, which was introduced in commit ac243ac0 --- src/Base/ItemTreeView.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Base/ItemTreeView.cpp b/src/Base/ItemTreeView.cpp index 0db26b65a..a014a2f2f 100644 --- a/src/Base/ItemTreeView.cpp +++ b/src/Base/ItemTreeView.cpp @@ -129,7 +129,8 @@ void ItemTreeView::Impl::onContextMenuRequested(Item* item, MenuManager& menu) auto selectAll = menu.addItem(_("Select all")); auto clearSelection = menu.addItem(_("Clear selection")); - bool isContinuousUpdateStateSubTree = item->isContinuousUpdateStateSubTree(); + bool isContinuousUpdateStateSubTree = + item ? item->isContinuousUpdateStateSubTree() : false; if(!item || isContinuousUpdateStateSubTree){ rename->setEnabled(false); @@ -199,7 +200,7 @@ void ItemTreeView::Impl::onContextMenuRequested(Item* item, MenuManager& menu) [this](){ itemTreeWidget->toggleSelectedItemChecks(); }); } - if(itemTreeWidget->checkPastable(item) && !(item && isContinuousUpdateStateSubTree)){ + if(itemTreeWidget->checkPastable(item) && !isContinuousUpdateStateSubTree){ paste->setEnabled(true); paste->sigTriggered().connect( [this](){ itemTreeWidget->pasteItems(); });