first commit

This commit is contained in:
2024-06-10 12:48:14 +03:00
commit d54c9805b3
1398 changed files with 739400 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
AM_CPPFLAGS = -I$(top_srcdir)/include \
-I$(top_builddir)/include \
-DDRAWSTUFF_TEXTURE_PATH="\"$(abs_top_srcdir)/drawstuff/textures\""
if X11
AM_LDFLAGS = $(X_PRE_LIBS) $(X_LIBS) $(X_EXTRA_LIBS)
endif
# On Windows, GL_LIBS must go after libdrawstuff.la.
LDADD = $(top_builddir)/drawstuff/src/libdrawstuff.la \
$(top_builddir)/ode/src/libode.la @GL_LIBS@
noinst_HEADERS = basket_geom.h bunny_geom.h convex_bunny_geom.h convex_prism.h \
icosahedron_geom.h halton235_geom.h texturepath.h world_geom3.h
AM_DEFAULT_SOURCE_EXT = .cpp
noinst_PROGRAMS = \
demo_boxstack \
demo_buggy \
demo_cards \
demo_chain1 \
demo_chain2 \
demo_collision \
demo_convex \
demo_crash \
demo_cylvssphere \
demo_dball \
demo_dhinge \
demo_transmission \
demo_feedback \
demo_friction \
demo_gyroscopic \
demo_gyro2 \
demo_heightfield \
demo_hinge \
demo_I \
demo_jointPR \
demo_joints \
demo_jointPU \
demo_kinematic \
demo_motion \
demo_motor \
demo_ode \
demo_piston \
demo_plane2d \
demo_rfriction \
demo_slider \
demo_space \
demo_space_stress \
demo_step \
demo_tracks
demo_chain1_SOURCES = demo_chain1.c
demo_chain1_LDADD = $(LDADD) -lstdc++
if TRIMESH
noinst_PROGRAMS += \
demo_basket \
demo_cyl \
demo_moving_trimesh \
demo_moving_convex \
demo_trimesh
AM_CPPFLAGS += -DdTRIMESH_ENABLED
endif
if WIN32
resources.o: $(top_srcdir)/drawstuff/src/resources.rc $(top_srcdir)/drawstuff/src/resource.h
@WINDRES@ $(top_srcdir)/drawstuff/src/resources.rc -o resources.o
LDADD += resources.o
endif

1133
thirdparty/ode-0.16.5/ode/demo/Makefile.in vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,468 @@
const unsigned int convexBunnyPlaneCount = 176;
dReal convexBunnyPlanes[] =
{
0.986167, -0.0612533, -0.154021, 0.399481,
0.982735, -0.0691036, -0.171628, 0.409884,
-0.984387, -0.0582774, -0.166089, 0.403079,
0.985044, -0.172279, 0.00302105, 0.437531,
0.976915, -0.184361, 0.107929, 0.465334,
0.951478, -0.281619, 0.124019, 0.475223,
0.798136, -0.502214, 0.332805, 0.535555,
0.949728, -0.211128, -0.231176, 0.528156,
-0.000894561, -0.995066, -0.0992088, 0.80299,
-0.000896015, -0.995066, -0.0992131, 0.802991,
-0.0035709, -0.935822, 0.352454, 0.618504,
-0.291551, -0.828515, 0.478081, 0.681579,
-0.978715, -0.181408, 0.0959605, 0.468907,
-0.985523, -0.169302, -0.00904739, 0.441129,
-0.953768, -0.278749, 0.11236, 0.478704,
0.372745, -0.827499, 0.419888, 0.630174,
0.976911, -0.18316, 0.109991, 0.466086,
0.817827, -0.387738, 0.425227, 0.569153,
-0.978732, -0.180211, 0.0980152, 0.469656,
0.662794, -0.0277654, 0.748287, 0.803459,
0.00359857, -0.660581, -0.750746, 0.877267,
0.00359952, -0.660579, -0.750748, 0.877266,
-0.947456, -0.208272, -0.242797, 0.531628,
-0.980764, -0.0661375, -0.18365, 0.413468,
-0.940835, -0.0698657, -0.331585, 0.494827,
0.983751, 0.0529367, -0.171556, 0.403533,
0.981839, 0.0996302, -0.16145, 0.410144,
0.977938, 0.0857834, -0.190468, 0.411823,
0.959636, 0.106068, -0.260476, 0.44898,
0.85334, -0.0495414, -0.518996, 0.60489,
-0.803667, -0.499793, 0.322995, 0.538478,
-0.689742, -0.615484, 0.381361, 0.574754,
-0.380353, -0.826364, 0.415277, 0.63155,
-0.39985, -0.817283, 0.414933, 0.630682,
-0.380309, -0.826285, 0.415473, 0.631677,
-0.981411, 0.0559147, -0.183592, 0.407121,
-0.979526, 0.101914, -0.173615, 0.413635,
-0.975381, 0.0881975, -0.202119, 0.415257,
0.988445, 0.140182, 0.0576755, 0.485174,
0.876515, 0.0408992, 0.479634, 0.620093,
0.848907, -0.0996824, 0.519057, 0.631268,
0.895754, -0.195088, 0.399457, 0.563346,
0.861448, -0.256989, 0.438023, 0.574909,
0.775672, -0.447481, 0.445076, 0.586422,
0.683157, -0.617557, 0.389768, 0.572247,
0.391755, -0.818722, 0.419789, 0.629264,
0.28317, -0.829384, 0.481599, 0.680529,
0.3727, -0.827422, 0.420079, 0.630298,
-0.824143, -0.385255, 0.415171, 0.57215,
-0.782413, -0.445128, 0.435536, 0.589267,
0.00152876, 0.999994, -0.00308275, 0.665646,
0.00242466, 0.999989, -0.0038994, 0.665879,
-0.979892, 0.121321, -0.158406, 0.420287,
0.767537, -0.190214, -0.612132, 0.695479,
0.372649, -0.42747, -0.823652, 0.869878,
0.537245, -0.335515, -0.77382, 0.82472,
0.0263648, -0.598975, -0.800334, 0.873623,
0.00393345, -0.60959, -0.792707, 0.869865,
-0.0183706, -0.598907, -0.800608, 0.873704,
0.00875728, 0.676014, -0.736836, 0.825597,
0.852333, -0.0355955, -0.521786, 0.607886,
0.392036, 0.534934, -0.748434, 0.818042,
0.847696, -0.122973, -0.516033, 0.615814,
0.884763, -0.0760716, -0.45979, 0.565893,
0.9446, -0.0727144, -0.320069, 0.491401,
0.904971, -0.0675211, -0.420081, 0.541673,
-0.899959, -0.0647928, -0.431134, 0.544968,
-0.955972, 0.108494, -0.272667, 0.452769,
-0.363823, -0.426358, -0.828161, 0.871222,
-0.528689, -0.333936, -0.780368, 0.826685,
0.982068, 0.118277, -0.146811, 0.416542,
0.98951, 0.144455, 0.00164104, 0.468616,
0.50797, -0.0708041, 0.85846, 0.883126,
0.748614, -0.431275, 0.503565, 0.634026,
0.214863, -0.405791, 0.888351, 0.94048,
-0.901162, -0.192379, 0.388455, 0.566627,
-0.867521, -0.254376, 0.427435, 0.578065,
-0.226957, -0.405135, 0.885639, 0.941284,
-0.756029, -0.429007, 0.494341, 0.636765,
-0.00629553, -0.188362, 0.982079, 0.968197,
0.0165684, 0.999846, -0.00581961, 0.670373,
0.00313267, 0.999987, -0.00405124, 0.666103,
0.545069, 0.472158, -0.692796, 0.780052,
0.932011, 0.148856, -0.330451, 0.498417,
0.844043, 0.227673, -0.485547, 0.599903,
-0.019033, 0.999801, -0.00590978, 0.672252,
-0.959662, 0.239262, -0.147656, 0.488538,
0.00151234, 0.999999, -0.000399466, 0.665855,
-0.988649, 0.143168, 0.0455675, 0.488784,
-0.989015, 0.147444, -0.01048, 0.472227,
-0.972439, 0.232727, -0.01415, 0.518344,
0.587681, -0.160147, -0.793085, 0.823999,
0.640479, -0.269179, -0.719256, 0.778142,
0.541109, -0.332896, -0.772257, 0.823226,
0.546185, -0.14771, -0.824538, 0.84854,
0.528519, -0.026044, -0.848522, 0.873136,
0.447231, -0.0756684, -0.891212, 0.903953,
0.490619, -0.0795123, -0.867739, 0.884255,
0.279393, 0.264257, -0.923097, 0.950045,
0.374653, 0.39486, -0.83888, 0.886593,
0.00050174, 0.999994, -0.00331563, 0.665976,
-0.0103777, 0.999934, -0.00487936, 0.669494,
-0.927571, 0.150741, -0.341889, 0.501807,
-0.267268, 0.265084, -0.926444, 0.951043,
-0.845984, -0.0330207, -0.532184, 0.610986,
-0.518165, -0.0244575, -0.854931, 0.875047,
-0.83753, 0.228953, -0.496108, 0.603116,
-0.535666, 0.472122, -0.700116, 0.78259,
-0.381083, 0.534649, -0.754272, 0.820328,
-0.363157, 0.395975, -0.843398, 0.88794,
-0.326829, -0.256634, -0.909572, 0.922946,
0.394875, -0.128601, -0.90969, 0.920236,
0.337169, -0.257642, -0.905504, 0.921733,
0.398433, -0.193767, -0.896496, 0.910015,
-0.536477, -0.146072, -0.831177, 0.850523,
-0.436512, -0.0743406, -0.896622, 0.905564,
-0.480187, -0.0780522, -0.873687, 0.886029,
-0.384093, -0.127432, -0.914458, 0.921656,
-0.388009, -0.192572, -0.901313, 0.911451,
0.977045, 0.15796, 0.14294, 0.521934,
0.930035, 0.231515, 0.28537, 0.600301,
-0.855499, -0.0971121, 0.508616, 0.634376,
-0.875419, 0.136849, 0.463589, 0.62897,
-0.882196, 0.0435387, 0.468864, 0.623303,
0.0204398, -0.0238739, 0.999506, 0.958419,
-0.0062197, -0.0777937, 0.99695, 0.962769,
0.907123, 0.250746, 0.338015, 0.623205,
0.902358, 0.173321, 0.394601, 0.607696,
0.870085, 0.134211, 0.474278, 0.625782,
0.0015108, 0.999999, 6.34978e-06, 0.665945,
0.00150567, 0.999999, 0.000568537, 0.666143,
0.00150738, 0.999999, 0.000565012, 0.666141,
-0.963954, 0.266039, -0.00405118, 0.539571,
0.0015136, 0.999999, -0.000393102, 0.665856,
0.00151117, 0.999999, 4.32104e-06, 0.665944,
0.0272711, 0.999604, -0.00696439, 0.673709,
0.962047, 0.236383, -0.136341, 0.484917,
0.973236, 0.229796, -0.00223071, 0.514797,
0.964728, 0.263133, 0.00776342, 0.536054,
-0.906596, 0.176056, 0.383521, 0.610999,
-0.978237, 0.160918, 0.130987, 0.525513,
-0.910434, 0.253486, 0.326887, 0.626522,
-0.932759, 0.234321, 0.27396, 0.603697,
0.800621, -0.0921333, -0.592045, 0.665278,
0.679569, -0.15358, -0.717356, 0.765121,
0.684928, -0.199829, -0.700672, 0.756959,
-0.532604, -0.33128, -0.778837, 0.82519,
-0.578395, -0.158384, -0.800234, 0.826134,
-0.671209, -0.151537, -0.725613, 0.767576,
-0.00530287, 0.323551, 0.946196, 0.94547,
-0.719766, 0.229227, 0.655281, 0.774388,
-0.604194, 0.29171, 0.741522, 0.841564,
-0.544989, 0.302925, 0.781808, 0.866398,
-0.518662, -0.0692529, 0.85217, 0.884999,
-0.671987, -0.0257512, 0.740115, 0.805898,
-0.00613626, -0.00823685, 0.999947, 0.957141,
-0.032747, -0.0237908, 0.99918, 0.958516,
-0.00530611, 0.323546, 0.946198, 0.945471,
-0.545061, 0.302657, 0.781861, 0.866377,
-0.639902, 0.23832, 0.730568, 0.823722,
0.00149706, 0.999997, 0.00193434, 0.667038,
0.00149731, 0.999997, 0.00193252, 0.667037,
-0.0048341, 0.44008, 0.897946, 0.936327,
-0.00483143, 0.440078, 0.897947, 0.936327,
-0.632454, -0.267241, -0.727039, 0.780455,
-0.67691, -0.197765, -0.709, 0.759436,
-0.841667, -0.120432, -0.526396, 0.618913,
-0.760706, -0.187792, -0.621337, 0.698143,
-0.87929, -0.0734062, -0.470597, 0.569116,
-0.847068, -0.0469762, -0.529405, 0.607991,
-0.793572, -0.0897399, -0.601823, 0.668201,
0.536355, 0.301024, 0.788485, 0.864403,
0.536284, 0.301291, 0.788431, 0.864424,
0.595945, 0.289897, 0.748872, 0.839373,
0.631626, 0.236397, 0.738353, 0.8214,
0.712378, 0.227061, 0.664049, 0.771772,
};
const unsigned int convexBunnyPointCount = 105;
dReal convexBunnyPoints[] =
{
-0.459488, -0.093017, -0.311341,
0.466635, -0.094416, -0.305669,
-0.309239, 0.776868, 0.304726,
-0.004458, -0.042526, 1.01567,
8.40779e-45, 3.00321e-39, 2.8026e-44,
0.007957, 0.282241, -0.93168,
0.204445, -0.66438, 0.513353,
-0.303961, 0.054199, 0.625921,
0.265619, 0.756464, 0.504187,
-0.402162, 0.133528, -0.443247,
8.40779e-45, 3.00321e-39, 2.8026e-44,
-0.266772, 0.64233, 0.602061,
8.40779e-45, 3.00321e-39, 2.8026e-44,
8.40779e-45, 3.00321e-39, 2.8026e-44,
0.411612, 0.132299, -0.438264,
0.31148, 0.775931, 0.308527,
0.300086, 0.053287, 0.62962,
-0.414624, 0.164083, -0.278254,
-0.248382, 0.255825, -0.627493,
-0.216201, -0.126776, -0.886936,
0.267564, -0.666174, -0.654834,
-0.135892, -0.03552, 0.945455,
-0.265837, 0.757267, 0.500933,
-0.003873, 0.161605, 0.970499,
8.40779e-45, 3.00321e-39, 2.8026e-44,
-0.282599, -0.663393, 0.412411,
0.007237, 0.361687, -0.794439,
0.093627, 0.258494, -0.920589,
0.422146, 0.162819, -0.27313,
0.279163, -0.664604, 0.417328,
0.263086, 0.512567, 0.637832,
-0.099875, 0.310931, -0.799381,
-0.446838, -0.118517, -0.466159,
-0.168842, 0.102387, -0.920381,
0.455805, -0.119881, -0.460632,
0.337743, -0.666396, -0.074503,
-0.134547, -0.119852, -0.959004,
-0.183807, 0.19697, 0.84448,
0.264969, 0.641527, 0.605317,
-0.209063, -0.663393, 0.509344,
-0.364126, -0.200299, 0.202388,
-0.253475, -0.081797, 0.756541,
0.260471, 0.255056, -0.624378,
0.114248, 0.310608, -0.79807,
0.364663, -0.201399, 0.20685,
0.127847, -0.035919, 0.94707,
8.40779e-45, 3.00321e-39, 2.8026e-44,
-0.381071, -0.629723, -0.350777,
-0.339884, -0.04115, -0.668211,
-0.077913, 0.258753, -0.92164,
0.184061, 0.101854, -0.91822,
-0.335166, -0.66538, -0.078623,
0.386561, -0.625221, -0.21687,
8.40779e-45, 3.00321e-39, 2.8026e-44,
-0.241585, 0.527592, 0.669296,
-0.086969, 0.133224, 0.947633,
-0.003127, 0.28407, 0.87887,
-0.004433, -0.146642, 0.985872,
8.40779e-45, 3.00321e-39, 2.8026e-44,
-0.138444, -0.10425, 0.945975,
-0.265676, 0.513366, 0.634594,
8.40779e-45, 3.00321e-39, 2.8026e-44,
0.247593, -0.082554, 0.75961,
0.07941, 0.132973, 0.948652,
0.238615, 0.526867, 0.672237,
8.40779e-45, 3.00321e-39, 2.8026e-44,
8.40779e-45, 3.00321e-39, 2.8026e-44,
-0.382112, -0.62406, -0.221577,
-0.104072, 0.177278, -0.95253,
0.351567, -0.042194, -0.663976,
0.138234, -0.293905, -0.897958,
0.119916, 0.17694, -0.951159,
-0.371322, -0.665382, -0.35362,
-0.263384, -0.663396, 0.466604,
0.376722, -0.666513, -0.219833,
0.387086, -0.630883, -0.346073,
-0.125544, 0.140012, 0.917678,
-0.070612, 0.036849, 0.975733,
-0.083497, -0.084934, 0.979607,
0.259286, -0.664547, 0.471281,
8.40779e-45, 3.00321e-39, 2.8026e-44,
0.074888, -0.085173, 0.980577,
0.152305, 0.125256, 0.890786,
0.130184, -0.104656, 0.94762,
-0.004249, 0.046042, 1.00324,
0.062419, 0.036648, 0.976547,
8.40779e-45, 3.00321e-39, 2.8026e-44,
-0.392666, -0.488581, -0.427494,
0.230315, -0.12745, -0.884202,
8.40779e-45, 3.00321e-39, 2.8026e-44,
0.193434, -0.665946, -0.715325,
0.007865, 0.122104, -0.956137,
8.40779e-45, 3.00321e-39, 2.8026e-44,
-0.257884, -0.665381, -0.658052,
0.377265, -0.666513, -0.349036,
-0.372362, -0.665381, -0.22442,
0.400045, -0.489778, -0.42264,
-0.159174, 0.125726, 0.888878,
0.118369, 0.139643, 0.919173,
-0.124463, -0.293508, -0.899566,
0.21172, -0.302754, -0.843303,
0.149571, -0.120281, -0.957264,
-0.183019, -0.665378, -0.71763,
0.177696, 0.196424, 0.846693,
-0.198638, -0.302135, -0.845816,
};
unsigned int convexBunnyPolygons[] =
{
3, 7, 2, 0,
3, 2, 7, 11,
3, 1, 15, 16,
3, 0, 2, 17,
3, 17, 9, 0,
3, 2, 9, 17,
3, 18, 9, 2,
3, 2, 11, 22,
3, 22, 15, 2,
3, 8, 15, 22,
3, 2, 15, 26,
3, 5, 26, 27,
3, 1, 14, 28,
3, 28, 15, 1,
3, 14, 15, 28,
3, 2, 26, 31,
3, 0, 9, 32,
3, 9, 18, 33,
3, 34, 14, 1,
3, 19, 33, 36,
3, 8, 22, 38,
3, 38, 22, 11,
3, 38, 15, 8,
3, 38, 16, 15,
3, 38, 30, 16,
3, 40, 7, 0,
3, 0, 25, 40,
3, 40, 25, 7,
3, 7, 25, 41,
3, 21, 37, 41,
3, 42, 15, 14,
3, 42, 27, 15,
3, 43, 26, 15,
3, 15, 27, 43,
3, 43, 27, 26,
3, 1, 16, 44,
3, 44, 29, 1,
3, 16, 29, 44,
3, 0, 32, 47,
3, 19, 32, 48,
3, 48, 33, 19,
3, 48, 32, 9,
3, 9, 33, 48,
3, 49, 33, 18,
3, 49, 18, 2,
3, 2, 31, 49,
3, 49, 26, 5,
3, 49, 31, 26,
3, 50, 42, 14,
3, 27, 42, 50,
3, 51, 35, 6,
3, 6, 39, 51,
3, 1, 29, 52,
3, 11, 37, 54,
3, 55, 23, 11,
3, 11, 54, 55,
3, 11, 23, 56,
3, 56, 38, 11,
3, 23, 38, 56,
3, 57, 39, 6,
3, 21, 41, 59,
3, 39, 57, 59,
3, 60, 37, 11,
3, 60, 41, 37,
3, 60, 11, 7,
3, 7, 41, 60,
3, 16, 30, 62,
3, 62, 29, 16,
3, 63, 38, 23,
3, 38, 63, 64,
3, 67, 25, 0,
3, 0, 47, 67,
3, 68, 36, 33,
3, 33, 49, 68,
3, 68, 49, 5,
3, 14, 34, 69,
3, 69, 50, 14,
3, 5, 27, 71,
3, 27, 50, 71,
3, 71, 68, 5,
3, 25, 51, 73,
3, 73, 51, 39,
3, 39, 59, 73,
3, 73, 41, 25,
3, 73, 59, 41,
3, 29, 35, 74,
3, 74, 52, 29,
3, 35, 51, 74,
3, 75, 34, 1,
3, 1, 52, 75,
3, 52, 74, 75,
3, 21, 55, 76,
3, 76, 54, 37,
3, 76, 55, 54,
3, 77, 55, 21,
3, 21, 59, 78,
3, 3, 77, 78,
3, 78, 77, 21,
3, 78, 57, 3,
3, 78, 59, 57,
3, 6, 35, 79,
3, 79, 35, 29,
3, 29, 62, 79,
3, 3, 57, 81,
3, 83, 62, 45,
3, 45, 81, 83,
3, 83, 79, 62,
3, 6, 79, 83,
3, 83, 57, 6,
3, 83, 81, 57,
3, 84, 63, 23,
3, 84, 77, 3,
3, 23, 55, 84,
3, 55, 77, 84,
3, 45, 63, 85,
3, 3, 81, 85,
3, 85, 81, 45,
3, 85, 84, 3,
3, 63, 84, 85,
3, 87, 47, 32,
3, 87, 72, 47,
3, 50, 69, 88,
3, 88, 34, 20,
3, 88, 69, 34,
3, 36, 68, 91,
3, 68, 71, 91,
3, 72, 87, 93,
3, 93, 87, 32,
3, 93, 32, 19,
3, 94, 74, 72,
3, 94, 93, 20,
3, 72, 93, 94,
3, 94, 75, 74,
3, 95, 74, 51,
3, 72, 74, 95,
3, 95, 51, 25,
3, 25, 67, 95,
3, 95, 67, 47,
3, 47, 72, 95,
3, 20, 34, 96,
3, 34, 75, 96,
3, 96, 94, 20,
3, 75, 94, 96,
3, 97, 37, 21,
3, 21, 76, 97,
3, 97, 76, 37,
3, 98, 64, 63,
3, 98, 63, 45,
3, 45, 82, 98,
3, 36, 70, 99,
3, 100, 88, 20,
3, 20, 90, 100,
3, 100, 90, 70,
3, 101, 71, 50,
3, 50, 88, 101,
3, 36, 91, 101,
3, 101, 91, 71,
3, 101, 70, 36,
3, 101, 100, 70,
3, 88, 100, 101,
3, 102, 90, 20,
3, 20, 93, 102,
3, 70, 90, 102,
3, 102, 99, 70,
3, 64, 98, 103,
3, 103, 98, 82,
3, 30, 38, 103,
3, 38, 64, 103,
3, 103, 62, 30,
3, 45, 62, 103,
3, 103, 82, 45,
3, 36, 99, 104,
3, 99, 102, 104,
3, 104, 102, 93,
3, 19, 36, 104,
3, 104, 93, 19,
};

View File

@@ -0,0 +1,28 @@
unsigned int prism_pointcount = 8;
unsigned int prism_planecount = 6;
dReal prism_points[24]={
10.0, 1.0,-1.0,
10.0,-1.0,-1.0,
-10.0,-1.0,-1.0,
-10.0, 1.0,-1.0,
10.0, 1.0, 1.0,
10.0,-1.0, 1.0,
-10.0,-1.0, 1.0,
-10.0, 1.0, 1.0
};
unsigned int prism_polygons[]={
4,0,1,2,3,
4,4,7,6,5,
4,0,4,5,1,
4,1,5,6,2,
4,2,6,7,3,
4,4,0,3,7,
};
dReal prism_planes[]={
0.0,0.0,-1.0,1.0,
0.0,0.0,1.0,1.0,
1.0,0.0,0.0,10.0,
0.0,-1.0,0.0,1.0,
-1.0,0.0,-0.0,10.0,
0.0,1.0,0.0,1.0,
};

View File

@@ -0,0 +1,253 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/*
test that the rotational physics is correct.
an "anchor body" has a number of other randomly positioned bodies
("particles") attached to it by ball-and-socket joints, giving it some
random effective inertia tensor. the effective inertia matrix is calculated,
and then this inertia is assigned to another "test" body. a random torque is
applied to both bodies and the difference in angular velocity and orientation
is observed after a number of iterations.
typical errors for each test cycle are about 1e-5 ... 1e-4.
*/
#include <time.h>
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
// some constants
#define NUM 10 // number of particles
#define SIDE 0.1 // visual size of the particles
// dynamics objects an globals
static dWorldID world=0;
static dBodyID anchor_body,particle[NUM],test_body;
static dJointID particle_joint[NUM];
static dReal torque[3];
static int iteration;
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {1.5572f,-1.8886f,1.5700f};
static float hpr[3] = {118.5000f,-17.0000f,0.0000f};
dsSetViewpoint (xyz,hpr);
}
// compute the mass parameters of a particle set. q = particle positions,
// pm = particle masses
#define _I(i,j) I[(i)*4+(j)]
void computeMassParams (dMass *m, dReal q[NUM][3], dReal pm[NUM])
{
int i,j;
dMassSetZero (m);
for (i=0; i<NUM; i++) {
m->mass += pm[i];
for (j=0; j<3; j++) m->c[j] += pm[i]*q[i][j];
m->_I(0,0) += pm[i]*(q[i][1]*q[i][1] + q[i][2]*q[i][2]);
m->_I(1,1) += pm[i]*(q[i][0]*q[i][0] + q[i][2]*q[i][2]);
m->_I(2,2) += pm[i]*(q[i][0]*q[i][0] + q[i][1]*q[i][1]);
m->_I(0,1) -= pm[i]*(q[i][0]*q[i][1]);
m->_I(0,2) -= pm[i]*(q[i][0]*q[i][2]);
m->_I(1,2) -= pm[i]*(q[i][1]*q[i][2]);
}
for (j=0; j<3; j++) m->c[j] /= m->mass;
m->_I(1,0) = m->_I(0,1);
m->_I(2,0) = m->_I(0,2);
m->_I(2,1) = m->_I(1,2);
}
void reset_test()
{
int i;
dMass m,anchor_m;
dReal q[NUM][3], pm[NUM]; // particle positions and masses
dReal pos1[3] = {1,0,1}; // point of reference (POR)
dReal pos2[3] = {-1,0,1}; // point of reference (POR)
// make random particle positions (relative to POR) and masses
for (i=0; i<NUM; i++) {
pm[i] = dRandReal()+0.1;
q[i][0] = dRandReal()-0.5;
q[i][1] = dRandReal()-0.5;
q[i][2] = dRandReal()-0.5;
}
// adjust particle positions so centor of mass = POR
computeMassParams (&m,q,pm);
for (i=0; i<NUM; i++) {
q[i][0] -= m.c[0];
q[i][1] -= m.c[1];
q[i][2] -= m.c[2];
}
if (world) dWorldDestroy (world);
world = dWorldCreate();
anchor_body = dBodyCreate (world);
dBodySetPosition (anchor_body,pos1[0],pos1[1],pos1[2]);
dMassSetBox (&anchor_m,1,SIDE,SIDE,SIDE);
dMassAdjust (&anchor_m,0.1);
dBodySetMass (anchor_body,&anchor_m);
for (i=0; i<NUM; i++) {
particle[i] = dBodyCreate (world);
dBodySetPosition (particle[i],
pos1[0]+q[i][0],pos1[1]+q[i][1],pos1[2]+q[i][2]);
dMassSetBox (&m,1,SIDE,SIDE,SIDE);
dMassAdjust (&m,pm[i]);
dBodySetMass (particle[i],&m);
}
for (i=0; i < NUM; i++) {
particle_joint[i] = dJointCreateBall (world,0);
dJointAttach (particle_joint[i],anchor_body,particle[i]);
const dReal *p = dBodyGetPosition (particle[i]);
dJointSetBallAnchor (particle_joint[i],p[0],p[1],p[2]);
}
// make test_body with the same mass and inertia of the anchor_body plus
// all the particles
test_body = dBodyCreate (world);
dBodySetPosition (test_body,pos2[0],pos2[1],pos2[2]);
computeMassParams (&m,q,pm);
m.mass += anchor_m.mass;
for (i=0; i<12; i++) m.I[i] = m.I[i] + anchor_m.I[i];
dBodySetMass (test_body,&m);
// rotate the test and anchor bodies by a random amount
dQuaternion qrot;
for (i=0; i<4; i++) qrot[i] = dRandReal()-0.5;
dNormalize4 (qrot);
dBodySetQuaternion (anchor_body,qrot);
dBodySetQuaternion (test_body,qrot);
dMatrix3 R;
dQtoR (qrot,R);
for (i=0; i<NUM; i++) {
dVector3 v;
dMultiply0 (v,R,&q[i][0],3,3,1);
dBodySetPosition (particle[i],pos1[0]+v[0],pos1[1]+v[1],pos1[2]+v[2]);
}
// set random torque
for (i=0; i<3; i++) torque[i] = (dRandReal()-0.5) * 0.1;
iteration=0;
}
// simulation loop
static void simLoop (int pause)
{
if (!pause) {
dBodyAddTorque (anchor_body,torque[0],torque[1],torque[2]);
dBodyAddTorque (test_body,torque[0],torque[1],torque[2]);
dWorldStep (world,0.03);
iteration++;
if (iteration >= 100) {
// measure the difference between the anchor and test bodies
const dReal *w1 = dBodyGetAngularVel (anchor_body);
const dReal *w2 = dBodyGetAngularVel (test_body);
const dReal *q1 = dBodyGetQuaternion (anchor_body);
const dReal *q2 = dBodyGetQuaternion (test_body);
dReal maxdiff = dMaxDifference (w1,w2,1,3);
printf ("w-error = %.4e (%.2f,%.2f,%.2f) and (%.2f,%.2f,%.2f)\n",
maxdiff,w1[0],w1[1],w1[2],w2[0],w2[1],w2[2]);
maxdiff = dMaxDifference (q1,q2,1,4);
printf ("q-error = %.4e\n",maxdiff);
reset_test();
}
}
dReal sides[3] = {SIDE,SIDE,SIDE};
dReal sides2[3] = {6*SIDE,6*SIDE,6*SIDE};
dReal sides3[3] = {3*SIDE,3*SIDE,3*SIDE};
dsSetColor (1,1,1);
dsDrawBox (dBodyGetPosition(anchor_body), dBodyGetRotation(anchor_body),
sides3);
dsSetColor (1,0,0);
dsDrawBox (dBodyGetPosition(test_body), dBodyGetRotation(test_body), sides2);
dsSetColor (1,1,0);
for (int i=0; i<NUM; i++)
dsDrawBox (dBodyGetPosition (particle[i]),
dBodyGetRotation (particle[i]), sides);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = 0;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
dInitODE2(0);
dRandSetSeed (time(0));
reset_test();
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,276 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
// Basket ball demo.
// Serves as a test for the sphere vs trimesh collider
// By Bram Stolk.
// Press the spacebar to reset the position of the ball.
#include <assert.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#include "basket_geom.h" // this is our world mesh
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// some constants
#define RADIUS 0.14
// dynamics and collision objects (chassis, 3 wheels, environment)
static dWorldID world;
static dSpaceID space;
static dBodyID sphbody;
static dGeomID sphgeom;
static dJointGroupID contactgroup;
static dGeomID world_mesh;
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
assert(o1);
assert(o2);
if (dGeomIsSpace(o1) || dGeomIsSpace(o2))
{
fprintf(stderr,"testing space %p %p\n", (void*)o1, (void*)o2);
// colliding a space with something
dSpaceCollide2(o1,o2,data,&nearCallback);
// Note we do not want to test intersections within a space,
// only between spaces.
return;
}
// fprintf(stderr,"testing geoms %p %p\n", o1, o2);
const int N = 32;
dContact contact[N];
int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact));
if (n > 0)
{
for (int i=0; i<n; i++)
{
// Paranoia <-- not working for some people, temporarily removed for 0.6
//dIASSERT(dVALIDVEC3(contact[i].geom.pos));
//dIASSERT(dVALIDVEC3(contact[i].geom.normal));
//dIASSERT(!dIsNan(contact[i].geom.depth));
contact[i].surface.slip1 = 0.7;
contact[i].surface.slip2 = 0.7;
contact[i].surface.mode = dContactSoftERP | dContactSoftCFM | dContactApprox1 | dContactSlip1 | dContactSlip2;
contact[i].surface.mu = 50.0; // was: dInfinity
contact[i].surface.soft_erp = 0.96;
contact[i].surface.soft_cfm = 0.04;
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
dJointAttach (c,
dGeomGetBody(contact[i].geom.g1),
dGeomGetBody(contact[i].geom.g2));
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {-8,0,5};
static float hpr[3] = {0.0f,-29.5000f,0.0000f};
dsSetViewpoint (xyz,hpr);
}
static void reset_ball(void)
{
float sx=0.0f, sy=3.40f, sz=7.15;
dQuaternion q;
dQSetIdentity(q);
dBodySetPosition (sphbody, sx, sy, sz);
dBodySetQuaternion(sphbody, q);
dBodySetLinearVel (sphbody, 0,0,0);
dBodySetAngularVel (sphbody, 0,0,0);
}
// called when a key pressed
static void command (int cmd)
{
switch (cmd)
{
case ' ':
reset_ball();
break;
}
}
// simulation loop
static void simLoop (int pause)
{
double simstep = 0.001; // 1ms simulation steps
double dt = dsElapsedTime();
int nrofsteps = (int) ceilf(dt/simstep);
// fprintf(stderr, "dt=%f, nr of steps = %d\n", dt, nrofsteps);
for (int i=0; i<nrofsteps && !pause; i++)
{
dSpaceCollide (space,0,&nearCallback);
dWorldQuickStep (world, simstep);
dJointGroupEmpty (contactgroup);
}
dsSetColor (1,1,1);
const dReal *SPos = dBodyGetPosition(sphbody);
const dReal *SRot = dBodyGetRotation(sphbody);
float spos[3] = {SPos[0], SPos[1], SPos[2]};
float srot[12] = { SRot[0], SRot[1], SRot[2], SRot[3], SRot[4], SRot[5], SRot[6], SRot[7], SRot[8], SRot[9], SRot[10], SRot[11] };
dsDrawSphere
(
spos,
srot,
RADIUS
);
// draw world trimesh
dsSetColor(0.4,0.7,0.9);
dsSetTexture (DS_NONE);
const dReal* Pos = dGeomGetPosition(world_mesh);
//dIASSERT(dVALIDVEC3(Pos));
float pos[3] = { Pos[0], Pos[1], Pos[2] };
const dReal* Rot = dGeomGetRotation(world_mesh);
//dIASSERT(dVALIDMAT3(Rot));
float rot[12] = { Rot[0], Rot[1], Rot[2], Rot[3], Rot[4], Rot[5], Rot[6], Rot[7], Rot[8], Rot[9], Rot[10], Rot[11] };
int numi = sizeof(world_indices) / sizeof(dTriIndex);
for (int i=0; i<numi/3; i++)
{
int i0 = world_indices[i*3+0];
int i1 = world_indices[i*3+1];
int i2 = world_indices[i*3+2];
float *v0 = world_vertices+i0*3;
float *v1 = world_vertices+i1*3;
float *v2 = world_vertices+i2*3;
dsDrawTriangle(pos, rot, v0,v1,v2, true); // single precision draw
}
}
int main (int argc, char **argv)
{
dMass m;
dMatrix3 R;
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-9.8);
dWorldSetQuickStepNumIterations (world, 64);
// Create a static world using a triangle mesh that we can collide with.
int numv = sizeof(world_vertices)/(3*sizeof(float));
int numi = sizeof(world_indices)/ sizeof(dTriIndex);
printf("numv=%d, numi=%d\n", numv, numi);
dTriMeshDataID Data = dGeomTriMeshDataCreate();
// fprintf(stderr,"Building Single Precision Mesh\n");
dGeomTriMeshDataBuildSingle
(
Data,
world_vertices,
3 * sizeof(float),
numv,
world_indices,
numi,
3 * sizeof(dTriIndex)
);
world_mesh = dCreateTriMesh(space, Data, 0, 0, 0);
dGeomTriMeshEnableTC(world_mesh, dSphereClass, false);
dGeomTriMeshEnableTC(world_mesh, dBoxClass, false);
dGeomSetPosition(world_mesh, 0, 0, 0.5);
dRSetIdentity(R);
//dIASSERT(dVALIDMAT3(R));
dGeomSetRotation (world_mesh, R);
//float sx=0.0, sy=3.40, sz=6.80;
(void)world_normals; // get rid of compiler warning
sphbody = dBodyCreate (world);
dMassSetSphere (&m,1,RADIUS);
dBodySetMass (sphbody,&m);
sphgeom = dCreateSphere(0, RADIUS);
dGeomSetBody (sphgeom,sphbody);
reset_ball();
dSpaceAdd (space, sphgeom);
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
// Causes segm violation? Why?
// (because dWorldDestroy() destroys body connected to geom; must call first!)
dGeomDestroy(sphgeom);
dGeomDestroy (world_mesh);
dJointGroupEmpty (contactgroup);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,619 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
#include "icosahedron_geom.h"
//<---- Convex Object
dReal planes[]= // planes for a cube, these should coincide with the face array
{
1.0f ,0.0f ,0.0f ,0.25f,
0.0f ,1.0f ,0.0f ,0.25f,
0.0f ,0.0f ,1.0f ,0.25f,
-1.0f,0.0f ,0.0f ,0.25f,
0.0f ,-1.0f,0.0f ,0.25f,
0.0f ,0.0f ,-1.0f,0.25f
/*
1.0f ,0.0f ,0.0f ,2.0f,
0.0f ,1.0f ,0.0f ,1.0f,
0.0f ,0.0f ,1.0f ,1.0f,
0.0f ,0.0f ,-1.0f,1.0f,
0.0f ,-1.0f,0.0f ,1.0f,
-1.0f,0.0f ,0.0f ,0.0f
*/
};
const unsigned int planecount=6;
dReal points[]= // points for a cube
{
0.25f,0.25f,0.25f, // point 0
-0.25f,0.25f,0.25f, // point 1
0.25f,-0.25f,0.25f, // point 2
-0.25f,-0.25f,0.25f,// point 3
0.25f,0.25f,-0.25f, // point 4
-0.25f,0.25f,-0.25f,// point 5
0.25f,-0.25f,-0.25f,// point 6
-0.25f,-0.25f,-0.25f,// point 7
};
const unsigned int pointcount=8;
unsigned int polygons[] = //Polygons for a cube (6 squares)
{
4,0,2,6,4, // positive X
4,1,0,4,5, // positive Y
4,0,1,3,2, // positive Z
4,3,1,5,7, // negative X
4,2,3,7,6, // negative Y
4,5,4,6,7, // negative Z
};
//----> Convex Object
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#define dsDrawConvex dsDrawConvexD
#endif
// some constants
#define NUM 100 // max number of objects
#define DENSITY (5.0) // density of all objects
#define GPB 3 // maximum number of geometries per body
#define MAX_CONTACTS 8 // maximum number of contact points per body
#define MAX_FEEDBACKNUM 20
#define GRAVITY REAL(0.5)
// dynamics and collision objects
struct MyObject {
dBodyID body; // the body
dGeomID geom[GPB]; // geometries representing this body
};
static int num=0; // number of objects in simulation
static int nextobj=0; // next object to recycle if num==NUM
static dWorldID world;
static dSpaceID space;
static MyObject obj[NUM];
static dJointGroupID contactgroup;
static int selected = -1; // selected object
static int show_aabb = 0; // show geom AABBs?
static int show_contacts = 0; // show contact points?
static int random_pos = 1; // drop objects from random position?
static int write_world = 0;
static int show_body = 0;
struct MyFeedback {
dJointFeedback fb;
bool first;
};
static int doFeedback=0;
static MyFeedback feedbacks[MAX_FEEDBACKNUM];
static int fbnum=0;
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i;
// if (o1->body && o2->body) return;
// exit without doing anything if the two bodies are connected by a joint
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnectedExcluding(b1,b2,dJointTypeContact))
return;
dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
for (i=0; i<MAX_CONTACTS; i++) {
contact[i].surface.mode = dContactBounce | dContactSoftCFM;
contact[i].surface.mu = dInfinity;
contact[i].surface.mu2 = 0;
contact[i].surface.bounce = 0.1;
contact[i].surface.bounce_vel = 0.1;
contact[i].surface.soft_cfm = 0.01;
}
if (int numc = dCollide(o1,o2,MAX_CONTACTS,&contact[0].geom,
sizeof(dContact))) {
dMatrix3 RI;
dRSetIdentity (RI);
const dReal ss[3] = {0.02,0.02,0.02};
for (i=0; i<numc; i++) {
dJointID c = dJointCreateContact (world,contactgroup,contact+i);
dJointAttach (c,b1,b2);
if (show_contacts) {
dsSetColor(0,0,1);
dsDrawBox(contact[i].geom.pos,RI,ss);
}
if (doFeedback && (b1==obj[selected].body || b2==obj[selected].body)) {
if (fbnum<MAX_FEEDBACKNUM) {
feedbacks[fbnum].first = b1==obj[selected].body;
dJointSetFeedback(c,&feedbacks[fbnum++].fb);
}
else fbnum++;
}
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {2.1640f,-1.3079f,1.7600f};
static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
dsSetViewpoint (xyz,hpr);
printf ("To drop another object, press:\n");
printf (" b for box.\n");
printf (" s for sphere.\n");
printf (" c for capsule.\n");
printf (" y for cylinder.\n");
printf (" v for a convex object.\n");
printf (" x for a composite object.\n");
printf ("To select an object, press space.\n");
printf ("To disable the selected object, press d.\n");
printf ("To enable the selected object, press e.\n");
printf ("To dump transformation data for the selected object, press p.\n");
printf ("To toggle showing the geom AABBs, press a.\n");
printf ("To toggle showing the contact points, press t.\n");
printf ("To toggle dropping from random position/orientation, press r.\n");
printf ("To save the current state to 'state.dif', press 1.\n");
printf ("To show joint feedbacks of selected object, press f.\n");
}
static char locase(char c)
{
if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
else return c;
}
// called when a key pressed
static void command(int cmd)
{
dsizeint i;
int j,k;
dReal sides[3];
dMass m;
bool setBody = false;
cmd = locase(cmd);
if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' || cmd == 'y' || cmd == 'v') {
if (num < NUM) {
// new object to be created
i = num;
num++;
} else {
// recycle existing object
i = nextobj++;
nextobj %= num; // wrap-around if needed
// destroy the body and geoms for slot i
dBodyDestroy (obj[i].body);
obj[i].body = 0;
for (k=0; k < GPB; k++)
if (obj[i].geom[k]) {
dGeomDestroy(obj[i].geom[k]);
obj[i].geom[k] = 0;
}
}
obj[i].body = dBodyCreate(world);
for (k=0; k<3; k++)
sides[k] = dRandReal()*0.5+0.1;
dMatrix3 R;
if (random_pos) {
dBodySetPosition(obj[i].body,
dRandReal()*2-1,dRandReal()*2-1,dRandReal()+2);
dRFromAxisAndAngle(R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
} else {
// higher than highest body position
dReal maxheight = 0;
for (k=0; k<num; k++) {
const dReal *pos = dBodyGetPosition(obj[k].body);
if (pos[2] > maxheight)
maxheight = pos[2];
}
dBodySetPosition(obj[i].body, 0,0,maxheight+1);
dRSetIdentity(R);
//dRFromAxisAndAngle (R,0,0,1,/*dRandReal()*10.0-5.0*/0);
}
dBodySetRotation(obj[i].body,R);
if (cmd == 'b') {
dMassSetBox(&m,DENSITY,sides[0],sides[1],sides[2]);
obj[i].geom[0] = dCreateBox(space,sides[0],sides[1],sides[2]);
} else if (cmd == 'c') {
sides[0] *= 0.5;
dMassSetCapsule(&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]);
} else if (cmd == 'v') {
dMassSetBox(&m,DENSITY,0.25,0.25,0.25);
#if 0
obj[i].geom[0] = dCreateConvex(space,
planes,
planecount,
points,
pointcount,
polygons);
#else
obj[i].geom[0] = dCreateConvex(space,
Sphere_planes,
Sphere_planecount,
Sphere_points,
Sphere_pointcount,
Sphere_polygons);
#endif
} else if (cmd == 'y') {
dMassSetCylinder(&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCylinder(space,sides[0],sides[1]);
} else if (cmd == 's') {
sides[0] *= 0.5;
dMassSetSphere (&m,DENSITY,sides[0]);
obj[i].geom[0] = dCreateSphere (space,sides[0]);
} else if (cmd == 'x') {
setBody = true;
// start accumulating masses for the composite geometries
dMass m2;
dMassSetZero (&m);
dReal dpos[GPB][3]; // delta-positions for composite geometries
dMatrix3 drot[GPB];
// set random delta positions
for (j=0; j<GPB; j++)
for (k=0; k<3; k++)
dpos[j][k] = dRandReal()*0.3-0.15;
for (k=0; k<GPB; k++) {
if (k==0) {
dReal radius = dRandReal()*0.25+0.05;
obj[i].geom[k] = dCreateSphere (space,radius);
dMassSetSphere (&m2,DENSITY,radius);
} else if (k==1) {
obj[i].geom[k] = dCreateBox(space,sides[0],sides[1],sides[2]);
dMassSetBox(&m2,DENSITY,sides[0],sides[1],sides[2]);
} else {
dReal radius = dRandReal()*0.1+0.05;
dReal length = dRandReal()*1.0+0.1;
obj[i].geom[k] = dCreateCapsule(space,radius,length);
dMassSetCapsule(&m2,DENSITY,3,radius,length);
}
dRFromAxisAndAngle(drot[k],dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
dMassRotate(&m2,drot[k]);
dMassTranslate(&m2,dpos[k][0],dpos[k][1],dpos[k][2]);
// add to the total mass
dMassAdd(&m,&m2);
}
for (k=0; k<GPB; k++) {
dGeomSetBody(obj[i].geom[k],obj[i].body);
dGeomSetOffsetPosition(obj[i].geom[k],
dpos[k][0]-m.c[0],
dpos[k][1]-m.c[1],
dpos[k][2]-m.c[2]);
dGeomSetOffsetRotation(obj[i].geom[k], drot[k]);
}
dMassTranslate(&m,-m.c[0],-m.c[1],-m.c[2]);
dBodySetMass(obj[i].body,&m);
}
if (!setBody) { // avoid calling for composite geometries
for (k=0; k < GPB; k++)
if (obj[i].geom[k])
dGeomSetBody(obj[i].geom[k],obj[i].body);
dBodySetMass(obj[i].body,&m);
}
}
if (cmd == ' ') {
selected++;
if (selected >= num)
selected = 0;
if (selected == -1)
selected = 0;
} else if (cmd == 'd' && selected >= 0 && selected < num) {
dBodyDisable(obj[selected].body);
} else if (cmd == 'e' && selected >= 0 && selected < num) {
dBodyEnable(obj[selected].body);
} else if (cmd == 'a') {
show_aabb = !show_aabb;
} else if (cmd == 't') {
show_contacts = !show_contacts;
} else if (cmd == 'r') {
random_pos = !random_pos;
} else if (cmd == '1') {
write_world = 1;
} else if (cmd == 'p'&& selected >= 0) {
const dReal* pos = dGeomGetPosition(obj[selected].geom[0]);
const dReal* rot = dGeomGetRotation(obj[selected].geom[0]);
printf("POSITION:\n\t[%f,%f,%f]\n\n",pos[0],pos[1],pos[2]);
printf("ROTATION:\n\t[%f,%f,%f,%f]\n\t[%f,%f,%f,%f]\n\t[%f,%f,%f,%f]\n\n",
rot[0],rot[1],rot[2],rot[3],
rot[4],rot[5],rot[6],rot[7],
rot[8],rot[9],rot[10],rot[11]);
} else if (cmd == 'f' && selected >= 0 && selected < num) {
if (dBodyIsEnabled(obj[selected].body))
doFeedback = 1;
}
}
// draw a geom
void drawGeom(dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
{
int i;
if (!g)
return;
if (!pos)
pos = dGeomGetPosition(g);
if (!R)
R = dGeomGetRotation(g);
int type = dGeomGetClass(g);
if (type == dBoxClass) {
dVector3 sides;
dGeomBoxGetLengths (g,sides);
dsDrawBox(pos,R,sides);
} else if (type == dSphereClass) {
dsDrawSphere(pos,R,dGeomSphereGetRadius(g));
} else if (type == dCapsuleClass) {
dReal radius,length;
dGeomCapsuleGetParams(g,&radius,&length);
dsDrawCapsule(pos,R,length,radius);
} else if (type == dConvexClass) {
#if 0
dsDrawConvex(pos,R,planes,
planecount,
points,
pointcount,
polygons);
#else
dsDrawConvex(pos,R,
Sphere_planes,
Sphere_planecount,
Sphere_points,
Sphere_pointcount,
Sphere_polygons);
#endif
} else if (type == dCylinderClass) {
dReal radius,length;
dGeomCylinderGetParams(g,&radius,&length);
dsDrawCylinder(pos,R,length,radius);
}
if (show_body) {
dBodyID body = dGeomGetBody(g);
if (body) {
const dReal *bodypos = dBodyGetPosition(body);
const dReal *bodyr = dBodyGetRotation(body);
dReal bodySides[3] = { 0.1, 0.1, 0.1 };
dsSetColorAlpha(0,1,0,1);
dsDrawBox(bodypos,bodyr,bodySides);
}
}
if (show_aabb) {
// draw the bounding box for this geom
dReal aabb[6];
dGeomGetAABB(g,aabb);
dVector3 bbpos;
for (i=0; i<3; i++)
bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
dVector3 bbsides;
for (i=0; i<3; i++)
bbsides[i] = aabb[i*2+1] - aabb[i*2];
dMatrix3 RI;
dRSetIdentity (RI);
dsSetColorAlpha(1,0,0,0.5);
dsDrawBox(bbpos,RI,bbsides);
}
}
// simulation loop
static void simLoop(int pause)
{
dSpaceCollide(space, 0, &nearCallback);
if (!pause)
dWorldQuickStep(world, 0.02);
if (write_world) {
FILE *f = fopen("state.dif","wt");
if (f) {
dWorldExportDIF(world,f,"X");
fclose (f);
}
write_world = 0;
}
if (doFeedback) {
if (fbnum>MAX_FEEDBACKNUM)
printf("joint feedback buffer overflow!\n");
else {
dVector3 sum = {0, 0, 0};
printf("\n");
for (int i=0; i<fbnum; i++) {
dReal* f = feedbacks[i].first?feedbacks[i].fb.f1:feedbacks[i].fb.f2;
printf("%f %f %f\n", f[0], f[1], f[2]);
sum[0] += f[0];
sum[1] += f[1];
sum[2] += f[2];
}
printf("Sum: %f %f %f\n", sum[0], sum[1], sum[2]);
dMass m;
dBodyGetMass(obj[selected].body, &m);
printf("Object G=%f\n", GRAVITY*m.mass);
}
doFeedback = 0;
fbnum = 0;
}
// remove all contact joints
dJointGroupEmpty(contactgroup);
dsSetTexture(DS_WOOD);
for (int i=0; i<num; i++) {
for (int j=0; j < GPB; j++) {
if (i==selected) {
dsSetColor(0,0.7,1);
} else if (!dBodyIsEnabled(obj[i].body)) {
dsSetColor(1,0.8,0);
} else {
dsSetColor(1,1,0);
}
drawGeom(obj[i].geom[j],0,0,show_aabb);
}
}
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dHashSpaceCreate(0);
contactgroup = dJointGroupCreate(0);
dWorldSetGravity(world,0,0,-GRAVITY);
dWorldSetCFM(world,1e-5);
dWorldSetAutoDisableFlag(world,1);
#if 1
dWorldSetAutoDisableAverageSamplesCount( world, 10 );
#endif
dWorldSetLinearDamping(world, 0.00001);
dWorldSetAngularDamping(world, 0.005);
dWorldSetMaxAngularSpeed(world, 200);
dWorldSetContactMaxCorrectingVel(world,0.1);
dWorldSetContactSurfaceLayer(world,0.001);
dCreatePlane(space,0,0,1,0);
memset(obj,0,sizeof(obj));
dThreadingImplementationID threading = dThreadingAllocateMultiThreadedImplementation();
dThreadingThreadPoolID pool = dThreadingAllocateThreadPool(4, 0, dAllocateFlagBasicData, NULL);
dThreadingThreadPoolServeMultiThreadedImplementation(pool, threading);
// dWorldSetStepIslandsProcessingMaxThreadCount(world, 1);
dWorldSetStepThreadingImplementation(world, dThreadingImplementationGetFunctions(threading), threading);
// run simulation
dsSimulationLoop(argc,argv,640,480,&fn);
dThreadingImplementationShutdownProcessing(threading);
dThreadingFreeThreadPool(pool);
dWorldSetStepThreadingImplementation(world, NULL, NULL);
dThreadingFreeImplementation(threading);
dJointGroupDestroy(contactgroup);
dSpaceDestroy(space);
dWorldDestroy(world);
dCloseODE();
}

View File

@@ -0,0 +1,308 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/*
buggy with suspension.
this also shows you how to use geom groups.
*/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
// some constants
#define LENGTH 0.7 // chassis length
#define WIDTH 0.5 // chassis width
#define HEIGHT 0.2 // chassis height
#define RADIUS 0.18 // wheel radius
#define STARTZ 0.5 // starting height of chassis
#define CMASS 1 // chassis mass
#define WMASS 0.2 // wheel mass
static const dVector3 yunit = { 0, 1, 0 }, zunit = { 0, 0, 1 };
// dynamics and collision objects (chassis, 3 wheels, environment)
static dWorldID world;
static dSpaceID space;
static dBodyID body[4];
static dJointID joint[3]; // joint[0] is the front wheel
static dJointGroupID contactgroup;
static dGeomID ground;
static dSpaceID car_space;
static dGeomID box[1];
static dGeomID sphere[3];
static dGeomID ground_box;
// things that the user controls
static dReal speed=0,steer=0; // user commands
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i,n;
// only collide things with the ground
int g1 = (o1 == ground || o1 == ground_box);
int g2 = (o2 == ground || o2 == ground_box);
if (!(g1 ^ g2)) return;
const int N = 10;
dContact contact[N];
n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
if (n > 0) {
for (i=0; i<n; i++) {
contact[i].surface.mode = dContactSlip1 | dContactSlip2 |
dContactSoftERP | dContactSoftCFM | dContactApprox1;
contact[i].surface.mu = dInfinity;
contact[i].surface.slip1 = 0.1;
contact[i].surface.slip2 = 0.1;
contact[i].surface.soft_erp = 0.5;
contact[i].surface.soft_cfm = 0.3;
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
dJointAttach (c,
dGeomGetBody(contact[i].geom.g1),
dGeomGetBody(contact[i].geom.g2));
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {0.8317f,-0.9817f,0.8000f};
static float hpr[3] = {121.0000f,-27.5000f,0.0000f};
dsSetViewpoint (xyz,hpr);
printf ("Press:\t'a' to increase speed.\n"
"\t'z' to decrease speed.\n"
"\t',' to steer left.\n"
"\t'.' to steer right.\n"
"\t' ' to reset speed and steering.\n"
"\t'1' to save the current state to 'state.dif'.\n");
}
// called when a key pressed
static void command (int cmd)
{
switch (cmd) {
case 'a': case 'A':
speed += 0.3;
break;
case 'z': case 'Z':
speed -= 0.3;
break;
case ',':
steer -= 0.5;
break;
case '.':
steer += 0.5;
break;
case ' ':
speed = 0;
steer = 0;
break;
case '1': {
FILE *f = fopen ("state.dif","wt");
if (f) {
dWorldExportDIF (world,f,"");
fclose (f);
}
}
}
}
// simulation loop
static void simLoop (int pause)
{
int i;
if (!pause) {
// motor
dJointSetHinge2Param (joint[0],dParamVel2,-speed);
dJointSetHinge2Param (joint[0],dParamFMax2,0.1);
// steering
dReal v = steer - dJointGetHinge2Angle1 (joint[0]);
if (v > 0.1) v = 0.1;
if (v < -0.1) v = -0.1;
v *= 10.0;
dJointSetHinge2Param (joint[0],dParamVel,v);
dJointSetHinge2Param (joint[0],dParamFMax,0.2);
dJointSetHinge2Param (joint[0],dParamLoStop,-0.75);
dJointSetHinge2Param (joint[0],dParamHiStop,0.75);
dJointSetHinge2Param (joint[0],dParamFudgeFactor,0.1);
dSpaceCollide (space,0,&nearCallback);
dWorldStep (world,0.05);
// remove all contact joints
dJointGroupEmpty (contactgroup);
}
dsSetColor (0,1,1);
dsSetTexture (DS_WOOD);
dReal sides[3] = {LENGTH,WIDTH,HEIGHT};
dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides);
dsSetColor (1,1,1);
for (i=1; i<=3; i++) dsDrawCylinder (dBodyGetPosition(body[i]),
dBodyGetRotation(body[i]),0.02f,RADIUS);
dVector3 ss;
dGeomBoxGetLengths (ground_box,ss);
dsDrawBox (dGeomGetPosition(ground_box),dGeomGetRotation(ground_box),ss);
}
int main (int argc, char **argv)
{
int i;
dMass m;
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-0.5);
ground = dCreatePlane (space,0,0,1,0);
// chassis body
body[0] = dBodyCreate (world);
dBodySetPosition (body[0],0,0,STARTZ);
dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT);
dMassAdjust (&m,CMASS);
dBodySetMass (body[0],&m);
box[0] = dCreateBox (0,LENGTH,WIDTH,HEIGHT);
dGeomSetBody (box[0],body[0]);
// wheel bodies
for (i=1; i<=3; i++) {
body[i] = dBodyCreate (world);
dQuaternion q;
dQFromAxisAndAngle (q,1,0,0,M_PI*0.5);
dBodySetQuaternion (body[i],q);
dMassSetSphere (&m,1,RADIUS);
dMassAdjust (&m,WMASS);
dBodySetMass (body[i],&m);
sphere[i-1] = dCreateSphere (0,RADIUS);
dGeomSetBody (sphere[i-1],body[i]);
}
dBodySetPosition (body[1],0.5*LENGTH,0,STARTZ-HEIGHT*0.5);
dBodySetPosition (body[2],-0.5*LENGTH, WIDTH*0.5,STARTZ-HEIGHT*0.5);
dBodySetPosition (body[3],-0.5*LENGTH,-WIDTH*0.5,STARTZ-HEIGHT*0.5);
// front and back wheel hinges
for (i=0; i<3; i++) {
joint[i] = dJointCreateHinge2 (world,0);
dJointAttach (joint[i],body[0],body[i+1]);
const dReal *a = dBodyGetPosition (body[i+1]);
dJointSetHinge2Anchor (joint[i],a[0],a[1],a[2]);
dJointSetHinge2Axes (joint[i], zunit, yunit);
}
// set joint suspension
for (i=0; i<3; i++) {
dJointSetHinge2Param (joint[i],dParamSuspensionERP,0.4);
dJointSetHinge2Param (joint[i],dParamSuspensionCFM,0.8);
}
// lock back wheels along the steering axis
for (i=1; i<3; i++) {
// set stops to make sure wheels always stay in alignment
dJointSetHinge2Param (joint[i],dParamLoStop,0);
dJointSetHinge2Param (joint[i],dParamHiStop,0);
// the following alternative method is no good as the wheels may get out
// of alignment:
// dJointSetHinge2Param (joint[i],dParamVel,0);
// dJointSetHinge2Param (joint[i],dParamFMax,dInfinity);
}
// create car space and add it to the top level space
car_space = dSimpleSpaceCreate (space);
dSpaceSetCleanup (car_space,0);
dSpaceAdd (car_space,box[0]);
dSpaceAdd (car_space,sphere[0]);
dSpaceAdd (car_space,sphere[1]);
dSpaceAdd (car_space,sphere[2]);
// environment
ground_box = dCreateBox (space,2,1.5,1);
dMatrix3 R;
dRFromAxisAndAngle (R,0,1,0,-0.15);
dGeomSetPosition (ground_box,2,0,-0.34);
dGeomSetRotation (ground_box,R);
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dGeomDestroy (box[0]);
dGeomDestroy (sphere[0]);
dGeomDestroy (sphere[1]);
dGeomDestroy (sphere[2]);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,237 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <vector>
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#endif
static int levels = 5;
static int ncards = 0;
static dSpaceID space;
static dWorldID world;
static dJointGroupID contactgroup;
struct Card {
dBodyID body;
dGeomID geom;
static const dReal sides[3];
Card()
{
body = dBodyCreate(world);
geom = dCreateBox(space, sides[0], sides[1], sides[2]);
dGeomSetBody(geom, body);
dGeomSetData(geom, this);
dMass mass;
mass.setBox(1, sides[0], sides[1], sides[2]);
dBodySetMass(body, &mass);
}
~Card()
{
dBodyDestroy(body);
dGeomDestroy(geom);
}
void draw() const
{
dsDrawBox(dBodyGetPosition(body),
dBodyGetRotation(body), sides);
}
};
static const dReal cwidth=.5, cthikness=.02, clength=1;
const dReal Card::sides[3] = { cwidth, cthikness, clength };
std::vector<Card*> cards;
int getncards(int levels)
{
return (3*levels*levels + levels) / 2;
}
void place_cards()
{
ncards = getncards(levels);
// destroy removed cards (if any)
int oldcards = cards.size();
for (int i=ncards; i<oldcards; ++i)
delete cards[i];
cards.resize(ncards);
// construct new cards (if any)
for (int i=oldcards; i<ncards; ++i)
cards[i] = new Card;
// for each level
int c = 0;
dMatrix3 right, left, hrot;
dReal angle = 20*M_PI/180.;
dRFromAxisAndAngle(right, 1, 0, 0, -angle);
dRFromAxisAndAngle(left, 1, 0, 0, angle);
dRFromAxisAndAngle(hrot, 1, 0, 0, 91*M_PI/180.);
dReal eps = 0.05;
dReal vstep = cos(angle)*clength + eps;
dReal hstep = sin(angle)*clength + eps;
for (int lvl=0; lvl<levels; ++lvl) {
// there are 3*(levels-lvl)-1 cards in each level, except last
int n = (levels-lvl);
dReal height = (lvl)*vstep + vstep/2;
// inclined cards
for (int i=0; i<2*n; ++i, ++c) {
dBodySetPosition(cards[c]->body,
0,
-n*hstep + hstep*i,
height
);
if (i%2)
dBodySetRotation(cards[c]->body, left);
else
dBodySetRotation(cards[c]->body, right);
}
if (n==1) // top of the house
break;
// horizontal cards
for (int i=0; i<n-1; ++i, ++c) {
dBodySetPosition(cards[c]->body,
0,
-(n-1 - (clength-hstep)/2)*hstep + 2*hstep*i,
height + vstep/2);
dBodySetRotation(cards[c]->body, hrot);
}
}
}
void start()
{
puts("Controls:");
puts(" SPACE - reposition cards");
puts(" - - one less level");
puts(" = - one more level");
}
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
// exit without doing anything if the two bodies are connected by a joint
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
const int MAX_CONTACTS = 8;
dContact contact[MAX_CONTACTS];
int numc = dCollide (o1, o2, MAX_CONTACTS,
&contact[0].geom,
sizeof(dContact));
for (int i=0; i<numc; i++) {
contact[i].surface.mode = dContactApprox1;
contact[i].surface.mu = 5;
dJointID c = dJointCreateContact (world, contactgroup, contact+i);
dJointAttach (c, b1, b2);
}
}
void simLoop(int pause)
{
if (!pause) {
dSpaceCollide (space, 0, &nearCallback);
dWorldQuickStep(world, 0.01);
dJointGroupEmpty(contactgroup);
}
dsSetColor (1,1,0);
for (int i=0; i<ncards; ++i) {
dsSetColor (1, dReal(i)/ncards, 0);
cards[i]->draw();
}
}
void command(int c)
{
switch (c) {
case '=':
levels++;
place_cards();
break;
case '-':
levels--;
if (levels <= 0)
levels++;
place_cards();
break;
case ' ':
place_cards();
break;
}
}
int main(int argc, char **argv)
{
dInitODE();
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
world = dWorldCreate();
dWorldSetGravity(world, 0, 0, -0.5);
dWorldSetQuickStepNumIterations(world, 50); // <-- increase for more stability
space = dSimpleSpaceCreate(0);
contactgroup = dJointGroupCreate(0);
dGeomID ground = dCreatePlane(space, 0, 0, 1, 0);
place_cards();
// run simulation
dsSimulationLoop (argc, argv, 640, 480, &fn);
levels = 0;
place_cards();
dJointGroupDestroy(contactgroup);
dWorldDestroy(world);
dGeomDestroy(ground);
dSpaceDestroy(space);
dCloseODE();
}

View File

@@ -0,0 +1,171 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/* exercise the C interface */
#include <stdio.h>
#include "ode/ode.h"
#include "drawstuff/drawstuff.h"
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) /* for VC++, no precision loss complaints */
#endif
/* select correct drawing functions */
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
/* some constants */
#define NUM 10 /* number of boxes */
#define SIDE (0.2) /* side length of a box */
#define MASS (1.0) /* mass of a box */
#define RADIUS (0.1732f) /* sphere radius */
/* dynamics and collision objects */
static dWorldID world;
static dSpaceID space;
static dBodyID body[NUM];
static dJointID joint[NUM-1];
static dJointGroupID contactgroup;
static dGeomID sphere[NUM];
/* this is called by dSpaceCollide when two objects in space are
* potentially colliding.
*/
static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
/* exit without doing anything if the two bodies are connected by a joint */
dBodyID b1,b2;
dContact contact;
(void)data;
b1 = dGeomGetBody(o1);
b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnected (b1,b2)) return;
contact.surface.mode = 0;
contact.surface.mu = 0.1;
contact.surface.mu2 = 0;
if (dCollide (o1,o2,1,&contact.geom,sizeof(dContactGeom))) {
dJointID c = dJointCreateContact (world,contactgroup,&contact);
dJointAttach (c,b1,b2);
}
}
/* start simulation - set viewpoint */
static void start()
{
static float xyz[3] = {2.1640f,-1.3079f,1.7600f};
static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
dAllocateODEDataForThread(dAllocateMaskAll);
dsSetViewpoint (xyz,hpr);
}
/* simulation loop */
static void simLoop (int pause)
{
int i;
if (!pause) {
static double angle = 0;
angle += 0.05;
dBodyAddForce (body[NUM-1],0,0,1.5*(sin(angle)+1.0));
dSpaceCollide (space,0,&nearCallback);
dWorldStep (world,0.05);
/* remove all contact joints */
dJointGroupEmpty (contactgroup);
}
dsSetColor (1,1,0);
dsSetTexture (DS_WOOD);
for (i=0; i<NUM; i++) dsDrawSphere (dBodyGetPosition(body[i]),
dBodyGetRotation(body[i]),RADIUS);
}
int main (int argc, char **argv)
{
int i;
dReal k;
dMass m;
/* setup pointers to drawstuff callback functions */
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = 0;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
/* create world */
dInitODE2(0);
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (1000000);
dWorldSetGravity (world,0,0,-0.5);
dCreatePlane (space,0,0,1,0);
for (i=0; i<NUM; i++) {
body[i] = dBodyCreate (world);
k = i*SIDE;
dBodySetPosition (body[i],k,k,k+0.4);
dMassSetBox (&m,1,SIDE,SIDE,SIDE);
dMassAdjust (&m,MASS);
dBodySetMass (body[i],&m);
sphere[i] = dCreateSphere (space,RADIUS);
dGeomSetBody (sphere[i],body[i]);
}
for (i=0; i<(NUM-1); i++) {
joint[i] = dJointCreateBall (world,0);
dJointAttach (joint[i],body[i],body[i+1]);
k = (i+0.5)*SIDE;
dJointSetBallAnchor (joint[i],k,k,k+0.4);
}
/* run simulation */
dsSimulationLoop (argc,argv,352,288,&fn);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,165 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/* exercise the C++ interface */
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
// some constants
#define NUM 10 // number of boxes
#define SIDE (0.2) // side length of a box
#define MASS (1.0) // mass of a box
#define RADIUS (0.1732f) // sphere radius
//using namespace ode;
// dynamics and collision objects
static dWorld world;
static dSimpleSpace space (0);
static dBody body[NUM];
static dBallJoint joint[NUM-1];
static dJointGroup contactgroup;
static dBox box[NUM];
// this is called by space.collide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
// exit without doing anything if the two bodies are connected by a joint
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnected (b1,b2)) return;
// @@@ it's still more convenient to use the C interface here.
dContact contact;
contact.surface.mode = 0;
contact.surface.mu = dInfinity;
if (dCollide (o1,o2,1,&contact.geom,sizeof(dContactGeom))) {
dJointID c = dJointCreateContact (world.id(),contactgroup.id(),&contact);
dJointAttach (c,b1,b2);
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {2.1640f,-1.3079f,1.7600f};
static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
dsSetViewpoint (xyz,hpr);
}
// simulation loop
static void simLoop (int pause)
{
if (!pause) {
static double angle = 0;
angle += 0.05;
body[NUM-1].addForce (0,0,1.5*(sin(angle)+1.0));
space.collide (0,&nearCallback);
world.step (0.05);
// remove all contact joints
contactgroup.empty();
}
dReal sides[3] = {SIDE,SIDE,SIDE};
dsSetColor (1,1,0);
dsSetTexture (DS_WOOD);
for (int i=0; i<NUM; i++)
dsDrawBox (body[i].getPosition(),body[i].getRotation(),sides);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = 0;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
int i;
contactgroup.create ();
world.setGravity (0,0,-0.5);
dWorldSetCFM (world.id(),1e-5);
dPlane plane (space,0,0,1,0);
for (i=0; i<NUM; i++) {
body[i].create (world);
dReal k = i*SIDE;
body[i].setPosition (k,k,k+0.4);
dMass m;
m.setBox (1,SIDE,SIDE,SIDE);
m.adjust (MASS);
body[i].setMass (&m);
body[i].setData ((void*)(dsizeint)i);
box[i].create (space,SIDE,SIDE,SIDE);
box[i].setBody (body[i]);
}
for (i=0; i<(NUM-1); i++) {
joint[i].create (world);
joint[i].attach (body[i],body[i+1]);
dReal k = (i+0.5)*SIDE;
joint[i].setAnchor (k,k,k+0.4);
}
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dCloseODE();
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,307 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
// Convex demo.
// Serves as a test for the convex geometry.
// By Bram Stolk.
#include <assert.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#include "halton235_geom.h"
#ifdef dDOUBLE
# define dsDrawConvex dsDrawConvexD
# define dsDrawLine dsDrawLineD
#endif
#ifdef _MSC_VER
# pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// Height at which we drop the composite block.
const dReal H=4.20;
static dWorldID world;
static dSpaceID space;
static dBodyID mbody;
static dBodyID hbody[ halton_numc ];
static dGeomID hgeom[ halton_numc ];
static dJointGroupID contactgroup;
static bool drawpos=false;
static bool solidkernel=false;
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback(void *data, dGeomID o1, dGeomID o2)
{
assert(o1);
assert(o2);
if (dGeomIsSpace(o1) || dGeomIsSpace(o2))
{
// colliding a space with something
dSpaceCollide2(o1,o2,data,&nearCallback);
// Note we do not want to test intersections within a space,
// only between spaces.
return;
}
const int N = 32;
dContact contact[N];
int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact));
if (n > 0)
{
for (int i=0; i<n; i++)
{
contact[i].surface.slip1 = 0.7;
contact[i].surface.slip2 = 0.7;
contact[i].surface.mode = dContactSoftERP | dContactSoftCFM | dContactApprox1 | dContactSlip1 | dContactSlip2;
contact[i].surface.mu = 500.0; // was: dInfinity
contact[i].surface.soft_erp = 0.50;
contact[i].surface.soft_cfm = 0.03;
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
dJointAttach
(
c,
dGeomGetBody(contact[i].geom.g1),
dGeomGetBody(contact[i].geom.g2)
);
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {-8,0,5};
static float hpr[3] = {0.0f,-29.5000f,0.0000f};
dsSetViewpoint (xyz,hpr);
fprintf(stderr,"Press SPACE to reset the simulation.\n");
}
static void reset()
{
dQuaternion q;
dQSetIdentity(q);
dBodySetPosition(mbody,0,0,0+H);
dBodySetQuaternion(mbody, q);
dBodySetLinearVel(mbody, 0,0,0);
dBodySetAngularVel(mbody, 0,0,0);
dBodyEnable(mbody);
for ( int i=0; i<halton_numc; ++i )
{
dBodyID body = hbody[i];
if ( !body ) continue;
dBodySetPosition(body, halton_pos[i][0], halton_pos[i][1], halton_pos[i][2]+H);
dBodySetQuaternion(body, q);
dBodySetLinearVel(body, 0,0,0);
dBodySetAngularVel(body, 0,0,0);
dBodyEnable(body);
}
}
// called when a key pressed
static void command(int cmd)
{
switch (cmd)
{
case ' ':
reset();
break;
default:
break;
}
}
static void simLoop(int pause)
{
double simstep = 1/240.0;
double dt = dsElapsedTime();
int nrofsteps = (int) ceilf(dt/simstep);
nrofsteps = nrofsteps > 8 ? 8 : nrofsteps;
for (int i=0; i<nrofsteps && !pause; i++)
{
dSpaceCollide (space,0,&nearCallback);
dWorldQuickStep (world, simstep);
dJointGroupEmpty (contactgroup);
}
dsSetColor (1,1,1);
// Draw the convex objects.
for ( int i=0; i<halton_numc; ++i )
{
dGeomID geom = hgeom[i];
dBodyID body = dGeomGetBody(geom);
//const dReal *pos = dBodyGetPosition(body);
//const dReal *rot = dBodyGetRotation(body);
const dReal *pos = dGeomGetPosition(geom);
const dReal *rot = dGeomGetRotation(geom);
dsDrawConvex
(
pos, rot,
halton_planes[i],
halton_numf[i],
halton_verts[i],
halton_numv[i],
halton_faces[i]
);
}
if (drawpos)
{
dsSetColor(1,0,0.2);
dsSetTexture(DS_NONE);
const dReal l = 0.35;
for ( int i=0; i<halton_numc; ++i )
{
dBodyID body = hbody[i];
const dReal *pos = dBodyGetPosition(body);
dReal x0[3] = { pos[0]-l, pos[1], pos[2] };
dReal x1[3] = { pos[0]+l, pos[1], pos[2] };
dReal y0[3] = { pos[0], pos[1]-l, pos[2] };
dReal y1[3] = { pos[0], pos[1]+l, pos[2] };
dReal z0[3] = { pos[0], pos[1], pos[2]-l };
dReal z1[3] = { pos[0], pos[1], pos[2]+l };
dsDrawLine(x0,x1);
dsDrawLine(y0,y1);
dsDrawLine(z0,z1);
}
}
}
int main (int argc, char **argv)
{
dMass m;
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dHashSpaceCreate (0);
dHashSpaceSetLevels(space, -3, 5);
dCreatePlane(space,0,0,1,0); // Add a ground plane.
contactgroup = dJointGroupCreate (0);
dWorldSetGravity(world,0,0,-9.8);
dWorldSetQuickStepNumIterations(world, 32);
dWorldSetContactMaxCorrectingVel(world, 40);
dWorldSetMaxAngularSpeed(world, 62.8);
dWorldSetERP(world, 0.7);
dWorldSetQuickStepW(world, 0.75); // For increased stability.
dWorldSetAutoDisableFlag( world, true );
dWorldSetAutoDisableLinearThreshold( world, 0.01 );
dWorldSetAutoDisableAngularThreshold( world, 0.03 );
dWorldSetAutoDisableTime( world, 0.15f );
const float kernelrad = 0.7;
mbody = dBodyCreate(world);
dBodySetPosition(mbody, 0,0,0+H);
dMassSetSphere( &m, 5, kernelrad );
dBodySetMass( mbody, &m );
for (int i=0; i<halton_numc; ++i )
{
dGeomID geom = dCreateConvex
(
space,
halton_planes[i],
halton_numf[i],
halton_verts[i],
halton_numv[i],
halton_faces[i]
);
hgeom[i] = geom;
const dReal x = halton_pos[i][0];
const dReal y = halton_pos[i][1];
const dReal z = halton_pos[i][2];
const dReal dsqr = x*x + y*y + z*z;
if ( dsqr < kernelrad*kernelrad && solidkernel )
{
dGeomSetBody(geom, mbody);
dGeomSetOffsetPosition(geom, x,y,z);
}
else
{
dBodyID body = dBodyCreate(world);
hbody[i] = body;
dBodySetPosition(body, x,y,z+H);
dReal volu = halton_volu[i];
dReal rad = pow( volu * 3 / (4*M_PI), (1/3.0) );
dMassSetSphere( &m,5,rad );
dBodySetMass( body,&m );
#if 1
dBodySetLinearDamping (body, 0.0005);
dBodySetAngularDamping(body, 0.0300);
#endif
dGeomSetBody(geom,body);
}
}
// run simulation
const int w=1280;
const int h=720;
dsSimulationLoop (argc,argv,w,h,&fn);
dJointGroupEmpty (contactgroup);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,652 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
// This is a demo of the QuickStep and StepFast methods,
// originally by David Whittaker.
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
// some constants
#define LENGTH 3.5 // chassis length
#define WIDTH 2.5 // chassis width
#define HEIGHT 1.0 // chassis height
#define RADIUS 0.5 // wheel radius
#define STARTZ 1.0 // starting height of chassis
#define CMASS 1 // chassis mass
#define WMASS 1 // wheel mass
#define COMOFFSET -5 // center of mass offset
#define WALLMASS 1 // wall box mass
#define BALLMASS 1 // ball mass
#define FMAX 25 // car engine fmax
#define ROWS 1 // rows of cars
#define COLS 1 // columns of cars
#define ITERS 20 // number of iterations
#define WBOXSIZE 1.0 // size of wall boxes
#define WALLWIDTH 12 // width of wall
#define WALLHEIGHT 10 // height of wall
#define DISABLE_THRESHOLD 0.008 // maximum velocity (squared) a body can have and be disabled
#define DISABLE_STEPS 10 // number of steps a box has to have been disable-able before it will be disabled
#define CANNON_X -10 // x position of cannon
#define CANNON_Y 5 // y position of cannon
#define CANNON_BALL_MASS 10 // mass of the cannon ball
#define CANNON_BALL_RADIUS 0.5
static const dVector3 xunit = { 1, 0, 0 }, yunit = { 0, 1, 0 }, zpunit = { 0, 0, 1 }, zmunit = { 0, 0, -1 };
//#define BOX
#define CARS
#define WALL
//#define BALLS
//#define BALLSTACK
//#define ONEBALL
//#define CENTIPEDE
#define CANNON
// dynamics and collision objects (chassis, 3 wheels, environment)
static dWorldID world;
static dSpaceID space;
static dThreadingImplementationID threading;
static dThreadingThreadPoolID pool;
static dBodyID body[10000];
static int bodies;
static dJointID joint[100000];
static int joints;
static dJointGroupID contactgroup;
static dGeomID ground;
static dGeomID box[10000];
static int boxes;
static dGeomID sphere[10000];
static int spheres;
static dGeomID wall_boxes[10000];
static dBodyID wall_bodies[10000];
static dGeomID cannon_ball_geom;
static dBodyID cannon_ball_body;
static int wb_stepsdis[10000];
static int wb;
static bool doFast;
static dBodyID b;
static dMass m;
// things that the user controls
static dReal turn = 0, speed = 0; // user commands
static dReal cannon_angle=0,cannon_elevation=-1.2;
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i,n;
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnected(b1, b2))
return;
const int N = 4;
dContact contact[N];
n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
if (n > 0) {
for (i=0; i<n; i++) {
contact[i].surface.mode = dContactSlip1 | dContactSlip2 | dContactSoftERP | dContactSoftCFM | dContactApprox1;
if (dGeomGetClass(o1) == dSphereClass || dGeomGetClass(o2) == dSphereClass)
contact[i].surface.mu = 20;
else
contact[i].surface.mu = 0.5;
contact[i].surface.slip1 = 0.0;
contact[i].surface.slip2 = 0.0;
contact[i].surface.soft_erp = 0.8;
contact[i].surface.soft_cfm = 0.01;
dJointID c = dJointCreateContact (world,contactgroup,contact+i);
dJointAttach (c,dGeomGetBody(o1),dGeomGetBody(o2));
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {3.8548f,9.0843f,7.5900f};
static float hpr[3] = {-145.5f,-22.5f,0.25f};
dsSetViewpoint (xyz,hpr);
printf ("Press:\t'a' to increase speed.\n"
"\t'z' to decrease speed.\n"
"\t',' to steer left.\n"
"\t'.' to steer right.\n"
"\t' ' to reset speed and steering.\n"
"\t'[' to turn the cannon left.\n"
"\t']' to turn the cannon right.\n"
"\t'1' to raise the cannon.\n"
"\t'2' to lower the cannon.\n"
"\t'x' to shoot from the cannon.\n"
"\t'f' to toggle fast step mode.\n"
"\t'r' to reset simulation.\n");
}
void makeCar(dReal x, dReal y, int &bodyI, int &jointI, int &boxI, int &sphereI)
{
int i;
dMass m;
// chassis body
body[bodyI] = dBodyCreate (world);
dBodySetPosition (body[bodyI],x,y,STARTZ);
dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT);
dMassAdjust (&m,CMASS/2.0);
dBodySetMass (body[bodyI],&m);
box[boxI] = dCreateBox (space,LENGTH,WIDTH,HEIGHT);
dGeomSetBody (box[boxI],body[bodyI]);
// wheel bodies
for (i=1; i<=4; i++) {
body[bodyI+i] = dBodyCreate (world);
dQuaternion q;
dQFromAxisAndAngle (q,1,0,0,M_PI*0.5);
dBodySetQuaternion (body[bodyI+i],q);
dMassSetSphere (&m,1,RADIUS);
dMassAdjust (&m,WMASS);
dBodySetMass (body[bodyI+i],&m);
sphere[sphereI+i-1] = dCreateSphere (space,RADIUS);
dGeomSetBody (sphere[sphereI+i-1],body[bodyI+i]);
}
dBodySetPosition (body[bodyI+1],x+0.4*LENGTH-0.5*RADIUS,y+WIDTH*0.5,STARTZ-HEIGHT*0.5);
dBodySetPosition (body[bodyI+2],x+0.4*LENGTH-0.5*RADIUS,y-WIDTH*0.5,STARTZ-HEIGHT*0.5);
dBodySetPosition (body[bodyI+3],x-0.4*LENGTH+0.5*RADIUS,y+WIDTH*0.5,STARTZ-HEIGHT*0.5);
dBodySetPosition (body[bodyI+4],x-0.4*LENGTH+0.5*RADIUS,y-WIDTH*0.5,STARTZ-HEIGHT*0.5);
// front and back wheel hinges
for (i=0; i<4; i++) {
joint[jointI+i] = dJointCreateHinge2 (world,0);
dJointAttach (joint[jointI+i],body[bodyI],body[bodyI+i+1]);
const dReal *a = dBodyGetPosition (body[bodyI+i+1]);
dJointSetHinge2Anchor (joint[jointI+i],a[0],a[1],a[2]);
dJointSetHinge2Axes (joint[jointI+i], (i<2 ? zpunit : zmunit), yunit);
dJointSetHinge2Param (joint[jointI+i],dParamSuspensionERP,0.8);
dJointSetHinge2Param (joint[jointI+i],dParamSuspensionCFM,1e-5);
dJointSetHinge2Param (joint[jointI+i],dParamVel2,0);
dJointSetHinge2Param (joint[jointI+i],dParamFMax2,FMAX);
}
//center of mass offset body. (hang another copy of the body COMOFFSET units below it by a fixed joint)
dBodyID b = dBodyCreate (world);
dBodySetPosition (b,x,y,STARTZ+COMOFFSET);
dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT);
dMassAdjust (&m,CMASS/2.0);
dBodySetMass (b,&m);
dJointID j = dJointCreateFixed(world, 0);
dJointAttach(j, body[bodyI], b);
dJointSetFixed(j);
//box[boxI+1] = dCreateBox(space,LENGTH,WIDTH,HEIGHT);
//dGeomSetBody (box[boxI+1],b);
bodyI += 5;
jointI += 4;
boxI += 1;
sphereI += 4;
}
static
void shutdownSimulation()
{
// destroy world if it exists
if (bodies)
{
dThreadingImplementationShutdownProcessing(threading);
dThreadingFreeThreadPool(pool);
dWorldSetStepThreadingImplementation(world, NULL, NULL);
dThreadingFreeImplementation(threading);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
bodies = 0;
}
}
static
void setupSimulation()
{
int i;
for (i = 0; i < 1000; i++)
wb_stepsdis[i] = 0;
// recreate world
world = dWorldCreate();
// space = dHashSpaceCreate( 0 );
// space = dSimpleSpaceCreate( 0 );
space = dSweepAndPruneSpaceCreate( 0, dSAP_AXES_XYZ );
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-1.5);
dWorldSetCFM (world, 1e-5);
dWorldSetERP (world, 0.8);
dWorldSetQuickStepNumIterations (world,ITERS);
threading = dThreadingAllocateMultiThreadedImplementation();
pool = dThreadingAllocateThreadPool(4, 0, dAllocateFlagBasicData, NULL);
dThreadingThreadPoolServeMultiThreadedImplementation(pool, threading);
// dWorldSetStepIslandsProcessingMaxThreadCount(world, 1);
dWorldSetStepThreadingImplementation(world, dThreadingImplementationGetFunctions(threading), threading);
ground = dCreatePlane (space,0,0,1,0);
bodies = 0;
joints = 0;
boxes = 0;
spheres = 0;
wb = 0;
#ifdef CARS
for (dReal x = 0.0; x < COLS*(LENGTH+RADIUS); x += LENGTH+RADIUS)
for (dReal y = -((ROWS-1)*(WIDTH/2+RADIUS)); y <= ((ROWS-1)*(WIDTH/2+RADIUS)); y += WIDTH+RADIUS*2)
makeCar(x, y, bodies, joints, boxes, spheres);
#endif
#ifdef WALL
bool offset = false;
for (dReal z = WBOXSIZE/2.0; z <= WALLHEIGHT; z+=WBOXSIZE)
{
offset = !offset;
for (dReal y = (-WALLWIDTH+z)/2; y <= (WALLWIDTH-z)/2; y+=WBOXSIZE)
{
wall_bodies[wb] = dBodyCreate (world);
dBodySetPosition (wall_bodies[wb],-20,y,z);
dMassSetBox (&m,1,WBOXSIZE,WBOXSIZE,WBOXSIZE);
dMassAdjust (&m, WALLMASS);
dBodySetMass (wall_bodies[wb],&m);
wall_boxes[wb] = dCreateBox (space,WBOXSIZE,WBOXSIZE,WBOXSIZE);
dGeomSetBody (wall_boxes[wb],wall_bodies[wb]);
//dBodyDisable(wall_bodies[wb++]);
wb++;
}
}
dMessage(0,"wall boxes: %i", wb);
#endif
#ifdef BALLS
for (dReal x = -7; x <= -4; x+=1)
for (dReal y = -1.5; y <= 1.5; y+=1)
for (dReal z = 1; z <= 4; z+=1)
{
b = dBodyCreate (world);
dBodySetPosition (b,x*RADIUS*2,y*RADIUS*2,z*RADIUS*2);
dMassSetSphere (&m,1,RADIUS);
dMassAdjust (&m, BALLMASS);
dBodySetMass (b,&m);
sphere[spheres] = dCreateSphere (space,RADIUS);
dGeomSetBody (sphere[spheres++],b);
}
#endif
#ifdef ONEBALL
b = dBodyCreate (world);
dBodySetPosition (b,0,0,2);
dMassSetSphere (&m,1,RADIUS);
dMassAdjust (&m, 1);
dBodySetMass (b,&m);
sphere[spheres] = dCreateSphere (space,RADIUS);
dGeomSetBody (sphere[spheres++],b);
#endif
#ifdef BALLSTACK
for (dReal z = 1; z <= 6; z+=1)
{
b = dBodyCreate (world);
dBodySetPosition (b,0,0,z*RADIUS*2);
dMassSetSphere (&m,1,RADIUS);
dMassAdjust (&m, 0.1);
dBodySetMass (b,&m);
sphere[spheres] = dCreateSphere (space,RADIUS);
dGeomSetBody (sphere[spheres++],b);
}
#endif
#ifdef CENTIPEDE
dBodyID lastb = 0;
for (dReal y = 0; y < 10*LENGTH; y+=LENGTH+0.1)
{
// chassis body
b = body[bodies] = dBodyCreate (world);
dBodySetPosition (body[bodies],-15,y,STARTZ);
dMassSetBox (&m,1,WIDTH,LENGTH,HEIGHT);
dMassAdjust (&m,CMASS);
dBodySetMass (body[bodies],&m);
box[boxes] = dCreateBox (space,WIDTH,LENGTH,HEIGHT);
dGeomSetBody (box[boxes++],body[bodies++]);
for (dReal x = -17; x > -20; x-=RADIUS*2)
{
body[bodies] = dBodyCreate (world);
dBodySetPosition(body[bodies], x, y, STARTZ);
dMassSetSphere(&m, 1, RADIUS);
dMassAdjust(&m, WMASS);
dBodySetMass(body[bodies], &m);
sphere[spheres] = dCreateSphere (space, RADIUS);
dGeomSetBody (sphere[spheres++], body[bodies]);
joint[joints] = dJointCreateHinge2 (world,0);
if (x == -17)
dJointAttach (joint[joints],b,body[bodies]);
else
dJointAttach (joint[joints],body[bodies-2],body[bodies]);
const dReal *a = dBodyGetPosition (body[bodies++]);
dJointSetHinge2Anchor (joint[joints],a[0],a[1],a[2]);
dJointSetHinge2Axes (joint[joints], zpunit, xunit);
dJointSetHinge2Param (joint[joints],dParamSuspensionERP,1.0);
dJointSetHinge2Param (joint[joints],dParamSuspensionCFM,1e-5);
dJointSetHinge2Param (joint[joints],dParamLoStop,0);
dJointSetHinge2Param (joint[joints],dParamHiStop,0);
dJointSetHinge2Param (joint[joints],dParamVel2,-10.0);
dJointSetHinge2Param (joint[joints++],dParamFMax2,FMAX);
body[bodies] = dBodyCreate (world);
dBodySetPosition(body[bodies], -30 - x, y, STARTZ);
dMassSetSphere(&m, 1, RADIUS);
dMassAdjust(&m, WMASS);
dBodySetMass(body[bodies], &m);
sphere[spheres] = dCreateSphere (space, RADIUS);
dGeomSetBody (sphere[spheres++], body[bodies]);
joint[joints] = dJointCreateHinge2 (world,0);
if (x == -17)
dJointAttach (joint[joints],b,body[bodies]);
else
dJointAttach (joint[joints],body[bodies-2],body[bodies]);
const dReal *b = dBodyGetPosition (body[bodies++]);
dJointSetHinge2Anchor (joint[joints],b[0],b[1],b[2]);
dJointSetHinge2Axes (joint[joints], zpunit, xunit);
dJointSetHinge2Param (joint[joints],dParamSuspensionERP,1.0);
dJointSetHinge2Param (joint[joints],dParamSuspensionCFM,1e-5);
dJointSetHinge2Param (joint[joints],dParamLoStop,0);
dJointSetHinge2Param (joint[joints],dParamHiStop,0);
dJointSetHinge2Param (joint[joints],dParamVel2,10.0);
dJointSetHinge2Param (joint[joints++],dParamFMax2,FMAX);
}
if (lastb)
{
dJointID j = dJointCreateFixed(world,0);
dJointAttach (j, b, lastb);
dJointSetFixed(j);
}
lastb = b;
}
#endif
#ifdef BOX
body[bodies] = dBodyCreate (world);
dBodySetPosition (body[bodies],0,0,HEIGHT/2);
dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT);
dMassAdjust (&m, 1);
dBodySetMass (body[bodies],&m);
box[boxes] = dCreateBox (space,LENGTH,WIDTH,HEIGHT);
dGeomSetBody (box[boxes++],body[bodies++]);
#endif
#ifdef CANNON
cannon_ball_body = dBodyCreate (world);
cannon_ball_geom = dCreateSphere (space,CANNON_BALL_RADIUS);
dMassSetSphereTotal (&m,CANNON_BALL_MASS,CANNON_BALL_RADIUS);
dBodySetMass (cannon_ball_body,&m);
dGeomSetBody (cannon_ball_geom,cannon_ball_body);
dBodySetPosition (cannon_ball_body,CANNON_X,CANNON_Y,CANNON_BALL_RADIUS);
#endif
}
// called when a key pressed
static void command (int cmd)
{
switch (cmd) {
case 'a': case 'A':
speed += 0.3;
break;
case 'z': case 'Z':
speed -= 0.3;
break;
case ',':
turn += 0.1;
if (turn > 0.3)
turn = 0.3;
break;
case '.':
turn -= 0.1;
if (turn < -0.3)
turn = -0.3;
break;
case ' ':
speed = 0;
turn = 0;
break;
case 'f': case 'F':
doFast = !doFast;
break;
case 'r': case 'R':
shutdownSimulation();
setupSimulation();
break;
case '[':
cannon_angle += 0.1;
break;
case ']':
cannon_angle -= 0.1;
break;
case '1':
cannon_elevation += 0.1;
break;
case '2':
cannon_elevation -= 0.1;
break;
case 'x': case 'X': {
dMatrix3 R2,R3,R4;
dRFromAxisAndAngle (R2,0,0,1,cannon_angle);
dRFromAxisAndAngle (R3,0,1,0,cannon_elevation);
dMultiply0 (R4,R2,R3,3,3,3);
dReal cpos[3] = {CANNON_X,CANNON_Y,1};
for (int i=0; i<3; i++) cpos[i] += 3*R4[i*4+2];
dBodySetPosition (cannon_ball_body,cpos[0],cpos[1],cpos[2]);
dReal force = 10;
dBodySetLinearVel (cannon_ball_body,force*R4[2],force*R4[6],force*R4[10]);
dBodySetAngularVel (cannon_ball_body,0,0,0);
break;
}
}
}
// simulation loop
static void simLoop (int pause)
{
int i, j;
dsSetTexture (DS_WOOD);
if (!pause) {
#ifdef BOX
dBodyAddForce(body[bodies-1],lspeed,0,0);
#endif
for (j = 0; j < joints; j++)
{
dReal curturn = dJointGetHinge2Angle1 (joint[j]);
//dMessage (0,"curturn %e, turn %e, vel %e", curturn, turn, (turn-curturn)*1.0);
dJointSetHinge2Param(joint[j],dParamVel,(turn-curturn)*1.0);
dJointSetHinge2Param(joint[j],dParamFMax,dInfinity);
dJointSetHinge2Param(joint[j],dParamVel2,speed);
dJointSetHinge2Param(joint[j],dParamFMax2,FMAX);
dBodyEnable(dJointGetBody(joint[j],0));
dBodyEnable(dJointGetBody(joint[j],1));
}
if (doFast)
{
dSpaceCollide (space,0,&nearCallback);
dWorldQuickStep (world,0.05);
dJointGroupEmpty (contactgroup);
}
else
{
dSpaceCollide (space,0,&nearCallback);
dWorldStep (world,0.05);
dJointGroupEmpty (contactgroup);
}
for (i = 0; i < wb; i++)
{
b = dGeomGetBody(wall_boxes[i]);
if (dBodyIsEnabled(b))
{
bool disable = true;
const dReal *lvel = dBodyGetLinearVel(b);
dReal lspeed = lvel[0]*lvel[0]+lvel[1]*lvel[1]+lvel[2]*lvel[2];
if (lspeed > DISABLE_THRESHOLD)
disable = false;
const dReal *avel = dBodyGetAngularVel(b);
dReal aspeed = avel[0]*avel[0]+avel[1]*avel[1]+avel[2]*avel[2];
if (aspeed > DISABLE_THRESHOLD)
disable = false;
if (disable)
wb_stepsdis[i]++;
else
wb_stepsdis[i] = 0;
if (wb_stepsdis[i] > DISABLE_STEPS)
{
dBodyDisable(b);
dsSetColor(0.5,0.5,1);
}
else
dsSetColor(1,1,1);
}
else
dsSetColor(0.4,0.4,0.4);
dVector3 ss;
dGeomBoxGetLengths (wall_boxes[i], ss);
dsDrawBox(dGeomGetPosition(wall_boxes[i]), dGeomGetRotation(wall_boxes[i]), ss);
}
}
else
{
for (i = 0; i < wb; i++)
{
b = dGeomGetBody(wall_boxes[i]);
if (dBodyIsEnabled(b))
dsSetColor(1,1,1);
else
dsSetColor(0.4,0.4,0.4);
dVector3 ss;
dGeomBoxGetLengths (wall_boxes[i], ss);
dsDrawBox(dGeomGetPosition(wall_boxes[i]), dGeomGetRotation(wall_boxes[i]), ss);
}
}
dsSetColor (0,1,1);
dReal sides[3] = {LENGTH,WIDTH,HEIGHT};
for (i = 0; i < boxes; i++)
dsDrawBox (dGeomGetPosition(box[i]),dGeomGetRotation(box[i]),sides);
dsSetColor (1,1,1);
for (i=0; i< spheres; i++) dsDrawSphere (dGeomGetPosition(sphere[i]),
dGeomGetRotation(sphere[i]),RADIUS);
// draw the cannon
dsSetColor (1,1,0);
dMatrix3 R2,R3,R4;
dRFromAxisAndAngle (R2,0,0,1,cannon_angle);
dRFromAxisAndAngle (R3,0,1,0,cannon_elevation);
dMultiply0 (R4,R2,R3,3,3,3);
dReal cpos[3] = {CANNON_X,CANNON_Y,1};
dReal csides[3] = {2,2,2};
dsDrawBox (cpos,R2,csides);
for (i=0; i<3; i++) cpos[i] += 1.5*R4[i*4+2];
dsDrawCylinder (cpos,R4,3,0.5);
// draw the cannon ball
dsDrawSphere (dBodyGetPosition(cannon_ball_body),dBodyGetRotation(cannon_ball_body),
CANNON_BALL_RADIUS);
}
int main (int argc, char **argv)
{
doFast = true;
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
dInitODE2(0);
bodies = 0;
joints = 0;
boxes = 0;
spheres = 0;
setupSimulation();
dThreadingImplementationID threading = dThreadingAllocateMultiThreadedImplementation();
dThreadingThreadPoolID pool = dThreadingAllocateThreadPool(8, 0, dAllocateFlagBasicData, NULL);
dThreadingThreadPoolServeMultiThreadedImplementation(pool, threading);
// dWorldSetStepIslandsProcessingMaxThreadCount(world, 1);
dWorldSetStepThreadingImplementation(world, dThreadingImplementationGetFunctions(threading), threading);
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dThreadingImplementationShutdownProcessing(threading);
dThreadingFreeThreadPool(pool);
dWorldSetStepThreadingImplementation(world, NULL, NULL);
dThreadingFreeImplementation(threading);
shutdownSimulation();
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,321 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
// Test for non-capped cylinder, by Bram Stolk
#include <ode/odeconfig.h>
#include <assert.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#include "world_geom3.h" // this is our world mesh
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
#define BOX
#define CYL
// some constants
#define RADIUS 0.22 // wheel radius
#define WMASS 0.2 // wheel mass
#define WHEELW 0.2 // wheel width
#define BOXSZ 0.4 // box size
//#define CYL_GEOM_OFFSET // rotate cylinder using geom offset
// dynamics and collision objects (chassis, 3 wheels, environment)
static dWorldID world;
static dSpaceID space;
#ifdef BOX
static dBodyID boxbody;
static dGeomID boxgeom;
#endif
#ifdef CYL
static dBodyID cylbody;
static dGeomID cylgeom;
#endif
static dJointGroupID contactgroup;
static dGeomID world_mesh;
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
assert(o1);
assert(o2);
if (dGeomIsSpace(o1) || dGeomIsSpace(o2))
{
fprintf(stderr,"testing space %p %p\n", (void*)o1, (void*)o2);
// colliding a space with something
dSpaceCollide2(o1,o2,data,&nearCallback);
// Note we do not want to test intersections within a space,
// only between spaces.
return;
}
// fprintf(stderr,"testing geoms %p %p\n", o1, o2);
const int N = 32;
dContact contact[N];
int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact));
if (n > 0)
{
for (int i=0; i<n; i++)
{
contact[i].surface.slip1 = 0.7;
contact[i].surface.slip2 = 0.7;
contact[i].surface.mode = dContactSoftERP | dContactSoftCFM | dContactApprox1 | dContactSlip1 | dContactSlip2;
contact[i].surface.mu = 50.0; // was: dInfinity
contact[i].surface.soft_erp = 0.96;
contact[i].surface.soft_cfm = 0.04;
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
dJointAttach (c,
dGeomGetBody(contact[i].geom.g1),
dGeomGetBody(contact[i].geom.g2));
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {-8,-9,3};
static float hpr[3] = {45.0000f,-27.5000f,0.0000f};
dsSetViewpoint (xyz,hpr);
}
static void reset_state(void)
{
float sx=-4, sy=-4, sz=2;
dQuaternion q;
dQFromAxisAndAngle (q,1,0,0,M_PI*0.5);
#ifdef BOX
dBodySetPosition (boxbody, sx, sy+1, sz);
dBodySetLinearVel (boxbody, 0,0,0);
dBodySetAngularVel (boxbody, 0,0,0);
dBodySetQuaternion (boxbody, q);
#endif
#ifdef CYL
dBodySetPosition (cylbody, sx, sy, sz);
dBodySetLinearVel (cylbody, 0,0,0);
dBodySetAngularVel (cylbody, 0,0,0);
dBodySetQuaternion (cylbody, q);
#endif
}
// called when a key pressed
static void command (int cmd)
{
switch (cmd)
{
case ' ':
reset_state();
break;
}
}
// simulation loop
static void simLoop (int pause)
{
double simstep = 0.005; // 5ms simulation steps
double dt = dsElapsedTime();
int nrofsteps = (int) ceilf(dt/simstep);
for (int i=0; i<nrofsteps && !pause; i++)
{
dSpaceCollide (space,0,&nearCallback);
dWorldQuickStep (world, simstep);
dJointGroupEmpty (contactgroup);
}
dsSetColor (1,1,1);
#ifdef BOX
const dReal *BPos = dBodyGetPosition(boxbody);
const dReal *BRot = dBodyGetRotation(boxbody);
float bpos[3] = {BPos[0], BPos[1], BPos[2]};
float brot[12] = { BRot[0], BRot[1], BRot[2], BRot[3], BRot[4], BRot[5], BRot[6], BRot[7], BRot[8], BRot[9], BRot[10], BRot[11] };
float sides[3] = {BOXSZ, BOXSZ, BOXSZ};
dsDrawBox
(
bpos,
brot,
sides
); // single precision
#endif
#ifdef CYL
const dReal *CPos = dGeomGetPosition(cylgeom);
const dReal *CRot = dGeomGetRotation(cylgeom);
float cpos[3] = {CPos[0], CPos[1], CPos[2]};
float crot[12] = { CRot[0], CRot[1], CRot[2], CRot[3], CRot[4], CRot[5], CRot[6], CRot[7], CRot[8], CRot[9], CRot[10], CRot[11] };
dsDrawCylinder
(
// dBodyGetPosition(cylbody),
// dBodyGetRotation(cylbody),
cpos,
crot,
WHEELW,
RADIUS
); // single precision
#endif
// draw world trimesh
dsSetColor(0.7,0.7,0.4);
dsSetTexture (DS_NONE);
const dReal* Pos = dGeomGetPosition(world_mesh);
float pos[3] = { Pos[0], Pos[1], Pos[2] };
const dReal* Rot = dGeomGetRotation(world_mesh);
float rot[12] = { Rot[0], Rot[1], Rot[2], Rot[3], Rot[4], Rot[5], Rot[6], Rot[7], Rot[8], Rot[9], Rot[10], Rot[11] };
int numi = sizeof(world_indices) / sizeof(dTriIndex);
for (int i=0; i<numi/3; i++)
{
int i0 = world_indices[i*3+0];
int i1 = world_indices[i*3+1];
int i2 = world_indices[i*3+2];
float *v0 = world_vertices+i0*3;
float *v1 = world_vertices+i1*3;
float *v2 = world_vertices+i2*3;
dsDrawTriangle(pos, rot, v0,v1,v2, true); // single precision draw
}
}
int main (int argc, char **argv)
{
dMass m;
dMatrix3 R;
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-9.8);
dWorldSetQuickStepNumIterations (world, 12);
// Create a static world using a triangle mesh that we can collide with.
int numv = sizeof(world_vertices)/(3*sizeof(float));
int numi = sizeof(world_indices)/ sizeof(dTriIndex);
printf("numv=%d, numi=%d\n", numv, numi);
dTriMeshDataID Data = dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSingle
(
Data,
world_vertices,
3 * sizeof(float),
numv,
world_indices,
numi,
3 * sizeof(dTriIndex)
);
world_mesh = dCreateTriMesh(space, Data, 0, 0, 0);
dGeomSetPosition(world_mesh, 0, 0, 0.5);
dRFromAxisAndAngle (R, 0,1,0, 0.0);
dGeomSetRotation (world_mesh, R);
#ifdef BOX
boxbody = dBodyCreate (world);
dMassSetBox (&m,1, BOXSZ, BOXSZ, BOXSZ);
dMassAdjust (&m, 1);
dBodySetMass (boxbody,&m);
boxgeom = dCreateBox (0, BOXSZ, BOXSZ, BOXSZ);
dGeomSetBody (boxgeom,boxbody);
dSpaceAdd (space, boxgeom);
#endif
#ifdef CYL
cylbody = dBodyCreate (world);
dMassSetSphere (&m,1,RADIUS);
dMassAdjust (&m,WMASS);
dBodySetMass (cylbody,&m);
cylgeom = dCreateCylinder(0, RADIUS, WHEELW);
dGeomSetBody (cylgeom,cylbody);
#if defined(CYL_GEOM_OFFSET)
dMatrix3 mat;
dRFromAxisAndAngle(mat,1.0f,0.0f,0.0f,M_PI/2.0);
dGeomSetOffsetRotation(cylgeom,mat);
#endif
dSpaceAdd (space, cylgeom);
#endif
reset_state();
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dJointGroupEmpty (contactgroup);
dJointGroupDestroy (contactgroup);
// First destroy geoms, then space, then the world.
#ifdef CYL
dGeomDestroy (cylgeom);
#endif
#ifdef BOX
dGeomDestroy (boxgeom);
#endif
dGeomDestroy (world_mesh);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
(void)world_normals; // get rid of compiler warnings
}

View File

@@ -0,0 +1,240 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
// Test for cylinder vs sphere, by Bram Stolk
#include <ode/odeconfig.h>
#include <assert.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// dynamics and collision objects (chassis, 3 wheels, environment)
static dWorldID world;
static dSpaceID space;
static dBodyID cylbody;
static dGeomID cylgeom;
static dBodyID sphbody;
static dGeomID sphgeom;
static dJointGroupID contactgroup;
static bool show_contacts = true;
#define CYLRADIUS 0.6
#define CYLLENGTH 2.0
#define SPHERERADIUS 0.5
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawLine dsDrawLineD
#endif
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
assert(o1);
assert(o2);
if (dGeomIsSpace(o1) || dGeomIsSpace(o2))
{
fprintf(stderr,"testing space %p %p\n", (void*)o1, (void*)o2);
// colliding a space with something
dSpaceCollide2(o1,o2,data,&nearCallback);
// Note we do not want to test intersections within a space,
// only between spaces.
return;
}
const int N = 32;
dContact contact[N];
int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact));
if (n > 0)
{
for (int i=0; i<n; i++)
{
contact[i].surface.mode = 0;
contact[i].surface.mu = 50.0; // was: dInfinity
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
dJointAttach (c, dGeomGetBody(contact[i].geom.g1), dGeomGetBody(contact[i].geom.g2));
if (show_contacts)
{
dMatrix3 RI;
dRSetIdentity (RI);
const dReal ss[3] = {0.12,0.12,0.12};
dsSetColorAlpha (0,0,1,0.5);
dsDrawBox (contact[i].geom.pos,RI,ss);
dReal *pos = contact[i].geom.pos;
dReal depth = contact[i].geom.depth;
dReal *norm = contact[i].geom.normal;
dReal endp[3] = {pos[0]+depth*norm[0], pos[1]+depth*norm[1], pos[2]+depth*norm[2]};
dsSetColorAlpha (1,1,1,1);
dsDrawLine (contact[i].geom.pos, endp);
}
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {-8,-9,3};
static float hpr[3] = {45.0000f,-27.5000f,0.0000f};
dsSetViewpoint (xyz,hpr);
}
// called when a key pressed
static void command (int cmd)
{
switch (cmd)
{
case ' ':
break;
}
}
// simulation loop
static void simLoop (int pause)
{
dSpaceCollide (space,0,&nearCallback);
if (!pause)
{
dWorldQuickStep (world, 0.01); // 100 Hz
}
dJointGroupEmpty (contactgroup);
dsSetColorAlpha (1,1,0,0.5);
const dReal *CPos = dBodyGetPosition(cylbody);
const dReal *CRot = dBodyGetRotation(cylbody);
float cpos[3] = {CPos[0], CPos[1], CPos[2]};
float crot[12] = { CRot[0], CRot[1], CRot[2], CRot[3], CRot[4], CRot[5], CRot[6], CRot[7], CRot[8], CRot[9], CRot[10], CRot[11] };
dsDrawCylinder
(
cpos,
crot,
CYLLENGTH,
CYLRADIUS
); // single precision
const dReal *SPos = dBodyGetPosition(sphbody);
const dReal *SRot = dBodyGetRotation(sphbody);
float spos[3] = {SPos[0], SPos[1], SPos[2]};
float srot[12] = { SRot[0], SRot[1], SRot[2], SRot[3], SRot[4], SRot[5], SRot[6], SRot[7], SRot[8], SRot[9], SRot[10], SRot[11] };
dsDrawSphere
(
spos,
srot,
SPHERERADIUS
); // single precision
}
int main (int argc, char **argv)
{
dMass m;
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-9.8);
dWorldSetQuickStepNumIterations (world, 32);
dCreatePlane (space,0,0,1, 0.0);
cylbody = dBodyCreate (world);
dQuaternion q;
#if 0
dQFromAxisAndAngle (q,1,0,0,M_PI*0.5);
#else
// dQFromAxisAndAngle (q,1,0,0, M_PI * 1.0);
dQFromAxisAndAngle (q,1,0,0, M_PI * -0.77);
#endif
dBodySetQuaternion (cylbody,q);
dMassSetCylinder (&m,1.0,3,CYLRADIUS,CYLLENGTH);
dBodySetMass (cylbody,&m);
cylgeom = dCreateCylinder(0, CYLRADIUS, CYLLENGTH);
dGeomSetBody (cylgeom,cylbody);
dBodySetPosition (cylbody, 0, 0, 3);
dSpaceAdd (space, cylgeom);
sphbody = dBodyCreate (world);
dMassSetSphere (&m,1,SPHERERADIUS);
dBodySetMass (sphbody,&m);
sphgeom = dCreateSphere(0, SPHERERADIUS);
dGeomSetBody (sphgeom,sphbody);
dBodySetPosition (sphbody, 0, 0, 5.5);
dSpaceAdd (space, sphgeom);
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dJointGroupEmpty (contactgroup);
dJointGroupDestroy (contactgroup);
dGeomDestroy(sphgeom);
dGeomDestroy (cylgeom);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,194 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef dDOUBLE
#define dsDrawSphere dsDrawSphereD
#define dsDrawBox dsDrawBoxD
#define dsDrawLine dsDrawLineD
#endif
dWorldID world;
dSpaceID space;
dBodyID body1;
dBodyID body2;
dJointID joint1, joint2;
void start()
{
world = dWorldCreate();
dWorldSetGravity (world,0,0,-9.8);
dWorldSetDamping(world, 1e-4, 1e-5);
// dWorldSetERP(world, 1);
space = dSimpleSpaceCreate (0);
body1 = dBodyCreate(world);
body2 = dBodyCreate(world);
dBodySetPosition(body1, 0, 0, 3);
dBodySetPosition(body2, 0, 0, 1);
dGeomID g;
dMass mass;
g = dCreateBox(space, 0.2, 0.2, 1);
dGeomSetBody(g, body1);
dMassSetBox(&mass, 1, 0.2, 0.2, 1);
dBodySetMass(body1, &mass);
g = dCreateBox(space, 0.2, 0.2, 1);
dGeomSetBody(g, body2);
dMassSetBox(&mass, 1, 0.2, 0.2, 1);
dBodySetMass(body2, &mass);
joint1 = dJointCreateDBall(world, 0);
dJointAttach(joint1, body1, 0);
dJointSetDBallAnchor1(joint1, 0, 0, 3.5);
dJointSetDBallAnchor2(joint1, 0, 0, 4.5);
joint2 = dJointCreateDBall(world, 0);
dJointAttach(joint2, body1, body2);
dJointSetDBallAnchor1(joint2, 0, 0, 2.5);
dJointSetDBallAnchor2(joint2, 0, 0, 1.5);
// initial camera position
static float xyz[3] = {3.8966, -2.0614, 4.0300};
static float hpr[3] = {153.5, -16.5, 0};
dsSetViewpoint (xyz,hpr);
}
void stop()
{
dSpaceDestroy(space);
dWorldDestroy(world);
}
void drawGeom(dGeomID g)
{
int gclass = dGeomGetClass(g);
const dReal *pos = dGeomGetPosition(g);
const dReal *rot = dGeomGetRotation(g);
switch (gclass) {
case dSphereClass:
dsSetColorAlpha(0, 0.75, 0.5, 1);
dsSetTexture (DS_CHECKERED);
dsDrawSphere(pos, rot, dGeomSphereGetRadius(g));
break;
case dBoxClass:
{
dVector3 lengths;
dsSetColorAlpha(1, 1, 0, 1);
dsSetTexture (DS_WOOD);
dGeomBoxGetLengths(g, lengths);
dsDrawBox(pos, rot, lengths);
break;
}
default:
{}
}
}
void simLoop(int pause)
{
if (!pause) {
static dReal t = 0;
const dReal step = 0.005;
const unsigned nsteps = 4;
for (unsigned i=0; i<nsteps; ++i) {
dReal f = sin(t*1.2)*0.8;
dBodyAddForceAtRelPos(body1,
f, 0, 0,
0, 0, -0.5); // at the lower end
dReal g = sin(t*0.7)*0.8;
dBodyAddForceAtRelPos(body2,
0, g, 0,
0, 0, -0.5); // at the lower end
t += step;
dWorldQuickStep(world, step);
}
}
// now we draw everything
unsigned ngeoms = dSpaceGetNumGeoms(space);
for (unsigned i=0; i<ngeoms; ++i) {
dGeomID g = dSpaceGetGeom(space, i);
drawGeom(g);
}
dVector3 a11, a12;
dJointGetDBallAnchor1(joint1, a11);
dJointGetDBallAnchor2(joint1, a12);
dsSetColor(1, 0, 0);
dsDrawLine(a11, a12);
//printf("Error 1: %f\n", fabs(dJointGetDBallDistance(joint1) - dCalcPointsDistance3(a11, a12)));
dVector3 a21, a22;
dJointGetDBallAnchor1(joint2, a21);
dJointGetDBallAnchor2(joint2, a22);
dsSetColor(0, 1, 0);
dsDrawLine(a21, a22);
//printf("Error 2: %f\n", fabs(dJointGetDBallDistance(joint2) - dCalcPointsDistance3(a21, a22)));
}
int main(int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = 0;
fn.stop = stop;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE();
// run demo
dsSimulationLoop (argc, argv, 800, 600, &fn);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,217 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef dDOUBLE
#define dsDrawSphere dsDrawSphereD
#define dsDrawBox dsDrawBoxD
#define dsDrawLine dsDrawLineD
#endif
dWorldID world;
dSpaceID space;
dBodyID body1;
dBodyID body2;
dJointID joint1, joint2;
bool applyForce = false;
void start()
{
world = dWorldCreate();
dWorldSetGravity (world,0,0,-9.8);
dWorldSetDamping(world, 1e-4, 1e-5);
// dWorldSetERP(world, 1);
space = dSimpleSpaceCreate (0);
body1 = dBodyCreate(world);
body2 = dBodyCreate(world);
dBodySetPosition(body1, 0, 0, 3);
dBodySetPosition(body2, 0, 0, 1);
dGeomID g;
dMass mass;
g = dCreateBox(space, 0.2, 0.2, 1);
dGeomSetBody(g, body1);
dMassSetBox(&mass, 1, 0.2, 0.2, 1);
dBodySetMass(body1, &mass);
g = dCreateBox(space, 0.2, 0.2, 1);
dGeomSetBody(g, body2);
dMassSetBox(&mass, 1, 0.2, 0.2, 1);
dBodySetMass(body2, &mass);
#if 1
joint1 = dJointCreateDHinge(world, 0);
dJointAttach(joint1, body1, 0);
dJointSetDHingeAxis(joint1, 0, 1, 0);
dJointSetDHingeAnchor1(joint1, 0, 0, 3.5);
dJointSetDHingeAnchor2(joint1, 0, 0, 4.5);
#endif
#if 1
joint2 = dJointCreateDHinge(world, 0);
dJointAttach(joint2, body1, body2);
dJointSetDHingeAxis(joint2, 1, 0, 0);
dJointSetDHingeAnchor1(joint2, 0, 0, 2.5);
dJointSetDHingeAnchor2(joint2, 0, 0, 1.5);
#else
joint2 = dJointCreateDBall(world, 0);
dJointAttach(joint2, body1, body2);
dJointSetDBallAnchor1(joint2, 0, 0, 2.5);
dJointSetDBallAnchor2(joint2, 0, 0, 1.5);
#endif
//dBodyAddForce(body1, 20, 0, 0);
// initial camera position
static float xyz[3] = {3.8966, -2.0614, 4.0300};
static float hpr[3] = {153.5, -16.5, 0};
dsSetViewpoint (xyz,hpr);
}
void stop()
{
dSpaceDestroy(space);
dWorldDestroy(world);
}
void drawGeom(dGeomID g)
{
int gclass = dGeomGetClass(g);
const dReal *pos = dGeomGetPosition(g);
const dReal *rot = dGeomGetRotation(g);
switch (gclass) {
case dBoxClass:
{
dVector3 lengths;
if (applyForce)
dsSetColor(1, .5, 0);
else
dsSetColor(1, 1, 0);
dsSetTexture (DS_WOOD);
dGeomBoxGetLengths(g, lengths);
dsDrawBox(pos, rot, lengths);
break;
}
default:
{}
}
}
void simLoop(int pause)
{
if (!pause) {
static dReal t = 0;
const dReal step = 0.005;
const unsigned nsteps = 2;
for (unsigned i=0; i<nsteps; ++i) {
applyForce = fmodf(t, 3.) > 2.;
if (applyForce) {
dReal f = 0.3 * sin(t*1.2);
dBodyAddForceAtRelPos(body1,
f, 0, 0,
0, 0, -0.5); // at the lower end
dReal g = 0.3 * sin(t*0.7);
dBodyAddForceAtRelPos(body2,
0, g, 0,
0, 0, -0.5); // at the lower end
}
t += step;
if (t > 20.)
t = 0.;
dWorldQuickStep(world, step);
}
}
// now we draw everything
unsigned ngeoms = dSpaceGetNumGeoms(space);
for (unsigned i=0; i<ngeoms; ++i) {
dGeomID g = dSpaceGetGeom(space, i);
drawGeom(g);
}
#if 1
dVector3 a11, a12;
dJointGetDHingeAnchor1(joint1, a11);
dJointGetDHingeAnchor2(joint1, a12);
dsSetColor(1, 0, 0);
dsDrawLine(a11, a12);
//printf("Error 1: %f\n", fabs(dJointGetDHingeDistance(joint1) - dCalcPointsDistance3(a11, a12)));
#endif
#if 1
dVector3 a21, a22;
dJointGetDHingeAnchor1(joint2, a21);
dJointGetDHingeAnchor2(joint2, a22);
dsSetColor(0, 1, 0);
dsDrawLine(a21, a22);
//printf("Error 2: %f\n", fabs(dJointGetDHingeDistance(joint2) - dCalcPointsDistance3(a21, a22)));
#endif
}
int main(int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = 0;
fn.stop = stop;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE();
// run demo
dsSimulationLoop (argc, argv, 800, 600, &fn);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,312 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
// Test for breaking joints, by Bram Stolk
#include <ode/odeconfig.h>
#include <assert.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawCylinder dsDrawCylinderD
#endif
// dynamics and collision objects (chassis, 3 wheels, environment)
static dWorldID world;
static dSpaceID space;
static const int STACKCNT=10; // nr of weights on bridge
static const int SEGMCNT=16; // nr of segments in bridge
static const float SEGMDIM[3] = { 0.9, 4, 0.1 };
static dGeomID groundgeom;
static dBodyID segbodies[SEGMCNT];
static dGeomID seggeoms[SEGMCNT];
static dBodyID stackbodies[STACKCNT];
static dGeomID stackgeoms[STACKCNT];
static dJointID hinges[SEGMCNT-1];
static dJointID sliders[2];
static dJointFeedback jfeedbacks[SEGMCNT-1];
static dReal colours[SEGMCNT];
static int stress[SEGMCNT-1];
static dJointGroupID contactgroup;
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
assert(o1);
assert(o2);
if (dGeomIsSpace(o1) || dGeomIsSpace(o2))
{
fprintf(stderr,"testing space %p %p\n", (void*)o1, (void*)o2);
// colliding a space with something
dSpaceCollide2(o1,o2,data,&nearCallback);
// Note we do not want to test intersections within a space,
// only between spaces.
return;
}
const int N = 32;
dContact contact[N];
int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact));
if (n > 0)
{
for (int i=0; i<n; i++)
{
contact[i].surface.mode = dContactSoftERP | dContactSoftCFM | dContactApprox1;
contact[i].surface.mu = 100.0;
contact[i].surface.soft_erp = 0.96;
contact[i].surface.soft_cfm = 0.02;
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
dJointAttach (c,
dGeomGetBody(contact[i].geom.g1),
dGeomGetBody(contact[i].geom.g2));
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = { -6, 8, 6};
static float hpr[3] = { -65.0f, -27.0f, 0.0f};
dsSetViewpoint (xyz,hpr);
}
// called when a key pressed
static void command (int)
{}
void drawGeom (dGeomID g)
{
const dReal *pos = dGeomGetPosition(g);
const dReal *R = dGeomGetRotation(g);
int type = dGeomGetClass (g);
if (type == dBoxClass)
{
dVector3 sides;
dGeomBoxGetLengths (g, sides);
dsDrawBox (pos,R,sides);
}
if (type == dCylinderClass)
{
dReal r,l;
dGeomCylinderGetParams(g, &r, &l);
dsDrawCylinder (pos, R, l, r);
}
}
static void inspectJoints(void)
{
const dReal forcelimit = 4000.0;
int i;
for (i=0; i<SEGMCNT-1; i++)
{
if (dJointGetBody(hinges[i], 0))
{
// This joint has not snapped already... inspect it.
dReal l0 = dCalcVectorLength3(jfeedbacks[i].f1);
dReal l1 = dCalcVectorLength3(jfeedbacks[i].f2);
colours[i+0] = 0.95*colours[i+0] + 0.05 * l0/forcelimit;
colours[i+1] = 0.95*colours[i+1] + 0.05 * l1/forcelimit;
if (l0 > forcelimit || l1 > forcelimit)
stress[i]++;
else
stress[i]=0;
if (stress[i]>4)
{
// Low-pass filter the noisy feedback data.
// Only after 4 consecutive timesteps with excessive load, snap.
fprintf(stderr,"SNAP! (that was the sound of joint %d breaking)\n", i);
dJointAttach (hinges[i], 0, 0);
}
}
}
}
// simulation loop
static void simLoop (int pause)
{
int i;
double simstep = 0.002; // 2ms simulation steps
double dt = dsElapsedTime();
int nrofsteps = (int) ceilf(dt/simstep);
for (i=0; i<nrofsteps && !pause; i++)
{
dSpaceCollide (space,0,&nearCallback);
dWorldQuickStep (world, simstep);
dJointGroupEmpty (contactgroup);
inspectJoints();
}
for (i=0; i<SEGMCNT; i++)
{
float r=0,g=0,b=0.2;
float v = colours[i];
if (v>1.0) v=1.0;
if (v<0.5)
{
r=2*v;
g=1.0;
}
else
{
r=1.0;
g=2*(1.0-v);
}
dsSetColor (r,g,b);
drawGeom(seggeoms[i]);
}
dsSetColor (1,1,1);
for (i=0; i<STACKCNT; i++)
drawGeom(stackgeoms[i]);
}
int main (int argc, char **argv)
{
dMass m;
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-9.8);
dWorldSetQuickStepNumIterations (world, 20);
int i;
for (i=0; i<SEGMCNT; i++)
{
segbodies[i] = dBodyCreate (world);
dBodySetPosition(segbodies[i], i - SEGMCNT/2.0, 0, 5);
dMassSetBox (&m, 1, SEGMDIM[0], SEGMDIM[1], SEGMDIM[2]);
dBodySetMass (segbodies[i], &m);
seggeoms[i] = dCreateBox (0, SEGMDIM[0], SEGMDIM[1], SEGMDIM[2]);
dGeomSetBody (seggeoms[i], segbodies[i]);
dSpaceAdd (space, seggeoms[i]);
}
for (i=0; i<SEGMCNT-1; i++)
{
hinges[i] = dJointCreateHinge (world,0);
dJointAttach (hinges[i], segbodies[i],segbodies[i+1]);
dJointSetHingeAnchor (hinges[i], i + 0.5 - SEGMCNT/2.0, 0, 5);
dJointSetHingeAxis (hinges[i], 0,1,0);
dJointSetHingeParam (hinges[i],dParamFMax, 8000.0);
// NOTE:
// Here we tell ODE where to put the feedback on the forces for this hinge
dJointSetFeedback (hinges[i], jfeedbacks+i);
stress[i]=0;
}
for (i=0; i<STACKCNT; i++)
{
stackbodies[i] = dBodyCreate(world);
dMassSetBox (&m, 2.0, 2, 2, 0.6);
dBodySetMass(stackbodies[i],&m);
stackgeoms[i] = dCreateBox(0, 2, 2, 0.6);
dGeomSetBody(stackgeoms[i], stackbodies[i]);
dBodySetPosition(stackbodies[i], 0,0,8+2*i);
dSpaceAdd(space, stackgeoms[i]);
}
sliders[0] = dJointCreateSlider (world,0);
dJointAttach(sliders[0], segbodies[0], 0);
dJointSetSliderAxis (sliders[0], 1,0,0);
dJointSetSliderParam (sliders[0],dParamFMax, 4000.0);
dJointSetSliderParam (sliders[0],dParamLoStop, 0.0);
dJointSetSliderParam (sliders[0],dParamHiStop, 0.2);
sliders[1] = dJointCreateSlider (world,0);
dJointAttach(sliders[1], segbodies[SEGMCNT-1], 0);
dJointSetSliderAxis (sliders[1], 1,0,0);
dJointSetSliderParam (sliders[1],dParamFMax, 4000.0);
dJointSetSliderParam (sliders[1],dParamLoStop, 0.0);
dJointSetSliderParam (sliders[1],dParamHiStop, -0.2);
groundgeom = dCreatePlane(space, 0,0,1,0);
for (i=0; i<SEGMCNT; i++)
colours[i]=0.0;
// run simulation
dsSimulationLoop (argc,argv,1280,720,&fn);
dJointGroupEmpty(contactgroup);
dJointGroupDestroy (contactgroup);
// First destroy seggeoms, then space, then the world.
for (i=0; i<SEGMCNT; i++)
dGeomDestroy (seggeoms[i]);
for (i=0; i<STACKCNT; i++)
dGeomDestroy (stackgeoms[i]);
dSpaceDestroy(space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,205 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/*
test the Coulomb friction approximation.
a 10x10 array of boxes is made, each of which rests on the ground.
a horizantal force is applied to each box to try and get it to slide.
box[i][j] has a mass (i+1)*MASS and a force (j+1)*FORCE. by the Coloumb
friction model, the box should only slide if the force is greater than MU
times the contact normal force, i.e.
f > MU * body_mass * GRAVITY
(j+1)*FORCE > MU * (i+1)*MASS * GRAVITY
(j+1) > (i+1) * (MU*MASS*GRAVITY/FORCE)
(j+1) > (i+1) * k
this should be independent of the number of contact points, as N contact
points will each have 1/N'th the normal force but the pushing force will
have to overcome N contacts. the constants are chosen so that k=1.
thus you should see a triangle made of half the bodies in the array start to
slide.
*/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
// some constants
#define LENGTH 0.2 // box length & width
#define HEIGHT 0.05 // box height
#define MASS 0.2 // mass of box[i][j] = (i+1) * MASS
#define FORCE 0.05 // force applied to box[i][j] = (j+1) * FORCE
#define MU 0.5 // the global mu to use
#define GRAVITY 0.5 // the global gravity to use
#define N1 10 // number of different forces to try
#define N2 10 // number of different masses to try
// dynamics and collision objects
static dWorldID world;
static dSpaceID space;
static dBodyID body[N1][N2];
static dJointGroupID contactgroup;
static dGeomID ground;
static dGeomID box[N1][N2];
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i;
// only collide things with the ground
int g1 = (o1 == ground);
int g2 = (o2 == ground);
if (!(g1 ^ g2)) return;
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
dContact contact[3]; // up to 3 contacts per box
for (i=0; i<3; i++) {
contact[i].surface.mode = dContactSoftCFM | dContactApprox1;
contact[i].surface.mu = MU;
contact[i].surface.soft_cfm = 0.01;
}
if (int numc = dCollide (o1,o2,3,&contact[0].geom,sizeof(dContact))) {
for (i=0; i<numc; i++) {
dJointID c = dJointCreateContact (world,contactgroup,contact+i);
dJointAttach (c,b1,b2);
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {1.7772,-0.7924,2.7600};
static float hpr[3] = {90.0000,-54.0000,0.0000};
dsSetViewpoint (xyz,hpr);
}
// simulation loop
static void simLoop (int pause)
{
int i;
if (!pause) {
// apply forces to all bodies
for (i=0; i<N1; i++) {
for (int j=0; j<N2; j++) {
dBodyAddForce (body[i][j],FORCE*(i+1),0,0);
}
}
dSpaceCollide (space,0,&nearCallback);
dWorldStep (world,0.05);
// remove all contact joints
dJointGroupEmpty (contactgroup);
}
dsSetColor (1,0,1);
dReal sides[3] = {LENGTH,LENGTH,HEIGHT};
for (i=0; i<N1; i++) {
for (int j=0; j<N2; j++) {
dsDrawBox (dGeomGetPosition(box[i][j]),dGeomGetRotation(box[i][j]),
sides);
}
}
}
int main (int argc, char **argv)
{
int i,j;
dMass m;
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = 0;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-GRAVITY);
ground = dCreatePlane (space,0,0,1,0);
// bodies
for (i=0; i<N1; i++) {
for (j=0; j<N2; j++) {
body[i][j] = dBodyCreate (world);
dMassSetBox (&m,1,LENGTH,LENGTH,HEIGHT);
dMassAdjust (&m,MASS*(j+1));
dBodySetMass (body[i][j],&m);
dBodySetPosition (body[i][j],i*2*LENGTH,j*2*LENGTH,HEIGHT*0.5);
box[i][j] = dCreateBox (space,LENGTH,LENGTH,HEIGHT);
dGeomSetBody (box[i][j],body[i][j]);
}
}
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,210 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/*
Angular friction demo:
A bunch of ramps of different pitch.
A bunch of spheres with rolling friction.
*/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
// dynamics and collision objects
static dWorldID world = 0;
static const dReal dt = 1/REAL(60.0); // 60 fps
// Water density if units are meters and kg
static const dReal density = 1000;
// A long skinny thing
static dVector3 sides = {2,.5,.25};
// Initial angular velocity
static dVector3 omega = {5,1,2};
static dVector3 torque = {0,10,0};
static dBodyID noGyroBody;
static dBodyID expGyroBody;
static dBodyID impGyroBody;
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {0,-4.0f,3.0f};
static float hpr[3] = {90.0000,-15.0000,0.0000};
dsSetViewpoint (xyz,hpr);
printf ("Press:\n"
"\t'a' to apply a torque\n"
"\t'r' to reset simulation.\n");
}
/**
Delete the bodies, etc.
*/
static void clear()
{
if (world) dWorldDestroy (world);
world = 0;
}
/**
Cleanup if necessary and rebuild the
world.
*/
static void reset()
{
clear();
// create world
world = dWorldCreate();
// Calculate mass for a box;
dMass boxMass;
dMassSetBox(&boxMass,density,sides[0],sides[1],sides[2]);
noGyroBody = dBodyCreate(world);// Conservation of ang-velocity
expGyroBody = dBodyCreate(world);// Explicit conservation of ang-momentum
impGyroBody = dBodyCreate(world);// Implicit conservation of ang-momentum
dBodySetMass( noGyroBody , &boxMass );
dBodySetMass( expGyroBody, &boxMass );
dBodySetMass( impGyroBody, &boxMass );
// Try to avoid collisions.
dReal sep = dCalcVectorLength3(sides);
dBodySetPosition( noGyroBody , -sep, 0, sep);
dBodySetPosition( expGyroBody, 0, 0, sep);
dBodySetPosition( impGyroBody, sep, 0, sep);
// Set the initial angular velocity
dBodySetAngularVel( noGyroBody , omega[0], omega[1], omega[2]);
dBodySetAngularVel( expGyroBody, omega[0], omega[1], omega[2]);
dBodySetAngularVel( impGyroBody, omega[0], omega[1], omega[2]);
dBodySetGyroscopicMode( noGyroBody, 0);
// We compute this ourselves using the math
// that was in the old stepper.
dBodySetGyroscopicMode(expGyroBody, 0);
// Keep things from crashing by limiting
// the angular speed of the explicit body.
// Note that this isn't necessary for
// the other two bodies.
dBodySetMaxAngularSpeed( expGyroBody, 40 );
}
static void command (int cmd)
{
switch (cmd) {
case 'a': case 'A':
dBodyAddTorque( noGyroBody, torque[0], torque[1], torque[2]);
dBodyAddTorque(expGyroBody, torque[0], torque[1], torque[2]);
dBodyAddTorque(impGyroBody, torque[0], torque[1], torque[2]);
break;
case 'r': case 'R':
reset();
break;
}
}
/**
This is the explicit computation of
gyroscopic forces.
*/
static void expStep(dBodyID body)
{
// Explicit computation
dMatrix3 I,tmp;
dMass m;
dBodyGetMass(body,&m);
const dReal* R = dBodyGetRotation(body);
// compute inertia tensor in global frame
dMultiply2_333 (tmp,m.I,R);
dMultiply0_333 (I,R,tmp);
// compute explicit rotational force
// we treat 'tmp'like a vector, but that's okay.
const dReal* w = dBodyGetAngularVel(body);
dMultiply0_331 (tmp,I,w);
dVector3 tau;
dCalcVectorCross3(tau,tmp,w);
dBodyAddTorque(body,tau[0],tau[1],tau[2]);
}
// simulation loop
static void simLoop (int pause)
{
if (!pause) {
expStep(expGyroBody);
dWorldStep (world,dt);
}
dsSetTexture (DS_WOOD);
dsSetColor(1,0,0);
dsDrawBox(dBodyGetPosition(noGyroBody ),dBodyGetRotation(noGyroBody ),sides);
dsSetColor(1,1,0);
dsDrawBox(dBodyGetPosition(expGyroBody),dBodyGetRotation(expGyroBody),sides);
dsSetColor(0,1,0);
dsDrawBox(dBodyGetPosition(impGyroBody),dBodyGetRotation(impGyroBody),sides);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
dInitODE2(0);
reset();
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
clear();
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,258 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#define dsDrawConvex dsDrawConvexD
#endif
bool write_world = false;
bool show_contacts = false;
dWorld * world;
dBody *top1, *top2;
dSpace *space;
dJointGroup contactgroup;
const dReal pinradius = 0.05f;
const dReal pinlength = 1.5f;
const dReal topradius = 1.0f;
const dReal toplength = 0.25f;
const dReal topmass = 1.0f;
#define MAX_CONTACTS 4
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
// for drawing the contact points
dMatrix3 RI;
dRSetIdentity (RI);
const dReal ss[3] = {0.02,0.02,0.02};
int i;
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
dContact contact[MAX_CONTACTS];
int numc = dCollide (o1,o2,MAX_CONTACTS,&contact[0].geom,
sizeof(dContact));
for (i=0; i<numc; i++) {
contact[i].surface.mode = dContactApprox1;
contact[i].surface.mu = 2;
dJointID c = dJointCreateContact (*world,contactgroup,contact+i);
dJointAttach (c,b1,b2);
if (show_contacts)
dsDrawBox (contact[i].geom.pos, RI, ss);
}
}
// start simulation - set viewpoint
static void start()
{
static float xyz[3] = {4.777f, -2.084f, 2.18f};
static float hpr[3] = {153.0f, -14.5f, 0.0f};
dsSetViewpoint (xyz,hpr);
printf ("Orange top approximates conservation of angular momentum\n");
printf ("Green top uses conservation of angular velocity\n");
printf ("---\n");
printf ("SPACE to reset\n");
printf ("A to tilt the tops.\n");
printf ("T to toggle showing the contact points.\n");
printf ("1 to save the current state to 'state.dif'.\n");
}
char locase (char c)
{
if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
else return c;
}
// called when a key pressed
static void reset();
static void tilt();
static void command (int cmd)
{
cmd = locase (cmd);
if (cmd == ' ')
{
reset();
}
else if (cmd == 'a') {
tilt();
}
else if (cmd == 't') {
show_contacts = !show_contacts;
}
else if (cmd == '1') {
write_world = true;
}
}
// simulation loop
static void simLoop (int pause)
{
dsSetColor (0,0,2);
space->collide(0,&nearCallback);
if (!pause)
//world->quickStep(0.02);
world->step(0.02);
if (write_world) {
FILE *f = fopen ("state.dif","wt");
if (f) {
dWorldExportDIF (*world,f,"X");
fclose (f);
}
write_world = false;
}
// remove all contact joints
dJointGroupEmpty (contactgroup);
dsSetTexture (DS_WOOD);
dsSetColor (1,0.5f,0);
dsDrawCylinder(top1->getPosition(),
top1->getRotation(),
toplength, topradius);
dsDrawCapsule(top1->getPosition(),
top1->getRotation(),
pinlength, pinradius);
dsSetColor (0.5f,1,0);
dsDrawCylinder(top2->getPosition(),
top2->getRotation(),
toplength, topradius);
dsDrawCapsule(top2->getPosition(),
top2->getRotation(),
pinlength, pinradius);
}
static void reset()
{
dMatrix3 R;
dRSetIdentity(R);
top1->setRotation(R);
top2->setRotation(R);
top1->setPosition(0.8f, -2, 2);
top2->setPosition(0.8f, 2, 2);
top1->setAngularVel(1,0,7);
top2->setAngularVel(1,0,7);
top1->setLinearVel(0,0.2f,0);
top2->setLinearVel(0,0.2f,0);
}
static void tilt()
{
top1->addTorque(0, 10, 0);
top2->addTorque(0, 10, 0);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE();
world = new dWorld();
world->setGravity(0,0,-0.5f);
world->setCFM(1e-5f);
world->setLinearDamping(0.00001f);
world->setAngularDamping(0.0001f);
space = new dSimpleSpace(0);
dPlane *floor = new dPlane(*space, 0,0,1,0);
top1 = new dBody(*world);
top2 = new dBody(*world);
dMass m;
m.setCylinderTotal(1, 3, topradius, toplength);
top1->setMass(m);
top2->setMass(m);
dGeom *g1, *g2, *pin1, *pin2;
g1 = new dCylinder(*space, topradius, toplength);
g1->setBody(*top1);
g2 = new dCylinder(*space, topradius, toplength);
g2->setBody(*top2);
pin1 = new dCapsule(*space, pinradius, pinlength);
pin1->setBody(*top1);
pin2 = new dCapsule(*space, pinradius, pinlength);
pin2->setBody(*top2);
top2->setGyroscopicMode(false);
reset();
// run simulation
dsSimulationLoop (argc,argv,512,384,&fn);
delete g1;
delete g2;
delete pin1;
delete pin2;
delete floor;
contactgroup.empty();
delete top1;
delete top2;
delete space;
delete world;
dCloseODE();
}

View File

@@ -0,0 +1,714 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#include "bunny_geom.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
#define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians
int g_allow_trimesh;
// Our heightfield geom
dGeomID gheight;
// Heightfield dimensions
#define HFIELD_WSTEP 15 // Vertex count along edge >= 2
#define HFIELD_DSTEP 31
#define HFIELD_WIDTH REAL( 4.0 )
#define HFIELD_DEPTH REAL( 8.0 )
#define HFIELD_WSAMP ( HFIELD_WIDTH / ( HFIELD_WSTEP-1 ) )
#define HFIELD_DSAMP ( HFIELD_DEPTH / ( HFIELD_DSTEP-1 ) )
//<---- Convex Object
dReal planes[]= // planes for a cube
{
1.0f ,0.0f ,0.0f ,0.25f,
0.0f ,1.0f ,0.0f ,0.25f,
0.0f ,0.0f ,1.0f ,0.25f,
0.0f ,0.0f ,-1.0f,0.25f,
0.0f ,-1.0f,0.0f ,0.25f,
-1.0f,0.0f ,0.0f ,0.25f
/*
1.0f ,0.0f ,0.0f ,2.0f,
0.0f ,1.0f ,0.0f ,1.0f,
0.0f ,0.0f ,1.0f ,1.0f,
0.0f ,0.0f ,-1.0f,1.0f,
0.0f ,-1.0f,0.0f ,1.0f,
-1.0f,0.0f ,0.0f ,0.0f
*/
};
const unsigned int planecount=6;
dReal points[]= // points for a cube
{
0.25f,0.25f,0.25f, // point 0
-0.25f,0.25f,0.25f, // point 1
0.25f,-0.25f,0.25f, // point 2
-0.25f,-0.25f,0.25f,// point 3
0.25f,0.25f,-0.25f, // point 4
-0.25f,0.25f,-0.25f,// point 5
0.25f,-0.25f,-0.25f,// point 6
-0.25f,-0.25f,-0.25f,// point 7
};
const unsigned int pointcount=8;
unsigned int polygons[] = //Polygons for a cube (6 squares)
{
4,0,2,6,4, // positive X
4,1,0,4,5, // positive Y
4,0,1,3,2, // positive Z
4,3,1,5,7, // negative X
4,2,3,7,6, // negative Y
4,5,4,6,7, // negative Z
};
//----> Convex Object
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#define dsDrawConvex dsDrawConvexD
#define dsDrawTriangle dsDrawTriangleD
#endif
// some constants
#define NUM 100 // max number of objects
#define DENSITY (5.0) // density of all objects
#define GPB 3 // maximum number of geometries per body
#define MAX_CONTACTS 64 // maximum number of contact points per body
// dynamics and collision objects
struct MyObject {
dBodyID body; // the body
dGeomID geom[GPB]; // geometries representing this body
// Trimesh only - double buffered matrices for 'last transform' setup
dReal matrix_dblbuff[ 16 * 2 ];
int last_matrix_index;
};
static int num=0; // number of objects in simulation
static int nextobj=0; // next object to recycle if num==NUM
static dWorldID world;
static dSpaceID space;
static MyObject obj[NUM];
static dJointGroupID contactgroup;
static int selected = -1; // selected object
static int show_aabb = 0; // show geom AABBs?
static int show_contacts = 0; // show contact points?
static int random_pos = 1; // drop objects from random position?
static int write_world = 0;
//============================
dGeomID TriMesh1;
dGeomID TriMesh2;
//static dTriMeshDataID TriData1, TriData2; // reusable static trimesh data
//============================
dReal heightfield_callback( void*, int x, int z )
{
dReal fx = ( ((dReal)x) - ( HFIELD_WSTEP-1 )/2 ) / (dReal)( HFIELD_WSTEP-1 );
dReal fz = ( ((dReal)z) - ( HFIELD_DSTEP-1 )/2 ) / (dReal)( HFIELD_DSTEP-1 );
// Create an interesting 'hump' shape
dReal h = REAL( 1.0 ) + ( REAL( -16.0 ) * ( fx*fx*fx + fz*fz*fz ) );
return h;
}
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i;
// if (o1->body && o2->body) return;
// exit without doing anything if the two bodies are connected by a joint
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnectedExcluding(b1,b2,dJointTypeContact))
return;
dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
for (i=0; i<MAX_CONTACTS; i++) {
contact[i].surface.mode = dContactBounce | dContactSoftCFM;
contact[i].surface.mu = dInfinity;
contact[i].surface.mu2 = 0;
contact[i].surface.bounce = 0.1;
contact[i].surface.bounce_vel = 0.1;
contact[i].surface.soft_cfm = 0.01;
}
if (int numc = dCollide(o1,o2,MAX_CONTACTS,&contact[0].geom,
sizeof(dContact))) {
dMatrix3 RI;
dRSetIdentity(RI);
const dReal ss[3] = {0.02,0.02,0.02};
for (i=0; i<numc; i++) {
dJointID c = dJointCreateContact(world,contactgroup,contact+i);
dJointAttach(c,b1,b2);
if (show_contacts) {
dsSetColor(0,0,1);
dsDrawBox(contact[i].geom.pos,RI,ss);
}
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {2.1640f,-1.3079f,1.7600f};
static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
dsSetViewpoint (xyz,hpr);
printf("To drop another object, press:\n");
printf(" b for box.\n");
printf(" s for sphere.\n");
printf(" c for capsule.\n");
printf(" y for cylinder.\n");
printf(" v for a convex object.\n");
printf(" x for a composite object.\n");
if ( g_allow_trimesh )
printf(" m for a trimesh.\n");
printf("To select an object, press space.\n");
printf("To disable the selected object, press d.\n");
printf("To enable the selected object, press e.\n");
printf("To toggle showing the geom AABBs, press a.\n");
printf("To toggle showing the contact points, press t.\n");
printf("To toggle dropping from random position/orientation, press r.\n");
printf("To save the current state to 'state.dif', press 1.\n");
}
char locase(char c)
{
if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
else return c;
}
// called when a key pressed
static void command(int cmd)
{
dsizeint i;
int j,k;
dReal sides[3];
dMass m;
bool setBody = false;
cmd = locase (cmd);
//
// Geom Creation
//
if ( cmd == 'b' || cmd == 's' || cmd == 'c' || ( cmd == 'm' && g_allow_trimesh ) ||
cmd == 'x' || cmd == 'y' || cmd == 'v' ) {
if ( num < NUM ) {
i = num;
num++;
} else {
i = nextobj++;
nextobj %= num;
// destroy the body and geoms for slot i
dBodyDestroy(obj[i].body);
obj[i].body = 0;
for (k=0; k < GPB; k++)
if (obj[i].geom[k]) {
dGeomDestroy(obj[i].geom[k]);
obj[i].geom[k] = 0;
}
}
obj[i].body = dBodyCreate(world);
for (k=0; k<3; k++)
sides[k] = dRandReal()*0.5+0.1;
dMatrix3 R;
if (random_pos) {
dBodySetPosition(obj[i].body,
(dRandReal()-0.5)*HFIELD_WIDTH*0.75,
(dRandReal()-0.5)*HFIELD_DEPTH*0.75,
dRandReal() + 2 );
dRFromAxisAndAngle(R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
} else {
dReal maxheight = 0;
for (k=0; k<num; k++) {
const dReal *pos = dBodyGetPosition(obj[k].body);
if (pos[2] > maxheight)
maxheight = pos[2];
}
dBodySetPosition(obj[i].body, 0,maxheight+1,0);
dRFromAxisAndAngle(R,0,0,1,dRandReal()*10.0-5.0);
}
dBodySetRotation(obj[i].body,R);
if (cmd == 'b') {
dMassSetBox(&m,DENSITY,sides[0],sides[1],sides[2]);
obj[i].geom[0] = dCreateBox(space,sides[0],sides[1],sides[2]);
} else if (cmd == 'c') {
sides[0] *= 0.5;
dMassSetCapsule(&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCapsule(space,sides[0],sides[1]);
} else if (cmd == 'v') {
dMassSetBox (&m,DENSITY,0.25,0.25,0.25);
obj[i].geom[0] = dCreateConvex(space,
planes,
planecount,
points,
pointcount,
polygons);
} else if (cmd == 'y') {
dMassSetCylinder(&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCylinder(space,sides[0],sides[1]);
} else if (cmd == 's') {
sides[0] *= 0.5;
dMassSetSphere(&m,DENSITY,sides[0]);
obj[i].geom[0] = dCreateSphere(space,sides[0]);
} else if (cmd == 'm' && g_allow_trimesh) {
dTriMeshDataID new_tmdata = dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSingle(new_tmdata, &Vertices[0], 3 * sizeof(float), VertexCount,
&Indices[0], IndexCount, 3 * sizeof(dTriIndex));
dGeomTriMeshDataPreprocess2(new_tmdata, (1U << dTRIDATAPREPROCESS_BUILD_FACE_ANGLES), NULL);
obj[i].geom[0] = dCreateTriMesh(space, new_tmdata, 0, 0, 0);
dMassSetTrimesh( &m, DENSITY, obj[i].geom[0] );
printf("mass at %f %f %f\n", m.c[0], m.c[1], m.c[2]);
dGeomSetPosition(obj[i].geom[0], -m.c[0], -m.c[1], -m.c[2]);
dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]);
} else if (cmd == 'x') {
setBody = 1;
// start accumulating masses for the composite geometries
dMass m2;
dMassSetZero (&m);
dReal dpos[GPB][3]; // delta-positions for composite geometries
dMatrix3 drot[GPB];
// set random delta positions
for (j=0; j<GPB; j++)
for (k=0; k<3; k++)
dpos[j][k] = dRandReal()*0.3-0.15;
for (k=0; k<GPB; k++) {
if (k==0) {
dReal radius = dRandReal()*0.25+0.05;
obj[i].geom[k] = dCreateSphere (space,radius);
dMassSetSphere (&m2,DENSITY,radius);
}
else if (k==1) {
obj[i].geom[k] = dCreateBox(space,sides[0],sides[1],sides[2]);
dMassSetBox(&m2,DENSITY,sides[0],sides[1],sides[2]);
} else {
dReal radius = dRandReal()*0.1+0.05;
dReal length = dRandReal()*1.0+0.1;
obj[i].geom[k] = dCreateCapsule(space,radius,length);
dMassSetCapsule(&m2,DENSITY,3,radius,length);
}
dRFromAxisAndAngle(drot[k],dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
dMassRotate(&m2,drot[k]);
dMassTranslate(&m2,dpos[k][0],dpos[k][1],dpos[k][2]);
// add to the total mass
dMassAdd(&m,&m2);
}
for (k=0; k<GPB; k++) {
dGeomSetBody(obj[i].geom[k],obj[i].body);
dGeomSetOffsetPosition(obj[i].geom[k],
dpos[k][0]-m.c[0],
dpos[k][1]-m.c[1],
dpos[k][2]-m.c[2]);
dGeomSetOffsetRotation(obj[i].geom[k], drot[k]);
}
dMassTranslate(&m,-m.c[0],-m.c[1],-m.c[2]);
dBodySetMass(obj[i].body,&m);
}
if (!setBody) { // avoid calling for composite geometries
for (k=0; k < GPB; k++)
if (obj[i].geom[k])
dGeomSetBody(obj[i].geom[k],obj[i].body);
dBodySetMass(obj[i].body,&m);
}
}
//
// Control Commands
//
if (cmd == ' ') {
selected++;
if (selected >= num)
selected = 0;
if (selected < -1)
selected = 0;
} else if (cmd == 'd' && selected >= 0 && selected < num) {
dBodyDisable(obj[selected].body);
} else if (cmd == 'e' && selected >= 0 && selected < num) {
dBodyEnable(obj[selected].body);
} else if (cmd == 'a') {
show_aabb = !show_aabb;
} else if (cmd == 't') {
show_contacts = !show_contacts;
} else if (cmd == 'r') {
random_pos = !random_pos;
} else if (cmd == '1') {
write_world = 1;
}
}
// draw a geom
void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
{
if (!g)
return;
if (!pos)
pos = dGeomGetPosition(g);
if (!R)
R = dGeomGetRotation(g);
int type = dGeomGetClass(g);
if (type == dBoxClass) {
dVector3 sides;
dGeomBoxGetLengths(g,sides);
dsDrawBox(pos,R,sides);
} else if (type == dSphereClass) {
dsDrawSphere(pos,R,dGeomSphereGetRadius(g));
} else if (type == dCapsuleClass) {
dReal radius,length;
dGeomCapsuleGetParams(g,&radius,&length);
dsDrawCapsule(pos,R,length,radius);
} else if (type == dConvexClass) {
//dVector3 sides={0.50,0.50,0.50};
dsDrawConvex(pos,R,planes,
planecount,
points,
pointcount,
polygons);
} else if (type == dCylinderClass) {
dReal radius,length;
dGeomCylinderGetParams(g,&radius,&length);
dsDrawCylinder(pos,R,length,radius);
} else if (type == dTriMeshClass) {
dTriIndex* Indices = (dTriIndex*)::Indices;
// assume all trimeshes are drawn as bunnies
for (int ii = 0; ii < IndexCount / 3; ii++) {
const dReal v[9] = { // explicit conversion from float to dReal
Vertices[Indices[ii * 3 + 0] * 3 + 0],
Vertices[Indices[ii * 3 + 0] * 3 + 1],
Vertices[Indices[ii * 3 + 0] * 3 + 2],
Vertices[Indices[ii * 3 + 1] * 3 + 0],
Vertices[Indices[ii * 3 + 1] * 3 + 1],
Vertices[Indices[ii * 3 + 1] * 3 + 2],
Vertices[Indices[ii * 3 + 2] * 3 + 0],
Vertices[Indices[ii * 3 + 2] * 3 + 1],
Vertices[Indices[ii * 3 + 2] * 3 + 2]
};
dsDrawTriangle(pos, R, &v[0], &v[3], &v[6], 1);
}
} else if (type == dHeightfieldClass) {
// Set ox and oz to zero for DHEIGHTFIELD_CORNER_ORIGIN mode.
int ox = (int) ( -HFIELD_WIDTH/2 );
int oz = (int) ( -HFIELD_DEPTH/2 );
// for ( int tx = -1; tx < 2; ++tx )
// for ( int tz = -1; tz < 2; ++tz )
dsSetColorAlpha (0.5,1,0.5,0.5);
dsSetTexture( DS_WOOD );
for ( int i = 0; i < HFIELD_WSTEP - 1; ++i )
for ( int j = 0; j < HFIELD_DSTEP - 1; ++j ) {
dReal a[3], b[3], c[3], d[3];
a[ 0 ] = ox + ( i ) * HFIELD_WSAMP;
a[ 1 ] = heightfield_callback( NULL, i, j );
a[ 2 ] = oz + ( j ) * HFIELD_DSAMP;
b[ 0 ] = ox + ( i + 1 ) * HFIELD_WSAMP;
b[ 1 ] = heightfield_callback( NULL, i + 1, j );
b[ 2 ] = oz + ( j ) * HFIELD_DSAMP;
c[ 0 ] = ox + ( i ) * HFIELD_WSAMP;
c[ 1 ] = heightfield_callback( NULL, i, j + 1 );
c[ 2 ] = oz + ( j + 1 ) * HFIELD_DSAMP;
d[ 0 ] = ox + ( i + 1 ) * HFIELD_WSAMP;
d[ 1 ] = heightfield_callback( NULL, i + 1, j + 1 );
d[ 2 ] = oz + ( j + 1 ) * HFIELD_DSAMP;
dsDrawTriangle( pos, R, a, c, b, 1 );
dsDrawTriangle( pos, R, b, c, d, 1 );
}
}
if (show_aabb) {
// draw the bounding box for this geom
dReal aabb[6];
dGeomGetAABB(g,aabb);
dVector3 bbpos;
for (int i=0; i<3; i++)
bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
dVector3 bbsides;
for (int i=0; i<3; i++)
bbsides[i] = aabb[i*2+1] - aabb[i*2];
dMatrix3 RI;
dRSetIdentity(RI);
dsSetColorAlpha(1,0,0,0.5);
dsDrawBox(bbpos,RI,bbsides);
}
}
// simulation loop
static void simLoop (int pause)
{
int i,j;
dSpaceCollide(space,0,&nearCallback);
if (!pause)
dWorldQuickStep(world,0.05);
if (write_world) {
FILE *f = fopen ("state.dif","wt");
if (f) {
dWorldExportDIF(world,f,"X");
fclose (f);
}
write_world = 0;
}
// remove all contact joints
dJointGroupEmpty(contactgroup);
//
// Draw Heightfield
//
drawGeom(gheight, 0, 0, 0);
dsSetColor (1,1,0);
dsSetTexture (DS_WOOD);
for (i=0; i<num; i++) {
for (j=0; j < GPB; j++) {
if (i==selected) {
dsSetColor (0,0.7,1);
} else if (! dBodyIsEnabled (obj[i].body)) {
dsSetColor (1,0.8,0);
} else {
dsSetColor (1,1,0);
}
drawGeom (obj[i].geom[j],0,0,show_aabb);
}
}
}
int main (int argc, char **argv)
{
printf("ODE configuration: %s\n", dGetConfiguration());
// Is trimesh support built into this ODE?
g_allow_trimesh = dCheckConfiguration( "ODE_EXT_trimesh" );
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity(world,0,0,-0.05);
dWorldSetCFM(world,1e-5);
dWorldSetAutoDisableFlag(world,1);
dWorldSetContactMaxCorrectingVel(world,0.1);
dWorldSetContactSurfaceLayer(world,0.001);
memset(obj,0,sizeof(obj));
dWorldSetAutoDisableAverageSamplesCount( world, 1 );
// base plane to catch overspill
dCreatePlane( space, 0, 0, 1, 0 );
// our heightfield floor
dHeightfieldDataID heightid = dGeomHeightfieldDataCreate();
// Create an finite heightfield.
dGeomHeightfieldDataBuildCallback( heightid, NULL, heightfield_callback,
HFIELD_WIDTH, HFIELD_DEPTH, HFIELD_WSTEP, HFIELD_DSTEP,
REAL( 1.0 ), REAL( 0.0 ), REAL( 0.0 ), 0 );
// Give some very bounds which, while conservative,
// makes AABB computation more accurate than +/-INF.
dGeomHeightfieldDataSetBounds( heightid, REAL( -4.0 ), REAL( +6.0 ) );
gheight = dCreateHeightfield( space, heightid, 1 );
dVector3 pos;
pos[ 0 ] = 0;
pos[ 1 ] = 0;
pos[ 2 ] = 0;
// Rotate so Z is up, not Y (which is the default orientation)
dMatrix3 R;
dRSetIdentity( R );
dRFromAxisAndAngle( R, 1, 0, 0, DEGTORAD * 90 );
// Place it.
dGeomSetRotation( gheight, R );
dGeomSetPosition( gheight, pos[0], pos[1], pos[2] );
dThreadingImplementationID threading = dThreadingAllocateMultiThreadedImplementation();
dThreadingThreadPoolID pool = dThreadingAllocateThreadPool(4, 0, dAllocateFlagBasicData, NULL);
dThreadingThreadPoolServeMultiThreadedImplementation(pool, threading);
// dWorldSetStepIslandsProcessingMaxThreadCount(world, 1);
dWorldSetStepThreadingImplementation(world, dThreadingImplementationGetFunctions(threading), threading);
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dThreadingImplementationShutdownProcessing(threading);
dThreadingFreeThreadPool(pool);
dWorldSetStepThreadingImplementation(world, NULL, NULL);
dThreadingFreeImplementation(threading);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
// destroy heightfield data, because _we_ own it not ODE
dGeomHeightfieldDataDestroy( heightid );
dCloseODE();
}

View File

@@ -0,0 +1,165 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#endif
// some constants
#define SIDE (0.5f) // side length of a box
#define MASS (1.0) // mass of a box
// dynamics and collision objects
static dWorldID world;
static dBodyID body[2];
static dJointID hinge;
// state set by keyboard commands
static int occasional_error = 0;
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {1.0382f,-1.0811f,1.4700f};
static float hpr[3] = {135.0000f,-19.5000f,0.0000f};
dsSetViewpoint (xyz,hpr);
printf ("Press 'e' to start/stop occasional error.\n");
}
// called when a key pressed
static void command (int cmd)
{
if (cmd == 'e' || cmd == 'E') {
occasional_error ^= 1;
}
}
// simulation loop
static void simLoop (int pause)
{
const dReal kd = -0.3; // angular damping constant
if (!pause) {
// add an oscillating torque to body 0, and also damp its rotational motion
static dReal a=0;
const dReal *w = dBodyGetAngularVel (body[0]);
dBodyAddTorque (body[0],kd*w[0],kd*w[1]+0.1*cos(a),kd*w[2]+0.1*sin(a));
dWorldStep (world,0.05);
a += 0.01;
// occasionally re-orient one of the bodies to create a deliberate error.
if (occasional_error) {
static int count = 0;
if ((count % 20)==0) {
// randomly adjust orientation of body[0]
const dReal *R1;
dMatrix3 R2,R3;
R1 = dBodyGetRotation (body[0]);
dRFromAxisAndAngle (R2,dRandReal()-0.5,dRandReal()-0.5,
dRandReal()-0.5,dRandReal()-0.5);
dMultiply0 (R3,R1,R2,3,3,3);
dBodySetRotation (body[0],R3);
// randomly adjust position of body[0]
const dReal *pos = dBodyGetPosition (body[0]);
dBodySetPosition (body[0],
pos[0]+0.2*(dRandReal()-0.5),
pos[1]+0.2*(dRandReal()-0.5),
pos[2]+0.2*(dRandReal()-0.5));
}
count++;
}
}
dReal sides1[3] = {SIDE,SIDE,SIDE};
dReal sides2[3] = {SIDE,SIDE,SIDE*0.8f};
dsSetTexture (DS_WOOD);
dsSetColor (1,1,0);
dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides1);
dsSetColor (0,1,1);
dsDrawBox (dBodyGetPosition(body[1]),dBodyGetRotation(body[1]),sides2);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
dMass m;
dMassSetBox (&m,1,SIDE,SIDE,SIDE);
dMassAdjust (&m,MASS);
dQuaternion q;
dQFromAxisAndAngle (q,1,1,0,0.25*M_PI);
body[0] = dBodyCreate (world);
dBodySetMass (body[0],&m);
dBodySetPosition (body[0],0.5*SIDE,0.5*SIDE,1);
dBodySetQuaternion (body[0],q);
body[1] = dBodyCreate (world);
dBodySetMass (body[1],&m);
dBodySetPosition (body[1],-0.5*SIDE,-0.5*SIDE,1);
dBodySetQuaternion (body[1],q);
hinge = dJointCreateHinge (world,0);
dJointAttach (hinge,body[0],body[1]);
dJointSetHingeAnchor (hinge,0,0,1);
dJointSetHingeAxis (hinge,1,-1,1.41421356);
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,434 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/*
This file try to demonstrate how the PR joint is working.
The axisP is draw in red and the axisR is in green
*/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include <iostream>
#include <math.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#endif
// physics parameters
#define BOX1_LENGTH 2 // Size along the X axis
#define BOX1_WIDTH 1 // Size along the Y axis
#define BOX1_HEIGHT 0.4 // Size along the Z axis (up) since gravity is (0,0,-10)
#define BOX2_LENGTH 0.2
#define BOX2_WIDTH 0.1
#define BOX2_HEIGHT 0.4
#define Mass1 10
#define Mass2 0.1
#define PRISMATIC_ONLY 1
#define ROTOIDE_ONLY 2
int flag = 0;
//camera view
static float xyz[3] = {2.0f,-3.5f,2.0000f};
static float hpr[3] = {90.000f,-25.5000f,0.0000f};
//world,space,body & geom
static dWorldID world;
static dSpaceID space;
static dSpaceID box1_space;
static dBodyID box1_body[1];
static dBodyID box2_body[1];
static dJointID joint[1];
static dJointGroupID contactgroup;
static dGeomID ground;
static dGeomID box1[1];
static dGeomID box2[1];
//collision detection
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i,n;
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return;
const int N = 10;
dContact contact[N];
n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
if (n > 0)
{
for (i=0; i<n; i++)
{
contact[i].surface.mode = dContactSlip1 | dContactSlip2 |
dContactSoftERP | dContactSoftCFM | dContactApprox1;
contact[i].surface.mu = 0.1;
contact[i].surface.slip1 = 0.02;
contact[i].surface.slip2 = 0.02;
contact[i].surface.soft_erp = 0.1;
contact[i].surface.soft_cfm = 0.0001;
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
dJointAttach (c,dGeomGetBody(contact[i].geom.g1),dGeomGetBody(contact[i].geom.g2));
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
dsSetViewpoint (xyz,hpr);
printf ("Press 'd' to add force along positive x direction.\nPress 'a' to add force along negative x direction.\n");
printf ("Press 'w' to add force along positive y direction.\nPress 's' to add force along negative y direction.\n");
printf ("Press 'e' to add torque around positive z direction.\nPress 'q' to add torque around negative z direction.\n");
printf ("Press 'o' to add force around positive x direction \n");
printf("Press 'v' to give a defined velocity and add a FMax to the rotoide axis\n");
printf("Press 'c' to set the velocity to zero and remove the FMax\n");
printf("Press 'l' to add limits (-0.5 to 0.5rad) on the rotoide axis\n");
printf("Press 'k' to remove the limits on the rotoide axis\n");
printf("Press 'i' to get joint info\n");
}
// function to update camera position at each step.
void update()
{
// const dReal *a =(dBodyGetPosition (box1_body[0]));
// float dx=a[0];
// float dy=a[1];
// float dz=a[2];
// xyz[0]=dx;
// xyz[1]=dy-5;
// xyz[2]=dz+2;
// hpr[1]=-22.5000f;
// dsSetViewpoint (xyz,hpr);
}
// called when a key pressed
static void command (int cmd)
{
switch (cmd)
{
case 'w':
case 'W':
dBodyAddForce(box2_body[0],0,500,0);
std::cout<<(dBodyGetPosition(box2_body[0])[1]-dBodyGetPosition(box1_body[0])[1])<<'\n';
break;
case 's':
case 'S':
dBodyAddForce(box2_body[0],0,-500,0);
std::cout<<(dBodyGetPosition(box2_body[0])[1]-dBodyGetPosition(box1_body[0])[1])<<'\n';
break;
case 'd':
case 'D':
dBodyAddForce(box2_body[0],500,0,0);
std::cout<<(dBodyGetPosition(box2_body[0])[0]-dBodyGetPosition(box1_body[0])[0])<<'\n';
break;
case 'a':
case 'A':
dBodyAddForce(box2_body[0],-500,0,0);
std::cout<<(dBodyGetPosition(box2_body[0])[0]-dBodyGetPosition(box1_body[0])[0])<<'\n';
break;
case 'e':
case 'E':
dBodyAddRelTorque(box2_body[0],0,0,200);
break;
case 'q':
case 'Q':
dBodyAddRelTorque(box2_body[0],0,0,-200);
break;
case 'o':
case 'O':
dBodyAddForce(box1_body[0],10000,0,0);
break;
case 'v':
case 'V':
dJointSetPRParam(joint[0], dParamVel2, 2);
dJointSetPRParam(joint[0], dParamFMax2, 500);
break;
case 'c':
case 'C':
dJointSetPRParam(joint[0], dParamVel2, 0);
dJointSetPRParam(joint[0], dParamFMax2, 0);
break;
case 'l':
case 'L':
dJointSetPRParam(joint[0], dParamLoStop2, -0.5);
dJointSetPRParam(joint[0], dParamHiStop2, 0.5);
break;
case 'k':
case 'K':
dJointSetPRParam(joint[0], dParamLoStop2, -dInfinity);
dJointSetPRParam(joint[0], dParamHiStop2, dInfinity);
break;
case 'i':
case 'I':
dVector3 anchor;
dJointGetPRAnchor(joint[0], anchor);
dReal angle = dJointGetPRAngle(joint[0]);
dReal w = dJointGetPRAngleRate(joint[0]);
dReal l = dJointGetPRPosition(joint[0]);
dReal v = dJointGetPRPositionRate(joint[0]);
printf("Anchor: [%6.4f, %6.4f, %6.4f]\n", anchor[0], anchor[1], anchor[2]);
printf("Position: %7.4f, Rate: %7.4f\n", l, v);
printf("Angle: %7.4f, Rate: %7.4f\n", angle, w);
break;
}
}
// simulation loop
static void simLoop (int pause)
{
if (!pause)
{
//draw 2 boxes
dVector3 ss;
dsSetTexture (DS_WOOD);
const dReal *posBox2 = dGeomGetPosition(box2[0]);
const dReal *rotBox2 = dGeomGetRotation(box2[0]);
dsSetColor (1,1,0);
dGeomBoxGetLengths (box2[0],ss);
dsDrawBox (posBox2, rotBox2, ss);
const dReal *posBox1 = dGeomGetPosition(box1[0]);
const dReal *rotBox1 = dGeomGetRotation(box1[0]);
dsSetColor (1,1,2);
dGeomBoxGetLengths (box1[0], ss);
dsDrawBox (posBox1, rotBox1, ss);
dVector3 anchorPos;
dJointGetPRAnchor (joint[0], anchorPos);
// Draw the axisP
if (ROTOIDE_ONLY != flag )
{
dsSetColor (1,0,0);
dVector3 sizeP = {0, 0.1, 0.1};
for (int i=0; i<3; ++i)
sizeP[0] += (anchorPos[i] - posBox1[i])*(anchorPos[i] - posBox1[i]);
sizeP[0] = sqrt(sizeP[0]);
dVector3 posAxisP;
for (int i=0; i<3; ++i)
posAxisP[i] = posBox1[i] + (anchorPos[i] - posBox1[i])/2.0;
dsDrawBox (posAxisP, rotBox1, sizeP);
}
// Draw the axisR
if (PRISMATIC_ONLY != flag )
{
dsSetColor (0,1,0);
dVector3 sizeR = {0, 0.1, 0.1};
for (int i=0; i<3; ++i)
sizeR[0] += (anchorPos[i] - posBox2[i])*(anchorPos[i] - posBox2[i]);
sizeR[0] = sqrt(sizeR[0]);
dVector3 posAxisR;
for (int i=0; i<3; ++i)
posAxisR[i] = posBox2[i] + (anchorPos[i] - posBox2[i])/2.0;
dsDrawBox (posAxisR, rotBox2, sizeR);
}
dSpaceCollide (space,0,&nearCallback);
dWorldQuickStep (world,0.0001);
update();
dJointGroupEmpty (contactgroup);
}
}
void Help(char **argv)
{
printf("%s ", argv[0]);
printf(" -h | --help : print this help\n");
printf(" -b | --both : Display how the complete joint works\n");
printf(" Default behavior\n");
printf(" -p | --prismatic-only : Display how the prismatic part works\n");
printf(" The anchor pts is set at the center of body 2\n");
printf(" -r | --rotoide-only : Display how the rotoide part works\n");
printf(" The anchor pts is set at the center of body 1\n");
printf(" -t | --texture-path path : Path to the texture.\n");
printf(" Default = %s\n", DRAWSTUFF_TEXTURE_PATH);
printf("--------------------------------------------------\n");
printf("Hit any key to continue:");
getchar();
exit(0);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
if (argc >= 2 )
{
for (int i=1; i < argc; ++i)
{
if ( 0 == strcmp("-h", argv[i]) || 0 == strcmp("--help", argv[i]) )
Help(argv);
if (!flag && (0 == strcmp("-p", argv[i]) ||0 == strcmp("--prismatic-only", argv[i])) )
flag = PRISMATIC_ONLY;
if (!flag && (0 == strcmp("-r", argv[i]) || 0 == strcmp("--rotoide-only", argv[i])) )
flag = ROTOIDE_ONLY;
if (0 == strcmp("-t", argv[i]) || 0 == strcmp("--texture-path", argv[i]))
{
int j = i+1;
if ( j >= argc || // Check if we have enough arguments
argv[j][0] == '\0' || // We should have a path here
argv[j][0] == '-' ) // We should have a path not a command line
Help(argv);
else
fn.path_to_textures = argv[++i]; // Increase i since we use this argument
}
}
}
dInitODE2(0);
// create world
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-10);
ground = dCreatePlane (space,0,0,1,0);
//create two boxes
dMass m;
box1_body[0] = dBodyCreate (world);
dMassSetBox (&m,1,BOX1_LENGTH,BOX1_WIDTH,BOX1_HEIGHT);
dMassAdjust (&m,Mass1);
dBodySetMass (box1_body[0],&m);
box1[0] = dCreateBox (0,BOX1_LENGTH,BOX1_WIDTH,BOX1_HEIGHT);
dGeomSetBody (box1[0],box1_body[0]);
box2_body[0] = dBodyCreate (world);
dMassSetBox (&m,10,BOX2_LENGTH,BOX2_WIDTH,BOX2_HEIGHT);
dMassAdjust (&m,Mass2);
dBodySetMass (box2_body[0],&m);
box2[0] = dCreateBox (0,BOX2_LENGTH,BOX2_WIDTH,BOX2_HEIGHT);
dGeomSetBody (box2[0],box2_body[0]);
//set the initial positions of body1 and body2
dMatrix3 R;
dRSetIdentity(R);
dBodySetPosition (box1_body[0],0,0,BOX1_HEIGHT/2.0);
dBodySetRotation (box1_body[0], R);
dBodySetPosition (box2_body[0],
2.1,
0.0,
BOX2_HEIGHT/2.0);
dBodySetRotation (box2_body[0], R);
//set PR joint
joint[0] = dJointCreatePR(world,0);
dJointAttach (joint[0],box1_body[0],box2_body[0]);
switch (flag)
{
case PRISMATIC_ONLY:
dJointSetPRAnchor (joint[0],
2.1,
0.0,
BOX2_HEIGHT/2.0);
dJointSetPRParam (joint[0],dParamLoStop, -0.5);
dJointSetPRParam (joint[0],dParamHiStop, 1.5);
break;
case ROTOIDE_ONLY:
dJointSetPRAnchor (joint[0],
0.0,
0.0,
BOX2_HEIGHT/2.0);
dJointSetPRParam (joint[0],dParamLoStop, 0.0);
dJointSetPRParam (joint[0],dParamHiStop, 0.0);
break;
default:
dJointSetPRAnchor (joint[0],
1.1,
0.0,
BOX2_HEIGHT/2.0);
dJointSetPRParam (joint[0],dParamLoStop, -0.5);
dJointSetPRParam (joint[0],dParamHiStop, 1.5);
break;
}
dJointSetPRAxis1(joint[0],1,0,0);
dJointSetPRAxis2(joint[0],0,0,1);
// We position the 2 body
// The position of the rotoide joint is on the second body so it can rotate on itself
// and move along the X axis.
// With this anchor
// - A force in X will move only the body 2 inside the low and hi limit
// of the prismatic
// - A force in Y will make the 2 bodies to rotate around on the plane
box1_space = dSimpleSpaceCreate (space);
dSpaceSetCleanup (box1_space,0);
dSpaceAdd(box1_space,box1[0]);
// run simulation
dsSimulationLoop (argc,argv,400,300,&fn);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,736 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/*
This program demonstrates how the PU joint works.
A PU joint is a combination of a Universal joint and a Slider joint.
It is a universal joint with a slider between the anchor point and
body 1.
The upper yellow body is fixed to the world
The lower yellow body is attached to the upper body by a PU joint
The green object is one aprt of the slider.
The purple object is the second part of the slider.
The red object represent the axis1 of the universal part.
The blue object represent the axis2 of the universal part.
The gray object represent the anchor2 of the PU joint.
*/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include <iostream>
#include <math.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
enum IDX_CYL_DIM
{
RADIUS,
LENGTH,
NUM_CYL_DIM
};
const dVector3 boxDim = {1,1,1};
const dVector3 extDim = {0.2,0.2,1.2};
const dVector3 ancDim = {0.2,0.2,0.5};
const dReal axDim[NUM_CYL_DIM] = {0.1,1.0};
int type = dJointTypePU;
const dReal VEL_INC = 0.01; // Velocity increment
// physics parameters
const dReal PI = 3.14159265358979323846264338327950288419716939937510;
const dReal INT_EXT_RATIO = 0.8;
#define X 0
#define Y 1
#define Z 2
enum INDEX
{
W = 0,
D,
EXT,
INT,
AXIS1,
AXIS2,
ANCHOR,
GROUND,
NUM_PARTS,
ALL = NUM_PARTS,
// INDEX for catBits
JOINT,
LAST_INDEX_CNT
};
const int catBits[LAST_INDEX_CNT] =
{
0x0001, ///< W Cylinder category
0x0002, ///< D Cylinder category
0x0004, ///< EXT sliderr category
0x0008, ///< INT slider category
0x0010, ///< AXIS1 universal category
0x0020, ///< AXIS2 universal category
0x0040, ///< ANCHOR category
0x0080, ///< Ground category
~0L, ///< All categories
0x0004 | 0x0008 | 0x0010 | 0x0020 ///< JOINT category
};
#define Mass1 10
#define Mass2 8
//camera view
static float xyz[3] = {6.0f,0.0f,6.0000f};
static float hpr[3] = {-180.000f,-25.5000f,0.0000f};
//world,space,body & geom
static dWorldID world;
static dSpaceID space;
static dJointGroupID contactgroup;
static dBodyID body[NUM_PARTS];
static dGeomID geom[NUM_PARTS];
static dJoint *joint;
const dReal BOX_SIDES[3] = {1.0,1.0,1.0};
const dReal OBS_SIDES[3] = {0.4,0.4,0.4};
const dReal RECT_SIDES[3] = {0.3, 0.1, 0.2};
//collision detection
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i,n;
const int N = 10;
dContact contact[N];
n = dCollide (o1,o2,N,&contact[0].geom,sizeof (dContact) );
if (n > 0) {
for (i=0; i<n; i++) {
contact[i].surface.mode = (dContactSlip1 | dContactSlip2 |
dContactSoftERP | dContactSoftCFM |
dContactApprox1);
contact[i].surface.mu = 0.1;
contact[i].surface.slip1 = 0.02;
contact[i].surface.slip2 = 0.02;
contact[i].surface.soft_erp = 0.1;
contact[i].surface.soft_cfm = 0.0001;
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
dJointAttach (c,dGeomGetBody (contact[i].geom.g1),dGeomGetBody (contact[i].geom.g2) );
}
}
}
static void printKeyBoardShortCut()
{
printf ("Press 'h' for this help.\n");
printf ("Press 'q' to add force on BLUE body along positive x direction.\n");
printf ("Press 'w' to add force on BLUE body along negative x direction.\n");
printf ("Press 'a' to add force on BLUE body along positive y direction.\n");
printf ("Press 's' to add force on BLUE body along negative y direction.\n");
printf ("Press 'z' to add force on BLUE body along positive z direction.\n");
printf ("Press 'x' to add force on BLUE body along negative z direction.\n");
printf ("Press 'e' to add torque on BLUE body around positive x direction \n");
printf ("Press 'r' to add torque on BLUE body around negative x direction \n");
printf ("Press 'd' to add torque on BLUE body around positive y direction \n");
printf ("Press 'f' to add torque on BLUE body around negative y direction \n");
printf ("Press 'c' to add torque on BLUE body around positive z direction \n");
printf ("Press 'v' to add torque on BLUE body around negative z direction \n");
printf ("Press '.' to increase joint velocity along the prismatic direction.\n");
printf ("Press ',' to decrease joint velocity along the prismatic direction.\n");
printf ("Press 'l' Toggle ON/OFF the limits on all the axis\n");
printf ("Press 'g' Toggle ON/OFF the gravity\n");
printf ("Press 'p' to print the position, angle and rates of the joint.\n");
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
dsSetViewpoint (xyz,hpr);
printf ("This program demonstrates how the PU joint works.\n");
printf ("A PU joint is a combination of a Universal joint and a Slider joint.\n");
printf ("It is a universal joint with a slider between the anchor point and \n");
printf ("body 1.\n\n");
printf ("The upper yellow body is fixed to the world\n");
printf ("The lower yellow body is attached to the upper body by a PU joint\n");
printf ("The green object is one aprt of the slider.\n");
printf ("The purple object is the second part of the slider.\n");
printf ("The red object represent the axis1 of the universal part. \n");
printf ("The blue object represent the axis2 of the universal part. \n");
printf ("The gray object represent the anchor2 of the PU joint. \n");
printKeyBoardShortCut();
}
// function to update camera position at each step.
void update()
{
// static FILE *file = fopen("x:/sim/src/libode/tstsrcSF/export.dat", "w");
// static int cnt = 0;
// char str[24];
// sprintf(str, "%06d",cnt++);
// dWorldExportDIF(world, file, str);
}
// called when a key pressed
static void command (int cmd)
{
switch (cmd) {
case 'h' : case 'H' : case '?' :
printKeyBoardShortCut();
break;
// Force
case 'q' : case 'Q' :
dBodyAddForce(body[D],40,0,0);
break;
case 'w' : case 'W' :
dBodyAddForce(body[D],-40,0,0);
break;
case 'a' : case 'A' :
dBodyAddForce(body[D],0,40,0);
break;
case 's' : case 'S' :
dBodyAddForce(body[D],0,-40,0);
break;
case 'z' : case 'Z' :
dBodyAddForce(body[D],0,0,40);
break;
case 'x' : case 'X' :
dBodyAddForce(body[D],0,0,-40);
break;
// Torque
case 'e': case 'E':
dBodyAddTorque(body[D],0.1,0,0);
break;
case 'r': case 'R':
dBodyAddTorque(body[D],-0.1,0,0);
break;
case 'd': case 'D':
dBodyAddTorque(body[D],0, 0.1,0);
break;
case 'f': case 'F':
dBodyAddTorque(body[D],0,-0.1,0);
break;
case 'c': case 'C':
dBodyAddTorque(body[D],0,0,0.1);
break;
case 'v': case 'V':
dBodyAddTorque(body[D],0,0,0.1);
break;
// Velocity of joint
case ',': case '<' : {
dReal vel = joint->getParam (dParamVel3) - VEL_INC;
joint->setParam (dParamVel3, vel);
joint->setParam (dParamFMax3, 2);
std::cout<<"Velocity = "<<vel<<" FMax = 2"<<'\n';
}
break;
case '.': case '>' : {
dReal vel = joint->getParam (dParamVel3) + VEL_INC;
joint->setParam (dParamVel3, vel);
joint->setParam (dParamFMax3, 2);
std::cout<<"Velocity = "<<vel<<" FMax = 2"<<'\n';
}
break;
case 'l': case 'L' : {
dReal aLimit, lLimit, fmax;
if ( joint->getParam (dParamFMax) ) {
aLimit = dInfinity;
lLimit = dInfinity;
fmax = 0;
}
else {
aLimit = 0.25*PI;
lLimit = 0.5*axDim[LENGTH];
fmax = 0.02;
}
joint->setParam (dParamFMax1, fmax);
joint->setParam (dParamFMax2, fmax);
joint->setParam (dParamFMax3, fmax);
switch (joint->getType() ) {
case dJointTypePR : {
dPRJoint *pr = reinterpret_cast<dPRJoint *> (joint);
pr->setParam (dParamLoStop, -lLimit);
pr->setParam (dParamHiStop, -lLimit);
pr->setParam (dParamLoStop2, aLimit);
pr->setParam (dParamHiStop2, -aLimit);
}
break;
case dJointTypePU : {
dPUJoint *pu = reinterpret_cast<dPUJoint *> (joint);
pu->setParam (dParamLoStop1, -aLimit);
pu->setParam (dParamHiStop1, aLimit);
pu->setParam (dParamLoStop2, -aLimit);
pu->setParam (dParamHiStop2, aLimit);
pu->setParam (dParamLoStop3, -lLimit);
pu->setParam (dParamHiStop3, lLimit);
}
break;
default: {} // keep the compiler happy
}
}
break;
case 'g': case 'G' : {
dVector3 g;
dWorldGetGravity(world, g);
if ( g[2]< -0.1 )
dWorldSetGravity(world, 0, 0, 0);
else
dWorldSetGravity(world, 0, 0, -0.5);
}
break;
case 'p' :case 'P' : {
switch (joint->getType() ) {
case dJointTypeSlider : {
dSliderJoint *sj = reinterpret_cast<dSliderJoint *> (joint);
std::cout<<"Position ="<<sj->getPosition() <<"\n";
}
break;
case dJointTypePU : {
dPUJoint *pu = reinterpret_cast<dPUJoint *> (joint);
std::cout<<"Position ="<<pu->getPosition() <<"\n";
std::cout<<"Position Rate="<<pu->getPositionRate() <<"\n";
std::cout<<"Angle1 ="<<pu->getAngle1() <<"\n";
std::cout<<"Angle1 Rate="<<pu->getAngle1Rate() <<"\n";
std::cout<<"Angle2 ="<<pu->getAngle2() <<"\n";
std::cout<<"Angle2 Rate="<<pu->getAngle2Rate() <<"\n";
}
break;
default: {} // keep the compiler happy
}
}
break;
}
}
static void drawBox (dGeomID id, int R, int G, int B)
{
if (!id)
return;
const dReal *pos = dGeomGetPosition (id);
const dReal *rot = dGeomGetRotation (id);
dsSetColor (R,G,B);
dVector3 l;
dGeomBoxGetLengths (id, l);
dsDrawBox (pos, rot, l);
}
// simulation loop
static void simLoop (int pause)
{
static bool todo = false;
if ( todo ) { // DEBUG
static int cnt = 0;
++cnt;
if (cnt == 5)
command ( 'q' );
if (cnt == 10)
dsStop();
}
if (!pause) {
double simstep = 0.01; // 10ms simulation steps
double dt = dsElapsedTime();
int nrofsteps = (int) ceilf (dt/simstep);
if (!nrofsteps)
nrofsteps = 1;
for (int i=0; i<nrofsteps && !pause; i++) {
dSpaceCollide (space,0,&nearCallback);
dWorldStep (world, simstep);
dJointGroupEmpty (contactgroup);
}
update();
dReal radius, length;
dsSetTexture (DS_WOOD);
drawBox (geom[W], 1,1,0);
drawBox (geom[EXT], 0,1,0);
dVector3 anchorPos;
dReal ang1 = 0;
dReal ang2 = 0;
dVector3 axisP, axisR1, axisR2;
if ( dJointTypePU == type ) {
dPUJoint *pu = dynamic_cast<dPUJoint *> (joint);
ang1 = pu->getAngle1();
ang2 = pu->getAngle2();
pu->getAxis1 (axisR1);
pu->getAxis2 (axisR2);
pu->getAxisP (axisP);
dJointGetPUAnchor (pu->id(), anchorPos);
}
else if ( dJointTypePR == type ) {
dPRJoint *pr = dynamic_cast<dPRJoint *> (joint);
pr->getAxis1 (axisP);
pr->getAxis2 (axisR1);
dJointGetPRAnchor (pr->id(), anchorPos);
}
// Draw the axisR
if ( geom[INT] ) {
dsSetColor (1,0,1);
dVector3 l;
dGeomBoxGetLengths (geom[INT], l);
const dReal *rotBox = dGeomGetRotation (geom[W]);
dVector3 pos;
for (int i=0; i<3; ++i)
pos[i] = anchorPos[i] - 0.5*extDim[Z]*axisP[i];
dsDrawBox (pos, rotBox, l);
}
dsSetTexture (DS_CHECKERED);
if ( geom[AXIS1] ) {
dQuaternion q, qAng;
dQFromAxisAndAngle (qAng,axisR1[X], axisR1[Y], axisR1[Z], ang1);
dGeomGetQuaternion (geom[AXIS1], q);
dQuaternion qq;
dQMultiply1 (qq, qAng, q);
dMatrix3 R;
dQtoR (qq,R);
dGeomCylinderGetParams (geom[AXIS1], &radius, &length);
dsSetColor (1,0,0);
dsDrawCylinder (anchorPos, R, length, radius);
}
if ( dJointTypePU == type && geom[AXIS2] ) {
//dPUJoint *pu = dynamic_cast<dPUJoint *> (joint);
dQuaternion q, qAng, qq, qq1;
dGeomGetQuaternion (geom[AXIS2], q);
dQFromAxisAndAngle (qAng, 0, 1, 0, ang2);
dQMultiply1 (qq, qAng, q);
dQFromAxisAndAngle (qAng,axisR1[X], axisR1[Y], axisR1[Z], ang1);
dQMultiply1 (qq1, qAng, qq);
dMatrix3 R;
dQtoR (qq1,R);
dGeomCylinderGetParams (geom[AXIS2], &radius, &length);
dsSetColor (0,0,1);
dsDrawCylinder (anchorPos, R, length, radius);
}
dsSetTexture (DS_WOOD);
// Draw the anchor
if ( geom[ANCHOR] ) {
dsSetColor (1,1,1);
dVector3 l;
dGeomBoxGetLengths (geom[ANCHOR], l);
const dReal *rotBox = dGeomGetRotation (geom[D]);
const dReal *posBox = dGeomGetPosition (geom[D]);
dVector3 e;
for (int i=0; i<3; ++i)
e[i] = posBox[i] - anchorPos[i];
dNormalize3 (e);
dVector3 pos;
for (int i=0; i<3; ++i)
pos[i] = anchorPos[i] + 0.5 * l[Z]*e[i];
dsDrawBox (pos, rotBox, l);
}
drawBox (geom[D], 1,1,0);
}
}
void Help (char **argv)
{
printf ("%s ", argv[0]);
printf (" -h | --help : print this help\n");
printf (" -p | --PRJoint : Use a PR joint instead of PU joint\n");
printf (" -t | --texture-path path : Path to the texture.\n");
printf (" Default = %s\n", DRAWSTUFF_TEXTURE_PATH);
printf ("--------------------------------------------------\n");
printf ("Hit any key to continue:");
getchar();
exit (0);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
if (argc >= 2 ) {
for (int i=1; i < argc; ++i) {
if ( 0 == strcmp ("-h", argv[i]) || 0 == strcmp ("--help", argv[i]) )
Help (argv);
if ( 0 == strcmp ("-p", argv[i]) || 0 == strcmp ("--PRJoint", argv[i]) )
type = dJointTypePR;
if (0 == strcmp ("-t", argv[i]) || 0 == strcmp ("--texture-path", argv[i]) ) {
int j = i+1;
if ( j >= argc || // Check if we have enough arguments
argv[j][0] == '\0' || // We should have a path here
argv[j][0] == '-' ) // We should have a path not a command line
Help (argv);
else
fn.path_to_textures = argv[++i]; // Increase i since we use this argument
}
}
}
dInitODE2(0);
world = dWorldCreate();
dWorldSetERP (world, 0.8);
space = dSimpleSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
geom[GROUND] = dCreatePlane (space, 0,0,1,0);
dGeomSetCategoryBits (geom[GROUND], catBits[GROUND]);
dGeomSetCollideBits (geom[GROUND], catBits[ALL]);
dMass m;
// Create the body attached to the World
body[W] = dBodyCreate (world);
// Main axis of cylinder is along X=1
m.setBox (1, boxDim[X], boxDim[Y], boxDim[Z]);
m.adjust (Mass1);
geom[W] = dCreateBox (space, boxDim[X], boxDim[Y], boxDim[Z]);
dGeomSetBody (geom[W], body[W]);
dGeomSetCategoryBits (geom[W], catBits[W]);
dGeomSetCollideBits (geom[W], catBits[ALL] & (~catBits[W]) & (~catBits[JOINT]) );
dBodySetMass (body[W], &m);
// Create the dandling body
body[D] = dBodyCreate (world);
// Main axis of capsule is along X=1
m.setBox (1, boxDim[X], boxDim[Y], boxDim[Z]);
m.adjust (Mass1);
geom[D] = dCreateBox (space, boxDim[X], boxDim[Y], boxDim[Z]);
dGeomSetBody (geom[D], body[D]);
dGeomSetCategoryBits (geom[D], catBits[D]);
dGeomSetCollideBits (geom[D], catBits[ALL] & (~catBits[D]) & (~catBits[JOINT]) );
dBodySetMass (body[D], &m);
// Create the external part of the slider joint
geom[EXT] = dCreateBox (0, extDim[X], extDim[Y], extDim[Z]);
dGeomSetCategoryBits (geom[EXT], catBits[EXT]);
dGeomSetCollideBits (geom[EXT],
catBits[ALL] & (~catBits[JOINT]) & (~catBits[W]) & (~catBits[D]) );
// Create the internal part of the slider joint
geom[INT] = dCreateBox (0, INT_EXT_RATIO*extDim[X],
INT_EXT_RATIO*extDim[Y],
INT_EXT_RATIO*extDim[Z]);
dGeomSetCategoryBits (geom[INT], catBits[INT]);
dGeomSetCollideBits (geom[INT],
catBits[ALL] & (~catBits[JOINT]) & (~catBits[W]) & (~catBits[D]) );
dMatrix3 R;
// Create the first axis of the universal joi9nt
//Rotation of 90deg around y
geom[AXIS1] = dCreateCylinder(0, axDim[RADIUS], axDim[LENGTH]);
dRFromAxisAndAngle(R, 0,1,0, 0.5*PI);
dGeomSetRotation(geom[AXIS1], R);
dGeomSetCategoryBits(geom[AXIS1], catBits[AXIS1]);
dGeomSetCollideBits(geom[AXIS1],
catBits[ALL] & ~catBits[JOINT] & ~catBits[W] & ~catBits[D]);
// Create the second axis of the universal joint
geom[AXIS2] = dCreateCylinder(0, axDim[RADIUS], axDim[LENGTH]);
//Rotation of 90deg around y
dRFromAxisAndAngle(R, 1,0,0, 0.5*PI);
dGeomSetRotation(geom[AXIS2], R);
dGeomSetCategoryBits(geom[AXIS2], catBits[AXIS2]);
dGeomSetCollideBits(geom[AXIS2],
catBits[ALL] & ~catBits[JOINT] & ~catBits[W] & ~catBits[D]);
// Create the anchor
geom[ANCHOR] = dCreateBox (0, ancDim[X], ancDim[Y], ancDim[Z]);
dGeomSetCategoryBits(geom[ANCHOR], catBits[ANCHOR]);
dGeomSetCollideBits(geom[ANCHOR],
catBits[ALL] & (~catBits[JOINT]) & (~catBits[W]) & (~catBits[D]) );
if (body[W]) {
dBodySetPosition(body[W], 0, 0, 5);
}
if (geom[EXT]) {
dGeomSetPosition(geom[EXT], 0,0,3.8);
}
if (geom[INT]) {
dGeomSetPosition(geom[INT], 0,0,2.6);
}
if (geom[AXIS1]) {
dGeomSetPosition(geom[AXIS1], 0,0,2.5);
}
if (geom[AXIS2]) {
dGeomSetPosition(geom[AXIS2], 0,0,2.5);
}
if (geom[ANCHOR]) {
dGeomSetPosition(geom[ANCHOR], 0,0,2.25);
}
if (body[D]) {
dBodySetPosition(body[D], 0,0,1.5);
}
// Attache the upper box to the world
dJointID fixed = dJointCreateFixed (world,0);
dJointAttach (fixed , NULL, body[W]);
dJointSetFixed (fixed );
if (type == dJointTypePR) {
dPRJoint *pr = new dPRJoint (world, 0);
pr->attach (body[W], body[D]);
pr->setAxis1 (0, 0, -1);
pr->setAxis2 (1, 0, 0);
joint = pr;
dJointSetPRAnchor (pr->id(), 0, 0, 2.5);
}
else {
dPUJoint *pu = new dPUJoint (world, 0);
pu->attach (body[W], body[D]);
pu->setAxis1 (1, 0, 0);
pu->setAxis2 (0, 1, 0);
pu->setAxisP (0, 0, -1);
joint = pu;
dJointSetPUAnchor (pu->id(), 0, 0, 2.5);
}
// run simulation
dsSimulationLoop (argc,argv,400,300,&fn);
delete joint;
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,239 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <iostream>
#include <set>
#include <algorithm>
#include <functional>
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawCylinder dsDrawCylinderD
#endif
using namespace std;
dWorld *world;
dSpace *space;
dPlane *ground;
dBody *kbody;
dBox *kbox;
dJointGroup joints;
dCylinder *kpole;
dBody *matraca;
dBox *matraca_geom;
dHingeJoint *hinge;
struct Box {
dBody body;
dBox geom;
Box() :
body(*world),
geom(*space, 0.2, 0.2, 0.2)
{
dMass mass;
mass.setBox(10, 0.2, 0.2, 0.2);
body.setMass(mass);
geom.setData(this);
geom.setBody(body);
}
void draw() const
{
dVector3 lengths;
geom.getLengths(lengths);
dsSetTexture(DS_WOOD);
dsSetColor(0,1,0);
dsDrawBox(geom.getPosition(), geom.getRotation(), lengths);
}
};
set<Box*> boxes;
set<Box*> to_remove;
void dropBox()
{
Box *box = new Box();
dReal px = (rand() / float(RAND_MAX)) * 2 - 1;
dReal py = (rand() / float(RAND_MAX)) * 2 - 1;
dReal pz = 2.5;
box->body.setPosition(px, py, pz);
boxes.insert(box);
}
void queueRemoval(dGeomID g)
{
Box *b = (Box*)dGeomGetData(g);
to_remove.insert(b);
}
void removeQueued()
{
while (!to_remove.empty()) {
Box *b = *to_remove.begin();
to_remove.erase(b);
boxes.erase(b);
delete b;
}
}
void nearCallback(void *, dGeomID g1, dGeomID g2)
{
if (g1 == ground->id()) {
queueRemoval(g2);
return;
}
if (g2 == ground->id()) {
queueRemoval(g1);
return;
}
dBodyID b1 = dGeomGetBody(g1);
dBodyID b2 = dGeomGetBody(g2);
if (b1 && b2 && dAreConnectedExcluding(b1, b2, dJointTypeContact))
return;
const int MAX_CONTACTS = 10;
dContact contact[MAX_CONTACTS];
int n = dCollide(g1, g2, MAX_CONTACTS, &contact[0].geom, sizeof(dContact));
for (int i=0; i<n; ++i) {
contact[i].surface.mode = 0;
contact[i].surface.mu = 1;
dJointID j = dJointCreateContact (*world, joints.id(), contact+i);
dJointAttach(j, b1, b2);
}
}
void
simLoop(int pause)
{
if (!pause) {
const dReal timestep = 0.04;
// this does a hard-coded circular motion animation
static float t=0;
t += timestep/4;
if (t > 2*M_PI)
t = 0;
dVector3 next_pos = { dCos(t), dSin(t), REAL(0.5)};
dVector3 vel;
// vel = (next_pos - cur_pos) / timestep
dSubtractVectors3(vel, next_pos, kbody->getPosition());
dScaleVector3(vel, 1/timestep);
kbody->setLinearVel(vel);
// end of hard-coded animation
space->collide(0, nearCallback);
removeQueued();
world->quickStep(timestep);
joints.clear();
}
dVector3 lengths;
// the moving platform
kbox->getLengths(lengths);
dsSetTexture(DS_WOOD);
dsSetColor(.3, .3, 1);
dsDrawBox(kbox->getPosition(), kbox->getRotation(), lengths);
dReal length, radius;
kpole->getParams(&radius, &length);
dsSetTexture(DS_CHECKERED);
dsSetColor(1, 1, 0);
dsDrawCylinder(kpole->getPosition(), kpole->getRotation(), length, radius);
// the matraca
matraca_geom->getLengths(lengths);
dsSetColor(1,0,0);
dsSetTexture(DS_WOOD);
dsDrawBox(matraca_geom->getPosition(), matraca_geom->getRotation(), lengths);
// and the boxes
for_each(boxes.begin(), boxes.end(), mem_fun(&Box::draw));
}
void command(int c)
{
switch (c) {
case ' ':
dropBox();
break;
}
}
int main(int argc, char **argv)
{
dInitODE();
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = 0;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
cout << endl << "*** Press SPACE to drop boxes **" << endl;
space = new dSimpleSpace();
ground = new dPlane(*space, 0, 0, 1, 0);
world = new dWorld;
world->setGravity(0, 0, -.5);
kbody = new dBody(*world);
kbody->setKinematic();
const dReal kx = 1, ky = 0, kz = .5;
kbody->setPosition(kx, ky, kz);
kbox = new dBox(*space, 3, 3, .5);
kbox->setBody(*kbody);
kpole = new dCylinder(*space, .125, 1.5);
kpole->setBody(*kbody);
dGeomSetOffsetPosition(kpole->id(), 0, 0, 0.8);
matraca = new dBody(*world);
matraca->setPosition(kx+0, ky+1, kz+1);
matraca_geom = new dBox(*space, 0.5, 2, 0.75);
matraca_geom->setBody(*matraca);
dMass mass;
mass.setBox(1, 0.5, 2, 0.75);
matraca->setMass(mass);
hinge = new dHingeJoint(*world);
hinge->attach(*kbody, *matraca);
hinge->setAnchor(kx, ky, kz+1);
hinge->setAxis(0, 0, 1);
dsSimulationLoop (argc, argv, 640, 480, &fn);
dCloseODE();
}

View File

@@ -0,0 +1,527 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/*
This demo shows how to use dContactMotionN in a lifting platform.
*/
//#include <unistd.h> // for usleep()
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#define dsDrawConvex dsDrawConvexD
#endif
// some constants
#define NUM 100 // max number of objects
#define DENSITY (5.0) // density of all objects
#define GPB 3 // maximum number of geometries per body
#define MAX_CONTACTS 8 // maximum number of contact points per body
#define USE_GEOM_OFFSET 1
// dynamics and collision objects
struct MyObject {
dBodyID body; // the body
dGeomID geom[GPB]; // geometries representing this body
};
static int num=0; // number of objects in simulation
static int nextobj=0; // next object to recycle if num==NUM
static dWorldID world;
static dSpaceID space;
static MyObject obj[NUM];
static dJointGroupID contactgroup;
static int show_aabb = 0; // show geom AABBs?
static int show_contacts = 0; // show contact points?
static int random_pos = 1; // drop objects from random position?
static int write_world = 0;
static int show_body = 0;
static dGeomID platform, ground;
dVector3 platpos = {0, 0, 0};
int mov_type = 2;
dReal mov_time = 0;
const dReal mov1_speed = 0.2;
dVector3 mov2_vel = { 0.2, 0.1, 0.25};
/****************************************************************
* Movement 1: move platform up, reset every 80 units of time. *
* This is the simplest case *
****************************************************************/
static void moveplat_1(dReal stepsize)
{
mov_time += stepsize;
if (mov_time > 80)
mov_time = 0;
platpos[0] = platpos[1] = 0;
// the platform moves up (Z) at constant speed: mov1_speed
platpos[2] = mov1_speed * mov_time;
}
// Generate contact info for movement 1
static void contactplat_1(dContact &contact)
{
contact.surface.mode |= dContactMotionN;
contact.surface.motionN = mov1_speed;
}
/****************************************************************
* Movement 2: move platform along direction mov2_vel, reset *
* every 80 units of time. *
* This is the most general case: the geom moves along *
* an arbitrary direction. *
****************************************************************/
static void moveplat_2(dReal stepsize)
{
mov_time += stepsize;
if (mov_time > 80)
mov_time = 0;
// the platform moves at constant speed: mov2_speed
platpos[0] = mov2_vel[0] * mov_time;
platpos[1] = mov2_vel[1] * mov_time;
platpos[2] = mov2_vel[2] * mov_time;
}
// Generate contact info for movement 1
static void contactplat_2(dContact &contact)
{
/*
For arbitrary contact directions we need to project the moving
geom's velocity against the contact normal and fdir1, fdir2
(obtained with dPlaneSpace()). Assuming moving geom=g2
(so the contact joint is in the moving geom's reference frame):
motion1 = dCalcVectorDot3(fdir1, vel);
motion2 = dCalcVectorDot3(fdir2, vel);
motionN = dCalcVectorDot3(normal, vel);
For geom=g1 just negate motionN and motion2. fdir1 is an arbitrary
vector, so there's no need to negate motion1.
*/
contact.surface.mode |=
dContactMotionN | // velocity along normal
dContactMotion1 | dContactMotion2 | // and along the contact plane
dContactFDir1; // don't forget to set the direction 1
// This is a convenience function: given a vector, it finds other 2 perpendicular vectors
dVector3 motiondir1, motiondir2;
dPlaneSpace(contact.geom.normal, motiondir1, motiondir2);
for (int i=0; i<3; ++i)
contact.fdir1[i] = motiondir1[i];
dReal inv = 1;
if (contact.geom.g1 == platform)
inv = -1;
contact.surface.motion1 = dCalcVectorDot3(mov2_vel, motiondir1);
contact.surface.motion2 = inv * dCalcVectorDot3(mov2_vel, motiondir2);
contact.surface.motionN = inv * dCalcVectorDot3(mov2_vel, contact.geom.normal);
}
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
dMatrix3 RI;
static const dReal ss[3] = {0.02,0.02,0.02};
dContact contact[MAX_CONTACTS];
int numc = dCollide (o1, o2, MAX_CONTACTS,
&contact[0].geom, sizeof(dContact));
if (numc)
dRSetIdentity(RI);
bool isplatform = (o1 == platform) || (o2 == platform);
for (int i=0; i< numc; i++) {
contact[i].surface.mode = dContactBounce;
contact[i].surface.mu = 1;
contact[i].surface.bounce = 0.25;
contact[i].surface.bounce_vel = 0.01;
if (isplatform) {
switch (mov_type) {
case 1:
contactplat_1(contact[i]);
break;
case 2:
contactplat_2(contact[i]);
break;
}
}
dJointID c = dJointCreateContact (world,contactgroup,contact+i);
dJointAttach (c, dGeomGetBody(o1), dGeomGetBody(o2));
if (show_contacts)
dsDrawBox (contact[i].geom.pos, RI, ss);
}
}
// start simulation - set viewpoint
static float xyz[3] = {2.1106f,-1.3007,2.f};
static float hpr[3] = {150.f,-13.5000f,0.0000f};
static void start()
{
//dAllocateODEDataForThread(dAllocateMaskAll);
dsSetViewpoint (xyz,hpr);
printf ("To drop another object, press:\n");
printf (" b for box.\n");
printf (" s for sphere.\n");
printf (" c for capsule.\n");
printf (" y for cylinder.\n");
printf ("Press m to change the movement type\n");
printf ("Press space to reset the platform\n");
printf ("To toggle showing the geom AABBs, press a.\n");
printf ("To toggle showing the contact points, press t.\n");
printf ("To toggle dropping from random position/orientation, press r.\n");
printf ("To save the current state to 'state.dif', press 1.\n");
}
char locase (char c)
{
if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
else return c;
}
// called when a key pressed
static void command (int cmd)
{
dsizeint i;
int k;
dReal sides[3];
dMass m;
int setBody;
cmd = locase (cmd);
if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'y')
{
setBody = 0;
if (num < NUM) {
i = num;
num++;
}
else {
i = nextobj;
nextobj++;
if (nextobj >= num) nextobj = 0;
// destroy the body and geoms for slot i
if (obj[i].body) {
dBodyDestroy (obj[i].body);
}
for (k=0; k < GPB; k++) {
if (obj[i].geom[k]) {
dGeomDestroy (obj[i].geom[k]);
}
}
memset (&obj[i],0,sizeof(obj[i]));
}
obj[i].body = dBodyCreate (world);
for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1;
dMatrix3 R;
if (random_pos)
{
dBodySetPosition (obj[i].body,
dRandReal()*2-1 + platpos[0],
dRandReal()*2-1 + platpos[1],
dRandReal()+2 + platpos[2]);
dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
}
else
{
dBodySetPosition (obj[i].body,
platpos[0],
platpos[1],
platpos[2]+2);
dRSetIdentity (R);
}
dBodySetRotation (obj[i].body,R);
dBodySetData (obj[i].body,(void*) i);
if (cmd == 'b') {
dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]);
obj[i].geom[0] = dCreateBox (space,sides[0],sides[1],sides[2]);
}
else if (cmd == 'c') {
sides[0] *= 0.5;
dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]);
}
else if (cmd == 'y') {
dMassSetCylinder (&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]);
}
else if (cmd == 's') {
sides[0] *= 0.5;
dMassSetSphere (&m,DENSITY,sides[0]);
obj[i].geom[0] = dCreateSphere (space,sides[0]);
}
if (!setBody)
for (k=0; k < GPB; k++) {
if (obj[i].geom[k]) {
dGeomSetBody (obj[i].geom[k],obj[i].body);
}
}
dBodySetMass (obj[i].body,&m);
}
else if (cmd == 'a') {
show_aabb ^= 1;
}
else if (cmd == 't') {
show_contacts ^= 1;
}
else if (cmd == 'r') {
random_pos ^= 1;
}
else if (cmd == '1') {
write_world = 1;
}
else if (cmd == ' ') {
mov_time = 0;
}
else if (cmd == 'm') {
mov_type = mov_type==1 ? 2 : 1;
mov_time = 0;
}
}
// draw a geom
void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
{
int i;
if (!g) return;
if (!pos) pos = dGeomGetPosition (g);
if (!R) R = dGeomGetRotation (g);
int type = dGeomGetClass (g);
if (type == dBoxClass) {
dVector3 sides;
dGeomBoxGetLengths (g,sides);
dsDrawBox (pos,R,sides);
}
else if (type == dSphereClass) {
dsDrawSphere (pos,R,dGeomSphereGetRadius (g));
}
else if (type == dCapsuleClass) {
dReal radius,length;
dGeomCapsuleGetParams (g,&radius,&length);
dsDrawCapsule (pos,R,length,radius);
}
else if (type == dCylinderClass) {
dReal radius,length;
dGeomCylinderGetParams (g,&radius,&length);
dsDrawCylinder (pos,R,length,radius);
}
if (show_body) {
dBodyID body = dGeomGetBody(g);
if (body) {
const dReal *bodypos = dBodyGetPosition (body);
const dReal *bodyr = dBodyGetRotation (body);
dReal bodySides[3] = { 0.1, 0.1, 0.1 };
dsSetColorAlpha(0,1,0,1);
dsDrawBox(bodypos,bodyr,bodySides);
}
}
if (show_aabb) {
// draw the bounding box for this geom
dReal aabb[6];
dGeomGetAABB (g,aabb);
dVector3 bbpos;
for (i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
dVector3 bbsides;
for (i=0; i<3; i++) bbsides[i] = aabb[i*2+1] - aabb[i*2];
dMatrix3 RI;
dRSetIdentity (RI);
dsSetColorAlpha (1,0,0,0.5);
dsDrawBox (bbpos,RI,bbsides);
}
}
// simulation loop
static void updatecam()
{
xyz[0] = platpos[0] + 3.3;
xyz[1] = platpos[1] - 1.8;
xyz[2] = platpos[2] + 2;
dsSetViewpoint (xyz, hpr);
}
static void simLoop (int pause)
{
const dReal stepsize = 0.02;
dsSetColor (0,0,2);
dSpaceCollide (space,0,&nearCallback);
if (!pause) {
if (mov_type == 1)
moveplat_1(stepsize);
else
moveplat_2(stepsize);
dGeomSetPosition(platform, platpos[0], platpos[1], platpos[2]);
updatecam();
dWorldQuickStep (world,stepsize);
//dWorldStep (world,stepsize);
}
if (write_world) {
FILE *f = fopen ("state.dif","wt");
if (f) {
dWorldExportDIF (world,f,"X");
fclose (f);
}
write_world = 0;
}
// remove all contact joints
dJointGroupEmpty (contactgroup);
dsSetColor (1,1,0);
dsSetTexture (DS_WOOD);
for (int i=0; i<num; i++) {
for (int j=0; j < GPB; j++) {
if (! dBodyIsEnabled (obj[i].body)) {
dsSetColor (1,0.8,0);
}
else {
dsSetColor (1,1,0);
}
drawGeom (obj[i].geom[j],0,0,show_aabb);
}
}
dsSetColor (1,0,0);
drawGeom (platform,0,0,show_aabb);
//usleep(5000);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE();
world = dWorldCreate();
#if 1
space = dHashSpaceCreate (0);
#elif 0
dVector3 center = {0,0,0}, extents = { 100, 100, 100};
space = dQuadTreeSpaceCreate(0, center, extents, 5);
#elif 0
space = dSweepAndPruneSpaceCreate (0, dSAP_AXES_XYZ);
#else
space = dSimpleSpaceCreate(0);
#endif
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-0.5);
dWorldSetCFM (world,1e-5);
dWorldSetLinearDamping(world, 0.00001);
dWorldSetAngularDamping(world, 0.005);
dWorldSetMaxAngularSpeed(world, 200);
dWorldSetContactSurfaceLayer (world,0.001);
ground = dCreatePlane (space,0,0,1,0);
memset (obj,0,sizeof(obj));
// create lift platform
platform = dCreateBox(space, 4, 4, 1);
dGeomSetCategoryBits(ground, 1ul);
dGeomSetCategoryBits(platform, 2ul);
dGeomSetCollideBits(ground, ~2ul);
dGeomSetCollideBits(platform, ~1ul);
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}
// Local Variables:
// c-basic-offset:4
// End:

View File

@@ -0,0 +1,209 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#endif
// some constants
#define SIDE (0.5f) // side length of a box
#define MASS (1.0) // mass of a box
// dynamics and collision objects
static dWorldID world;
static dBodyID body[2];
static dGeomID geom[2];
static dJointID lmotor[2];
static dJointID amotor[2];
static dSpaceID space;
static dJointGroupID contactgroup;
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {1.0382f,-1.0811f,1.4700f};
static float hpr[3] = {135.0000f,-19.5000f,0.0000f};
dsSetViewpoint (xyz,hpr);
printf ("Press 'q,a,z' to control one axis of lmotor connectiong two bodies. (q is +,a is 0, z is -)\n");
printf ("Press 'w,e,r' to control one axis of lmotor connectiong first body with world. (w is +,e is 0, r is -)\n");
}
// called when a key pressed
static void command (int cmd)
{
if (cmd == 'q' || cmd == 'Q') {
dJointSetLMotorParam(lmotor[0],dParamVel,0);
dJointSetLMotorParam(lmotor[0],dParamVel2,0);
dJointSetLMotorParam(lmotor[0],dParamVel3,0.1);
} else if (cmd == 'a' || cmd == 'A') {
dJointSetLMotorParam(lmotor[0],dParamVel,0);
dJointSetLMotorParam(lmotor[0],dParamVel2,0);
dJointSetLMotorParam(lmotor[0],dParamVel3,0);
} else if (cmd == 'z' || cmd == 'Z') {
dJointSetLMotorParam(lmotor[0],dParamVel,0);
dJointSetLMotorParam(lmotor[0],dParamVel2,0);
dJointSetLMotorParam(lmotor[0],dParamVel3,-0.1);
} else if (cmd == 'w' || cmd == 'W') {
dJointSetLMotorParam(lmotor[1],dParamVel,0.1);
dJointSetLMotorParam(lmotor[1],dParamVel2,0);
dJointSetLMotorParam(lmotor[1],dParamVel3,0);
} else if (cmd == 'e' || cmd == 'E') {
dJointSetLMotorParam(lmotor[1],dParamVel,0);
dJointSetLMotorParam(lmotor[1],dParamVel2,0);
dJointSetLMotorParam(lmotor[1],dParamVel3,0);
} else if (cmd == 'r' || cmd == 'R') {
dJointSetLMotorParam(lmotor[1],dParamVel,-0.1);
dJointSetLMotorParam(lmotor[1],dParamVel2,0);
dJointSetLMotorParam(lmotor[1],dParamVel3,0);
}
}
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
// exit without doing anything if the two bodies are connected by a joint
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
dContact contact;
contact.surface.mode = 0;
contact.surface.mu = dInfinity;
if (dCollide (o1,o2,1,&contact.geom,sizeof(dContactGeom))) {
dJointID c = dJointCreateContact (world,contactgroup,&contact);
dJointAttach (c,b1,b2);
}
}
// simulation loop
static void simLoop (int pause)
{
if (!pause) {
dSpaceCollide(space,0,&nearCallback);
dWorldQuickStep (world,0.05);
dJointGroupEmpty(contactgroup);
}
dReal sides1[3];
dGeomBoxGetLengths(geom[0], sides1);
dReal sides2[3];
dGeomBoxGetLengths(geom[1], sides2);
dsSetTexture (DS_WOOD);
dsSetColor (1,1,0);
dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides1);
dsSetColor (0,1,1);
dsDrawBox (dBodyGetPosition(body[1]),dBodyGetRotation(body[1]),sides2);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
contactgroup = dJointGroupCreate(0);
world = dWorldCreate();
space = dSimpleSpaceCreate(0);
dMass m;
dMassSetBox (&m,1,SIDE,SIDE,SIDE);
dMassAdjust (&m,MASS);
body[0] = dBodyCreate (world);
dBodySetMass (body[0],&m);
dBodySetPosition (body[0],0,0,1);
geom[0] = dCreateBox(space,SIDE,SIDE,SIDE);
body[1] = dBodyCreate (world);
dBodySetMass (body[1],&m);
dBodySetPosition (body[1],0,0,2);
geom[1] = dCreateBox(space,SIDE,SIDE,SIDE);
dGeomSetBody(geom[0],body[0]);
dGeomSetBody(geom[1],body[1]);
lmotor[0] = dJointCreateLMotor (world,0);
dJointAttach (lmotor[0],body[0],body[1]);
lmotor[1] = dJointCreateLMotor (world,0);
dJointAttach (lmotor[1],body[0],0);
amotor[0] = dJointCreateAMotor(world,0);
dJointAttach(amotor[0], body[0],body[1]);
amotor[1] = dJointCreateAMotor(world,0);
dJointAttach(amotor[1], body[0], 0);
for (int i=0; i<2; i++) {
dJointSetAMotorNumAxes(amotor[i], 3);
dJointSetAMotorAxis(amotor[i],0,1,1,0,0);
dJointSetAMotorAxis(amotor[i],1,1,0,1,0);
dJointSetAMotorAxis(amotor[i],2,1,0,0,1);
dJointSetAMotorParam(amotor[i],dParamFMax,0.00001);
dJointSetAMotorParam(amotor[i],dParamFMax2,0.00001);
dJointSetAMotorParam(amotor[i],dParamFMax3,0.00001);
dJointSetAMotorParam(amotor[i],dParamVel,0);
dJointSetAMotorParam(amotor[i],dParamVel2,0);
dJointSetAMotorParam(amotor[i],dParamVel3,0);
dJointSetLMotorNumAxes(lmotor[i],3);
dJointSetLMotorAxis(lmotor[i],0,1,1,0,0);
dJointSetLMotorAxis(lmotor[i],1,1,0,1,0);
dJointSetLMotorAxis(lmotor[i],2,1,0,0,1);
dJointSetLMotorParam(lmotor[i],dParamFMax,0.0001);
dJointSetLMotorParam(lmotor[i],dParamFMax2,0.0001);
dJointSetLMotorParam(lmotor[i],dParamFMax3,0.0001);
}
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dJointGroupDestroy(contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,415 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#include "bunny_geom.h"
#include "convex_bunny_geom.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#define dsDrawLine dsDrawLineD
#define dsDrawTriangle dsDrawTriangleD
#define dsDrawConvex dsDrawConvexD
#endif
// some constants
#define NUM 200 // max number of objects
#define DENSITY (5.0) // density of all objects
#define GPB 3 // maximum number of geometries per body
#define MAX_CONTACTS 64 // maximum number of contact points per body
// dynamics and collision objects
struct MyObject
{
dBodyID body; // the body
dGeomID geom[GPB]; // geometries representing this body
};
static int num=0; // number of objects in simulation
static int nextobj=0; // next object to recycle if num==NUM
static dWorldID world;
static dSpaceID space;
static MyObject obj[NUM];
static dJointGroupID contactgroup;
static int selected = -1; // selected object
static int show_aabb = 0; // show geom AABBs?
static int show_contacts = 0; // show contact points?
static int random_pos = 1; // drop objects from random position?
typedef dReal dVector3R[3];
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback( void *, dGeomID o1, dGeomID o2 )
{
int i;
// if (o1->body && o2->body) return;
// exit without doing anything if the two bodies are connected by a joint
dBodyID b1 = dGeomGetBody( o1 );
dBodyID b2 = dGeomGetBody( o2 );
if ( b1 && b2 && dAreConnectedExcluding( b1,b2,dJointTypeContact ) ) return;
dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
for ( i=0; i<MAX_CONTACTS; i++ )
{
contact[i].surface.mode = dContactBounce | dContactSoftCFM;
contact[i].surface.mu = dInfinity;
contact[i].surface.mu2 = 0;
contact[i].surface.bounce = 0.1;
contact[i].surface.bounce_vel = 0.1;
contact[i].surface.soft_cfm = 0.01;
}
if ( int numc = dCollide( o1,o2,MAX_CONTACTS,&contact[0].geom,
sizeof( dContact ) ) )
{
dMatrix3 RI;
dRSetIdentity( RI );
const dReal ss[3] = {0.02,0.02,0.02};
for ( i=0; i<numc; i++ )
{
dJointID c = dJointCreateContact( world,contactgroup,contact+i );
dJointAttach( c,b1,b2 );
if ( show_contacts ) dsDrawBox( contact[i].geom.pos,RI,ss );
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread( dAllocateMaskAll );
static float xyz[3] = {2.1640f,-1.3079f,1.7600f};
static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
dsSetViewpoint( xyz,hpr );
printf( "To drop another object, press:\n" );
printf( " b for box.\n" );
printf( " s for sphere.\n" );
printf( " c for capsule.\n" );
printf( " v for a convex.\n" );
printf( "To select an object, press space.\n" );
printf( "To disable the selected object, press d.\n" );
printf( "To enable the selected object, press e.\n" );
printf( "To toggle showing the geom AABBs, press a.\n" );
printf( "To toggle showing the contact points, press t.\n" );
printf( "To toggle dropping from random position/orientation, press r.\n" );
}
char locase( char c )
{
if ( c >= 'A' && c <= 'Z' ) return c - ( 'a'-'A' );
else return c;
}
// called when a key pressed
static void command( int cmd )
{
int i,k;
dReal sides[3];
dMass m;
cmd = locase( cmd );
if ( cmd == 'v' || cmd == 'b' || cmd == 'c' || cmd == 's' || cmd == 'y')
{
if ( num < NUM )
{
i = num;
num++;
}
else
{
i = nextobj;
nextobj++;
if ( nextobj >= num ) nextobj = 0;
// destroy the body and geoms for slot i
dBodyDestroy( obj[i].body );
for ( k=0; k < GPB; k++ )
{
if ( obj[i].geom[k] ) dGeomDestroy( obj[i].geom[k] );
}
memset( &obj[i],0,sizeof( obj[i] ) );
}
obj[i].body = dBodyCreate( world );
for ( k=0; k<3; k++ ) sides[k] = dRandReal()*0.5+0.1;
dMatrix3 R;
if ( random_pos )
{
dBodySetPosition( obj[i].body,
dRandReal()*2-1,dRandReal()*2-1,dRandReal()+3 );
dRFromAxisAndAngle( R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0 );
}
else
{
dReal maxheight = 0;
for ( k=0; k<num; k++ )
{
const dReal *pos = dBodyGetPosition( obj[k].body );
if ( pos[2] > maxheight ) maxheight = pos[2];
}
dBodySetPosition( obj[i].body, 0,0,maxheight+1 );
dRFromAxisAndAngle( R,0,0,1,dRandReal()*10.0-5.0 );
}
dBodySetRotation( obj[i].body,R );
dBodySetData( obj[i].body,( void* )( dsizeint )i );
if ( cmd == 'b' )
{
dMassSetBox( &m,DENSITY,sides[0],sides[1],sides[2] );
obj[i].geom[0] = dCreateBox( space,sides[0],sides[1],sides[2] );
}
else if ( cmd == 'c' )
{
sides[0] *= 0.5;
dMassSetCapsule( &m,DENSITY,3,sides[0],sides[1] );
obj[i].geom[0] = dCreateCapsule( space,sides[0],sides[1] );
}
else if (cmd == 'y') {
dMassSetCylinder (&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]);
}
else if ( cmd == 's' )
{
sides[0] *= 0.5;
dMassSetSphere( &m,DENSITY,sides[0] );
obj[i].geom[0] = dCreateSphere( space,sides[0] );
}
else if ( cmd == 'v' )
{
obj[i].geom[0] = dCreateConvex( space,
convexBunnyPlanes,
convexBunnyPlaneCount,
convexBunnyPoints,
convexBunnyPointCount,
convexBunnyPolygons );
/// Use equivalent TriMesh to set mass
dTriMeshDataID new_tmdata = dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSingle( new_tmdata, &Vertices[0], 3 * sizeof( float ), VertexCount,
( dTriIndex* )&Indices[0], IndexCount, 3 * sizeof( dTriIndex ) );
dGeomTriMeshDataPreprocess2( new_tmdata, (1U << dTRIDATAPREPROCESS_BUILD_FACE_ANGLES), NULL );
dGeomID triMesh = dCreateTriMesh( 0, new_tmdata, 0, 0, 0 );
dMassSetTrimesh( &m, DENSITY, triMesh );
dGeomDestroy( triMesh );
dGeomTriMeshDataDestroy( new_tmdata );
printf( "mass at %f %f %f\n", m.c[0], m.c[1], m.c[2] );
dGeomSetPosition( obj[i].geom[0], -m.c[0], -m.c[1], -m.c[2] );
dMassTranslate( &m, -m.c[0], -m.c[1], -m.c[2] );
}
for ( k=0; k < GPB; k++ )
{
if ( obj[i].geom[k] ) dGeomSetBody( obj[i].geom[k],obj[i].body );
}
dBodySetMass( obj[i].body,&m );
}
if ( cmd == ' ' )
{
selected++;
if ( selected >= num ) selected = 0;
if ( selected < 0 ) selected = 0;
}
else if ( cmd == 'd' && selected >= 0 && selected < num )
{
dBodyDisable( obj[selected].body );
}
else if ( cmd == 'e' && selected >= 0 && selected < num )
{
dBodyEnable( obj[selected].body );
}
else if ( cmd == 'a' )
{
show_aabb ^= 1;
}
else if ( cmd == 't' )
{
show_contacts ^= 1;
}
else if ( cmd == 'r' )
{
random_pos ^= 1;
}
}
// draw a geom
void drawGeom( dGeomID g, const dReal *pos, const dReal *R, int show_aabb )
{
if ( !g ) return;
if ( !pos ) pos = dGeomGetPosition( g );
if ( !R ) R = dGeomGetRotation( g );
int type = dGeomGetClass( g );
if ( type == dBoxClass )
{
dVector3 sides;
dGeomBoxGetLengths( g,sides );
dsDrawBox( pos,R,sides );
}
else if ( type == dSphereClass )
{
dsDrawSphere( pos,R,dGeomSphereGetRadius( g ) );
}
else if (type == dCylinderClass) {
dReal radius,length;
dGeomCylinderGetParams (g,&radius,&length);
dsDrawCylinder (pos,R,length,radius);
}
else if ( type == dCapsuleClass )
{
dReal radius,length;
dGeomCapsuleGetParams( g,&radius,&length );
dsDrawCapsule( pos,R,length,radius );
}
else if ( type == dConvexClass )
{
dsDrawConvex( pos,R,
convexBunnyPlanes,
convexBunnyPlaneCount,
convexBunnyPoints,
convexBunnyPointCount,
convexBunnyPolygons );
}
if ( show_aabb )
{
// draw the bounding box for this geom
dReal aabb[6];
dGeomGetAABB( g,aabb );
dVector3 bbpos;
for ( int i=0; i<3; i++ ) bbpos[i] = 0.5*( aabb[i*2] + aabb[i*2+1] );
dVector3 bbsides;
for ( int j=0; j<3; j++ ) bbsides[j] = aabb[j*2+1] - aabb[j*2];
dMatrix3 RI;
dRSetIdentity( RI );
dsSetColorAlpha( 1,0,0,0.5 );
dsDrawBox( bbpos,RI,bbsides );
}
}
// simulation loop
static void simLoop( int pause )
{
dsSetColor( 0,0,2 );
dSpaceCollide( space,0,&nearCallback );
if ( !pause ) dWorldQuickStep( world,0.05 );
for ( int j = 0; j < dSpaceGetNumGeoms( space ); j++ )
{
dSpaceGetGeom( space, j );
}
// remove all contact joints
dJointGroupEmpty( contactgroup );
dsSetColor( 1,1,0 );
dsSetTexture( DS_WOOD );
for ( int i=0; i<num; i++ )
{
for ( int j=0; j < GPB; j++ )
{
if ( obj[i].geom[j] )
{
if ( i==selected )
{
dsSetColor( 0,0.7,1 );
}
else if ( ! dBodyIsEnabled( obj[i].body ) )
{
dsSetColor( 1,0,0 );
}
else
{
dsSetColor( 1,1,0 );
}
drawGeom( obj[i].geom[j],0,0,show_aabb );
}
}
}
}
int main( int argc, char **argv )
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2( 0 );
world = dWorldCreate();
space = dSimpleSpaceCreate( 0 );
contactgroup = dJointGroupCreate( 0 );
dWorldSetGravity( world,0,0,-0.5 );
dWorldSetCFM( world,1e-5 );
dCreatePlane( space,0,0,1,0 );
memset( obj,0,sizeof( obj ) );
// run simulation
dsSimulationLoop( argc,argv,352,288,&fn );
dJointGroupDestroy( contactgroup );
dSpaceDestroy( space );
dWorldDestroy( world );
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,677 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#include "bunny_geom.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
//<---- Convex Object
static const dReal planes[] = // planes for a cube
{
1.0f ,0.0f ,0.0f ,0.25f,
0.0f ,1.0f ,0.0f ,0.25f,
0.0f ,0.0f ,1.0f ,0.25f,
0.0f ,0.0f ,-1.0f,0.25f,
0.0f ,-1.0f,0.0f ,0.25f,
-1.0f,0.0f ,0.0f ,0.25f
/*
1.0f ,0.0f ,0.0f ,2.0f,
0.0f ,1.0f ,0.0f ,1.0f,
0.0f ,0.0f ,1.0f ,1.0f,
0.0f ,0.0f ,-1.0f,1.0f,
0.0f ,-1.0f,0.0f ,1.0f,
-1.0f,0.0f ,0.0f ,0.0f
*/
};
static const unsigned int planecount=6;
static const dReal points[] = // points for a cube
{
0.25f,0.25f,0.25f,
-0.25f,0.25f,0.25f,
0.25f,-0.25f,0.25f,
-0.25f,-0.25f,0.25f,
0.25f,0.25f,-0.25f,
-0.25f,0.25f,-0.25f,
0.25f,-0.25f,-0.25f,
-0.25f,-0.25f,-0.25f,
};
static const unsigned int pointcount=8;
static const unsigned int polygons[] = //Polygons for a cube (6 squares)
{
4,0,2,6,4, // positive X
4,1,0,4,5, // positive Y
4,0,1,3,2, // positive Z
4,3,1,5,7, // negative X
4,2,3,7,6, // negative Y
4,5,4,6,7, // negative Z
};
//----> Convex Object
int tmTriangles[] =
{
0,2,6,
0,6,4,
1,0,4,
1,4,5,
0,1,3,
0,3,2,
3,1,5,
3,5,7,
2,3,7,
2,7,6,
5,4,6,
5,6,7
};
float tmVertices[] =
{
0.25f,0.25f,0.25f, // point 0
-0.25f,0.25f,0.25f, // point 1
0.25f,-0.25f,0.25f, // point 2
-0.25f,-0.25f,0.25f,// point 3
0.25f,0.25f,-0.25f, // point 4
-0.25f,0.25f,-0.25f,// point 5
0.25f,-0.25f,-0.25f,// point 6
-0.25f,-0.25f,-0.25f,// point 7
};
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#define dsDrawLine dsDrawLineD
#define dsDrawTriangle dsDrawTriangleD
#define dsDrawConvex dsDrawConvexD
#endif
// some constants
#define NUM 200 // max number of objects
#define DENSITY (5.0) // density of all objects
#define GPB 3 // maximum number of geometries per body
#define MAX_CONTACTS 64 // maximum number of contact points per body
// dynamics and collision objects
struct MyObject {
dBodyID body; // the body
dGeomID geom[GPB]; // geometries representing this body
// Trimesh only - double buffered matrices for 'last transform' setup
dReal matrix_dblbuff[ 16 * 2 ];
int last_matrix_index;
};
static int num=0; // number of objects in simulation
static int nextobj=0; // next object to recycle if num==NUM
static dWorldID world;
static dSpaceID space;
static MyObject obj[NUM];
static dJointGroupID contactgroup;
static int selected = -1; // selected object
static int show_aabb = 0; // show geom AABBs?
static int show_contacts = 0; // show contact points?
static int random_pos = 1; // drop objects from random position?
typedef dReal dVector3R[3];
dGeomID TriMesh1;
dGeomID TriMesh2;
static dTriMeshDataID TriData1, TriData2; // reusable static trimesh data
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i;
// if (o1->body && o2->body) return;
// exit without doing anything if the two bodies are connected by a joint
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return;
dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
for (i=0; i<MAX_CONTACTS; i++) {
contact[i].surface.mode = dContactBounce | dContactSoftCFM;
contact[i].surface.mu = dInfinity;
contact[i].surface.mu2 = 0;
contact[i].surface.bounce = 0.1;
contact[i].surface.bounce_vel = 0.1;
contact[i].surface.soft_cfm = 0.01;
}
if (int numc = dCollide (o1,o2,MAX_CONTACTS,&contact[0].geom,
sizeof(dContact))) {
dMatrix3 RI;
dRSetIdentity (RI);
const dReal ss[3] = {0.02,0.02,0.02};
for (i=0; i<numc; i++) {
dJointID c = dJointCreateContact (world,contactgroup,contact+i);
dJointAttach (c,b1,b2);
if (show_contacts) dsDrawBox (contact[i].geom.pos,RI,ss);
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {2.1640f,-1.3079f,1.7600f};
static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
dsSetViewpoint (xyz,hpr);
printf ("To drop another object, press:\n");
printf (" b for box.\n");
printf (" s for sphere.\n");
printf (" y for cylinder.\n");
printf (" c for capsule.\n");
printf (" x for a composite object.\n");
printf (" v for a convex object.\n");
printf (" m for a trimesh.\n");
printf ("To select an object, press space.\n");
printf ("To disable the selected object, press d.\n");
printf ("To enable the selected object, press e.\n");
printf ("To toggle showing the geom AABBs, press a.\n");
printf ("To toggle showing the contact points, press t.\n");
printf ("To toggle dropping from random position/orientation, press r.\n");
}
char locase (char c)
{
if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
else return c;
}
// called when a key pressed
static void command (int cmd)
{
int i,j,k;
dReal sides[3];
dMass m;
bool setBody = false;
cmd = locase (cmd);
if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' || cmd == 'm' || cmd == 'y' || cmd == 'v') {
if (num < NUM) {
i = num;
num++;
}
else {
i = nextobj;
nextobj++;
if (nextobj >= num) nextobj = 0;
// destroy the body and geoms for slot i
dBodyDestroy (obj[i].body);
for (k=0; k < GPB; k++) {
if (obj[i].geom[k]) dGeomDestroy (obj[i].geom[k]);
}
memset (&obj[i],0,sizeof(obj[i]));
}
obj[i].body = dBodyCreate (world);
for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1;
dMatrix3 R;
if (random_pos) {
dBodySetPosition (obj[i].body,
dRandReal()*2-1,dRandReal()*2-1,dRandReal()+3);
dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
}
else {
dReal maxheight = 0;
for (k=0; k<num; k++) {
const dReal *pos = dBodyGetPosition (obj[k].body);
if (pos[2] > maxheight) maxheight = pos[2];
}
dBodySetPosition (obj[i].body, 0,0,maxheight+1);
dRFromAxisAndAngle (R,0,0,1,dRandReal()*10.0-5.0);
}
dBodySetRotation (obj[i].body,R);
dBodySetData (obj[i].body,(void*)(dsizeint)i);
if (cmd == 'b') {
dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]);
obj[i].geom[0] = dCreateBox (space,sides[0],sides[1],sides[2]);
}
else if (cmd == 'c') {
sides[0] *= 0.5;
dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]);
} else if (cmd == 'v') {
dMassSetBox (&m,DENSITY,0.25,0.25,0.25);
obj[i].geom[0] = dCreateConvex(space,
planes,
planecount,
points,
pointcount,
polygons);
}
else if (cmd == 'y') {
sides[1] *= 0.5;
dMassSetCylinder (&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]);
}
else if (cmd == 's') {
sides[0] *= 0.5;
dMassSetSphere (&m,DENSITY,sides[0]);
obj[i].geom[0] = dCreateSphere (space,sides[0]);
}
else if (cmd == 'm') {
dTriMeshDataID new_tmdata = dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSingle(new_tmdata, &Vertices[0], 3 * sizeof(float), VertexCount,
(dTriIndex*)&Indices[0], IndexCount, 3 * sizeof(dTriIndex));
dGeomTriMeshDataPreprocess2(new_tmdata, (1U << dTRIDATAPREPROCESS_BUILD_FACE_ANGLES), NULL);
obj[i].geom[0] = dCreateTriMesh(space, new_tmdata, 0, 0, 0);
// remember the mesh's dTriMeshDataID on its userdata for convenience.
dGeomSetData(obj[i].geom[0], new_tmdata);
dMassSetTrimesh( &m, DENSITY, obj[i].geom[0] );
printf("mass at %f %f %f\n", m.c[0], m.c[1], m.c[2]);
dGeomSetPosition(obj[i].geom[0], -m.c[0], -m.c[1], -m.c[2]);
dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]);
}
else if (cmd == 'x') {
setBody = true;
// start accumulating masses for the composite geometries
dMass m2;
dMassSetZero (&m);
dReal dpos[GPB][3]; // delta-positions for composite geometries
dMatrix3 drot[GPB];
// set random delta positions
for (j=0; j<GPB; j++)
for (k=0; k<3; k++)
dpos[j][k] = dRandReal()*0.3-0.15;
for (k=0; k<GPB; k++) {
if (k==0) {
dReal radius = dRandReal()*0.25+0.05;
obj[i].geom[k] = dCreateSphere (space,radius);
dMassSetSphere (&m2,DENSITY,radius);
} else if (k==1) {
obj[i].geom[k] = dCreateBox(space,sides[0],sides[1],sides[2]);
dMassSetBox(&m2,DENSITY,sides[0],sides[1],sides[2]);
} else {
dReal radius = dRandReal()*0.1+0.05;
dReal length = dRandReal()*1.0+0.1;
obj[i].geom[k] = dCreateCapsule(space,radius,length);
dMassSetCapsule(&m2,DENSITY,3,radius,length);
}
dRFromAxisAndAngle(drot[k],dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
dMassRotate(&m2,drot[k]);
dMassTranslate(&m2,dpos[k][0],dpos[k][1],dpos[k][2]);
// add to the total mass
dMassAdd(&m,&m2);
}
for (k=0; k<GPB; k++) {
dGeomSetBody(obj[i].geom[k],obj[i].body);
dGeomSetOffsetPosition(obj[i].geom[k],
dpos[k][0]-m.c[0],
dpos[k][1]-m.c[1],
dpos[k][2]-m.c[2]);
dGeomSetOffsetRotation(obj[i].geom[k], drot[k]);
}
dMassTranslate(&m,-m.c[0],-m.c[1],-m.c[2]);
dBodySetMass(obj[i].body,&m);
}
if (!setBody) { // avoid calling for composite geometries
for (k=0; k < GPB; k++)
if (obj[i].geom[k])
dGeomSetBody(obj[i].geom[k],obj[i].body);
dBodySetMass(obj[i].body,&m);
}
}
if (cmd == ' ') {
selected++;
if (selected >= num) selected = 0;
if (selected < 0) selected = 0;
}
else if (cmd == 'd' && selected >= 0 && selected < num) {
dBodyDisable (obj[selected].body);
}
else if (cmd == 'e' && selected >= 0 && selected < num) {
dBodyEnable (obj[selected].body);
}
else if (cmd == 'a') {
show_aabb ^= 1;
}
else if (cmd == 't') {
show_contacts ^= 1;
}
else if (cmd == 'r') {
random_pos ^= 1;
}
}
// draw a geom
void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
{
if (!g) return;
if (!pos) pos = dGeomGetPosition (g);
if (!R) R = dGeomGetRotation (g);
int type = dGeomGetClass (g);
if (type == dBoxClass) {
dVector3 sides;
dGeomBoxGetLengths (g,sides);
dsDrawBox (pos,R,sides);
}
else if (type == dSphereClass) {
dsDrawSphere (pos,R,dGeomSphereGetRadius (g));
}
else if (type == dCapsuleClass) {
dReal radius,length;
dGeomCapsuleGetParams (g,&radius,&length);
dsDrawCapsule (pos,R,length,radius);
}
else if (type == dCylinderClass) {
dReal radius,length;
dGeomCylinderGetParams (g,&radius,&length);
dsDrawCylinder (pos,R,length,radius);
} else if (type == dConvexClass) {
//dVector3 sides={0.50,0.50,0.50};
dsDrawConvex(pos,R,planes,
planecount,
points,
pointcount,
polygons);
}
if (show_aabb) {
// draw the bounding box for this geom
dReal aabb[6];
dGeomGetAABB (g,aabb);
dVector3 bbpos;
for (int i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
dVector3 bbsides;
for (int j=0; j<3; j++) bbsides[j] = aabb[j*2+1] - aabb[j*2];
dMatrix3 RI;
dRSetIdentity (RI);
dsSetColorAlpha (1,0,0,0.5);
dsDrawBox (bbpos,RI,bbsides);
}
}
// set previous transformation matrix for trimesh
void setCurrentTransform(dGeomID geom)
{
const dReal* Pos = dGeomGetPosition(geom);
const dReal* Rot = dGeomGetRotation(geom);
const dReal Transform[16] =
{
Rot[0], Rot[4], Rot[8], 0,
Rot[1], Rot[5], Rot[9], 0,
Rot[2], Rot[6], Rot[10], 0,
Pos[0], Pos[1], Pos[2], 1
};
dGeomTriMeshSetLastTransform( geom, *(dMatrix4*)(&Transform) );
}
// simulation loop
static void simLoop (int pause)
{
dsSetColor (0,0,2);
dSpaceCollide (space,0,&nearCallback);
#if 1
// What is this for??? - Bram
if (!pause)
{
for (int i=0; i<num; i++)
for (int j=0; j < GPB; j++)
if (obj[i].geom[j])
if (dGeomGetClass(obj[i].geom[j]) == dTriMeshClass)
setCurrentTransform(obj[i].geom[j]);
setCurrentTransform(TriMesh1);
setCurrentTransform(TriMesh2);
}
#endif
//if (!pause) dWorldStep (world,0.05);
if (!pause) dWorldQuickStep (world,0.05);
for (int j = 0; j < dSpaceGetNumGeoms(space); j++){
dSpaceGetGeom(space, j);
}
// remove all contact joints
dJointGroupEmpty (contactgroup);
dsSetColor (1,1,0);
dsSetTexture (DS_WOOD);
for (int i=0; i<num; i++) {
for (int j=0; j < GPB; j++) {
if (obj[i].geom[j]) {
if (i==selected) {
dsSetColor (0,0.7,1);
}
else if (! dBodyIsEnabled (obj[i].body)) {
dsSetColor (1,0,0);
}
else {
dsSetColor (1,1,0);
}
if (dGeomGetClass(obj[i].geom[j]) == dTriMeshClass) {
dTriIndex* Indices = (dTriIndex*)::Indices;
// assume all trimeshes are drawn as bunnies
const dReal* Pos = dGeomGetPosition(obj[i].geom[j]);
const dReal* Rot = dGeomGetRotation(obj[i].geom[j]);
for (int ii = 0; ii < IndexCount / 3; ii++) {
const dReal v[9] = { // explicit conversion from float to dReal
Vertices[Indices[ii * 3 + 0] * 3 + 0],
Vertices[Indices[ii * 3 + 0] * 3 + 1],
Vertices[Indices[ii * 3 + 0] * 3 + 2],
Vertices[Indices[ii * 3 + 1] * 3 + 0],
Vertices[Indices[ii * 3 + 1] * 3 + 1],
Vertices[Indices[ii * 3 + 1] * 3 + 2],
Vertices[Indices[ii * 3 + 2] * 3 + 0],
Vertices[Indices[ii * 3 + 2] * 3 + 1],
Vertices[Indices[ii * 3 + 2] * 3 + 2]
};
dsDrawTriangle(Pos, Rot, &v[0], &v[3], &v[6], 1);
}
// tell the tri-tri collider the current transform of the trimesh --
// this is fairly important for good results.
// Fill in the (4x4) matrix.
dReal* p_matrix = obj[i].matrix_dblbuff + ( obj[i].last_matrix_index * 16 );
p_matrix[ 0 ] = Rot[ 0 ]; p_matrix[ 1 ] = Rot[ 1 ]; p_matrix[ 2 ] = Rot[ 2 ]; p_matrix[ 3 ] = 0;
p_matrix[ 4 ] = Rot[ 4 ]; p_matrix[ 5 ] = Rot[ 5 ]; p_matrix[ 6 ] = Rot[ 6 ]; p_matrix[ 7 ] = 0;
p_matrix[ 8 ] = Rot[ 8 ]; p_matrix[ 9 ] = Rot[ 9 ]; p_matrix[10 ] = Rot[10 ]; p_matrix[11 ] = 0;
p_matrix[12 ] = Pos[ 0 ]; p_matrix[13 ] = Pos[ 1 ]; p_matrix[14 ] = Pos[ 2 ]; p_matrix[15 ] = 1;
// Flip to other matrix.
obj[i].last_matrix_index = !obj[i].last_matrix_index;
dGeomTriMeshSetLastTransform( obj[i].geom[j],
*(dMatrix4*)( obj[i].matrix_dblbuff + obj[i].last_matrix_index * 16 ) );
} else {
drawGeom (obj[i].geom[j],0,0,show_aabb);
}
}
}
}
dTriIndex* Indices = (dTriIndex*)::Indices;
{const dReal* Pos = dGeomGetPosition(TriMesh1);
const dReal* Rot = dGeomGetRotation(TriMesh1);
{for (int i = 0; i < IndexCount / 3; i++){
const dReal v[9] = { // explicit conversion from float to dReal
Vertices[Indices[i * 3 + 0] * 3 + 0],
Vertices[Indices[i * 3 + 0] * 3 + 1],
Vertices[Indices[i * 3 + 0] * 3 + 2],
Vertices[Indices[i * 3 + 1] * 3 + 0],
Vertices[Indices[i * 3 + 1] * 3 + 1],
Vertices[Indices[i * 3 + 1] * 3 + 2],
Vertices[Indices[i * 3 + 2] * 3 + 0],
Vertices[Indices[i * 3 + 2] * 3 + 1],
Vertices[Indices[i * 3 + 2] * 3 + 2]
};
dsDrawTriangle(Pos, Rot, &v[0], &v[3], &v[6], 0);
}}}
{const dReal* Pos = dGeomGetPosition(TriMesh2);
const dReal* Rot = dGeomGetRotation(TriMesh2);
{for (int i = 0; i < IndexCount / 3; i++){
const dReal v[9] = { // explicit conversion from float to dReal
Vertices[Indices[i * 3 + 0] * 3 + 0],
Vertices[Indices[i * 3 + 0] * 3 + 1],
Vertices[Indices[i * 3 + 0] * 3 + 2],
Vertices[Indices[i * 3 + 1] * 3 + 0],
Vertices[Indices[i * 3 + 1] * 3 + 1],
Vertices[Indices[i * 3 + 1] * 3 + 2],
Vertices[Indices[i * 3 + 2] * 3 + 0],
Vertices[Indices[i * 3 + 2] * 3 + 1],
Vertices[Indices[i * 3 + 2] * 3 + 2]
};
dsDrawTriangle(Pos, Rot, &v[0], &v[3], &v[6], 1);
}}}
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dSimpleSpaceCreate(0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-0.5);
dWorldSetCFM (world,1e-5);
dCreatePlane (space,0,0,1,0);
memset (obj,0,sizeof(obj));
// note: can't share tridata if intending to trimesh-trimesh collide
const unsigned preprocessFlags = (1U << dTRIDATAPREPROCESS_BUILD_CONCAVE_EDGES) | (1U << dTRIDATAPREPROCESS_BUILD_FACE_ANGLES);
TriData1 = dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSingle(TriData1, &Vertices[0], 3 * sizeof(float), VertexCount, (dTriIndex*)&Indices[0], IndexCount, 3 * sizeof(dTriIndex));
dGeomTriMeshDataPreprocess2(TriData1, preprocessFlags, NULL);
TriData2 = dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSingle(TriData2, &Vertices[0], 3 * sizeof(float), VertexCount, (dTriIndex*)&Indices[0], IndexCount, 3 * sizeof(dTriIndex));
dGeomTriMeshDataPreprocess2(TriData2, preprocessFlags, NULL);
TriMesh1 = dCreateTriMesh(space, TriData1, 0, 0, 0);
TriMesh2 = dCreateTriMesh(space, TriData2, 0, 0, 0);
dGeomSetData(TriMesh1, TriData1);
dGeomSetData(TriMesh2, TriData2);
{dGeomSetPosition(TriMesh1, 0, 0, 0.9);
dMatrix3 Rotation;
dRFromAxisAndAngle(Rotation, 1, 0, 0, M_PI / 2);
dGeomSetRotation(TriMesh1, Rotation);}
{dGeomSetPosition(TriMesh2, 1, 0, 0.9);
dMatrix3 Rotation;
dRFromAxisAndAngle(Rotation, 1, 0, 0, M_PI / 2);
dGeomSetRotation(TriMesh2, Rotation);}
dThreadingImplementationID threading = dThreadingAllocateMultiThreadedImplementation();
dThreadingThreadPoolID pool = dThreadingAllocateThreadPool(4, 0, dAllocateFlagBasicData, NULL);
dThreadingThreadPoolServeMultiThreadedImplementation(pool, threading);
// dWorldSetStepIslandsProcessingMaxThreadCount(world, 1);
dWorldSetStepThreadingImplementation(world, dThreadingImplementationGetFunctions(threading), threading);
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dThreadingImplementationShutdownProcessing(threading);
dThreadingFreeThreadPool(pool);
dWorldSetStepThreadingImplementation(world, NULL, NULL);
dThreadingFreeImplementation(threading);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,813 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
* Created by: Remi Ricard *
* (remi.ricard@simlog.com or papaDoc@videotron.ca) *
* Creation date: 2007/05/04 *
*************************************************************************/
/*
This program demonstrates how the Piston joint works.
A Piston joint enables the sliding of a body with respect to another body
and the 2 bodies are free to rotate about the sliding axis.
- The yellow body is fixed to the world.
- The yellow body and the blue body are attached by a Piston joint with
the axis along the x direction.
- The purple object is a geometry obstacle.
- The red line is the representation of the prismatic axis
- The orange line is the representation of the rotoide axis
- The light blue ball is the anchor position
N.B. Many command options are available type -h to print them.
*/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include <iostream>
#include <math.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#define dsDrawSphere dsDrawSphereD
#endif
const dReal VEL_INC = 0.01; // Velocity increment
// physics parameters
const dReal PI = 3.14159265358979323846264338327950288419716939937510;
const dReal BODY1_LENGTH = 1.5; // Size along the X axis
const dReal RADIUS = 0.2;
const dReal AXIS_RADIUS = 0.01;
#define X 0
#define Y 1
#define Z 2
enum INDEX
{
BODY1 = 0,
BODY2,
RECT,
BOX,
OBS,
GROUND,
NUM_PARTS,
ALL = NUM_PARTS
};
const int catBits[NUM_PARTS+1] =
{
0x0001, ///< Ext Cylinder category
0x0002, ///< Int Cylinder category
0x0004, ///< Int_Rect Cylinder category
0x0008, ///< Box category
0x0010, ///< Obstacle category
0x0020, ///< Ground category
~0L ///< All categories
};
#define Mass1 10
#define Mass2 8
//camera view
static float xyz[3] = {2.0f,-3.5f,2.0000f};
static float hpr[3] = {90.000f,-25.5000f,0.0000f};
//world,space,body & geom
static dWorldID world;
static dSpaceID space;
static dJointGroupID contactgroup;
static dBodyID body[NUM_PARTS];
static dGeomID geom[NUM_PARTS];
// Default Positions and anchor of the 2 bodies
dVector3 pos1;
dVector3 pos2;
dVector3 anchor;
static dJoint *joint;
const dReal BODY2_SIDES[3] = {0.4, 0.4, 0.4};
const dReal OBS_SIDES[3] = {1,1,1};
const dReal RECT_SIDES[3] = {0.3, 0.1, 0.2};
int type = dJointTypePiston;
//#pragma message("tc to be changed to 0")
int tc = 0; // The test case choice;
//collision detection
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i,n;
dBodyID b1 = dGeomGetBody (o1);
dBodyID b2 = dGeomGetBody (o2);
if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact) ) return;
const int N = 10;
dContact contact[N];
n = dCollide (o1,o2,N,&contact[0].geom,sizeof (dContact) );
if (n > 0)
{
for (i=0; i<n; i++)
{
contact[i].surface.mode = (dContactSlip1 | dContactSlip2 |
dContactSoftERP | dContactSoftCFM |
dContactApprox1);
contact[i].surface.mu = 0.1;
contact[i].surface.slip1 = 0.02;
contact[i].surface.slip2 = 0.02;
contact[i].surface.soft_erp = 0.1;
contact[i].surface.soft_cfm = 0.0001;
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
dJointAttach (c,dGeomGetBody (contact[i].geom.g1),dGeomGetBody (contact[i].geom.g2) );
}
}
}
static void printKeyBoardShortCut()
{
printf ("Press 'h' for this help.\n");
printf ("Press 'q' to add force on BLUE body along positive x direction.\n");
printf ("Press 'w' to add force on BLUE body along negative x direction.\n");
printf ("Press 'a' to add force on BLUE body along positive y direction.\n");
printf ("Press 's' to add force on BLUE body along negative y direction.\n");
printf ("Press 'z' to add force on BLUE body along positive z direction.\n");
printf ("Press 'x' to add force on BLUE body along negative z direction.\n");
printf ("Press 'e' to add torque on BLUE body around positive x direction \n");
printf ("Press 'r' to add torque on BLUE body around negative x direction \n");
printf ("Press 'd' to add torque on BLUE body around positive y direction \n");
printf ("Press 'f' to add torque on BLUE body around negative y direction \n");
printf ("Press 'c' to add torque on BLUE body around positive z direction \n");
printf ("Press 'v' to add torque on BLUE body around negative z direction \n");
printf ("Press 't' to add force on prismatic joint in the positive axis direction\n");
printf ("Press 'y' to add force on prismatic joint in the negative axis direction\n");
printf ("Press 'i' to add limits on the prismatic joint (0 to 0) \n");
printf ("Press 'o' to add limits on the rotoide joint (0 to 0)\n");
printf ("Press 'k' to add limits on the rotoide joint (-45 to 45deg) \n");
printf ("Press 'l' to remove limits on the rotoide joint \n");
printf ("Press '.' to increase joint velocity along the prismatic direction.\n");
printf ("Press ',' to decrease joint velocity along the prismatic direction.\n");
printf ("Press 'p' to print the Position of the joint.\n");
printf ("Press '+' Go to the next test case.\n");
printf ("Press '-' Go to the previous test case.\n");
printf ("Press '8' To remove one of the body. The blue body and the world will be\n");
printf (" attached to the joint (blue body at position 1)\n");
printf ("Press '9' To remove one of the body. The blue body and the world will be\n");
printf (" attached to the joint (body body at position 2)\n");
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
dsSetViewpoint (xyz,hpr);
printf ("This program demonstrates how the Piston joint works.\n");
printf ("A Piston joint enables the sliding of a body with respect to another body\n");
printf ("and the 2 bodies are free to rotate about the sliding axis.\n\n");
printf ("The yellow body is fixed to the world\n");
printf ("The yellow body and the blue body are attached by a Piston joint with\n");
printf ("the axis along the x direction.\n");
printf ("The purple object is a geometry obstacle.\n");
printKeyBoardShortCut();
}
void setPositionBodies (int val)
{
const dVector3 POS1 = {0,0,1.5,0};
const dVector3 POS2 = {0,0,1.5,0};
const dVector3 ANCHOR = {0,0,1.5,0};
for (int i=0; i<3; ++i)
{
pos1[i] = POS1[i];
pos2[i] = POS2[i];
anchor[i] = ANCHOR[i];
}
if (body[BODY1])
{
dBodySetLinearVel (body[BODY1], 0,0,0);
dBodySetAngularVel (body[BODY1], 0,0,0);
}
if (body[BODY2])
{
dBodySetLinearVel (body[BODY2], 0,0,0);
dBodySetAngularVel (body[BODY2], 0,0,0);
}
switch (val)
{
case 3:
pos1[Z] += -0.5;
anchor[Z] -= 0.25;
break;
case 2:
pos1[Z] -= 0.5;
anchor[Z] -= 0.5;
break;
case 1:
pos1[Z] += -0.5;
break;
default: // This is also case 0
// Nothing to be done
break;
}
const dMatrix3 R =
{
1,0,0,0,
0,1,0,0,
0,0,1,0
};
if (body[BODY1])
{
dBodySetPosition (body[BODY1], pos1[X], pos1[Y], pos1[Z]);
dBodySetRotation (body[BODY1], R);
}
if (body[BODY2])
{
dBodySetPosition (body[BODY2], pos2[X], pos2[Y], pos2[Z]);
dBodySetRotation (body[BODY2], R);
}
if (joint)
{
joint->attach (body[BODY1], body[BODY2]);
if (joint->getType() == dJointTypePiston)
dJointSetPistonAnchor(joint->id(), anchor[X], anchor[Y], anchor[Z]);
}
}
// function to update camera position at each step.
void update()
{
// static FILE *file = fopen("x:/sim/src/libode/tstsrcSF/export.dat", "w");
// static int cnt = 0;
// char str[24];
// sprintf(str, "%06d",cnt++);
// dWorldExportDIF(world, file, str);
}
// called when a key pressed
static void command (int cmd)
{
switch (cmd)
{
case 'h' :
case 'H' :
case '?' :
printKeyBoardShortCut();
break;
// Force
case 'q' :
case 'Q' :
dBodyAddForce (body[BODY1],4,0,0);
break;
case 'w' :
case 'W' :
dBodyAddForce (body[BODY1],-4,0,0);
break;
case 'a' :
case 'A' :
dBodyAddForce (body[BODY1],0,40,0);
break;
case 's' :
case 'S' :
dBodyAddForce (body[BODY1],0,-40,0);
break;
case 'z' :
case 'Z' :
dBodyAddForce (body[BODY1],0,0,4);
break;
case 'x' :
case 'X' :
dBodyAddForce (body[BODY1],0,0,-4);
break;
// Torque
case 'e':
case 'E':
dBodyAddTorque (body[BODY1],0.1,0,0);
break;
case 'r':
case 'R':
dBodyAddTorque (body[BODY1],-0.1,0,0);
break;
case 'd':
case 'D':
dBodyAddTorque (body[BODY1],0, 0.1,0);
break;
case 'f':
case 'F':
dBodyAddTorque (body[BODY1],0,-0.1,0);
break;
case 'c':
case 'C':
dBodyAddTorque (body[BODY1],0.1,0,0);
break;
case 'v':
case 'V':
dBodyAddTorque (body[BODY1],-0.1,0,0);
break;
case 't':
case 'T':
if (joint->getType() == dJointTypePiston)
dJointAddPistonForce (joint->id(),1);
else
dJointAddSliderForce (joint->id(),1);
break;
case 'y':
case 'Y':
if (joint->getType() == dJointTypePiston)
dJointAddPistonForce (joint->id(),-1);
else
dJointAddSliderForce (joint->id(),-1);
break;
case '8' :
dJointAttach(joint->id(), body[0], 0);
break;
case '9' :
dJointAttach(joint->id(), 0, body[0]);
break;
case 'i':
case 'I' :
joint->setParam (dParamLoStop, 0);
joint->setParam (dParamHiStop, 0);
break;
case 'o':
case 'O' :
joint->setParam (dParamLoStop2, 0);
joint->setParam (dParamHiStop2, 0);
break;
case 'k':
case 'K':
joint->setParam (dParamLoStop2, -45.0*3.14159267/180.0);
joint->setParam (dParamHiStop2, 45.0*3.14159267/180.0);
break;
case 'l':
case 'L':
joint->setParam (dParamLoStop2, -dInfinity);
joint->setParam (dParamHiStop2, dInfinity);
break;
// Velocity of joint
case ',':
case '<' :
{
dReal vel = joint->getParam (dParamVel) - VEL_INC;
joint->setParam (dParamVel, vel);
std::cout<<"Velocity = "<<vel<<" FMax = 2"<<'\n';
}
break;
case '.':
case '>' :
{
dReal vel = joint->getParam (dParamVel) + VEL_INC;
joint->setParam (dParamVel, vel);
std::cout<<"Velocity = "<<vel<<" FMax = 2"<<'\n';
}
break;
case 'p' :
case 'P' :
{
switch (joint->getType() )
{
case dJointTypeSlider :
{
dSliderJoint *sj = reinterpret_cast<dSliderJoint *> (joint);
std::cout<<"Position ="<<sj->getPosition() <<"\n";
}
break;
case dJointTypePiston :
{
dPistonJoint *rj = reinterpret_cast<dPistonJoint *> (joint);
std::cout<<"Position ="<<rj->getPosition() <<"\n";
}
break;
default:
{} // keep the compiler happy
}
}
break;
case '+' :
(++tc) %= 4;
setPositionBodies (tc);
break;
case '-' :
(--tc) %= 4;
setPositionBodies (tc);
break;
}
}
static void drawBox (dGeomID id, int R, int G, int B)
{
if (!id)
return;
const dReal *pos = dGeomGetPosition (id);
const dReal *rot = dGeomGetRotation (id);
dsSetColor (R,G,B);
dVector3 l;
dGeomBoxGetLengths (id, l);
dsDrawBox (pos, rot, l);
}
// simulation loop
static void simLoop (int pause)
{
const dReal *rot;
dVector3 ax;
dReal l=0;
switch (joint->getType() )
{
case dJointTypeSlider :
( (dSliderJoint *) joint)->getAxis (ax);
l = ( (dSliderJoint *) joint)->getPosition();
break;
case dJointTypePiston :
( (dPistonJoint *) joint)->getAxis (ax);
l = ( (dPistonJoint *) joint)->getPosition();
break;
default:
{} // keep the compiler happy
}
if (!pause)
{
double simstep = 0.01; // 1ms simulation steps
double dt = dsElapsedTime();
int nrofsteps = (int) ceilf (dt/simstep);
if (!nrofsteps)
nrofsteps = 1;
for (int i=0; i<nrofsteps && !pause; i++)
{
dSpaceCollide (space,0,&nearCallback);
dWorldStep (world, simstep);
dJointGroupEmpty (contactgroup);
}
update();
dReal radius, length;
dsSetTexture (DS_WOOD);
drawBox (geom[BODY2], 1,1,0);
drawBox (geom[RECT], 0,0,1);
if ( geom[BODY1] )
{
const dReal *pos = dGeomGetPosition (geom[BODY1]);
rot = dGeomGetRotation (geom[BODY1]);
dsSetColor (0,0,1);
dGeomCapsuleGetParams (geom[BODY1], &radius, &length);
dsDrawCapsule (pos, rot, length, radius);
}
drawBox (geom[OBS], 1,0,1);
// Draw the prismatic axis
if ( geom[BODY1] )
{
const dReal *pos = dGeomGetPosition (geom[BODY1]);
rot = dGeomGetRotation (geom[BODY2]);
dVector3 p;
p[X] = pos[X] - l*ax[X];
p[Y] = pos[Y] - l*ax[Y];
p[Z] = pos[Z] - l*ax[Z];
dsSetColor (1,0,0);
dsDrawCylinder (p, rot, 3.75, 1.05*AXIS_RADIUS);
}
if (joint->getType() == dJointTypePiston )
{
dVector3 anchor;
dJointGetPistonAnchor(joint->id(), anchor);
// Draw the rotoide axis
rot = dGeomGetRotation (geom[BODY2]);
dsSetColor (1,0.5,0);
dsDrawCylinder (anchor, rot, 4, AXIS_RADIUS);
dsSetColor (0,1,1);
rot = dGeomGetRotation (geom[BODY1]);
dsDrawSphere (anchor, rot, 1.5*RADIUS);
}
}
}
void Help (char **argv)
{
printf ("%s ", argv[0]);
printf (" -h | --help : print this help\n");
printf (" -s | --slider : Set the joint as a slider\n");
printf (" -p | --piston : Set the joint as a Piston. (Default joint)\n");
printf (" -1 | --offset1 : Create an offset between the 2 bodies\n");
printf (" Offset one of the body by z=-0.5 and keep the anchor\n");
printf (" point in the middle of the fixed body\n");
printf (" -2 | --offset2 : Create an offset between the 2 bodies\n");
printf (" Offset one of the body by z=-0.5 and set the anchor\n");
printf (" point in the middle of the movable body\n");
printf (" -3 | --offset3 : Create an offset between the 2 bodies\n");
printf (" Offset one of the body by z=-0.5 and set the anchor\n");
printf (" point in the middle of the 2 bodies\n");
printf (" -t | --texture-path path : Path to the texture.\n");
printf (" Default = %s\n", DRAWSTUFF_TEXTURE_PATH);
printf (" -n | --notFixed : In free space with no gravity mode");
printf ("-notex : Don't use texture\n");
printf ("-noshadow : No shadow\n");
printf ("-noshadows : No shadows\n");
printf ("-pause : Initial pause\n");
printf ("--------------------------------------------------\n");
printf ("Hit any key to continue:");
getchar();
exit (0);
}
int main (int argc, char **argv)
{
dInitODE2(0);
bool fixed = true;
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
dVector3 offset;
dSetZero (offset, 4);
// Default test case
if (argc >= 2 )
{
for (int i=1; i < argc; ++i)
{
//static int tata = 0;
if (1)
{
if ( 0 == strcmp ("-h", argv[i]) || 0 == strcmp ("--help", argv[i]) )
Help (argv);
if ( 0 == strcmp ("-s", argv[i]) || 0 == strcmp ("--slider", argv[i]) )
type = dJointTypeSlider;
if ( 0 == strcmp ("-t", argv[i]) || 0 == strcmp ("--texture-path", argv[i]) )
{
int j = i+1;
if ( j >= argc || // Check if we have enough arguments
argv[j][0] == '\0' || // We should have a path here
argv[j][0] == '-' ) // We should have a path not a command line
Help (argv);
else
fn.path_to_textures = argv[++i]; // Increase i since we use this argument
}
}
if ( 0 == strcmp ("-1", argv[i]) || 0 == strcmp ("--offset1", argv[i]) )
tc = 1;
if ( 0 == strcmp ("-2", argv[i]) || 0 == strcmp ("--offset2", argv[i]) )
tc = 2;
if ( 0 == strcmp ("-3", argv[i]) || 0 == strcmp ("--offset3", argv[i]) )
tc = 3;
if (0 == strcmp ("-n", argv[i]) || 0 == strcmp ("--notFixed", argv[i]) )
fixed = false;
}
}
world = dWorldCreate();
dWorldSetERP (world, 0.8);
space = dSimpleSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
geom[GROUND] = dCreatePlane (space, 0,0,1,0);
dGeomSetCategoryBits (geom[GROUND], catBits[GROUND]);
dGeomSetCollideBits (geom[GROUND], catBits[ALL]);
dMass m;
dMatrix3 R;
// Create the Obstacle
geom[OBS] = dCreateBox (space, OBS_SIDES[0], OBS_SIDES[1], OBS_SIDES[2]);
dGeomSetCategoryBits (geom[OBS], catBits[OBS]);
dGeomSetCollideBits (geom[OBS], catBits[ALL]);
//Rotation of 45deg around y
dRFromAxisAndAngle (R, 1,1,0, -0.25*PI);
dGeomSetRotation (geom[OBS], R);
dGeomSetPosition (geom[OBS], 1.95, -0.2, 0.5);
//Rotation of 90deg around y
// Will orient the Z axis along X
dRFromAxisAndAngle (R, 0,1,0, -0.5*PI);
// Create Body2 (Wiil be attached to the world)
body[BODY2] = dBodyCreate (world);
// Main axis of cylinder is along X=1
dMassSetBox (&m, 1, BODY2_SIDES[0], BODY2_SIDES[1], BODY2_SIDES[2]);
dMassAdjust (&m, Mass1);
geom[BODY2] = dCreateBox (space, BODY2_SIDES[0], BODY2_SIDES[1], BODY2_SIDES[2]);
dGeomSetBody (geom[BODY2], body[BODY2]);
dGeomSetOffsetRotation (geom[BODY2], R);
dGeomSetCategoryBits (geom[BODY2], catBits[BODY2]);
dGeomSetCollideBits (geom[BODY2], catBits[ALL] & (~catBits[BODY1]) );
dBodySetMass (body[BODY2], &m);
// Create Body 1 (Slider on the prismatic axis)
body[BODY1] = dBodyCreate (world);
// Main axis of capsule is along X=1
dMassSetCapsule (&m, 1, 1, RADIUS, BODY1_LENGTH);
dMassAdjust (&m, Mass1);
geom[BODY1] = dCreateCapsule (space, RADIUS, BODY1_LENGTH);
dGeomSetBody (geom[BODY1], body[BODY1]);
dGeomSetOffsetRotation (geom[BODY1], R);
dGeomSetCategoryBits (geom[BODY1], catBits[BODY1]);
dGeomSetCollideBits (geom[BODY1], catBits[ALL] & ~catBits[BODY2] & ~catBits[RECT]);
dMass mRect;
dMassSetBox (&mRect, 1, RECT_SIDES[0], RECT_SIDES[1], RECT_SIDES[2]);
dMassAdd (&m, &mRect);
// TODO: translate m?
geom[RECT] = dCreateBox (space, RECT_SIDES[0], RECT_SIDES[1], RECT_SIDES[2]);
dGeomSetBody (geom[RECT], body[BODY1]);
dGeomSetOffsetPosition (geom[RECT],
(BODY1_LENGTH-RECT_SIDES[0]) /2.0,
0.0,
-RADIUS -RECT_SIDES[2]/2.0);
dGeomSetCategoryBits (geom[RECT], catBits[RECT]);
dGeomSetCollideBits (geom[RECT], catBits[ALL] & (~catBits[BODY1]) );
dBodySetMass (body[BODY1], &m);
setPositionBodies (tc);
if ( fixed )
{
// Attache external cylinder to the world
dJointID fixed = dJointCreateFixed (world,0);
dJointAttach (fixed , NULL, body[BODY2]);
dJointSetFixed (fixed );
dWorldSetGravity (world,0,0,-0.8);
}
else
{
dWorldSetGravity (world,0,0,0);
}
// The static is here only to help debugging
switch (type)
{
case dJointTypeSlider :
{
dSliderJoint *sj = new dSliderJoint (world, 0);
sj->attach (body[BODY1], body[BODY2]);
sj->setAxis (1, 0, 0);
joint = sj;
}
break;
case dJointTypePiston : // fall through default
default:
{
dPistonJoint *pj = new dPistonJoint (world, 0);
pj->attach (body[BODY1], body[BODY2]);
pj->setAxis (1, 0, 0);
dJointSetPistonAnchor(pj->id(), anchor[X], anchor[Y], anchor[Z]);
joint = pj;
}
break;
};
// run simulation
dsSimulationLoop (argc,argv,400,300,&fn);
delete joint;
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,304 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
// Test my Plane2D constraint.
// Uses ode-0.35 collision API.
# include <stdio.h>
# include <stdlib.h>
# include <math.h>
# include <ode/ode.h>
# include <drawstuff/drawstuff.h>
#include "texturepath.h"
# define drand48() ((double) (((double) rand()) / ((double) RAND_MAX)))
# define N_BODIES 40
# define STAGE_SIZE 8.0 // in m
# define TIME_STEP 0.01
# define K_SPRING 10.0
# define K_DAMP 10.0
//using namespace ode;
struct GlobalVars
{
dWorld dyn_world;
dBody dyn_bodies[N_BODIES];
dReal bodies_sides[N_BODIES][3];
dSpaceID coll_space_id;
dJointID plane2d_joint_ids[N_BODIES];
dJointGroup coll_contacts;
};
static GlobalVars *g_globals_ptr = NULL;
static void cb_start ()
/*************************/
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = { 0.5f*STAGE_SIZE, 0.5f*STAGE_SIZE, 0.65f*STAGE_SIZE};
static float hpr[3] = { 90.0f, -90.0f, 0 };
dsSetViewpoint (xyz, hpr);
}
static void cb_near_collision (void *, dGeomID o1, dGeomID o2)
/********************************************************************/
{
dBodyID b1 = dGeomGetBody (o1);
dBodyID b2 = dGeomGetBody (o2);
dContact contact;
// exit without doing anything if the two bodies are static
if (b1 == 0 && b2 == 0)
return;
// exit without doing anything if the two bodies are connected by a joint
if (b1 && b2 && dAreConnected (b1, b2))
{
/* MTRAP; */
return;
}
contact.surface.mode = 0;
contact.surface.mu = 0; // frictionless
if (dCollide (o1, o2, 1, &contact.geom, sizeof (dContactGeom)))
{
dJointID c = dJointCreateContact (g_globals_ptr->dyn_world.id(),
g_globals_ptr->coll_contacts.id (), &contact);
dJointAttach (c, b1, b2);
}
}
static void track_to_pos (dBody &body, dJointID joint_id,
dReal target_x, dReal target_y)
/************************************************************************/
{
dReal curr_x = body.getPosition()[0];
dReal curr_y = body.getPosition()[1];
dJointSetPlane2DXParam (joint_id, dParamVel, 1 * (target_x - curr_x));
dJointSetPlane2DYParam (joint_id, dParamVel, 1 * (target_y - curr_y));
}
static void cb_sim_step (int pause)
/*************************************/
{
if (! pause)
{
static dReal angle = 0;
angle += REAL( 0.01 );
track_to_pos (g_globals_ptr->dyn_bodies[0], g_globals_ptr->plane2d_joint_ids[0],
dReal( STAGE_SIZE/2 + STAGE_SIZE/2.0 * cos (angle) ),
dReal( STAGE_SIZE/2 + STAGE_SIZE/2.0 * sin (angle) ));
/* double f0 = 0.001; */
/* for (int b = 0; b < N_BODIES; b ++) */
/* { */
/* double p = 1 + b / (double) N_BODIES; */
/* double q = 2 - b / (double) N_BODIES; */
/* g_globals_ptr->dyn_bodies[b].addForce (f0 * cos (p*angle), f0 * sin (q*angle), 0); */
/* } */
/* g_globals_ptr->dyn_bodies[0].addTorque (0, 0, 0.1); */
const int n = 10;
for (int i = 0; i < n; i ++)
{
dSpaceCollide (g_globals_ptr->coll_space_id, 0, &cb_near_collision);
g_globals_ptr->dyn_world.step (dReal(TIME_STEP/n));
g_globals_ptr->coll_contacts.empty ();
}
}
# if 1 /* [ */
{
// @@@ hack Plane2D constraint error reduction here:
for (int b = 0; b < N_BODIES; b ++)
{
const dReal *rot = dBodyGetAngularVel (g_globals_ptr->dyn_bodies[b].id());
const dReal *quat_ptr;
dReal quat[4],
quat_len;
quat_ptr = dBodyGetQuaternion (g_globals_ptr->dyn_bodies[b].id());
quat[0] = quat_ptr[0];
quat[1] = 0;
quat[2] = 0;
quat[3] = quat_ptr[3];
quat_len = sqrt (quat[0] * quat[0] + quat[3] * quat[3]);
quat[0] /= quat_len;
quat[3] /= quat_len;
dBodySetQuaternion (g_globals_ptr->dyn_bodies[b].id(), quat);
dBodySetAngularVel (g_globals_ptr->dyn_bodies[b].id(), 0, 0, rot[2]);
}
}
# endif /* ] */
# if 0 /* [ */
{
// @@@ friction
for (int b = 0; b < N_BODIES; b ++)
{
const dReal *vel = dBodyGetLinearVel (g_globals_ptr->dyn_bodies[b].id()),
*rot = dBodyGetAngularVel (g_globals_ptr->dyn_bodies[b].id());
dReal s = 1.00;
dReal t = 0.99;
dBodySetLinearVel (g_globals_ptr->dyn_bodies[b].id(), s*vel[0],s*vel[1],s*vel[2]);
dBodySetAngularVel (g_globals_ptr->dyn_bodies[b].id(),t*rot[0],t*rot[1],t*rot[2]);
}
}
# endif /* ] */
{
// ode drawstuff
dsSetTexture (DS_WOOD);
for (int b = 0; b < N_BODIES; b ++)
{
if (b == 0)
dsSetColor (1.0, 0.5, 1.0);
else
dsSetColor (0, 0.5, 1.0);
#ifdef dDOUBLE
dsDrawBoxD (g_globals_ptr->dyn_bodies[b].getPosition(), g_globals_ptr->dyn_bodies[b].getRotation(), g_globals_ptr->bodies_sides[b]);
#else
dsDrawBox (g_globals_ptr->dyn_bodies[b].getPosition(), g_globals_ptr->dyn_bodies[b].getRotation(), g_globals_ptr->bodies_sides[b]);
#endif
}
}
}
extern int main
/******************/
(
int argc,
char **argv
)
{
int b;
dsFunctions drawstuff_functions;
dInitODE2(0);
g_globals_ptr = new GlobalVars();
// dynamic world
dReal cf_mixing;// = 1 / TIME_STEP * K_SPRING + K_DAMP;
dReal err_reduct;// = TIME_STEP * K_SPRING * cf_mixing;
err_reduct = REAL( 0.5 );
cf_mixing = REAL( 0.001 );
dWorldSetERP (g_globals_ptr->dyn_world.id (), err_reduct);
dWorldSetCFM (g_globals_ptr->dyn_world.id (), cf_mixing);
g_globals_ptr->dyn_world.setGravity (0, 0.0, -1.0);
g_globals_ptr->coll_space_id = dSimpleSpaceCreate (0);
// dynamic bodies
for (b = 0; b < N_BODIES; b ++)
{
int l = (int) (1 + sqrt ((double) N_BODIES));
dReal x = dReal( (0.5 + (b / l)) / l * STAGE_SIZE );
dReal y = dReal( (0.5 + (b % l)) / l * STAGE_SIZE );
dReal z = REAL( 1.0 ) + REAL( 0.1 ) * (dReal)drand48();
g_globals_ptr->bodies_sides[b][0] = dReal( 5 * (0.2 + 0.7*drand48()) / sqrt((double)N_BODIES) );
g_globals_ptr->bodies_sides[b][1] = dReal( 5 * (0.2 + 0.7*drand48()) / sqrt((double)N_BODIES) );
g_globals_ptr->bodies_sides[b][2] = z;
g_globals_ptr->dyn_bodies[b].create (g_globals_ptr->dyn_world);
g_globals_ptr->dyn_bodies[b].setPosition (x, y, z/2);
g_globals_ptr->dyn_bodies[b].setData ((void*) (dsizeint)b);
dBodySetLinearVel (g_globals_ptr->dyn_bodies[b].id (),
dReal( 3 * (drand48 () - 0.5) ),
dReal( 3 * (drand48 () - 0.5) ), 0);
dMass m;
m.setBox (1, g_globals_ptr->bodies_sides[b][0],g_globals_ptr->bodies_sides[b][1],g_globals_ptr->bodies_sides[b][2]);
m.adjust (REAL(0.1) * g_globals_ptr->bodies_sides[b][0] * g_globals_ptr->bodies_sides[b][1]);
g_globals_ptr->dyn_bodies[b].setMass (&m);
g_globals_ptr->plane2d_joint_ids[b] = dJointCreatePlane2D (g_globals_ptr->dyn_world.id (), 0);
dJointAttach (g_globals_ptr->plane2d_joint_ids[b], g_globals_ptr->dyn_bodies[b].id (), 0);
}
dJointSetPlane2DXParam (g_globals_ptr->plane2d_joint_ids[0], dParamFMax, 10);
dJointSetPlane2DYParam (g_globals_ptr->plane2d_joint_ids[0], dParamFMax, 10);
// collision geoms and joints
dCreatePlane (g_globals_ptr->coll_space_id, 1, 0, 0, 0);
dCreatePlane (g_globals_ptr->coll_space_id, -1, 0, 0, -STAGE_SIZE);
dCreatePlane (g_globals_ptr->coll_space_id, 0, 1, 0, 0);
dCreatePlane (g_globals_ptr->coll_space_id, 0, -1, 0, -STAGE_SIZE);
for (b = 0; b < N_BODIES; b ++)
{
dGeomID coll_box_id;
coll_box_id = dCreateBox (g_globals_ptr->coll_space_id,
g_globals_ptr->bodies_sides[b][0], g_globals_ptr->bodies_sides[b][1], g_globals_ptr->bodies_sides[b][2]);
dGeomSetBody (coll_box_id, g_globals_ptr->dyn_bodies[b].id ());
}
g_globals_ptr->coll_contacts.create ();
{
// simulation loop (by drawstuff lib)
drawstuff_functions.version = DS_VERSION;
drawstuff_functions.start = &cb_start;
drawstuff_functions.step = &cb_sim_step;
drawstuff_functions.command = 0;
drawstuff_functions.stop = 0;
drawstuff_functions.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
dsSimulationLoop (argc, argv, 352,288,&drawstuff_functions);
}
delete g_globals_ptr;
g_globals_ptr = NULL;
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,258 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/*
Angular friction demo:
A bunch of ramps of different pitch.
A bunch of spheres with rolling friction.
*/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
// some constants
#define GRAVITY 10 // the global gravity to use
#define RAMP_COUNT 8
static const dReal rampX = 6.0f;
static const dReal rampY = 0.5f;
static const dReal rampZ = 0.25f;
static const dReal sphereRadius = 0.25f;
static const dReal maxRamp = M_PI/4.0f; // Needs to be less than pi/2
static const dReal rampInc = maxRamp/RAMP_COUNT;
// dynamics and collision objects
static dWorldID world = 0;
static dSpaceID space = 0;
static dJointGroupID contactgroup = 0;
static dGeomID ground;
static dReal mu = REAL(0.37); // the global mu to use
static dReal rho = REAL(0.1); // the global rho to use
static dReal omega = REAL(25.0);
static dGeomID rampGeom[RAMP_COUNT];
static dBodyID sphereBody[RAMP_COUNT];
static dGeomID sphereGeom[RAMP_COUNT];
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i;
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1==0 && b2==0) return;
dContact contact[3];
for (int ii=0; ii<3; ii++) {
contact[ii].surface.mode = dContactApprox1 | dContactRolling;
contact[ii].surface.mu = mu;
contact[ii].surface.rho = rho;
}
if (int numc = dCollide (o1,o2,3,&contact[0].geom,sizeof(dContact))) {
for (i=0; i<numc; i++) {
dJointID c = dJointCreateContact (world,contactgroup,contact+i);
dJointAttach (c,b1,b2);
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {0,-3.0f,3.0f};
static float hpr[3] = {90.0000,-15.0000,0.0000};
dsSetViewpoint (xyz,hpr);
printf ("Press:\n"
"\t'[' or ']' to change initial angular velocity\n"
"\t'm' to increase sliding friction\n"
"\t'n' to decrease sliding friction\n"
"\t'j' to increase rolling friction\n"
"\t'h' to decrease rolling friction\n"
"\t'r' to reset simulation.\n");
}
/**
Delete the bodies, etc.
*/
static void clear()
{
if (contactgroup) dJointGroupDestroy (contactgroup);
if (space) dSpaceDestroy (space);
if (world) dWorldDestroy (world);
}
/**
Cleanup if necessary and rebuild the
world.
*/
static void reset()
{
clear();
// create world
world = dWorldCreate();
space = dHashSpaceCreate (0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-GRAVITY);
ground = dCreatePlane (space,0,0,1,0);
// Calculate mass for sphere a capsule with water density.
dMass sphereMass;
dMassSetSphere(&sphereMass,1000,sphereRadius);
for (int ii=0;ii<RAMP_COUNT;++ii) {
dQuaternion q;
dReal angle = (ii+1)*rampInc;
dReal cosA = dCos(angle);
dReal sinA = dSin(angle);
dReal rampW = rampX/cosA; // Box width that preserves ground distance
dReal zPos = REAL(0.5)*(sinA*rampW-cosA*rampZ); // Position that makes end meet ground
dReal yPos = ii*1.25*rampY;
dReal xPos = 0;
// Create the ramp
rampGeom[ii] = dCreateBox(space,rampW,rampY,rampZ);
dQFromAxisAndAngle(q,0,1,0,angle);
dGeomSetQuaternion(rampGeom[ii],q);
dGeomSetPosition(rampGeom[ii],xPos,yPos,zPos);
// Create the spheres
xPos = -REAL(0.5)*rampX + sphereRadius;
zPos = sinA*rampW + sphereRadius;
sphereBody[ii] = dBodyCreate(world);
dBodySetMass(sphereBody[ii],&sphereMass);
sphereGeom[ii] = dCreateSphere(space,sphereRadius);
dGeomSetBody(sphereGeom[ii],sphereBody[ii]);
dBodySetPosition(sphereBody[ii],xPos,yPos,zPos);
dBodySetAngularVel(sphereBody[ii],0,omega,0);
}
}
static void command (int cmd)
{
switch (cmd) {
case 'h': case 'H':
rho-=0.02;
if (rho<0) rho=0;
break;
case 'j': case 'J':
rho+=0.02;
if (rho>1) rho=1;
break;
case 'n': case 'N':
mu-=0.02;
if (mu<0) mu=0;
break;
case 'm': case 'M':
mu+=0.02;
if (mu>1) mu=1;
break;
case 'r': case 'R':
reset();
break;
case ']':
omega+=1;
break;
case '[':
omega-=1;
break;
}
}
// simulation loop
static void simLoop (int pause)
{
if (!pause) {
dSpaceCollide (space,0,&nearCallback);
dWorldStep (world,0.017); // 60 fps
// remove all contact joints
dJointGroupEmpty (contactgroup);
}
// Render ramps and spheres
dsSetTexture (DS_WOOD);
for (int ii=0;ii<RAMP_COUNT;++ii) {
dVector3 sides;
dsSetColor (1,0.5,0);
dGeomBoxGetLengths(rampGeom[ii],sides);
dsDrawBox (dGeomGetPosition(rampGeom[ii]),dGeomGetRotation(rampGeom[ii]),sides);
dsSetColor(0,0,1);
dsDrawSphere (dGeomGetPosition(sphereGeom[ii]),dGeomGetRotation(sphereGeom[ii]), sphereRadius);
}
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
dInitODE2(0);
reset();
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
clear();
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,171 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#endif
// some constants
#define SIDE (0.5f) // side length of a box
#define MASS (1.0) // mass of a box
// dynamics and collision objects
static dWorldID world;
static dBodyID body[2];
static dJointID slider;
// state set by keyboard commands
static int occasional_error = 0;
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {1.0382f,-1.0811f,1.4700f};
static float hpr[3] = {135.0000f,-19.5000f,0.0000f};
dsSetViewpoint (xyz,hpr);
printf ("Press 'e' to start/stop occasional error.\n");
}
// called when a key pressed
static void command (int cmd)
{
if (cmd == 'e' || cmd == 'E') {
occasional_error ^= 1;
}
}
// simulation loop
static void simLoop (int pause)
{
const dReal kd = -0.3; // angular damping constant
const dReal ks = 0.5; // spring constant
if (!pause) {
// add an oscillating torque to body 0, and also damp its rotational motion
static dReal a=0;
const dReal *w = dBodyGetAngularVel (body[0]);
dBodyAddTorque (body[0],kd*w[0],kd*w[1]+0.1*cos(a),kd*w[2]+0.1*sin(a));
a += 0.01;
// add a spring force to keep the bodies together, otherwise they will
// fly apart along the slider axis.
const dReal *p1 = dBodyGetPosition (body[0]);
const dReal *p2 = dBodyGetPosition (body[1]);
dBodyAddForce (body[0],ks*(p2[0]-p1[0]),ks*(p2[1]-p1[1]),
ks*(p2[2]-p1[2]));
dBodyAddForce (body[1],ks*(p1[0]-p2[0]),ks*(p1[1]-p2[1]),
ks*(p1[2]-p2[2]));
// occasionally re-orient one of the bodies to create a deliberate error.
if (occasional_error) {
static int count = 0;
if ((count % 20)==0) {
// randomly adjust orientation of body[0]
const dReal *R1;
dMatrix3 R2,R3;
R1 = dBodyGetRotation (body[0]);
dRFromAxisAndAngle (R2,dRandReal()-0.5,dRandReal()-0.5,
dRandReal()-0.5,dRandReal()-0.5);
dMultiply0 (R3,R1,R2,3,3,3);
dBodySetRotation (body[0],R3);
// randomly adjust position of body[0]
const dReal *pos = dBodyGetPosition (body[0]);
dBodySetPosition (body[0],
pos[0]+0.2*(dRandReal()-0.5),
pos[1]+0.2*(dRandReal()-0.5),
pos[2]+0.2*(dRandReal()-0.5));
}
count++;
}
dWorldStep (world,0.05);
}
dReal sides1[3] = {SIDE,SIDE,SIDE};
dReal sides2[3] = {SIDE*0.8f,SIDE*0.8f,SIDE*2.0f};
dsSetTexture (DS_WOOD);
dsSetColor (1,1,0);
dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides1);
dsSetColor (0,1,1);
dsDrawBox (dBodyGetPosition(body[1]),dBodyGetRotation(body[1]),sides2);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
dMass m;
dMassSetBox (&m,1,SIDE,SIDE,SIDE);
dMassAdjust (&m,MASS);
body[0] = dBodyCreate (world);
dBodySetMass (body[0],&m);
dBodySetPosition (body[0],0,0,1);
body[1] = dBodyCreate (world);
dBodySetMass (body[1],&m);
dQuaternion q;
dQFromAxisAndAngle (q,-1,1,0,0.25*M_PI);
dBodySetPosition (body[1],0.2,0.2,1.2);
dBodySetQuaternion (body[1],q);
slider = dJointCreateSlider (world,0);
dJointAttach (slider,body[0],body[1]);
dJointSetSliderAxis (slider,1,1,1);
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,232 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
/*
testing procedure:
* create a bunch of random boxes
* test for intersections directly, put results in n^2 array
* get space to report collisions:
- all correct collisions reported
- no pair reported more than once
- no incorrect collisions reported
*/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
// some constants
#define NUM 20 // number of boxes to test
// collision objects and globals
static dSpaceID space;
static dGeomID geom[NUM];
static dReal bounds[NUM][6];
static dsizeint good_matrix[NUM][NUM]; // correct collision matrix
static dsizeint test_matrix[NUM][NUM]; // testing collision matrix
static dsizeint hits[NUM]; // number of collisions a box has
static unsigned long seed=37;
static void init_test()
{
int i,j;
const dReal scale = 0.5;
// set random boxes
dRandSetSeed (seed);
for (i=0; i < NUM; i++) {
bounds[i][0] = dRandReal()*2-1;
bounds[i][1] = bounds[i][0] + dRandReal()*scale;
bounds[i][2] = dRandReal()*2-1;
bounds[i][3] = bounds[i][2] + dRandReal()*scale;
bounds[i][4] = dRandReal()*2;
bounds[i][5] = bounds[i][4] + dRandReal()*scale;
if (geom[i]) dGeomDestroy (geom[i]);
geom[i] = dCreateBox (space,
bounds[i][1] - bounds[i][0],
bounds[i][3] - bounds[i][2],
bounds[i][5] - bounds[i][4]);
dGeomSetPosition (geom[i],
(bounds[i][0] + bounds[i][1])*0.5,
(bounds[i][2] + bounds[i][3])*0.5,
(bounds[i][4] + bounds[i][5])*0.5);
dGeomSetData (geom[i],(void*)(dsizeint)(i));
}
// compute all intersections and put the results in "good_matrix"
for (i=0; i < NUM; i++) {
for (j=0; j < NUM; j++) good_matrix[i][j] = 0;
}
for (i=0; i < NUM; i++) hits[i] = 0;
for (i=0; i < NUM; i++) {
for (j=i+1; j < NUM; j++) {
dReal *bounds1 = &bounds[i][0];
dReal *bounds2 = &bounds[j][0];
if (bounds1[0] > bounds2[1] ||
bounds1[1] < bounds2[0] ||
bounds1[2] > bounds2[3] ||
bounds1[3] < bounds2[2] ||
bounds1[4] > bounds2[5] ||
bounds1[5] < bounds2[4]) continue;
good_matrix[i][j] = 1;
good_matrix[j][i] = 1;
hits[i]++;
hits[j]++;
}
}
}
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
dsizeint i,j;
i = (dsizeint) dGeomGetData (o1);
j = (dsizeint) dGeomGetData (o2);
if (i==j)
printf ("collision (%d,%d) is between the same object\n",(int)i,(int)j);
if (!good_matrix[i][j] || !good_matrix[j][i])
printf ("collision (%d,%d) is incorrect\n",(int)i,(int)j);
if (test_matrix[i][j] || test_matrix[j][i])
printf ("collision (%d,%d) reported more than once\n",(int)i,(int)j);
test_matrix[i][j] = 1;
test_matrix[j][i] = 1;
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {2.1640f,-1.3079f,1.7600f};
static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
dsSetViewpoint (xyz,hpr);
}
static void command (int cmd)
{
if (cmd == ' ') {
seed++;
init_test();
}
}
// simulation loop
static void simLoop (int)
{
int i,j;
for (i=0; i < NUM; i++) {
for (j=0; j < NUM; j++) test_matrix[i][j] = 0;
}
dSpaceCollide (space,0,&nearCallback);
for (i=0; i < NUM; i++) {
for (j=i+1; j < NUM; j++) {
if (good_matrix[i][j] && !test_matrix[i][j]) {
printf ("failed to report collision (%d,%d) (seed=%ld)\n",i,j,seed);
}
}
}
seed++;
init_test();
for (i=0; i<NUM; i++) {
dVector3 pos,side;
dMatrix3 R;
dRSetIdentity (R);
for (j=0; j<3; j++) pos[j] = (bounds[i][j*2+1] + bounds[i][j*2]) * 0.5;
for (j=0; j<3; j++) side[j] = bounds[i][j*2+1] - bounds[i][j*2];
if (hits[i] > 0) dsSetColor (1,0,0);
else dsSetColor (1,1,0);
dsDrawBox (pos,R,side);
}
}
int main (int argc, char **argv)
{
int i;
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
dInitODE2(0);
// test the simple space:
// space = dSimpleSpaceCreate();
// test the hash space:
// space = dHashSpaceCreate (0);
// dHashSpaceSetLevels (space,-10,10);
// test the quadtree space
dVector3 Center = {0, 0, 0, 0};
dVector3 Extents = {10, 0, 10, 0};
space = dQuadTreeSpaceCreate(0, Center, Extents, 7);
for (i=0; i < NUM; i++) geom[i] = 0;
init_test();
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dSpaceDestroy (space);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,449 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <string>
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
// some constants
#define NUM 10000 // max number of objects
#define DENSITY (5.0) // density of all objects
#define GPB 3 // maximum number of geometries per body
#define MAX_CONTACTS 4 // maximum number of contact points per body
#define WORLD_SIZE 20
#define WORLD_HEIGHT 20
// dynamics and collision objects
struct MyObject {
dBodyID body; // the body
dGeomID geom[GPB]; // geometries representing this body
};
static int num=0; // number of objects in simulation
static int nextobj=0; // next object to recycle if num==NUM
static dWorldID world;
static dSpaceID space = NULL;
static MyObject obj[NUM];
static dJointGroupID contactgroup;
static int selected = -1; // selected object
static int show_aabb = 0; // show geom AABBs?
static int show_contacts = 0; // show contact points?
static int random_pos = 1; // drop objects from random position?
static int draw_geom = 1;
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i;
// if (o1->body && o2->body) return;
// exit without doing anything if the two bodies are connected by a joint
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return;
dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
for (i=0; i<MAX_CONTACTS; i++) {
contact[i].surface.mode = dContactBounce | dContactSoftCFM;
contact[i].surface.mu = dInfinity;
contact[i].surface.mu2 = 0;
contact[i].surface.bounce = 0.1;
contact[i].surface.bounce_vel = 0.1;
contact[i].surface.soft_cfm = 0.01;
}
if (int numc = dCollide (o1,o2,MAX_CONTACTS,&contact[0].geom,
sizeof(dContact))) {
dMatrix3 RI;
dRSetIdentity (RI);
const dReal ss[3] = {0.02,0.02,0.02};
for (i=0; i<numc; i++) {
dJointID c = dJointCreateContact (world,contactgroup,contact+i);
dJointAttach (c,b1,b2);
if (show_contacts) dsDrawBox (contact[i].geom.pos,RI,ss);
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {2.1640f,-1.3079f,3.7600f};
static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
dsSetViewpoint (xyz,hpr);
printf ("To drop another object, press:\n");
printf (" o to disable rendering.\n");
printf (" b for box.\n");
printf (" s for sphere.\n");
printf (" c for cylinder.\n");
printf (" x for a composite object.\n");
printf (" y for cylinder.\n");
printf ("To select an object, press space.\n");
printf ("To disable the selected object, press d.\n");
printf ("To enable the selected object, press e.\n");
printf ("To toggle showing the geom AABBs, press a.\n");
printf ("To toggle showing the contact points, press t.\n");
printf ("To toggle dropping from random position/orientation, press r.\n");
}
char locase(char c)
{
if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
else return c;
}
// called when a key pressed
static void command (int cmd)
{
int i,j,k;
dReal sides[3];
dMass m;
bool setBody = false;
cmd = locase(cmd);
if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' || cmd == 'y') {
if (num < NUM) {
// new object to be created
i = num;
num++;
} else {
// recycle existing object
i = nextobj++;
nextobj %= num; // wrap-around if needed
// destroy the body and geoms for slot i
dBodyDestroy (obj[i].body);
obj[i].body = 0;
for (k=0; k < GPB; k++)
if (obj[i].geom[k]) {
dGeomDestroy(obj[i].geom[k]);
obj[i].geom[k] = 0;
}
}
obj[i].body = dBodyCreate(world);
for (k=0; k<3; k++)
sides[k] = dRandReal()*0.5+0.1;
dMatrix3 R;
if (random_pos) {
dBodySetPosition(obj[i].body,
dRandReal()*2-1,dRandReal()*2-1,dRandReal()+2);
dRFromAxisAndAngle(R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
} else {
// higher than highest body position
dReal maxheight = 0;
for (k=0; k<num; k++) {
const dReal *pos = dBodyGetPosition(obj[k].body);
if (pos[2] > maxheight)
maxheight = pos[2];
}
dBodySetPosition(obj[i].body, 0,0,maxheight+1);
dRSetIdentity(R);
//dRFromAxisAndAngle (R,0,0,1,/*dRandReal()*10.0-5.0*/0);
}
dBodySetRotation(obj[i].body,R);
if (cmd == 'b') {
dMassSetBox(&m,DENSITY,sides[0],sides[1],sides[2]);
obj[i].geom[0] = dCreateBox(space,sides[0],sides[1],sides[2]);
} else if (cmd == 'c') {
sides[0] *= 0.5;
dMassSetCapsule(&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]);
} else if (cmd == 'y') {
dMassSetCylinder(&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCylinder(space,sides[0],sides[1]);
} else if (cmd == 's') {
sides[0] *= 0.5;
dMassSetSphere (&m,DENSITY,sides[0]);
obj[i].geom[0] = dCreateSphere (space,sides[0]);
} else if (cmd == 'x') {
setBody = true;
// start accumulating masses for the composite geometries
dMass m2;
dMassSetZero (&m);
dReal dpos[GPB][3]; // delta-positions for composite geometries
dMatrix3 drot[GPB];
// set random delta positions
for (j=0; j<GPB; j++)
for (k=0; k<3; k++)
dpos[j][k] = dRandReal()*0.3-0.15;
for (k=0; k<GPB; k++) {
if (k==0) {
dReal radius = dRandReal()*0.25+0.05;
obj[i].geom[k] = dCreateSphere (space,radius);
dMassSetSphere (&m2,DENSITY,radius);
} else if (k==1) {
obj[i].geom[k] = dCreateBox(space,sides[0],sides[1],sides[2]);
dMassSetBox(&m2,DENSITY,sides[0],sides[1],sides[2]);
} else {
dReal radius = dRandReal()*0.1+0.05;
dReal length = dRandReal()*1.0+0.1;
obj[i].geom[k] = dCreateCapsule(space,radius,length);
dMassSetCapsule(&m2,DENSITY,3,radius,length);
}
dRFromAxisAndAngle(drot[k],dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
dMassRotate(&m2,drot[k]);
dMassTranslate(&m2,dpos[k][0],dpos[k][1],dpos[k][2]);
// add to the total mass
dMassAdd(&m,&m2);
}
for (k=0; k<GPB; k++) {
dGeomSetBody(obj[i].geom[k],obj[i].body);
dGeomSetOffsetPosition(obj[i].geom[k],
dpos[k][0]-m.c[0],
dpos[k][1]-m.c[1],
dpos[k][2]-m.c[2]);
dGeomSetOffsetRotation(obj[i].geom[k], drot[k]);
}
dMassTranslate(&m,-m.c[0],-m.c[1],-m.c[2]);
dBodySetMass(obj[i].body,&m);
}
if (!setBody) { // avoid calling for composite geometries
for (k=0; k < GPB; k++)
if (obj[i].geom[k])
dGeomSetBody(obj[i].geom[k],obj[i].body);
dBodySetMass(obj[i].body,&m);
}
}
if (cmd == ' ') {
selected++;
if (selected >= num) selected = 0;
if (selected < 0) selected = 0;
}
else if (cmd == 'd' && selected >= 0 && selected < num) {
dBodyDisable (obj[selected].body);
}
else if (cmd == 'e' && selected >= 0 && selected < num) {
dBodyEnable (obj[selected].body);
}
else if (cmd == 'a') {
show_aabb ^= 1;
}
else if (cmd == 't') {
show_contacts ^= 1;
}
else if (cmd == 'r') {
random_pos ^= 1;
}
else if (cmd == 'o') {
draw_geom ^= 1;
}
}
// draw a geom
void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
{
if (!draw_geom){
return;
}
if (!g) return;
if (!pos) pos = dGeomGetPosition(g);
if (!R) R = dGeomGetRotation(g);
int type = dGeomGetClass (g);
if (type == dBoxClass) {
dVector3 sides;
dGeomBoxGetLengths(g,sides);
dsDrawBox(pos,R,sides);
}
else if (type == dSphereClass) {
dsDrawSphere(pos,R,dGeomSphereGetRadius (g));
}
else if (type == dCapsuleClass) {
dReal radius,length;
dGeomCapsuleGetParams(g,&radius,&length);
dsDrawCapsule (pos,R,length,radius);
} else if (type == dCylinderClass) {
dReal radius,length;
dGeomCylinderGetParams(g,&radius,&length);
dsDrawCylinder(pos,R,length,radius);
}
if (show_aabb) {
// draw the bounding box for this geom
dReal aabb[6];
dGeomGetAABB(g,aabb);
dVector3 bbpos;
for (int i=0; i<3; i++)
bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
dVector3 bbsides;
for (int j=0; j<3; j++)
bbsides[j] = aabb[j*2+1] - aabb[j*2];
dMatrix3 RI;
dRSetIdentity(RI);
dsSetColorAlpha(1,0,0,0.5);
dsDrawBox(bbpos,RI,bbsides);
}
}
// simulation loop
static void simLoop (int pause)
{
dsSetColor (0,0,2);
dSpaceCollide (space,0,&nearCallback);
//if (!pause) dWorldStep (world,0.05);
if (!pause) dWorldQuickStep (world,0.05);
//if (!pause) dWorldStepFast (world,0.05, 1);
// remove all contact joints
dJointGroupEmpty (contactgroup);
dsSetColor (1,1,0);
dsSetTexture (DS_WOOD);
for (int i=0; i<num; i++) {
for (int j=0; j < GPB; j++) {
if (i==selected) {
dsSetColor (0,0.7,1);
}
else if (! dBodyIsEnabled (obj[i].body)) {
dsSetColor (1,0,0);
}
else {
dsSetColor (1,1,0);
}
drawGeom (obj[i].geom[j],0,0,show_aabb);
}
}
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
dsSetSphereQuality(0);
// create world
dInitODE2(0);
world = dWorldCreate();
for (int i=1; i<argc; ++i) {
if (argv[i] == std::string("quad")) {
dVector3 Center = {0, 0, 0, 0};
dVector3 Extents = {WORLD_SIZE * 0.55, WORLD_SIZE * 0.55, WORLD_SIZE * 0.55, 0};
puts(":::: Using dQuadTreeSpace");
space = dQuadTreeSpaceCreate (0, Center, Extents, 6);
} else if (argv[i] == std::string("hash")) {
puts(":::: Using dHashSpace");
space = dHashSpaceCreate (0);
} else if (argv[i] == std::string("sap")) {
puts(":::: Using dSweepAndPruneSpace");
space = dSweepAndPruneSpaceCreate (0, dSAP_AXES_XYZ);
} else if (argv[i] == std::string("simple")) {
puts(":::: Using dSimpleSpace");
space = dSimpleSpaceCreate(0);
}
}
if (!space) {
puts(":::: You can specify 'quad', 'hash', 'sap' or 'simple' in the");
puts(":::: command line to specify the type of space.");
puts(":::: Using SAP space by default.");
space = dSweepAndPruneSpaceCreate (0, dSAP_AXES_XYZ);
}
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-0.5);
dWorldSetCFM (world,1e-5);
dCreatePlane (space,0,0,1,0);
memset (obj,0,sizeof(obj));
for (int i = 0; i < NUM; i++){
command('s');
}
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,192 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
// test the step function by comparing the output of the fast and the slow
// version, for various systems. currently you have to define COMPARE_METHODS
// in step.cpp for this to work properly.
//
// @@@ report MAX error
#include <time.h>
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#endif
// some constants
#define NUM 10 // number of bodies
#define NUMJ 9 // number of joints
#define SIDE (0.2) // side length of a box
#define MASS (1.0) // mass of a box
#define RADIUS (0.1732f) // sphere radius
// dynamics and collision objects
static dWorldID world=0;
static dBodyID body[NUM];
static dJointID joint[NUMJ];
// create the test system
void createTest()
{
int i,j;
if (world) dWorldDestroy (world);
world = dWorldCreate();
// create random bodies
for (i=0; i<NUM; i++) {
// create bodies at random position and orientation
body[i] = dBodyCreate (world);
dBodySetPosition (body[i],dRandReal()*2-1,dRandReal()*2-1,
dRandReal()*2+RADIUS);
dReal q[4];
for (j=0; j<4; j++) q[j] = dRandReal()*2-1;
dBodySetQuaternion (body[i],q);
// set random velocity
dBodySetLinearVel (body[i], dRandReal()*2-1,dRandReal()*2-1,
dRandReal()*2-1);
dBodySetAngularVel (body[i], dRandReal()*2-1,dRandReal()*2-1,
dRandReal()*2-1);
// set random mass (random diagonal mass rotated by a random amount)
dMass m;
dMatrix3 R;
dMassSetBox (&m,1,dRandReal()+0.1,dRandReal()+0.1,dRandReal()+0.1);
dMassAdjust (&m,dRandReal()+1);
for (j=0; j<4; j++) q[j] = dRandReal()*2-1;
dQtoR (q,R);
dMassRotate (&m,R);
dBodySetMass (body[i],&m);
}
// create ball-n-socket joints at random positions, linking random bodies
// (but make sure not to link the same pair of bodies twice)
char linked[NUM*NUM];
for (i=0; i<NUM*NUM; i++) linked[i] = 0;
for (i=0; i<NUMJ; i++) {
int b1,b2;
do {
b1 = dRandInt (NUM);
b2 = dRandInt (NUM);
} while (linked[b1*NUM + b2] || b1==b2);
linked[b1*NUM + b2] = 1;
linked[b2*NUM + b1] = 1;
joint[i] = dJointCreateBall (world,0);
dJointAttach (joint[i],body[b1],body[b2]);
dJointSetBallAnchor (joint[i],dRandReal()*2-1,
dRandReal()*2-1,dRandReal()*2+RADIUS);
}
for (i=0; i<NUM; i++) {
// move bodies a bit to get some joint error
const dReal *pos = dBodyGetPosition (body[i]);
dBodySetPosition (body[i],pos[0]+dRandReal()*0.2-0.1,
pos[1]+dRandReal()*0.2-0.1,pos[2]+dRandReal()*0.2-0.1);
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {2.6117f,-1.4433f,2.3700f};
static float hpr[3] = {151.5000f,-30.5000f,0.0000f};
dsSetViewpoint (xyz,hpr);
}
// simulation loop
static void simLoop (int pause)
{
if (!pause) {
// add random forces and torques to all bodies
int i;
const dReal scale1 = 5;
const dReal scale2 = 5;
for (i=0; i<NUM; i++) {
dBodyAddForce (body[i],
scale1*(dRandReal()*2-1),
scale1*(dRandReal()*2-1),
scale1*(dRandReal()*2-1));
dBodyAddTorque (body[i],
scale2*(dRandReal()*2-1),
scale2*(dRandReal()*2-1),
scale2*(dRandReal()*2-1));
}
dWorldStep (world,0.05);
createTest();
}
// float sides[3] = {SIDE,SIDE,SIDE};
dsSetColor (1,1,0);
for (int i=0; i<NUM; i++)
dsDrawSphere (dBodyGetPosition(body[i]), dBodyGetRotation(body[i]),RADIUS);
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = 0;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
dInitODE2(0);
dRandSetSeed (time(0));
createTest();
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dWorldDestroy (world);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,498 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
//#include <iostream>
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef dDOUBLE
#define dsDrawSphere dsDrawSphereD
#define dsDrawBox dsDrawBoxD
#define dsDrawTriangle dsDrawTriangleD
#define dsDrawLine dsDrawLineD
#endif
const dReal ball_radius = 0.4;
const dReal balls_sep = 2; // separation between the balls
/* Choose one test case
*/
#define TEST_CASE 0
#if TEST_CASE == 0
const dReal track_len = 10;
const dReal track_height = 1;
const dReal track_width = 0.1;
const dReal track_gauge = 1;
const dReal track_elevation = 2;
const dReal track_angle = 80 * M_PI/180.;
const dReal track_incl = 10 * M_PI/180.;
#elif TEST_CASE == 1
const dReal track_len = 10;
const dReal track_height = 1;
const dReal track_width = 0.1;
const dReal track_gauge = 1.9*ball_radius;
const dReal track_elevation = 2;
const dReal track_angle = 0 * M_PI/180.;
const dReal track_incl = 10 * M_PI/180.;
#elif TEST_CASE == 2
const dReal track_len = 10;
const dReal track_height = 1;
const dReal track_width = 0.1;
const dReal track_gauge = 1.9*ball_radius;
const dReal track_elevation = 2;
const dReal track_angle = 15 * M_PI/180.;
const dReal track_incl = 10 * M_PI/180.;
#elif TEST_CASE == 3
const dReal track_len = 10;
const dReal track_height = .7;
const dReal track_width = 0.1;
const dReal track_gauge = track_height*1.1;
const dReal track_elevation = 2;
const dReal track_angle = 90 * M_PI/180.;
const dReal track_incl = 10 * M_PI/180.;
#else
#error "TEST_CAST to a valid value!"
#endif
dWorldID world;
dSpaceID space;
dJointGroupID contact_group;
dGeomID ground;
dGeomID ball1_geom, ball2_geom;
dTriMeshDataID mesh_data;
dGeomID mesh_geom;
dBodyID ball1_body, ball2_body;
const unsigned n_box_verts = 8;
dVector3 box_verts[n_box_verts] = {
{-track_len/2, -track_width/2, track_height/2}, // 0
{ track_len/2, -track_width/2, track_height/2}, // 1
{ track_len/2, track_width/2, track_height/2}, // 2
{-track_len/2, track_width/2, track_height/2}, // 3
{ track_len/2, -track_width/2, -track_height/2}, // 4
{-track_len/2, -track_width/2, -track_height/2}, // 5
{-track_len/2, track_width/2, -track_height/2}, // 6
{ track_len/2, track_width/2, -track_height/2} // 7
};
const unsigned n_box_faces = 12;
dTriIndex box_faces[n_box_faces * 3] = {
0, 1, 2,
0, 2, 3,
1, 4, 7,
1, 7, 2,
4, 5, 6,
4, 6, 7,
5, 0, 3,
5, 3, 6,
3, 2, 7,
3, 7, 6,
0, 5, 4,
0, 4, 1
};
const unsigned n_track_verts = n_box_verts * 2;
const unsigned n_track_faces = n_box_faces * 2;
dVector3 track_verts[n_track_verts];
dTriIndex track_faces[n_track_faces * 3];
void resetBall(dBodyID b, unsigned idx)
{
dBodySetPosition(b,
0.5*track_len*cos(track_incl) // Z
- 0.5*track_height*sin(track_incl)
- ball_radius, // X
balls_sep*idx, // Y
track_elevation + ball_radius// Z
+ 0.5*track_len*sin(track_incl)
+ 0.5*track_height*cos(track_incl));
dMatrix3 r = {1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0};
dBodySetRotation(b, r);
dBodySetLinearVel(b, 0, 0, 0);
dBodySetAngularVel(b, 0, 0, 0);
}
void resetSim()
{
resetBall(ball1_body, 0);
resetBall(ball2_body, 1);
}
void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
world = dWorldCreate();
dWorldSetGravity (world,0,0,-9.8);
contact_group = dJointGroupCreate(0);
space = dSimpleSpaceCreate (0);
// first, the ground plane
// it has to coincide with the plane we have in drawstuff
ground = dCreatePlane(space, 0, 0, 1, 0);
// now a ball
dMass m;
dMassSetSphere(&m, 0.1, ball_radius);
ball1_geom = dCreateSphere(space, ball_radius);
ball1_body = dBodyCreate(world);
dGeomSetBody(ball1_geom, ball1_body);
dBodySetMass(ball1_body, &m);
ball2_geom = dCreateSphere(space, ball_radius);
ball2_body = dBodyCreate(world);
dGeomSetBody(ball2_geom, ball2_body);
dBodySetMass(ball2_body, &m);
// tracks made out of boxes
dGeomID trk;
dMatrix3 r1, r2, r3;
dVector3 ro = {0, -(0.5*track_gauge + 0.5*track_width), track_elevation};
dMatrix3 s1, s2, s3;
dVector3 so = {0, 0.5*track_gauge + 0.5*track_width, track_elevation};
dRFromAxisAndAngle(r1, 1, 0, 0, track_angle);
dRFromAxisAndAngle(r2, 0, 1, 0, -track_incl);
dMultiply0_333(r3, r2, r1);
dRFromAxisAndAngle(s1, 1, 0, 0, -track_angle);
dRFromAxisAndAngle(s2, 0, 1, 0, -track_incl);
dMultiply0_333(s3, s2, s1);
trk = dCreateBox(space, track_len, track_width, track_height);
dGeomSetPosition(trk, ro[0], ro[1] + balls_sep, ro[2]);
dGeomSetRotation(trk, r3);
trk = dCreateBox(space, track_len, track_width, track_height);
dGeomSetPosition(trk, so[0], so[1] + balls_sep, so[2]);
dGeomSetRotation(trk, s3);
// tracks made out of trimesh
for (unsigned i=0; i<n_box_verts; ++i) {
dVector3 p;
dMultiply0_331(p, s3, box_verts[i]);
dAddVectors3(p, p, so);
dCopyVector3(track_verts[i], p);
}
// trimesh tracks 2, transform all vertices by s3
for (unsigned i=0; i<n_box_verts; ++i) {
dVector3 p;
dMultiply0_331(p, r3, box_verts[i]);
dAddVectors3(p, p, ro);
dCopyVector3(track_verts[n_box_verts + i], p);
}
// copy face indices
for (unsigned i=0; i<n_box_faces; ++i)
for (unsigned j=0; j<3; ++j) // each face index
track_faces[3*i+j] = box_faces[3*i+j];
for (unsigned i=0; i<n_box_faces; ++i)
for (unsigned j=0; j<3; ++j) // each face index
track_faces[3*(i + n_box_faces)+j] = box_faces[3*i+j] + n_box_verts;
mesh_data = dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSimple(mesh_data,
track_verts[0], n_track_verts,
track_faces, 3*n_track_faces);
mesh_geom = dCreateTriMesh(space, mesh_data, 0, 0, 0);
resetSim();
// initial camera position
static float xyz[3] = {-5.9414,-0.4804,2.9800};
static float hpr[3] = {32.5000,-10.0000,0.0000};
dsSetViewpoint (xyz,hpr);
dsSetSphereQuality(3);
}
void nearCallback(void *, dGeomID a, dGeomID b)
{
const unsigned max_contacts = 8;
dContact contacts[max_contacts];
if (!dGeomGetBody(a) && !dGeomGetBody(b))
return; // don't handle static geom collisions
int n = dCollide(a, b, max_contacts, &contacts[0].geom, sizeof(dContact));
//clog << "got " << n << " contacts" << endl;
/* Simple contact merging:
* If we have contacts that are too close with the same normal, keep only
* the one with maximum depth.
* The epsilon that defines what "too close" means can be a heuristic.
*/
int new_n = 0;
dReal epsilon = 1e-1; // default
/* If we know one of the geoms is a sphere, we can base the epsilon on the
* sphere's radius.
*/
dGeomID s = 0;
if ((dGeomGetClass(a) == dSphereClass && (s = a)) ||
(dGeomGetClass(b) == dSphereClass && (s = b))) {
epsilon = dGeomSphereGetRadius(s) * 0.3;
}
for (int i=0; i<n; ++i) {
// this block draws the contact points before merging, in red
dMatrix3 r;
dRSetIdentity(r);
dsSetColor(1, 0, 0);
dsSetTexture(DS_NONE);
dsDrawSphere(contacts[i].geom.pos, r, 0.008);
// let's offset the line a bit to avoid drawing overlap issues
float xyzf[3], hprf[3];
dsGetViewpoint(xyzf, hprf);
dVector3 xyz = {dReal(xyzf[0]), dReal(xyzf[1]), dReal(xyzf[2])};
dVector3 v;
dSubtractVectors3(v, contacts[i].geom.pos, xyz);
dVector3 c;
dCalcVectorCross3(c, v, contacts[i].geom.pos);
dNormalize3(c);
dVector3 pos1;
dAddScaledVectors3(pos1, contacts[i].geom.pos, c, 1, 0.005);
dVector3 pos2;
dAddScaledVectors3(pos2, pos1, contacts[i].geom.normal, 1, 0.05);
dsDrawLine(pos1, pos2);
// end of contacts drawing code
int closest_point = i;
for (int j=0; j<new_n; ++j) {
dReal alignment = dCalcVectorDot3(contacts[i].geom.normal, contacts[j].geom.normal);
if (alignment > 0.99 // about 8 degrees of difference
&&
dCalcPointsDistance3(contacts[i].geom.pos, contacts[j].geom.pos) < epsilon) {
// they are too close
closest_point = j;
//clog << "found close points: " << j << " and " << i << endl;
break;
}
}
if (closest_point != i) {
// we discard one of the points
if (contacts[i].geom.depth > contacts[closest_point].geom.depth)
// the new point is deeper, copy it over closest_point
contacts[closest_point] = contacts[i];
} else
contacts[new_n++] = contacts[i]; // the point is preserved
}
//clog << "reduced from " << n << " to " << new_n << endl;
n = new_n;
for (int i=0; i<n; ++i) {
contacts[i].surface.mode = dContactBounce | dContactApprox1 | dContactSoftERP;
contacts[i].surface.mu = 10;
contacts[i].surface.bounce = 0.2;
contacts[i].surface.bounce_vel = 0;
contacts[i].surface.soft_erp = 1e-3;
//clog << "depth: " << contacts[i].geom.depth << endl;
dJointID contact = dJointCreateContact(world, contact_group, &contacts[i]);
dJointAttach(contact, dGeomGetBody(a), dGeomGetBody(b));
dMatrix3 r;
dRSetIdentity(r);
dsSetColor(0, 0, 1);
dsSetTexture(DS_NONE);
dsDrawSphere(contacts[i].geom.pos, r, 0.01);
dsSetColor(0, 1, 0);
dVector3 pos2;
dAddScaledVectors3(pos2, contacts[i].geom.pos, contacts[i].geom.normal, 1, 0.1);
dsDrawLine(contacts[i].geom.pos, pos2);
}
//clog << "----" << endl;
}
void stop()
{
dGeomDestroy(mesh_geom);
dGeomTriMeshDataDestroy(mesh_data);
dBodyDestroy(ball1_body);
dBodyDestroy(ball2_body);
dGeomDestroy(ground);
dJointGroupDestroy(contact_group);
dSpaceDestroy(space); // will destroy all geoms
dWorldDestroy(world);
}
static void command (int cmd)
{
switch (cmd) {
case ' ':
resetSim();
break;
}
}
void drawGeom(dGeomID g)
{
int gclass = dGeomGetClass(g);
const dReal *pos = dGeomGetPosition(g);
const dReal *rot = dGeomGetRotation(g);
switch (gclass) {
case dSphereClass:
dsSetColorAlpha(0, 0.75, 0.5, 0.5);
dsSetTexture (DS_CHECKERED);
dsDrawSphere(pos, rot, dGeomSphereGetRadius(g));
break;
case dBoxClass:
{
dVector3 lengths;
dsSetColorAlpha(1, 1, 0, 0.5);
dsSetTexture (DS_WOOD);
dGeomBoxGetLengths(g, lengths);
dsDrawBox(pos, rot, lengths);
break;
}
case dTriMeshClass:
{
int numi = dGeomTriMeshGetTriangleCount(g);
for (int i=0; i<numi; ++i) {
dVector3 v0, v1, v2;
dGeomTriMeshGetTriangle(g, i, &v0, &v1, &v2);
dsSetTexture (DS_WOOD);
dsSetDrawMode(DS_WIREFRAME);
dsSetColorAlpha(0, 0, 0, 1.0);
dsDrawTriangle(pos, rot, v0, v1, v2, true);
dsSetDrawMode(DS_POLYFILL);
dsSetColorAlpha(1, 1, 0, 0.5);
dsDrawTriangle(pos, rot, v0, v1, v2, true);
}
break;
}
default:
{}
}
}
void simLoop (int pause)
{
if (!pause) {
const dReal step = 0.02;
const unsigned nsteps = 1;
for (unsigned i=0; i<nsteps; ++i) {
dSpaceCollide(space, 0, nearCallback);
dWorldQuickStep(world, step);
dJointGroupEmpty(contact_group);
}
} else {
dSpaceCollide(space, 0, nearCallback);
dJointGroupEmpty(contact_group);
}
// now we draw everything
unsigned ngeoms = dSpaceGetNumGeoms(space);
for (unsigned i=0; i<ngeoms; ++i) {
dGeomID g = dSpaceGetGeom(space, i);
if (g == ground)
continue; // drawstuff is already drawing it for us
drawGeom(g);
}
if (dBodyGetPosition(ball1_body)[0] < -track_len)
resetSim();
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = stop;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE();
// run demo
dsSimulationLoop (argc, argv, 800, 600, &fn);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,414 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef dDOUBLE
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawLine dsDrawLineD
#define dsDrawSphere dsDrawSphereD
#endif
dReal theta = M_PI / 4;
dReal ratio = 1, speed = 5, rho_1 = 1, rho_2 = 1, backlash = 0.1;
int mode = 0;
dWorldID world;
dSpaceID space;
dBodyID body1, body2;
dGeomID geom1, geom2;
dJointID hinge1, hinge2, transmission;
dJointFeedback feedback;
void setup() {
dMatrix3 R;
switch (mode) {
case 0:
// Parallel axes.
dBodySetPosition(body1, 1, 0, 1);
dBodySetPosition(body2, -1, 0, 1);
dRSetIdentity (R);
dBodySetRotation (body1, R);
dBodySetRotation (body2, R);
dJointSetHingeAnchor(hinge2, -1, 0, 1);
dJointSetHingeAxis(hinge2, 0, 0, 1);
dJointSetHingeAnchor(hinge1, 1, 0, 1);
dJointSetHingeAxis(hinge1, 0, 0, 1);
dJointSetTransmissionMode(transmission, dTransmissionParallelAxes);
dJointSetTransmissionRatio(transmission, ratio);
dJointSetTransmissionAnchor1(transmission, 1, 0, 1);
dJointSetTransmissionAnchor2(transmission, -1, 0, 1);
dJointSetTransmissionAxis(transmission, 0, 0, 1);
break;
case 1:
// Intersecting axes.
dBodySetPosition(body1, 1, 0, 1);
dBodySetPosition(body2, -1, 0, 2);
dRSetIdentity (R);
dBodySetRotation (body1, R);
dRFromZAxis (R, cos(theta), 0, sin(theta));
dBodySetRotation (body2, R);
dJointSetHingeAnchor(hinge2, -1, 0, 2);
dJointSetHingeAxis(hinge2, cos(theta), 0, sin(theta));
dJointSetHingeAnchor(hinge1, 1, 0, 1);
dJointSetHingeAxis(hinge1, 0, 0, 1);
dJointSetTransmissionMode(transmission, dTransmissionIntersectingAxes);
dJointSetTransmissionAnchor1(transmission, 1, 0, 1);
dJointSetTransmissionAnchor2(transmission, -1, 0, 2);
dJointSetTransmissionAxis1(transmission, 0, 0, -1);
dJointSetTransmissionAxis2(transmission, cos(theta), 0, sin(theta));
break;
case 2:
// Chain.
dBodySetPosition(body1, 2, 0, 1);
dBodySetPosition(body2, -2, 0, 1);
dRSetIdentity (R);
dBodySetRotation (body1, R);
dBodySetRotation (body2, R);
dJointSetHingeAnchor(hinge2, -2, 0, 1);
dJointSetHingeAxis(hinge2, 0, 0, 1);
dJointSetHingeAnchor(hinge1, 2, 0, 1);
dJointSetHingeAxis(hinge1, 0, 0, 1);
dJointSetTransmissionMode(transmission, dTransmissionChainDrive);
dJointSetTransmissionAnchor1(transmission, 2, 0, 1);
dJointSetTransmissionAnchor2(transmission, -2, 0, 1);
dJointSetTransmissionRadius1(transmission, rho_1);
dJointSetTransmissionRadius2(transmission, rho_2);
dJointSetTransmissionAxis(transmission, 0, 0, 1);
break;
}
dJointSetTransmissionBacklash(transmission, backlash);
dJointSetHingeParam(hinge2, dParamVel, speed);
dJointSetHingeParam(hinge2, dParamFMax, 50);
dJointSetHingeParam(hinge1, dParamVel, 0);
dJointSetHingeParam(hinge1, dParamFMax, 2);
dBodySetLinearVel(body1, 0, 0, 0);
dBodySetLinearVel(body2, 0, 0, 0);
dBodySetAngularVel(body1, 0, 0, 0);
dBodySetAngularVel(body2, 0, 0, 0);
}
void start()
{
dMass mass;
world = dWorldCreate();
dWorldSetGravity (world,0,0,-9.8);
dWorldSetERP(world, 0.2);
space = dSimpleSpaceCreate (0);
body1 = dBodyCreate(world);
body2 = dBodyCreate(world);
dBodySetFiniteRotationMode(body1, 1);
dBodySetFiniteRotationMode(body2, 1);
geom1 = dCreateCylinder(space, 0.2, 0.5);
dGeomSetBody(geom1, body1);
dMassSetCylinder(&mass, 100, 3, 0.2, 0.5);
dBodySetMass(body1, &mass);
geom2 = dCreateCylinder(space, 0.2, 0.5);
dGeomSetBody(geom2, body2);
dMassSetCylinder(&mass, 100, 3, 0.2, 0.5);
dBodySetMass(body2, &mass);
hinge1 = dJointCreateHinge(world, 0);
dJointAttach(hinge1, body1, 0);
hinge2 = dJointCreateHinge(world, 0);
dJointAttach(hinge2, body2, 0);
transmission = dJointCreateTransmission(world, 0);
dJointAttach(transmission, body1, body2);
dJointSetFeedback(transmission, &feedback);
setup();
// initial camera position
static float xyz[3] = {1.15,-2.78,4.1};
static float hpr[3] = {105,-45.5,0};
dsSetViewpoint (xyz,hpr);
fprintf (stderr,
"The green wheel is driving the red one. To control it use the following:\n"
" '[' : decrease wheel ratio\n"
" ']' : increase wheel ratio\n"
" ',' : decrease driving wheel speed\n"
" '.' : increase driving wheel speed\n"
" '-' : decrease backlash\n"
" '=' : increase backlash\n"
" '1' : switch to parallel axes gears mode\n"
" '2' : switch to intersecting axes gears mode\n"
" '3' : switch to chain (or belt) mode\n"
);
}
void stop()
{
dSpaceDestroy(space);
dWorldDestroy(world);
}
void drawGeom(dGeomID g)
{
int gclass = dGeomGetClass(g);
const dReal *pos = dGeomGetPosition(g);
const dReal *rot = dGeomGetRotation(g);
switch (gclass) {
case dCylinderClass:
{
dReal length, radius;
if (g == geom1) {
dsSetColorAlpha(1, 0, 0, 1);
} else {
dsSetColorAlpha(0, 1, 0, 1);
}
dsSetTexture (DS_WOOD);
dGeomCylinderGetParams(g, &radius, &length);
dsDrawCylinder(pos, rot, length, radius);
break;
}
default:
{
abort();
}
}
}
void simLoop(int pause)
{
if (!pause) {
const dReal step = 0.003;
const unsigned nsteps = 4;
for (unsigned i=0; i<nsteps; ++i) {
dWorldQuickStep(world, step);
}
}
#if 0
{
const dReal *omega_1, *omega_2;
omega_1 = dBodyGetAngularVel(body1);
omega_2 = dBodyGetAngularVel(body2);
printf ("T1: %f, %f, %f\n",
feedback.t1[0], feedback.t1[1], feedback.t1[2]);
printf ("T2: %f, %f, %f\n",
feedback.t2[0], feedback.t2[1], feedback.t2[2]);
printf ("F1: %f, %f, %f\n",
feedback.f1[0], feedback.f1[1], feedback.f1[2]);
printf ("F2: %f, %f, %f\n",
feedback.f2[0], feedback.f2[1], feedback.f2[2]);
}
#endif
// now we draw everything
unsigned ngeoms = dSpaceGetNumGeoms(space);
for (unsigned i=0; i<ngeoms; ++i) {
dGeomID g = dSpaceGetGeom(space, i);
drawGeom(g);
}
const dReal *R_1 = dGeomGetRotation(geom1);
const dReal *R_2 = dGeomGetRotation(geom2);
dVector3 c_1, c_2, a_1, a_2;
dJointGetTransmissionContactPoint1(transmission, c_1);
dJointGetTransmissionContactPoint2(transmission, c_2);
dJointGetTransmissionAnchor1(transmission, a_1);
dJointGetTransmissionAnchor2(transmission, a_2);
dsSetColorAlpha(1, 0, 0, 0.5);
dsDrawCylinder(a_1, R_1, 0.05, dCalcPointsDistance3(c_1, a_1));
dsSetColorAlpha(0, 1, 0, 0.5);
dsDrawCylinder(a_2, R_2, 0.05, dCalcPointsDistance3(c_2, a_2));
dsSetColorAlpha(1, 0, 0, 0.5);
dsDrawSphere (c_1, R_1, 0.05);
dsDrawSphere (c_2, R_1, 0.05);
dsSetColorAlpha(1, 1, 0, 0.5);
if (mode == dTransmissionChainDrive) {
dsDrawLine(c_1, c_2);
}
}
static void command (int cmd)
{
if (cmd == '[') {
switch(mode) {
case dTransmissionParallelAxes:
if (ratio > 0.125) {
ratio *= 0.5;
fprintf (stderr, "Gear ratio set to %.3f.\n", ratio);
}
break;
case dTransmissionIntersectingAxes:
if (theta > 0.1) {
theta -= 0.1;
fprintf (stderr, "Gear angle set to %.3f deg.\n",
theta / M_PI * 180);
}
break;
case dTransmissionChainDrive:
if (rho_2 > 0.125) {
rho_2 /= 2;
fprintf (stderr, "Sprocket ratio set to %.3f.\n", rho_2 / rho_1);
}
break;
}
setup();
} else if (cmd == ']') {
switch(mode) {
case dTransmissionParallelAxes:
if (ratio < 8) {
ratio *= 2;
fprintf (stderr, "Gear ratio set to %.3f.\n", ratio);
}
break;
case dTransmissionIntersectingAxes:
if (theta < 0.9) {
theta += 0.1;
fprintf (stderr, "Gear angle set to %.3f deg.\n",
theta / M_PI * 180);
}
break;
case dTransmissionChainDrive:
if (rho_2 < 2) {
rho_2 *= 2;
fprintf (stderr, "Sprocket ratio set to %.3f.\n", rho_2 / rho_1);
}
break;
}
setup();
} else if (cmd == '.') {
speed += 5;
fprintf (stderr, "Driving wheel speed set to %g rad/s.\n", speed);
dJointSetHingeParam(hinge2, dParamVel, speed);
} else if (cmd == ',') {
speed -= 5;
fprintf (stderr, "Driving wheel speed set to %g rad/s.\n", speed);
dJointSetHingeParam(hinge2, dParamVel, speed);
} else if (cmd == '/') {
if (dJointGetHingeParam(hinge2, dParamFMax) > 0) {
dJointSetHingeParam(hinge2, dParamFMax, 0);
} else {
dJointSetHingeParam(hinge2, dParamFMax, 50);
}
} else if (cmd == '-') {
backlash -= 0.1;
fprintf (stderr, "Backlash set to %g m.\n", backlash);
dJointSetTransmissionBacklash(transmission, backlash);
} else if (cmd == '=') {
backlash += 0.1;
fprintf (stderr, "Backlash set to %g m.\n", backlash);
dJointSetTransmissionBacklash(transmission, backlash);
} else if (cmd == '1') {
mode = dTransmissionParallelAxes;
setup();
} else if (cmd == '2') {
mode = dTransmissionIntersectingAxes;
setup();
} else if (cmd == '3') {
mode = dTransmissionChainDrive;
setup();
}
}
int main(int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = stop;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE();
// run demo
dsSimulationLoop (argc, argv, 800, 600, &fn);
dCloseODE();
return 0;
}

View File

@@ -0,0 +1,605 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
// TriMesh test by Erwin de Vries
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include "texturepath.h"
#ifdef _MSC_VER
#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
#endif
//<---- Convex Object
static const dReal planes[] = // planes for a cube
{
1.0f ,0.0f ,0.0f ,0.25f,
0.0f ,1.0f ,0.0f ,0.25f,
0.0f ,0.0f ,1.0f ,0.25f,
0.0f ,0.0f ,-1.0f,0.25f,
0.0f ,-1.0f,0.0f ,0.25f,
-1.0f,0.0f ,0.0f ,0.25f
/*
1.0f ,0.0f ,0.0f ,2.0f,
0.0f ,1.0f ,0.0f ,1.0f,
0.0f ,0.0f ,1.0f ,1.0f,
0.0f ,0.0f ,-1.0f,1.0f,
0.0f ,-1.0f,0.0f ,1.0f,
-1.0f,0.0f ,0.0f ,0.0f
*/
};
static const unsigned int planecount=6;
static const dReal points[] = // points for a cube
{
0.25f,0.25f,0.25f,
-0.25f,0.25f,0.25f,
0.25f,-0.25f,0.25f,
-0.25f,-0.25f,0.25f,
0.25f,0.25f,-0.25f,
-0.25f,0.25f,-0.25f,
0.25f,-0.25f,-0.25f,
-0.25f,-0.25f,-0.25f,
};
static const unsigned int pointcount=8;
static const unsigned int polygons[] = //Polygons for a cube (6 squares)
{
4,0,2,6,4, // positive X
4,1,0,4,5, // positive Y
4,0,1,3,2, // positive Z
4,3,1,5,7, // negative X
4,2,3,7,6, // negative Y
4,5,4,6,7, // negative Z
};
//----> Convex Object
// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#define dsDrawSphere dsDrawSphereD
#define dsDrawCylinder dsDrawCylinderD
#define dsDrawCapsule dsDrawCapsuleD
#define dsDrawLine dsDrawLineD
#define dsDrawTriangle dsDrawTriangleD
#define dsDrawConvex dsDrawConvexD
#endif
// some constants
#define NUM 200 // max number of objects
#define DENSITY (5.0) // density of all objects
#define GPB 3 // maximum number of geometries per body
#define MAX_CONTACTS 40 // maximum number of contact points per body
// dynamics and collision objects
struct MyObject {
dBodyID body; // the body
dGeomID geom[GPB]; // geometries representing this body
};
static int num=0; // number of objects in simulation
static int nextobj=0; // next object to recycle if num==NUM
static dWorldID world;
static dSpaceID space;
static MyObject obj[NUM];
static dJointGroupID contactgroup;
static int selected = -1; // selected object
static int show_aabb = 0; // show geom AABBs?
static int show_contacts = 0; // show contact points?
static int random_pos = 1; // drop objects from random position?
#define VertexCount 5
#define IndexCount 12
static dVector3 Size;
static float Vertices[VertexCount][3];
static dTriIndex Indices[IndexCount];
static dGeomID TriMesh;
static dGeomID Ray;
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
static void nearCallback (void *, dGeomID o1, dGeomID o2)
{
int i;
// if (o1->body && o2->body) return;
// exit without doing anything if the two bodies are connected by a joint
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return;
dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
for (i=0; i<MAX_CONTACTS; i++) {
contact[i].surface.mode = dContactBounce | dContactSoftCFM;
contact[i].surface.mu = dInfinity;
contact[i].surface.mu2 = 0;
contact[i].surface.bounce = 0.1;
contact[i].surface.bounce_vel = 0.1;
contact[i].surface.soft_cfm = 0.01;
}
if (int numc = dCollide (o1,o2,MAX_CONTACTS,&contact[0].geom,
sizeof(dContact))) {
dMatrix3 RI;
dRSetIdentity (RI);
const dReal ss[3] = {0.02,0.02,0.02};
for (i=0; i<numc; i++) {
if (dGeomGetClass(o1) == dRayClass || dGeomGetClass(o2) == dRayClass){
dMatrix3 Rotation;
dRSetIdentity(Rotation);
dsDrawSphere(contact[i].geom.pos, Rotation, REAL(0.01));
dVector3 End;
End[0] = contact[i].geom.pos[0] + (contact[i].geom.normal[0] * contact[i].geom.depth);
End[1] = contact[i].geom.pos[1] + (contact[i].geom.normal[1] * contact[i].geom.depth);
End[2] = contact[i].geom.pos[2] + (contact[i].geom.normal[2] * contact[i].geom.depth);
End[3] = contact[i].geom.pos[3] + (contact[i].geom.normal[3] * contact[i].geom.depth);
dsDrawLine(contact[i].geom.pos, End);
continue;
}
dJointID c = dJointCreateContact (world,contactgroup,contact+i);
dJointAttach (c,b1,b2);
if (show_contacts) dsDrawBox (contact[i].geom.pos,RI,ss);
}
}
}
// start simulation - set viewpoint
static void start()
{
dAllocateODEDataForThread(dAllocateMaskAll);
static float xyz[3] = {2.1640f,-1.3079f,1.7600f};
static float hpr[3] = {125.5000f,-17.0000f,0.0000f};
dsSetViewpoint (xyz,hpr);
printf ("To drop another object, press:\n");
printf (" b for box.\n");
printf (" s for sphere.\n");
printf (" c for cylinder.\n");
printf( " v for a convex.\n" );
printf (" x for a composite object.\n");
printf ("To select an object, press space.\n");
printf ("To disable the selected object, press d.\n");
printf ("To enable the selected object, press e.\n");
printf ("To toggle showing the geom AABBs, press a.\n");
printf ("To toggle showing the contact points, press t.\n");
printf ("To toggle dropping from random position/orientation, press r.\n");
}
char locase (char c)
{
if (c >= 'A' && c <= 'Z') return c - ('a'-'A');
else return c;
}
// called when a key pressed
static void command (int cmd)
{
int i,j,k;
dReal sides[3];
dMass m;
bool setBody = false;
cmd = locase (cmd);
if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' || cmd == 'v'
/* || cmd == 'l' */) {
if (num < NUM) {
i = num;
num++;
}
else {
i = nextobj;
nextobj++;
if (nextobj >= num) nextobj = 0;
// destroy the body and geoms for slot i
dBodyDestroy (obj[i].body);
for (k=0; k < GPB; k++) {
if (obj[i].geom[k]) dGeomDestroy (obj[i].geom[k]);
}
memset (&obj[i],0,sizeof(obj[i]));
}
obj[i].body = dBodyCreate (world);
for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1;
dMatrix3 R;
if (random_pos) {
dBodySetPosition (obj[i].body,
dRandReal()*2-1,dRandReal()*2-1,dRandReal()+1);
dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
}
else {
dReal maxheight = 0;
for (k=0; k<num; k++) {
const dReal *pos = dBodyGetPosition (obj[k].body);
if (pos[2] > maxheight) maxheight = pos[2];
}
dBodySetPosition (obj[i].body, 0,0,maxheight+1);
dRFromAxisAndAngle (R,0,0,1,dRandReal()*10.0-5.0);
}
dBodySetRotation (obj[i].body,R);
dBodySetData (obj[i].body,(void*)(dsizeint)i);
if (cmd == 'b') {
dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]);
obj[i].geom[0] = dCreateBox (space,sides[0],sides[1],sides[2]);
}
else if (cmd == 'c') {
sides[0] *= 0.5;
dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]);
}
/*
// cylinder option not yet implemented
else if (cmd == 'l') {
sides[1] *= 0.5;
dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]);
obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]);
}
*/
else if (cmd == 's') {
sides[0] *= 0.5;
dMassSetSphere (&m,DENSITY,sides[0]);
obj[i].geom[0] = dCreateSphere (space,sides[0]);
}
else if (cmd == 'x') {
setBody = true;
// start accumulating masses for the composite geometries
dMass m2;
dMassSetZero (&m);
dReal dpos[GPB][3]; // delta-positions for composite geometries
dMatrix3 drot[GPB];
// set random delta positions
for (j=0; j<GPB; j++)
for (k=0; k<3; k++)
dpos[j][k] = dRandReal()*0.3-0.15;
for (k=0; k<GPB; k++) {
if (k==0) {
dReal radius = dRandReal()*0.25+0.05;
obj[i].geom[k] = dCreateSphere (space,radius);
dMassSetSphere (&m2,DENSITY,radius);
} else if (k==1) {
obj[i].geom[k] = dCreateBox(space,sides[0],sides[1],sides[2]);
dMassSetBox(&m2,DENSITY,sides[0],sides[1],sides[2]);
} else {
dReal radius = dRandReal()*0.1+0.05;
dReal length = dRandReal()*1.0+0.1;
obj[i].geom[k] = dCreateCapsule(space,radius,length);
dMassSetCapsule(&m2,DENSITY,3,radius,length);
}
dRFromAxisAndAngle(drot[k],dRandReal()*2.0-1.0,dRandReal()*2.0-1.0,
dRandReal()*2.0-1.0,dRandReal()*10.0-5.0);
dMassRotate(&m2,drot[k]);
dMassTranslate(&m2,dpos[k][0],dpos[k][1],dpos[k][2]);
// add to the total mass
dMassAdd(&m,&m2);
}
for (k=0; k<GPB; k++) {
dGeomSetBody(obj[i].geom[k],obj[i].body);
dGeomSetOffsetPosition(obj[i].geom[k],
dpos[k][0]-m.c[0],
dpos[k][1]-m.c[1],
dpos[k][2]-m.c[2]);
dGeomSetOffsetRotation(obj[i].geom[k], drot[k]);
}
dMassTranslate(&m,-m.c[0],-m.c[1],-m.c[2]);
dBodySetMass(obj[i].body,&m);
} else if (cmd == 'v') {
dMassSetBox (&m,DENSITY,0.25,0.25,0.25);
obj[i].geom[0] = dCreateConvex(space,
planes,
planecount,
points,
pointcount,
polygons);
}
if (!setBody) { // avoid calling for composite geometries
for (k=0; k < GPB; k++)
if (obj[i].geom[k])
dGeomSetBody(obj[i].geom[k],obj[i].body);
dBodySetMass(obj[i].body,&m);
}
}
if (cmd == ' ') {
selected++;
if (selected >= num) selected = 0;
if (selected < 0) selected = 0;
}
else if (cmd == 'd' && selected >= 0 && selected < num) {
dBodyDisable (obj[selected].body);
}
else if (cmd == 'e' && selected >= 0 && selected < num) {
dBodyEnable (obj[selected].body);
}
else if (cmd == 'a') {
show_aabb ^= 1;
}
else if (cmd == 't') {
show_contacts ^= 1;
}
else if (cmd == 'r') {
random_pos ^= 1;
}
}
// draw a geom
void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb)
{
if (!g) return;
if (!pos) pos = dGeomGetPosition (g);
if (!R) R = dGeomGetRotation (g);
int type = dGeomGetClass (g);
if (type == dBoxClass) {
dVector3 sides;
dGeomBoxGetLengths (g,sides);
dsDrawBox (pos,R,sides);
}
else if (type == dSphereClass) {
dsDrawSphere (pos,R,dGeomSphereGetRadius (g));
}
else if (type == dCapsuleClass) {
dReal radius,length;
dGeomCapsuleGetParams (g,&radius,&length);
dsDrawCapsule (pos,R,length,radius);
} else if (type == dConvexClass) {
//dVector3 sides={0.50,0.50,0.50};
dsDrawConvex(pos,R,planes,
planecount,
points,
pointcount,
polygons);
}
/*
// cylinder option not yet implemented
else if (type == dCylinderClass) {
dReal radius,length;
dGeomCylinderGetParams (g,&radius,&length);
dsDrawCylinder (pos,R,length,radius);
}
*/
if (show_aabb) {
// draw the bounding box for this geom
dReal aabb[6];
dGeomGetAABB (g,aabb);
dVector3 bbpos;
for (int i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]);
dVector3 bbsides;
for (int j=0; j<3; j++) bbsides[j] = aabb[j*2+1] - aabb[j*2];
dMatrix3 RI;
dRSetIdentity (RI);
dsSetColorAlpha (1,0,0,0.5);
dsDrawBox (bbpos,RI,bbsides);
}
}
// simulation loop
static void simLoop (int pause)
{
dsSetColor (0,0,2);
dSpaceCollide (space,0,&nearCallback);
if (!pause) dWorldStep (world,0.05);
//if (!pause) dWorldStepFast (world,0.05, 1);
// remove all contact joints
dJointGroupEmpty (contactgroup);
dsSetColor (1,1,0);
dsSetTexture (DS_WOOD);
for (int i=0; i<num; i++) {
for (int j=0; j < GPB; j++) {
if (i==selected) {
dsSetColor (0,0.7,1);
}
else if (! dBodyIsEnabled (obj[i].body)) {
dsSetColor (1,0,0);
}
else {
dsSetColor (1,1,0);
}
drawGeom (obj[i].geom[j],0,0,show_aabb);
}
}
/*{
for (int i = 1; i < IndexCount; i++) {
dsDrawLine(Vertices[Indices[i - 1]], Vertices[Indices[i]]);
}
}*/
{const dReal* Pos = dGeomGetPosition(TriMesh);
const dReal* Rot = dGeomGetRotation(TriMesh);
{for (int i = 0; i < IndexCount / 3; i++){
const float *p = Vertices[Indices[i * 3 + 0]];
const dVector3 v0 = { p[0], p[1], p[2] };
p = Vertices[Indices[i * 3 + 1]];
const dVector3 v1 = { p[0], p[1], p[2] };
p = Vertices[Indices[i * 3 + 2]];
const dVector3 v2 = { p[0], p[1], p[2] };
dsDrawTriangle(Pos, Rot, v0, v1, v2, 0);
}}}
if (Ray){
dVector3 Origin, Direction;
dGeomRayGet(Ray, Origin, Direction);
dReal Length = dGeomRayGetLength(Ray);
dVector3 End;
End[0] = Origin[0] + (Direction[0] * Length);
End[1] = Origin[1] + (Direction[1] * Length);
End[2] = Origin[2] + (Direction[2] * Length);
End[3] = Origin[3] + (Direction[3] * Length);
dsDrawLine(Origin, End);
}
}
int main (int argc, char **argv)
{
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = &command;
fn.stop = 0;
fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;
// create world
dInitODE2(0);
world = dWorldCreate();
space = dSimpleSpaceCreate(0);
contactgroup = dJointGroupCreate (0);
dWorldSetGravity (world,0,0,-0.5);
dWorldSetCFM (world,1e-5);
//dCreatePlane (space,0,0,1,0);
memset (obj,0,sizeof(obj));
Size[0] = 5.0f;
Size[1] = 5.0f;
Size[2] = 2.5f;
Vertices[0][0] = -Size[0];
Vertices[0][1] = -Size[1];
Vertices[0][2] = Size[2];
Vertices[1][0] = Size[0];
Vertices[1][1] = -Size[1];
Vertices[1][2] = Size[2];
Vertices[2][0] = Size[0];
Vertices[2][1] = Size[1];
Vertices[2][2] = Size[2];
Vertices[3][0] = -Size[0];
Vertices[3][1] = Size[1];
Vertices[3][2] = Size[2];
Vertices[4][0] = 0;
Vertices[4][1] = 0;
Vertices[4][2] = 0;
Indices[0] = 0;
Indices[1] = 1;
Indices[2] = 4;
Indices[3] = 1;
Indices[4] = 2;
Indices[5] = 4;
Indices[6] = 2;
Indices[7] = 3;
Indices[8] = 4;
Indices[9] = 3;
Indices[10] = 0;
Indices[11] = 4;
dTriMeshDataID Data = dGeomTriMeshDataCreate();
//dGeomTriMeshDataBuildSimple(Data, (dReal*)Vertices, VertexCount, Indices, IndexCount);
dGeomTriMeshDataBuildSingle(Data, Vertices[0], 3 * sizeof(float), VertexCount, &Indices[0], IndexCount, 3 * sizeof(dTriIndex));
dGeomTriMeshDataPreprocess2(Data, (1U << dTRIDATAPREPROCESS_BUILD_FACE_ANGLES), NULL);
TriMesh = dCreateTriMesh(space, Data, 0, 0, 0);
//dGeomSetPosition(TriMesh, 0, 0, 1.0);
Ray = dCreateRay(space, 0.9);
dVector3 Origin, Direction;
Origin[0] = 0.0;
Origin[1] = 0;
Origin[2] = 0.5;
Origin[3] = 0;
Direction[0] = 0;
Direction[1] = 1.1f;
Direction[2] = -1;
Direction[3] = 0;
dNormalize3(Direction);
dGeomRaySet(Ray, Origin[0], Origin[1], Origin[2], Direction[0], Direction[1], Direction[2]);
dThreadingImplementationID threading = dThreadingAllocateMultiThreadedImplementation();
dThreadingThreadPoolID pool = dThreadingAllocateThreadPool(4, 0, dAllocateFlagBasicData, NULL);
dThreadingThreadPoolServeMultiThreadedImplementation(pool, threading);
// dWorldSetStepIslandsProcessingMaxThreadCount(world, 1);
dWorldSetStepThreadingImplementation(world, dThreadingImplementationGetFunctions(threading), threading);
// run simulation
dsSimulationLoop (argc,argv,352,288,&fn);
dThreadingImplementationShutdownProcessing(threading);
dThreadingFreeThreadPool(pool);
dWorldSetStepThreadingImplementation(world, NULL, NULL);
dThreadingFreeImplementation(threading);
dJointGroupDestroy (contactgroup);
dSpaceDestroy (space);
dWorldDestroy (world);
dCloseODE();
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,216 @@
//<---- Icosahedron ---->
/*
This is a description of a convex icosahedron, to test
the convex collision detection.
*/
unsigned int Sphere_pointcount = 42;
unsigned int Sphere_planecount = 80;
dReal Sphere_points[126]={
0.000000,0.000000,-0.300000,
0.217080,-0.157716,-0.134164,
-0.082915,-0.255192,-0.134164,
-0.268327,0.000000,-0.134164,
-0.082915,0.255192,-0.134164,
0.217080,0.157716,-0.134164,
0.082915,-0.255192,0.134164,
-0.217080,-0.157716,0.134164,
-0.217080,0.157716,0.134164,
0.082915,0.255192,0.134164,
0.268327,0.000000,0.134164,
0.000000,0.000000,0.300000,
0.127597,-0.092703,-0.255196,
-0.048737,-0.149999,-0.255196,
0.078861,-0.242703,-0.157721,
0.127597,0.092703,-0.255196,
0.255194,0.000000,-0.157721,
-0.157719,0.000000,-0.255195,
-0.206457,-0.149999,-0.157721,
-0.048737,0.149999,-0.255196,
-0.206457,0.149999,-0.157721,
0.078861,0.242703,-0.157721,
0.285317,0.092704,0.000000,
0.285317,-0.092704,0.000000,
0.176336,-0.242705,0.000000,
0.000000,-0.300000,0.000000,
-0.176336,-0.242705,0.000000,
-0.285317,-0.092704,0.000000,
-0.285317,0.092704,0.000000,
-0.176336,0.242705,0.000000,
0.000000,0.300000,0.000000,
0.176336,0.242705,0.000000,
0.206457,-0.149999,0.157721,
-0.078861,-0.242703,0.157721,
-0.255194,0.000000,0.157721,
-0.078861,0.242703,0.157721,
0.206457,0.149999,0.157721,
0.157719,0.000000,0.255195,
0.048737,-0.149999,0.255196,
-0.127597,-0.092703,0.255196,
-0.127597,0.092703,0.255196,
0.048737,0.149999,0.255196
};
unsigned int Sphere_polygons[]={
3,14,12,1,
3,12,14,13,
3,2,13,14,
3,13,0,12,
3,16,1,12,
3,12,15,16,
3,5,16,15,
3,12,0,15,
3,18,13,2,
3,13,18,17,
3,3,17,18,
3,17,0,13,
3,20,17,3,
3,17,20,19,
3,4,19,20,
3,19,0,17,
3,21,19,4,
3,19,21,15,
3,5,15,21,
3,15,0,19,
3,23,1,16,
3,16,22,23,
3,10,23,22,
3,22,16,5,
3,25,2,14,
3,14,24,25,
3,6,25,24,
3,24,14,1,
3,27,3,18,
3,18,26,27,
3,7,27,26,
3,26,18,2,
3,29,4,20,
3,20,28,29,
3,8,29,28,
3,28,20,3,
3,31,5,21,
3,21,30,31,
3,9,31,30,
3,30,21,4,
3,32,23,10,
3,23,32,24,
3,6,24,32,
3,24,1,23,
3,33,25,6,
3,25,33,26,
3,7,26,33,
3,26,2,25,
3,34,27,7,
3,27,34,28,
3,8,28,34,
3,28,3,27,
3,35,29,8,
3,29,35,30,
3,9,30,35,
3,30,4,29,
3,36,31,9,
3,31,36,22,
3,10,22,36,
3,22,5,31,
3,38,6,32,
3,32,37,38,
3,11,38,37,
3,37,32,10,
3,39,7,33,
3,33,38,39,
3,11,39,38,
3,38,33,6,
3,40,8,34,
3,34,39,40,
3,11,40,39,
3,39,34,7,
3,41,9,35,
3,35,40,41,
3,11,41,40,
3,40,35,8,
3,37,10,36,
3,36,41,37,
3,11,37,41,
3,41,36,9,
};
dReal Sphere_planes[]={
0.471317,-0.583121,-0.661687,0.283056,
0.187594,-0.577345,-0.794658,0.280252,
-0.038547,-0.748789,-0.661687,0.283056,
0.102381,-0.315090,-0.943523,0.283057,
0.700228,-0.268049,-0.661688,0.283056,
0.607060,0.000000,-0.794656,0.280252,
0.700228,0.268049,-0.661688,0.283056,
0.331305,0.000000,-0.943524,0.283057,
-0.408939,-0.628443,-0.661686,0.283056,
-0.491119,-0.356821,-0.794657,0.280252,
-0.724044,-0.194735,-0.661694,0.283057,
-0.268034,-0.194737,-0.943523,0.283057,
-0.724044,0.194735,-0.661694,0.283057,
-0.491119,0.356821,-0.794657,0.280252,
-0.408939,0.628443,-0.661686,0.283056,
-0.268034,0.194737,-0.943523,0.283057,
-0.038547,0.748789,-0.661687,0.283056,
0.187594,0.577345,-0.794658,0.280252,
0.471317,0.583121,-0.661687,0.283056,
0.102381,0.315090,-0.943523,0.283057,
0.904981,-0.268049,-0.330393,0.283056,
0.982246,0.000000,-0.187599,0.280252,
0.992077,0.000000,0.125631,0.283057,
0.904981,0.268049,-0.330393,0.283056,
0.024726,-0.943519,-0.330396,0.283056,
0.303531,-0.934171,-0.187598,0.280251,
0.306568,-0.943519,0.125651,0.283056,
0.534590,-0.777851,-0.330395,0.283056,
-0.889698,-0.315092,-0.330386,0.283056,
-0.794656,-0.577348,-0.187595,0.280251,
-0.802607,-0.583125,0.125648,0.283055,
-0.574584,-0.748793,-0.330397,0.283055,
-0.574584,0.748793,-0.330397,0.283055,
-0.794656,0.577348,-0.187595,0.280251,
-0.802607,0.583125,0.125648,0.283055,
-0.889698,0.315092,-0.330386,0.283056,
0.534590,0.777851,-0.330395,0.283056,
0.303531,0.934171,-0.187598,0.280251,
0.306568,0.943519,0.125651,0.283056,
0.024726,0.943519,-0.330396,0.283056,
0.889698,-0.315092,0.330386,0.283056,
0.794656,-0.577348,0.187595,0.280251,
0.574584,-0.748793,0.330397,0.283055,
0.802607,-0.583125,-0.125648,0.283055,
-0.024726,-0.943519,0.330396,0.283055,
-0.303531,-0.934171,0.187598,0.280251,
-0.534590,-0.777851,0.330395,0.283056,
-0.306568,-0.943519,-0.125651,0.283056,
-0.904981,-0.268049,0.330393,0.283056,
-0.982246,0.000000,0.187599,0.280252,
-0.904981,0.268049,0.330393,0.283056,
-0.992077,0.000000,-0.125631,0.283057,
-0.534590,0.777851,0.330395,0.283056,
-0.303531,0.934171,0.187598,0.280251,
-0.024726,0.943519,0.330396,0.283055,
-0.306568,0.943519,-0.125651,0.283056,
0.574584,0.748793,0.330397,0.283055,
0.794656,0.577348,0.187595,0.280251,
0.889698,0.315092,0.330386,0.283056,
0.802607,0.583125,-0.125648,0.283055,
0.408939,-0.628443,0.661686,0.283056,
0.491119,-0.356821,0.794657,0.280252,
0.268034,-0.194737,0.943523,0.283057,
0.724044,-0.194735,0.661694,0.283057,
-0.471317,-0.583121,0.661687,0.283056,
-0.187594,-0.577345,0.794658,0.280252,
-0.102381,-0.315090,0.943523,0.283057,
0.038547,-0.748789,0.661687,0.283056,
-0.700228,0.268049,0.661688,0.283056,
-0.607060,0.000000,0.794656,0.280252,
-0.331305,0.000000,0.943524,0.283057,
-0.700228,-0.268049,0.661688,0.283056,
0.038547,0.748789,0.661687,0.283056,
-0.187594,0.577345,0.794658,0.280252,
-0.102381,0.315090,0.943523,0.283057,
-0.471317,0.583121,0.661687,0.283056,
0.724044,0.194735,0.661694,0.283057,
0.491119,0.356821,0.794657,0.280252,
0.268034,0.194737,0.943523,0.283057,
0.408939,0.628443,0.661686,0.283056,
};

View File

@@ -0,0 +1,26 @@
/*************************************************************************
* *
* Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
* All rights reserved. Email: russ@q12.org Web: www.q12.org *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of EITHER: *
* (1) The GNU Lesser General Public License as published by the Free *
* Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. The text of the GNU Lesser *
* General Public License is included with this library in the *
* file LICENSE.TXT. *
* (2) The BSD-style license that is included with this library in *
* the file LICENSE-BSD.TXT. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
* LICENSE.TXT and LICENSE-BSD.TXT for more details. *
* *
*************************************************************************/
#ifndef DRAWSTUFF_TEXTURE_PATH
#define DRAWSTUFF_TEXTURE_PATH "../../drawstuff/textures"
#endif

File diff suppressed because one or more lines are too long