Skip to content

Commit b5c9cfb

Browse files
Merge pull request #36 from sofa-framework/Prefab_addLinkParameter
ADD: PrefabLinks
2 parents 675191b + be31d20 commit b5c9cfb

File tree

10 files changed

+219
-26
lines changed

10 files changed

+219
-26
lines changed

Plugin/src/SofaPython3/DataHelper.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -541,13 +541,12 @@ BaseData* addData(py::object py_self, const std::string& name, py::object value,
541541
BaseData* data;
542542

543543
bool isSet = true;
544-
if (value.is(py::none()))
544+
if (value.is_none())
545545
{
546546
value = defaultValue;
547547
isSet = false;
548548
}
549549

550-
551550
// create the data from the link passed as a string to the object
552551
if (py::isinstance<py::str>(value) &&
553552
!py::cast<std::string>(value).empty() &&
@@ -564,7 +563,7 @@ BaseData* addData(py::object py_self, const std::string& name, py::object value,
564563
self->addData(data, name);
565564
}
566565
// create the data from another data (use as parent)
567-
else if (py::isinstance<BaseData>(value) || py::isinstance<BaseData*>(value))
566+
else if (!value.is_none() && (py::isinstance<BaseData>(value) || py::isinstance<BaseData*>(value)))
568567
{
569568
data = deriveTypeFromParent(py::cast<BaseData*>(value));
570569
if (!data)
@@ -587,7 +586,8 @@ BaseData* addData(py::object py_self, const std::string& name, py::object value,
587586
throw py::type_error(std::string("Invalid Type string: available types are\n") + typesString);
588587
}
589588
self->addData(data, name);
590-
PythonFactory::fromPython(data, value);
589+
if (!value.is_none())
590+
PythonFactory::fromPython(data, value);
591591
}
592592
data->setName(name);
593593
data->setGroup(group.c_str());

Plugin/src/SofaPython3/DataHelper.h

+109-4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ along with sofaqtquick. If not, see <http://www.gnu.org/licenses/>.
3434
#include <sofa/core/sptr.h>
3535
#include <sofa/helper/Factory.h>
3636
#include <sofa/core/objectmodel/Data.h>
37+
#include <sofa/core/objectmodel/Base.h>
38+
#include <sofa/core/objectmodel/BaseObject.h>
39+
#include <sofa/core/objectmodel/BaseNode.h>
3740

3841
#include "config.h"
3942

@@ -44,10 +47,112 @@ namespace sofa {
4447
}
4548
namespace core {
4649
namespace objectmodel {
47-
class Base;
4850
class BaseData;
49-
class BaseNode;
50-
class BaseObject;
51+
52+
53+
class SOFAPYTHON3_API PrefabLink
54+
{
55+
public:
56+
PrefabLink() {}
57+
PrefabLink(const Base::SPtr& targetBase) { m_targetBase = targetBase; }
58+
PrefabLink(BaseLink* targetLink) { m_targetBase = targetLink->getLinkedBase(); }
59+
PrefabLink(const std::string& targetPath) { m_targetPath = targetPath; }
60+
61+
const Base::SPtr& getTargetBase() const { return m_targetBase; }
62+
void setTargetBase(const Base::SPtr& targetBase) { m_targetBase = targetBase; }
63+
64+
const std::string& getTargetPath() const { return m_targetPath; }
65+
void setTargetPath(const std::string& targetPath) { m_targetPath = targetPath; }
66+
67+
friend std::ostream& operator << ( std::ostream& out, const PrefabLink& l)
68+
{
69+
if (l.getTargetBase())
70+
{
71+
auto bn = l.getTargetBase()->toBaseNode();
72+
auto bo = l.getTargetBase()->toBaseObject();
73+
out << "@" + (bn ? bn->getPathName() : bo->getPathName());
74+
}
75+
out << l.getTargetPath();
76+
return out;
77+
}
78+
79+
friend std::istream& operator >> ( std::istream& in, PrefabLink& l)
80+
{
81+
std::string s;
82+
in >> s;
83+
l.setTargetPath(s);
84+
return in;
85+
}
86+
87+
private:
88+
Base::SPtr m_targetBase { nullptr };
89+
std::string m_targetPath {""};
90+
};
91+
92+
class SOFAPYTHON3_API DataLink : public Data<PrefabLink>
93+
{
94+
typedef Data<PrefabLink> Inherit;
95+
96+
DataLink( const std::string& helpMsg="", bool isDisplayed=true, bool isReadOnly=false )
97+
: Inherit(helpMsg, isDisplayed, isReadOnly)
98+
{
99+
}
100+
101+
DataLink( const std::string& value, const std::string& helpMsg="", bool isDisplayed=true, bool isReadOnly=false )
102+
: Inherit(value, helpMsg, isDisplayed, isReadOnly)
103+
{
104+
}
105+
106+
explicit DataLink(const BaseData::BaseInitData& init)
107+
: Inherit(init)
108+
{
109+
}
110+
111+
const PrefabLink& getValue() const
112+
{
113+
updateIfDirty();
114+
if (m_value.getValue().getTargetBase()) return m_value.getValue();
115+
116+
auto self = const_cast<DataLink*>(this);
117+
118+
Base* dst = nullptr;
119+
this->getOwner()->findLinkDest(dst, self->m_value.getValue().getTargetPath(), nullptr);
120+
if (dst) {
121+
auto edit = self->m_value.beginEdit();
122+
edit->setTargetBase(dst);
123+
edit->setTargetPath("");
124+
self->m_value.endEdit();
125+
}
126+
return m_value.getValue();
127+
}
128+
129+
std::string getValueString() const
130+
{
131+
const auto& ptr = getValue();
132+
if (ptr.getTargetBase())
133+
{
134+
auto bn = ptr.getTargetBase()->toBaseNode();
135+
auto bo = ptr.getTargetBase()->toBaseObject();
136+
return "@" + (bn ? bn->getPathName() : bo->getPathName());
137+
}
138+
return ptr.getTargetPath();
139+
}
140+
141+
142+
bool read(const std::string& value)
143+
{
144+
Base* dst;
145+
auto data = m_value.beginEdit();
146+
if (this->getOwner()->findLinkDest(dst, value, nullptr) && dst != nullptr)
147+
data->setTargetBase(dst);
148+
else {
149+
data->setTargetBase(nullptr);
150+
data->setTargetPath(value);
151+
}
152+
return true;
153+
}
154+
};
155+
51156
}
52157
}
53158
}
@@ -189,7 +294,7 @@ class scoped_writeonly_access
189294
~scoped_writeonly_access(){ data->endEditVoidPtr(); }
190295
};
191296

