Skip to content

Commit ddcc9bd

Browse files
committed
Constructing Scholz2015GeometryPaths from a list of path points and obstacles
1 parent c574766 commit ddcc9bd

File tree

7 files changed

+490
-572
lines changed

7 files changed

+490
-572
lines changed

Bindings/Java/Matlab/examples/Wrapping/exampleScholz2015GeometryPath.m

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
% This example demonstrates the basic elements of creating a geometry-based
2525
% path using the Scholz2015GeometryPath class. The path is used to define the
2626
% length and speed of a PathSpring, which applies forces to the bodies of a
27-
% double pendulum model. The path wraps around a cylindrical obstacle and
28-
% contains a via point.
27+
% double pendulum model. The path contains three path points and wraps around
28+
% a cylindrical obstacle.
2929

3030
function exampleScholz2015GeometryPath()
3131

@@ -37,33 +37,50 @@ function exampleScholz2015GeometryPath()
3737
% Create a PathSpring with a Scholz2015GeometryPath.
3838
spring = PathSpring();
3939
spring.setName('path_spring');
40-
spring.setRestingLength(0.5);
41-
spring.setDissipation(0.5);
42-
spring.setStiffness(25.0);
40+
spring.setRestingLength(0.25);
41+
spring.setDissipation(0.75);
42+
spring.setStiffness(10.0);
4343
spring.set_path(Scholz2015GeometryPath());
4444
model.addComponent(spring);
4545

46-
% Configure the Scholz2015GeometryPath.
46+
% Configure the Scholz2015GeometryPath. We will update the path after
47+
% adding it to the PathSpring, so that the Socket connections in each
48+
% Station (i.e., path point) remain valid.
4749
path = Scholz2015GeometryPath.safeDownCast(spring.updPath());
4850
path.setName('path');
4951

50-
% The origin and insertion points are stored using the 'origin' and
51-
% 'insertion' properties of Scholz2015GeometryPath, which are of type
52-
% Station. We must update these properties after the Scholz2015GeometryPath
53-
% has been added to the PathSpring, so that the Socket connections in each
54-
% Station remain valid.
55-
path.setOrigin(model.getGround(), Vec3(0.05, 0.05, 0.));
56-
path.setInsertion(model.getBodySet().get('b1'), Vec3(-0.25, 0.1, 0.));
52+
% Add a path point connected to ground. Since this is the first path point,
53+
% it defines the origin of the path.
54+
path.addPathPoint(model.getGround(), Vec3(0.05, 0.05, 0.));
5755

