Skip to content

Commit 8cd3e34

Browse files
authored
Merge pull request #1583 from opensim-org/WrapObject_updateFromXMLNode
Update WrapObject XML appearance options.
2 parents c89138b + 36d5cf8 commit 8cd3e34

File tree

6 files changed

+274
-9
lines changed

6 files changed

+274
-9
lines changed

OpenSim/Common/XMLDocument.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ using namespace std;
6161
// 30512 for removing Model::FrameSet and moving frames to components list
6262
// 30513 for removing internal (silent) clamping of Muscle controls (excitations)
6363
// 30514 for removing "reverse" property from Joint
64-
const int XMLDocument::LatestVersion = 30514;
64+
// 30515 for WrapObject color, display_preference, VisibleObject -> Appearance
65+
const int XMLDocument::LatestVersion = 30515;
6566
//=============================================================================
6667
// DESTRUCTOR AND CONSTRUCTOR(S)
6768
//=============================================================================

OpenSim/Simulation/Wrap/WrapObject.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,94 @@ int WrapObject::wrapPathSegment(const SimTK::State& s,
180180

181181
return return_code;
182182
}
183+
184+
void WrapObject::updateFromXMLNode(SimTK::Xml::Element& node,
185+
int versionNumber) {
186+
int documentVersion = versionNumber;
187+
if (documentVersion < XMLDocument::getLatestVersion()) {
188+
if (documentVersion < 30515) {
189+
// Replace 3.3 display_preference, color, and VisibleObject with
190+
// Appearance's visible and color.
191+
// We ignore most of VisibleObject's other properties (e.g.,
192+
// transform), since it would be misleading to draw the wrap object
193+
// in the wrong place.
194+
SimTK::Xml::Element appearanceNode("Appearance");
195+
// Use the correct defaults for WrapObject's appearance, which
196+
// are different from the default Appearance.
197+
SimTK::Xml::Element color("color");
198+
color.setValue("0 1 1"); // SimTK::Cyan
199+
appearanceNode.insertNodeAfter(appearanceNode.element_end(),
200+
color);
201+
SimTK::Xml::Element defaultOpacity("opacity");
202+
defaultOpacity.setValue("0.5");
203+
appearanceNode.insertNodeAfter(appearanceNode.element_end(),
204+
defaultOpacity);
205+
SimTK::Xml::Element defaultSurfProp("SurfaceProperties");
206+
appearanceNode.insertNodeAfter(appearanceNode.element_end(),
207+
defaultSurfProp);
208+
SimTK::Xml::Element rep("representation");
209+
rep.setValue("3"); // VisualRepresentation::DrawSurface
210+
defaultSurfProp.insertNodeAfter(defaultSurfProp.element_end(), rep);
211+
bool appearanceModified = false;
212+
213+
// color.
214+
SimTK::Xml::element_iterator colorIter =
215+
node.element_begin("color");
216+
if (colorIter != node.element_end()) {
217+
color.setValue(colorIter->getValue());
218+
node.removeNode(colorIter);
219+
appearanceModified = true;
220+
}
221+
222+
// display_preference -> visible, representation
223+
SimTK::Xml::Element visibleNode("visible");
224+
SimTK::Xml::element_iterator dispPrefIter =
225+
node.element_begin("display_preference");
226+
if (dispPrefIter != node.element_end()) {
227+
if (dispPrefIter->getValueAs<int>() == 0) {
228+
visibleNode.setValue("false");
229+
appearanceModified = true;
230+
} else if (dispPrefIter->getValueAs<int>() < 4) {
231+
// Set `representation`.
232+
// If the value is 4, we use 3 instead, which is the
233+
// default (above).
234+
rep.setValue(dispPrefIter->getValue());
235+
appearanceModified = true;
236+
}
237+
node.removeNode(dispPrefIter);
238+
}
239+
SimTK::Xml::element_iterator visObjIter =
240+
node.element_begin("VisibleObject");
241+
if (visObjIter != node.element_end()) {
242+
SimTK::Xml::element_iterator voDispPrefIter =
243+
visObjIter->element_begin("display_preference");
244+
if (voDispPrefIter != visObjIter->element_end()) {
245+
if (voDispPrefIter->getValueAs<int>() == 0) {
246+
visibleNode.setValue("false");
247+
appearanceModified = true;
248+
} else if (rep.getValue() == "3" &&
249+
voDispPrefIter->getValueAs<int>() < 4) {
250+
// Set `representation`.
251+
// The representation still has its default value,
252+
// meaning the user only specified the inner display
253+
// preference, therefore we should use this one.
254+
rep.setValue(voDispPrefIter->getValue());
255+
appearanceModified = true;
256+
}
257+
}
258+
node.removeNode(visObjIter);
259+
}
260+
if (visibleNode.getValue() != "") {
261+
appearanceNode.insertNodeAfter(appearanceNode.element_end(),
262+
visibleNode);
263+
appearanceModified = true;
264+
}
265+
266+
// Add Appearance to the WrapObject.
267+
if (appearanceModified) {
268+
node.insertNodeAfter(node.element_end(), appearanceNode);
269+
}
270+
}
271+
}
272+
Super::updateFromXMLNode(node, versionNumber);
273+
}