192-
SOFAPYTHON3_API BaseData* addData(py::object py_self, const std::string& name, py::object value = py::object(), py::object defaultValue = py::object(), const std::string& help = "", const std::string& group = "Property", std::string type = "");
297+
SOFAPYTHON3_API BaseData* addData(py::object py_self, const std::string& name, py::object value = py::none(), py::object defaultValue = py::none(), const std::string& help = "", const std::string& group = "Property", std::string type = "");
193298
SOFAPYTHON3_API BaseLink* addLink(py::object py_self, const std::string& name, py::object value, const std::string& help);
194299
SOFAPYTHON3_API bool isProtectedKeyword(const std::string& name);
195300

Plugin/src/SofaPython3/Prefab.cpp

+6-13
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ using sofa::core::objectmodel::Event;
2121

2222
void Prefab::init()
2323
{
24-
std::cout << "prefab::init" << std::endl;
2524
reinit();
2625
Inherit1::init(sofa::core::ExecParams::defaultInstance());
26+
m_is_initialized = true;
2727
}
2828

2929
void PrefabFileEventListener::fileHasChanged(const std::string &filename)
@@ -44,18 +44,15 @@ void PrefabFileEventListener::fileHasChanged(const std::string &filename)
4444

4545
void Prefab::reinit()
4646
{
47-
std::cout << "prefab::reinit" << std::endl;
4847
clearLoggedMessages();
4948

5049
/// remove everything in the node.
5150
execute<sofa::simulation::DeleteVisitor>(sofa::core::ExecParams::defaultInstance());
52-
std::cout << "prefab::doReInit" << std::endl;
51+
5352
doReInit();
5453

55-
std::cout << "simulation->initNode" << std::endl;
5654
/// Beurk beurk beurk
5755
sofa::simulation::getSimulation()->initNode(this);
58-
std::cout << "VisualInitVisitor" << std::endl;
5956
execute<VisualInitVisitor>(nullptr);
6057

6158
d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid);
@@ -78,27 +75,23 @@ Prefab::~Prefab()
7875
}
7976