58-
% Add a ContactCylinder wrapping obstacle to the path.
59-
obstacle = ContactCylinder(0.1, ...
60-
Vec3(-0.5, 0.1, 0.), Vec3(0), ...
56+
% Add a second path point, creating a straight line segment between the
57+
% ground and body "b0".
58+
path.addPathPoint(model.getBodySet().get('b0'), Vec3(-0.5, 0.1, 0.));
59+
60+
% Create a ContactCylinder to use as a wrapping obstacle to the path. The
61+
% cylinder has radius 0.15 m and is attached to body "b0".
62+
obstacle = ContactCylinder(0.15, ...
63+
Vec3(-0.2, 0.2, 0.), Vec3(0), ...
6164
model.getBodySet().get('b0'));
6265
model.addComponent(obstacle);
63-
path.addObstacle(obstacle, Vec3(0., 0.1, 0.));
6466

65-
% Add a via point to the path.
66-
path.addViaPoint(model.getBodySet().get('b1'), Vec3(-0.75, 0.1, 0.));
67+
% Before we add the obstacle to the path, we must provide a "contact hint"
68+
% to initialize the wrapping solver. The contact hint is a point on the
69+
% surface of the obstacle, expressed in the obstacle's frame. The point
70+
% does not have to lie on the contact geometry's surface, nor does it have
71+
% to belong to a valid cable path. The choice of the contact hint will
72+
% determine which side of the cylinder the path wraps around.
73+
contact_hint = Vec3(0., 0.15, 0.);
74+
path.addObstacle(obstacle, contact_hint);
75+
76+
% At least one path point must follow an obstacle (or list of obstacles)
77+
% in a Scholz2015GeometryPath. Since this is the last path point we are
78+
% adding, it defines the insertion of the path.
79+
path.addPathPoint(model.getBodySet().get('b1'), Vec3(-0.5, 0.1, 0.));
80+
81+
% Use the "minimum length" algorithm, which solves for a path that
82+
% minimizes the total length of the path.
83+
path.setAlgorithm("MinimumLength");
6784

6885
% Initialize the system.
6986
state = model.initSystem();

Bindings/Python/examples/Wrapping/exampleScholz2015GeometryPath.py

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
# This example demonstrates the basic elements of creating a geometry-based
2525
# path using the Scholz2015GeometryPath class. The path is used to define the
2626
# length and speed of a PathSpring, which applies forces to the bodies of a
27-
# double pendulum model. The path wraps around a cylindrical obstacle and
28-
# contains a via point.
27+
# double pendulum model. The path contains three path points and wraps around
28+
# a cylindrical obstacle.
2929

3030
import opensim as osim
3131

@@ -35,33 +35,50 @@
3535
# Create a PathSpring with a Scholz2015GeometryPath.
3636
spring = osim.PathSpring()
3737
spring.setName('path_spring')
38-
spring.setRestingLength(0.5)
39-
spring.setDissipation(0.5)
40-
spring.setStiffness(25.0)
38+
spring.setRestingLength(0.25)
39+
spring.setDissipation(0.75)
40+
spring.setStiffness(10.0)
4141
spring.set_path(osim.Scholz2015GeometryPath())
4242
model.addComponent(spring)
4343

44-
# Configure the Scholz2015GeometryPath.
44+
# Configure the Scholz2015GeometryPath. We will update the path after
45+
# adding it to the PathSpring, so that the Socket connections in each
46+
# Station (i.e., path point) remain valid.
4547
path = osim.Scholz2015GeometryPath.safeDownCast(spring.updPath())
4648
path.setName('path')
4749

48-
# The origin and insertion points are stored using the 'origin' and
49-
# 'insertion' properties of Scholz2015GeometryPath, which are of type
50-
# Station. We must update these properties after the Scholz2015GeometryPath
51-
# has been added to the PathSpring, so that the Socket connections in each
52-
# Station remain valid.
53-
path.setOrigin(model.getGround(), osim.Vec3(0.05, 0.05, 0.))
54-
path.setInsertion(model.getBodySet().get('b1'), osim.Vec3(-0.25, 0.1, 0.))
50+
# Add a path point connected to ground. Since this is the first path point,
51+
# it defines the origin of the path.
52+
path.addPathPoint(model.getGround(), osim.Vec3(0.05, 0.05, 0.))
5553

56-
# Add a ContactCylinder wrapping obstacle to the path.
57-
obstacle = osim.ContactCylinder(0.1,
58-
osim.Vec3(-0.5, 0.1, 0.), osim.Vec3(0),
54+
# Add a second path point, creating a straight line segment between the
55+
# ground and body "b0".
56+
path.addPathPoint(model.getBodySet().get('b0'), osim.Vec3(-0.5, 0.1, 0.))
57+
58+
# Create a ContactCylinder to use as a wrapping obstacle to the path. The
59+
# cylinder has radius 0.15 m and is attached to body "b0".
60+
obstacle = osim.ContactCylinder(0.15,
61+
osim.Vec3(-0.2, 0.2, 0.), osim.Vec3(0),
5962
model.getBodySet().get('b0'))
6063
model.addComponent(obstacle)
61-
path.addObstacle(obstacle, osim.Vec3(0., 0.1, 0.))
6264

63-
# Add a via point to the path.
64-
path.addViaPoint(model.getBodySet().get('b1'), osim.Vec3(-0.75, 0.1, 0.))
65+
# Before we add the obstacle to the path, we must provide a "contact hint"
66+
# to initialize the wrapping solver. The contact hint is a point on the
67+
# surface of the obstacle, expressed in the obstacle's frame. The point
68+
# does not have to lie on the contact geometry's surface, nor does it have
69+
# to belong to a valid cable path. The choice of the contact hint will
70+
# determine which side of the cylinder the path wraps around.
71+
contact_hint = osim.Vec3(0., 0.15, 0.)
72+
path.addObstacle(obstacle, contact_hint)
73+
74+
# At least one path point must follow an obstacle (or list of obstacles)
75+
# in a Scholz2015GeometryPath. Since this is the last path point we are
76+
# adding, it defines the insertion of the path.
77+
path.addPathPoint(model.getBodySet().get('b1'), osim.Vec3(-0.5, 0.1, 0.))
78+
79+
# Use the "minimum length" algorithm, which solves for a path that
80+
# minimizes the total length of the path.
81+
path.setAlgorithm('MinimumLength')
6582

6683
# Initialize the system.
6784
state = model.initSystem()

OpenSim/Examples/Wrapping/exampleScholz2015GeometryPath.cpp

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
/// This example demonstrates the basic elements of creating a geometry-based
2525
/// path using the Scholz2015GeometryPath class. The path is used to define the
2626
/// length and speed of a PathSpring, which applies forces to the bodies of a
27-
/// double pendulum model. The path wraps around a cylindrical obstacle and
28-
/// contains a via point.
27+
/// double pendulum model. The path contains three path points and wraps around
28+
/// a cylindrical obstacle.
2929

3030
#include <OpenSim/OpenSim.h>
3131

@@ -39,35 +39,52 @@ int main() {
3939
// Create a PathSpring with a Scholz2015GeometryPath.
4040
auto* spring = new PathSpring();
4141
spring->setName("path_spring");
42-
spring->setRestingLength(0.5);
43-
spring->setDissipation(0.5);
44-
spring->setStiffness(25.0);
42+
spring->setRestingLength(0.25);
43+
spring->setDissipation(0.75);
44+
spring->setStiffness(10.0);
4545
spring->set_path(Scholz2015GeometryPath());
4646
model.addComponent(spring);
4747

48-
// Configure the Scholz2015GeometryPath.
48+
// Configure the Scholz2015GeometryPath. We will update the path after
49+
// adding it to the PathSpring, so that the Socket connections in each
50+
// Station (i.e., path point) remain valid.
4951
Scholz2015GeometryPath& path = spring->updPath<Scholz2015GeometryPath>();
5052
path.setName("path");
5153

52-
// The origin and insertion points are stored using the 'origin' and
53-
// 'insertion' properties of Scholz2015GeometryPath, which are of type
54-
// Station. We must update these properties after the Scholz2015GeometryPath
55-
// has been added to the PathSpring, so that the Socket connections in each
56-
// Station remain valid.
57-
path.setOrigin(model.getGround(), SimTK::Vec3(0.05, 0.05, 0.));
58-
path.setInsertion(model.getComponent<Body>("/bodyset/b1"),
59-
SimTK::Vec3(-0.25, 0.1, 0.));
54+
// Add a path point connected to ground. Since this is the first path point,
55+
// it defines the origin of the path.
56+
path.addPathPoint(model.getGround(), SimTK::Vec3(0.05, 0.05, 0.));
6057

61-
// Add a ContactCylinder wrapping obstacle to the path.
62-
auto* obstacle = new ContactCylinder(0.1,
63-
SimTK::Vec3(-0.5, 0.1, 0.), SimTK::Vec3(0),
58+
// Add a second path point, creating a straight line segment between the
59+
// ground and body "b0".
60+
path.addPathPoint(model.getComponent<Body>("/bodyset/b0"),
61+
SimTK::Vec3(-0.5, 0.1, 0.));
62+
63+
// Create a ContactCylinder to use as a wrapping obstacle to the path. The
64+
// cylinder has radius 0.15 m and is attached to body "b0".
65+
auto* obstacle = new ContactCylinder(0.15,
66+
SimTK::Vec3(-0.2, 0.2, 0.), SimTK::Vec3(0),
6467
model.getComponent<Body>("/bodyset/b0"));
6568
model.addComponent(obstacle);
66-
path.addObstacle(*obstacle, SimTK::Vec3(0., 0.1, 0.));
6769

68-
// Add a via point to the path.
69-
path.addViaPoint(model.getComponent<Body>("/bodyset/b1"),
70-
SimTK::Vec3(-0.75, 0.1, 0.));
70+
// Before we add the obstacle to the path, we must provide a "contact hint"
71+
// to initialize the wrapping solver. The contact hint is a point on the
72+
// surface of the obstacle, expressed in the obstacle's frame. The point
73+
// does not have to lie on the contact geometry's surface, nor does it have
74+
// to belong to a valid cable path. The choice of the contact hint will
75+
// determine which side of the cylinder the path wraps around.
76+
SimTK::Vec3 contact_hint(0., 0.15, 0.);
77+
path.addObstacle(*obstacle, contact_hint);
78+
79+
// At least one path point must follow an obstacle (or list of obstacles)
80+
// in a Scholz2015GeometryPath. Since this is the last path point we are
81+
// adding, it defines the insertion of the path.
82+
path.addPathPoint(model.getComponent<Body>("/bodyset/b1"),
83+
SimTK::Vec3(-0.5, 0.1, 0.));
84+
85+
// Use the "minimum length" algorithm, which solves for a path that
86+
// minimizes the total length of the path.
87+
path.setAlgorithm("MinimumLength");
7188

7289
// Initialize the system.
7390
SimTK::State state = model.initSystem();

0 commit comments

Comments
 (0)