OpenSim/Simulation/Wrap/WrapObject.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(WrapObject, Component);
144144
* called whenever the quadrant property changes. */
145145
void extendFinalizeFromProperties() override;
146146

147+
void updateFromXMLNode(SimTK::Xml::Element& node, int versionNumber)
148+
override;
149+
147150
private:
148151
void constructProperties();
149152

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<OpenSimDocument Version="20302">
3+
<Model name="testWrapObject_updateFromXMLNode30515">
4+
<defaults/>
5+
<credits> Parts copied from TestShoulderModel.osim</credits>
6+
<publications> List of publications related to model... </publications>
7+
<length_units> meters </length_units>
8+
<force_units> N </force_units>
9+
<!--Acceleration due to gravity.-->
10+
<gravity> 0.00000000 -9.80665000 0.00000000 </gravity>
11+
<!--Bodies in the model.-->
12+
<BodySet name="">
13+
<objects>
14+
<Body name="ground">
15+
<WrapObjectSet name="">
16+
<objects>
17+
<WrapSphere name="wrapsphere">
18+
<xyz_body_rotation> 0.00000000 0.00000000 0.00000000 </xyz_body_rotation>
19+
<translation> -0.00320000 0.00490000 -0.00200000 </translation>
20+
<active> true </active>
21+
<quadrant> all </quadrant>
22+
<display_preference> 1 </display_preference>
23+
<VisibleObject name="">
24+
<!--Set of geometry files and associated attributes, allow .vtp, .stl,
25+
.obj-->
26+
<GeometrySet name="">
27+
<objects/>
28+
<groups/>
29+
</GeometrySet>
30+
<!--Three scale factors for display purposes: scaleX scaleY scaleZ-->
31+
<scale_factors> 1.00000000 1.00000000 1.00000000 </scale_factors>
32+
<!--transform relative to owner specified as 3 rotations (rad) followed by
33+
3 translations rX rY rZ tx ty tz-->
34+
<transform> 0.00000000 0.00000000 0.00000000 -0.00320000 0.00490000 -0.00200000 </transform>
35+
<!--Whether to show a coordinate frame-->
36+
<show_axes> false </show_axes>
37+
<!--Display Pref. 0:Hide 1:Wire 3:Flat 4:Shaded Can be overriden for
38+
individual geometries-->
39+
<display_preference> 0 </display_preference>
40+
</VisibleObject>
41+
<radius> 0.02300000 </radius>
42+
</WrapSphere>
43+
<WrapCylinder name="wrapcylinder">
44+
<display_preference> 0 </display_preference>
45+
<xyz_body_rotation> 1.63080000 -0.04120000 0.48750000 </xyz_body_rotation>
46+
<translation> 0.00060000 -0.05980000 -0.00250000 </translation>
47+
<active> true </active>
48+
<quadrant> -y </quadrant>
49+
<VisibleObject name="">
50+
<!--Set of geometry files and associated attributes, allow .vtp, .stl,
51+
.obj-->
52+
<GeometrySet name="">
53+
<objects/>
54+
<groups/>
55+
</GeometrySet>
56+
<!--Three scale factors for display purposes: scaleX scaleY scaleZ-->
57+
<scale_factors> 1.00000000 1.00000000 1.00000000 </scale_factors>
58+
<!--transform relative to owner specified as 3 rotations (rad) followed by
59+
3 translations rX rY rZ tx ty tz-->
60+
<transform> 1.63080000 -0.04120000 0.48750000 0.00060000 -0.05980000 -0.00250000 </transform>
61+
<!--Whether to show a coordinate frame-->
62+
<show_axes> false </show_axes>
63+
<!--Display Pref. 0:Hide 1:Wire 3:Flat 4:Shaded Can be overriden for
64+
individual geometries-->
65+
<display_preference> 4 </display_preference>
66+
</VisibleObject>
67+
<radius> 0.00950000 </radius>
68+
<length> 0.10000000 </length>
69+
</WrapCylinder>
70+
<WrapEllipsoid name="wrapellipsoid">
71+
<color> 1 0.5 0 </color>
72+
<display_preference> 2 </display_preference>
73+
<xyz_body_rotation> 1.66070000 -0.01880000 0.03250000 </xyz_body_rotation>
74+
<translation> -0.00080000 -0.05980000 -0.00170000 </translation>
75+
<active> true </active>
76+
<quadrant> -y </quadrant>
77+
<VisibleObject name="">
78+
<!--Set of geometry files and associated attributes, allow .vtp, .stl,
79+
.obj-->
80+
<GeometrySet name="">
81+
<objects/>
82+
<groups/>
83+
</GeometrySet>
84+
<!--Three scale factors for display purposes: scaleX scaleY scaleZ-->
85+
<scale_factors> 1.00000000 1.00000000 1.00000000 </scale_factors>
86+
<!--transform relative to owner specified as 3 rotations (rad) followed by
87+
3 translations rX rY rZ tx ty tz-->
88+
<transform> 1.66070000 -0.01880000 0.03250000 -0.00080000 -0.05980000 -0.00170000 </transform>
89+
<!--Whether to show a coordinate frame-->
90+
<show_axes> false </show_axes>
91+
<!--Display Pref. 0:Hide 1:Wire 3:Flat 4:Shaded Can be overriden for
92+
individual geometries-->
93+
<display_preference> 3 </display_preference>
94+
</VisibleObject>
95+
<dimensions> 0.00200000 0.00700000 0.08000000 </dimensions>
96+
</WrapEllipsoid>
97+
</objects>
98+
<groups/>
99+
</WrapObjectSet>
100+
</Body>
101+
</objects>
102+
<groups/>
103+
</BodySet>
104+
</Model>
105+
</OpenSimDocument>
106+