8077

81-
void Prefab::addPrefabParameter(const std::string& name, py::object value, const std::string& help, std::string type)
78+
void Prefab::addPrefabParameter(const std::string& name, const std::string& help, const std::string& type, py::object defaultValue)
8279
{
83-
sofa::core::objectmodel::BaseData* data = findData(name);
84-
if(data == nullptr)
80+
if(!findData(name) && !findLink(name))
8581
{
86-
sofa::core::objectmodel::BaseData* data = sofapython3::addData(py::cast(this), name, value, py::object(), help, "Prefab's properties", type);
82+
sofa::core::objectmodel::BaseData* data = sofapython3::addData(py::cast(this), name, py::none(), defaultValue, help, "Prefab's properties", type);
83+
data->setRequired(true);
8784
m_datacallback.addInputs({data});
88-
return;
8985
}
90-
//PythonFactory::fromPython(data, value);
9186
}
9287

9388
void Prefab::setSourceTracking(const std::string& filename)
9489
{
95-
std::cout << "Activating source tracking to " << filename << std::endl;
9690
FileMonitor::addFile(filename, &m_filelistener);
9791
}
9892

9993
void Prefab::breakPrefab()
10094
{
101-
std::cout << "Breaking prefab" << std::endl;
10295
FileMonitor::removeListener(&m_filelistener);
10396
for (auto& data : this->getDataFields())
10497
if (data->getGroup() == "Prefab's properties")

Plugin/src/SofaPython3/Prefab.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class SOFAPYTHON3_API Prefab : public BasePrefab
3939
void reinit();
4040
virtual void doReInit() ;
4141

42-
void addPrefabParameter(const std::string& name, pybind11::object value, const std::string& help, std::string type);
42+
void addPrefabParameter(const std::string& name, const std::string& help, const std::string& type, pybind11::object defaultValue = py::none());
4343
void setSourceTracking(const std::string& filename);
4444
void breakPrefab();
4545

@@ -48,5 +48,6 @@ class SOFAPYTHON3_API Prefab : public BasePrefab
4848

4949
PrefabFileEventListener m_filelistener;
5050
DataCallback m_datacallback;
51+
bool m_is_initialized {false};
5152
};
5253
} // namespace sofapython3

Plugin/src/SofaPython3/PythonFactory.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,10 @@ bool PythonFactory::registerDefaultTypes()
437437
// helper vector style containers
438438
std::string containers[] = {"vector"};
439439

440+
// PrefabLink
441+
PythonFactory::registerType<sofa::core::objectmodel::PrefabLink>("PrefabLink");
442+
PythonFactory::registerType<sofa::core::objectmodel::PrefabLink>("Link");
443+
440444
// Scalars
441445
PythonFactory::registerType<std::string>("string");
442446
PythonFactory::registerType<float>("float");

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Prefab.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,17 @@ class Prefab_Trampoline : public Prefab, public PythonTrampoline
6868

6969
void Prefab_Trampoline::doReInit()
7070
{
71+
if (!m_is_initialized) {
72+
this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Loading);
73+
msg_warning(this) << "Prefab instantiated. Check for required prefab parameters to fully populate";
74+
return;
75+
}
7176
try{
77+
this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid);
7278
PYBIND11_OVERLOAD(void, Prefab, doReInit, );
7379
} catch (std::exception& e)
7480
{
81+
this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid);
7582
msg_error(this) << e.what();
7683
}
7784
}
@@ -98,8 +105,6 @@ void moduleAddPrefab(py::module &m) {
98105
std::string key = py::cast<std::string>(kv.first);
99106
py::object value = py::reinterpret_borrow<py::object>(kv.second);
100107

101-
std::cout << "PREFAB ARE BROKEN " << key << std::endl;
102-
103108
if( key == "name")
104109
c->setName(py::cast<std::string>(kv.second));
105110
try {
@@ -117,7 +122,7 @@ void moduleAddPrefab(py::module &m) {
117122

118123
f.def("setSourceTracking", &Prefab::setSourceTracking);
119124
f.def("addPrefabParameter", &Prefab::addPrefabParameter,
120-
"name"_a, "value"_a, "help"_a, "type"_a);
125+
"name"_a, "help"_a, "type"_a, "default"_a = py::none());
121126
f.def("init", &Prefab::init);
122127
f.def("reinit", &Prefab::reinit);
123128
}

bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ set(HEADER_FILES
2929
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataContainer.h
3030
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataContainer_doc.h
3131
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataString.h
32+
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataLink.h
3233
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataString_doc.h
3334
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataVectorString.h
3435
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataVectorString_doc.h
@@ -52,6 +53,7 @@ set(SOURCE_FILES
5253
${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataEngine.cpp
5354
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataContainer.cpp
5455
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataString.cpp
56+
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataLink.cpp
5557
${CMAKE_CURRENT_SOURCE_DIR}/Data/Binding_DataVectorString.cpp
5658
${CMAKE_CURRENT_SOURCE_DIR}/Binding_ForceField.cpp
5759
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Visitor.cpp
@@ -79,4 +81,4 @@ SP3_add_python_module(
7981
SOURCES ${SOURCE_FILES}
8082
HEADERS ${HEADER_FILES}
8183
DEPENDS SofaCore SofaSimulationCore SofaSimulationGraph SofaBaseVisual SofaPython3::Plugin
82-
)
84+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "Binding_DataLink.h"
2+
3+
#include <sofa/core/objectmodel/BaseData.h>
4+
using sofa::core::objectmodel::BaseData;
5+
6+
7+
#include <SofaPython3/DataHelper.h>
8+
using sofa::core::objectmodel::PrefabLink;
9+
#include <SofaPython3/PythonFactory.h>
10+
11+
namespace sofapython3
12+
{
13+
14+
py::str getTargetPath(PrefabLink& link)
15+
{
16+
return link.getTargetPath();
17+
}
18+
19+
py::object getTargetBase(PrefabLink& link)
20+
{
21+
auto base = link.getTargetBase().get();
22+
if (base)
23+
return PythonFactory::toPython(base);
24+
return py::none();
25+
}
26+
27+
py::str DataLink::__str__()
28+
{
29+
std::stringstream s;
30+
s << "Sofa.Core.DataLink<name='" << getName()
31+
<< "', value='" << getValueString()
32+
<< "', address='"<< (void*)this <<"'>";
33+
return s.str();
34+
}
35+
36+
py::str DataLink::__repr__()
37+
{
38+
return py::repr(convertToPython(this));
39+
}
40+
41+
void moduleAddDataLink(py::module &m)
42+
{
43+
py::class_<PrefabLink, std::unique_ptr<PrefabLink, py::nodelete>> l(m, "PrefabLink");
44+
l.def(py::init<const Base::SPtr&>());
45+
l.def(py::init<BaseLink*>());
46+
l.def(py::init<const std::string&>());
47+
l.def("getTargetBase", &getTargetBase);
48+
l.def("getTargetPath", &getTargetPath);
49+
50+
py::class_<DataLink, BaseData, std::unique_ptr<DataLink, py::nodelete>> d(m, "DataLink");
51+
52+
PythonFactory::registerType("DataLink", [](BaseData* data) -> py::object {
53+
return py::cast(reinterpret_cast<DataLink*>(data));
54+
});
55+
56+
d.def("__repr__",&DataLink::__repr__);
57+
d.def("__str__", &DataLink::__str__);
58+
}
59+
60+
} // namespace sofapython3

0 commit comments

Comments
 (0)