OpenSim/Tests/Wrapping/testWrapping.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class TestInfo {
4747
};
4848

4949
void testWrapCylinder();
50+
void testWrapObjectUpdateFromXMLNode30515();
5051
void simulate(Model& osimModel, State& si, double initialTime, double finalTime);
5152
void simulateModelWithMusclesNoViz(const string &modelFile, double finalTime, double activation=0.5);
5253
void simulateModelWithPassiveMuscles(const string &modelFile, double finalTime);
@@ -66,6 +67,13 @@ int main()
6667
std::cout << "Exception: " << e.what() << std::endl;
6768
failures.push_back("TestShoulderModel (multiple wrap)"); }
6869

70+
try{
71+
testWrapObjectUpdateFromXMLNode30515();
72+
} catch (const std::exception& e) {
73+
std::cout << "Exception: " << e.what() << std::endl;
74+
failures.push_back("testWrapObjectUpdateFromXMLNode30515");
75+
}
76+
6977
if (!failures.empty()) {
7078
cout << "Done, with failure(s): " << failures << endl;
7179
return 1;
@@ -888,3 +896,59 @@ void simulate(Model& osimModel, State& si, double initialTime, double finalTime)
888896
states.print(osimModel.getName()+"_states_degrees.mot");
889897
} // end of simulate()
890898

899+
// In XMLDocument version 30515, we converted VisibleObject, color and
900+
// display_preference properties to Appearance properties.
901+
void testWrapObjectUpdateFromXMLNode30515() {
902+
XMLDocument doc("testWrapObject_updateFromXMLNode30515.osim");
903+
904+
// Make sure this test is not weakened by the model in the repository being
905+
// updated.
906+
SimTK_TEST(doc.getDocumentVersion() == 20302);
907+
Model model("testWrapObject_updateFromXMLNode30515.osim");
908+
model.finalizeFromProperties();
909+
model.print("testWrapObject_updateFromXMLNode30515_updated.osim");
910+
const auto& wrapObjSet = model.getGround().getWrapObjectSet();
911+
912+
// WrapSphere has:
913+
// display_preference = 1
914+
// color = default
915+
// VisibleObject display_preference = 0
916+
{
917+
const auto& sphere = wrapObjSet.get("wrapsphere");
918+
SimTK_TEST(!sphere.get_Appearance().get_visible());
919+
SimTK_TEST_EQ(sphere.get_Appearance().get_color(), SimTK::Cyan);
920+
SimTK_TEST(sphere.get_Appearance().get_representation() ==
921+
VisualRepresentation::DrawPoints /* == 1 */);
922+
}
923+
924+
// WrapCylinder has:
925+
// display_preference = 0
926+
// color = default
927+
// VisibleObject display_preference = 4
928+
{
929+
const auto& cyl = wrapObjSet.get("wrapcylinder");
930+
// The outer display_preference overrides the inner one.
931+
SimTK_TEST(!cyl.get_Appearance().get_visible());
932+
SimTK_TEST_EQ(cyl.get_Appearance().get_color(), SimTK::Cyan);
933+
SimTK_TEST(cyl.get_Appearance().get_representation() ==
934+
VisualRepresentation::DrawSurface /* == 3 */);
935+
}
936+
937+
// WrapEllipsoid has:
938+
// display_preference = 2
939+
// color = 1 0.5 0
940+
// VisibleObject display_preference = 3
941+
{
942+
const auto& ellipsoid = wrapObjSet.get("wrapellipsoid");
943+
SimTK_TEST(ellipsoid.get_Appearance().get_visible());
944+
SimTK_TEST_EQ(ellipsoid.get_Appearance().get_color(), Vec3(1, 0.5, 0));
945+
// Outer display_preference overrides inner one.
946+
SimTK_TEST(ellipsoid.get_Appearance().get_representation() ==
947+
VisualRepresentation::DrawWireframe /* == 2 */);
948+
}
949+
}
950+
951+
952+
953+
954+

OpenSim/Tools/Test/testVisualization.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,9 @@ void testVisModel(Model& model, const std::string standard_filename)
197197
int same = fromFile.compare(fromModel);
198198

199199
if (visualDebug) {
200-
char c;
201200
std::cout << "press Enter (or Return) to continue" << std::endl;
202-
std::cin >> c;
201+
std::cin.get();
202+
std::cout << "Continuing..." << std::endl;
203203
}
204204

205205
ASSERT(same == 0, __FILE__, __LINE__,
@@ -281,9 +281,9 @@ bool testVisModelAgainstStandard(Model& model, const SimTK::Array_<DecorativeGeo
281281
++i;
282282
}
283283
if (visualDebug) {
284-
char c;
285284
std::cout << "press Enter (or Return) to continue" << std::endl;
286-
std::cin >> c;
285+
std::cin.get();
286+
std::cout << "Continuing..." << std::endl;
287287
}
288288
return true;
289289
}
@@ -476,7 +476,7 @@ void populate_wrapModelPrimitives(SimTK::Array_<DecorativeGeometry>& stdPrimitiv
476476
// that DecorativeCylinder is Y aligned while WrapCylinder is Z aligned
477477
cylTransform.updR().setRotationFromAngleAboutX(SimTK_PI / 2);
478478
stdPrimitives.push_back(
479-
DecorativeCylinder(.025, .05).setBodyId(0).setColor(SimTK::Cyan)
479+
DecorativeCylinder(.025, .05).setBodyId(0).setColor(Vec3(0, 0.2, 0.8))
480480
.setIndexOnBody(-1).setScale(1).setOpacity(0.5)
481481
.setRepresentation(SimTK::DecorativeGeometry::DrawSurface)
482482
.setTransform(Transform(cylTransform.R(), Vec3({ .01, -.4, .01 }))));
@@ -491,17 +491,17 @@ void populate_wrapModelPrimitives(SimTK::Array_<DecorativeGeometry>& stdPrimitiv
491491
.setRepresentation(SimTK::DecorativeGeometry::DrawSurface)
492492
.setTransform(Transform(cylTransform.R(), Vec3({ .05, -.25, 0 }))));
493493
stdPrimitives.push_back(
494-
DecorativeSphere(.055).setBodyId(0).setColor(SimTK::Cyan)
494+
DecorativeSphere(.055).setBodyId(0).setColor(Vec3(0, 0.2, 0.8))
495495
.setIndexOnBody(-1).setScale(1).setOpacity(0.5)
496496
.setRepresentation(SimTK::DecorativeGeometry::DrawSurface)
497497
.setTransform(Vec3({ .01, -.3, .01 })));
498498
stdPrimitives.push_back(
499-
DecorativeEllipsoid(Vec3(.1, .05, .15)).setBodyId(0).setColor(SimTK::Cyan)
499+
DecorativeEllipsoid(Vec3(.1, .05, .15)).setBodyId(0).setColor(Vec3(0, 0.2, 0.8))
500500
.setIndexOnBody(-1).setScale(1).setOpacity(0.5)
501501
.setRepresentation(SimTK::DecorativeGeometry::DrawSurface)
502502
.setTransform(Vec3({ -.01, -.5, .0 })));
503503
stdPrimitives.push_back(
504-
DecorativeTorus(.08, .035).setBodyId(0).setColor(SimTK::Cyan)
504+
DecorativeTorus(.08, .035).setBodyId(0).setColor(Vec3(0, 0.2, 0.8))
505505
.setIndexOnBody(-1).setScale(1).setOpacity(0.5)
506506
.setRepresentation(SimTK::DecorativeGeometry::DrawSurface)
507507
.setTransform(Vec3({ -.02, -.6, .01 })));

0 commit comments

Comments
 (0)