Mercurial > cortex
comparison org/touch.org @ 233:f27c9fd9134d
seperated out image generating code from touch-kernel
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 12 Feb 2012 06:21:30 -0700 |
parents | b7762699eeb5 |
children | 712bd7e5b148 |
comparison
equal
deleted
inserted
replaced
232:b7762699eeb5 | 233:f27c9fd9134d |
---|---|
58 "Return the touch-sensor distribution image in BufferedImage format, | 58 "Return the touch-sensor distribution image in BufferedImage format, |
59 or nil if it does not exist." | 59 or nil if it does not exist." |
60 [#^Geometry obj] | 60 [#^Geometry obj] |
61 (if-let [image-path (meta-data obj "touch")] | 61 (if-let [image-path (meta-data obj "touch")] |
62 (load-image image-path))) | 62 (load-image image-path))) |
63 #+end_src | 63 |
64 | 64 (defn tactile-scale |
65 "Return the maximum length of a hair. All hairs are scalled between | |
66 0.0 and this length, depending on their color. Black is 0, and | |
67 white is maximum length, and everything in between is scalled | |
68 linearlly. Default scale is 0.01 jMonkeyEngine units." | |
69 [#^Geometry obj] | |
70 (if-let [scale (meta-data obj "scale")] | |
71 scale 0.1)) | |
72 #+end_src | |
65 | 73 |
66 ** TODO add image showing example touch-uv map | 74 ** TODO add image showing example touch-uv map |
67 ** TODO add metadata display for worm | 75 ** TODO add metadata display for worm |
68 | 76 |
69 * Triangle Manipulation Functions | |
70 | |
71 The rigid bodies which make up a creature have an underlying | |
72 =Geometry=, which is a =Mesh= plus a =Material= and other important | |
73 data involved with displaying the body. | |
74 | |
75 A =Mesh= is composed of =Triangles=, and each =Triangle= has three | |
76 verticies which have coordinates in XYZ space and UV space. | |
77 | |
78 Here, =(triangles)= gets all the triangles which compose a mesh, and | |
79 =(triangle-UV-coord)= returns the the UV coordinates of the verticies | |
80 of a triangle. | |
81 | |
82 #+name: triangles-1 | |
83 #+begin_src clojure | |
84 (defn triangles | |
85 "Return a sequence of all the Triangles which compose a given | |
86 Geometry." | |
87 [#^Geometry geom] | |
88 (let | |
89 [mesh (.getMesh geom) | |
90 triangles (transient [])] | |
91 (dorun | |
92 (for [n (range (.getTriangleCount mesh))] | |
93 (let [tri (Triangle.)] | |
94 (.getTriangle mesh n tri) | |
95 ;; (.calculateNormal tri) | |
96 ;; (.calculateCenter tri) | |
97 (conj! triangles tri)))) | |
98 (persistent! triangles))) | |
99 | |
100 (defn mesh-triangle | |
101 "Get the triangle specified by triangle-index from the mesh within | |
102 bounds." | |
103 [#^Mesh mesh triangle-index] | |
104 (let [scratch (Triangle.)] | |
105 (.getTriangle mesh triangle-index scratch) | |
106 scratch)) | |
107 | |
108 (defn triangle-vertex-indices | |
109 "Get the triangle vertex indices of a given triangle from a given | |
110 mesh." | |
111 [#^Mesh mesh triangle-index] | |
112 (let [indices (int-array 3)] | |
113 (.getTriangle mesh triangle-index indices) | |
114 (vec indices))) | |
115 | |
116 (defn vertex-UV-coord | |
117 "Get the UV-coordinates of the vertex named by vertex-index" | |
118 [#^Mesh mesh vertex-index] | |
119 (let [UV-buffer | |
120 (.getData | |
121 (.getBuffer | |
122 mesh | |
123 VertexBuffer$Type/TexCoord))] | |
124 [(.get UV-buffer (* vertex-index 2)) | |
125 (.get UV-buffer (+ 1 (* vertex-index 2)))])) | |
126 | |
127 (defn triangle-UV-coord | |
128 "Get the UV-cooridnates of the triangle's verticies." | |
129 [#^Mesh mesh width height triangle-index] | |
130 (map (fn [[u v]] (vector (* width u) (* height v))) | |
131 (map (partial vertex-UV-coord mesh) | |
132 (triangle-vertex-indices mesh triangle-index)))) | |
133 #+end_src | |
134 | |
135 * Schrapnel Conversion Functions | |
136 | |
137 It is convienent to treat a =Triangle= as a sequence of verticies, and | |
138 a =Vector2f= and =Vector3f= as a sequence of floats. These conversion | |
139 functions make this easy. If these classes implemented =Iterable= then | |
140 this code would not be necessary. Hopefully they will in the future. | |
141 | |
142 #+name: triangles-2 | |
143 #+begin_src clojure | |
144 (defn triangle-seq [#^Triangle tri] | |
145 [(.get1 tri) (.get2 tri) (.get3 tri)]) | |
146 | |
147 (defn vector3f-seq [#^Vector3f v] | |
148 [(.getX v) (.getY v) (.getZ v)]) | |
149 | |
150 (defn point->vector2f [[u v]] | |
151 (Vector2f. u v)) | |
152 | |
153 (defn vector2f->vector3f [v] | |
154 (Vector3f. (.getX v) (.getY v) 0)) | |
155 | |
156 (defn map-triangle [f #^Triangle tri] | |
157 (Triangle. | |
158 (f 0 (.get1 tri)) | |
159 (f 1 (.get2 tri)) | |
160 (f 2 (.get3 tri)))) | |
161 | |
162 (defn points->triangle | |
163 "Convert a list of points into a triangle." | |
164 [points] | |
165 (apply #(Triangle. %1 %2 %3) | |
166 (map (fn [point] | |
167 (let [point (vec point)] | |
168 (Vector3f. (get point 0 0) | |
169 (get point 1 0) | |
170 (get point 2 0)))) | |
171 (take 3 points)))) | |
172 #+end_src | |
173 | |
174 * Triangle Affine Transforms | |
175 | |
176 The position of each hair is stored in a 2D image in UV | |
177 coordinates. To place the hair in 3D space we must convert from UV | |
178 coordinates to XYZ coordinates. Each =Triangle= has coordinates in | |
179 both UV-space and XYZ-space, which defines a unique [[http://mathworld.wolfram.com/AffineTransformation.html ][Affine Transform]] | |
180 for translating any coordinate within the UV triangle to the | |
181 cooresponding coordinate in the XYZ triangle. | |
182 | |
183 #+name: triangles-3 | |
184 #+begin_src clojure | |
185 (defn triangle->matrix4f | |
186 "Converts the triangle into a 4x4 matrix: The first three columns | |
187 contain the vertices of the triangle; the last contains the unit | |
188 normal of the triangle. The bottom row is filled with 1s." | |
189 [#^Triangle t] | |
190 (let [mat (Matrix4f.) | |
191 [vert-1 vert-2 vert-3] | |
192 ((comp vec map) #(.get t %) (range 3)) | |
193 unit-normal (do (.calculateNormal t)(.getNormal t)) | |
194 vertices [vert-1 vert-2 vert-3 unit-normal]] | |
195 (dorun | |
196 (for [row (range 4) col (range 3)] | |
197 (do | |
198 (.set mat col row (.get (vertices row)col)) | |
199 (.set mat 3 row 1)))) | |
200 mat)) | |
201 | |
202 (defn triangle-transformation | |
203 "Returns the affine transformation that converts each vertex in the | |
204 first triangle into the corresponding vertex in the second | |
205 triangle." | |
206 [#^Triangle tri-1 #^Triangle tri-2] | |
207 (.mult | |
208 (triangle->matrix4f tri-2) | |
209 (.invert (triangle->matrix4f tri-1)))) | |
210 #+end_src | |
211 | |
212 * Triangle Boundaries | |
213 | |
214 For efficiency's sake I will divide the UV-image into small squares | |
215 which inscribe each UV-triangle, then extract the points which lie | |
216 inside the triangle and map them to 3D-space using | |
217 =(triangle-transform)= above. To do this I need a function, | |
218 =(inside-triangle?)=, which determines whether a point is inside a | |
219 triangle in 2D UV-space. | |
220 | |
221 #+name: triangles-4 | |
222 #+begin_src clojure | |
223 (defn convex-bounds | |
224 "Returns the smallest square containing the given vertices, as a | |
225 vector of integers [left top width height]." | |
226 [uv-verts] | |
227 (let [xs (map first uv-verts) | |
228 ys (map second uv-verts) | |
229 x0 (Math/floor (apply min xs)) | |
230 y0 (Math/floor (apply min ys)) | |
231 x1 (Math/ceil (apply max xs)) | |
232 y1 (Math/ceil (apply max ys))] | |
233 [x0 y0 (- x1 x0) (- y1 y0)])) | |
234 | |
235 (defn same-side? | |
236 "Given the points p1 and p2 and the reference point ref, is point p | |
237 on the same side of the line that goes through p1 and p2 as ref is?" | |
238 [p1 p2 ref p] | |
239 (<= | |
240 0 | |
241 (.dot | |
242 (.cross (.subtract p2 p1) (.subtract p p1)) | |
243 (.cross (.subtract p2 p1) (.subtract ref p1))))) | |
244 | |
245 (defn inside-triangle? | |
246 "Is the point inside the triangle?" | |
247 {:author "Dylan Holmes"} | |
248 [#^Triangle tri #^Vector3f p] | |
249 (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] | |
250 (and | |
251 (same-side? vert-1 vert-2 vert-3 p) | |
252 (same-side? vert-2 vert-3 vert-1 p) | |
253 (same-side? vert-3 vert-1 vert-2 p)))) | |
254 #+end_src | |
255 | |
256 | |
257 | |
258 * Sensor Related Functions | |
259 | |
260 These functions analyze the touch-sensor-profile image convert the | |
261 location of each touch sensor from pixel coordinates to UV-coordinates | |
262 and XYZ-coordinates. | |
263 | |
264 #+name: sensors | |
265 #+begin_src clojure | |
266 (defn sensors-in-triangle | |
267 "Locate the touch sensors in the triangle, returning a map of their | |
268 UV and geometry-relative coordinates." | |
269 [image mesh tri-index] | |
270 (let [width (.getWidth image) | |
271 height (.getHeight image) | |
272 UV-vertex-coords (triangle-UV-coord mesh width height tri-index) | |
273 bounds (convex-bounds UV-vertex-coords) | |
274 | |
275 cutout-triangle (points->triangle UV-vertex-coords) | |
276 UV-sensor-coords | |
277 (filter (comp (partial inside-triangle? cutout-triangle) | |
278 (fn [[u v]] (Vector3f. u v 0))) | |
279 (white-coordinates image bounds)) | |
280 UV->geometry (triangle-transformation | |
281 cutout-triangle | |
282 (mesh-triangle mesh tri-index)) | |
283 geometry-sensor-coords | |
284 (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0))) | |
285 UV-sensor-coords)] | |
286 {:UV UV-sensor-coords :geometry geometry-sensor-coords})) | |
287 | |
288 (defn-memo locate-feelers | |
289 "Search the geometry's tactile UV profile for touch sensors, | |
290 returning their positions in geometry-relative coordinates." | |
291 [#^Geometry geo] | |
292 (let [mesh (.getMesh geo) | |
293 num-triangles (.getTriangleCount mesh)] | |
294 (if-let [image (tactile-sensor-profile geo)] | |
295 (map | |
296 (partial sensors-in-triangle image mesh) | |
297 (range num-triangles)) | |
298 (repeat (.getTriangleCount mesh) {:UV nil :geometry nil})))) | |
299 | |
300 (defn-memo touch-topology | |
301 "Return a sequence of vectors of the form [x y] describing the | |
302 \"topology\" of the tactile sensors. Points that are close together | |
303 in the touch-topology are generally close together in the simulation." | |
304 [#^Gemoetry geo] | |
305 (vec (collapse (reduce concat (map :UV (locate-feelers geo)))))) | |
306 | |
307 (defn-memo feeler-coordinates | |
308 "The location of the touch sensors in world-space coordinates." | |
309 [#^Geometry geo] | |
310 (vec (map :geometry (locate-feelers geo)))) | |
311 #+end_src | |
312 | |
313 * Physics Collision Objects | |
314 | |
315 The "hairs" are actually rays which extend from a point on a | |
316 =Triangle= in the =Mesh= normal to the =Triangle's= surface. | |
317 | |
318 #+name: rays | |
319 #+begin_src clojure | |
320 (defn get-ray-origin | |
321 "Return the origin which a Ray would have to have to be in the exact | |
322 center of a particular Triangle in the Geometry in World | |
323 Coordinates." | |
324 [geom tri] | |
325 (let [new (Vector3f.)] | |
326 (.calculateCenter tri) | |
327 (.localToWorld geom (.getCenter tri) new) new)) | |
328 | |
329 (defn get-ray-direction | |
330 "Return the direction which a Ray would have to have to be to point | |
331 normal to the Triangle, in coordinates relative to the center of the | |
332 Triangle." | |
333 [geom tri] | |
334 (let [n+c (Vector3f.)] | |
335 (.calculateNormal tri) | |
336 (.calculateCenter tri) | |
337 (.localToWorld | |
338 geom | |
339 (.add (.getCenter tri) (.getNormal tri)) n+c) | |
340 (.subtract n+c (get-ray-origin geom tri)))) | |
341 #+end_src | |
342 | |
343 | |
344 * Skin Creation | 77 * Skin Creation |
345 #+name: kernel | 78 #+name: kernel |
346 #+begin_src clojure | 79 #+begin_src clojure |
347 (defn touch-fn | 80 (in-ns 'cortex.touch) |
81 | |
82 (defn touch-kernel | |
348 "Returns a function which returns tactile sensory data when called | 83 "Returns a function which returns tactile sensory data when called |
349 inside a running simulation." | 84 inside a running simulation." |
350 [#^Geometry geo] | 85 [#^Geometry geo] |
351 (let [feeler-coords (feeler-coordinates geo) | 86 (let [feeler-coords (feeler-coordinates geo) |
352 tris (triangles geo) | 87 tris (triangles geo) |
353 limit 0.1 | 88 limit (tactile-scale geo)] |
354 ;;results (CollisionResults.) | |
355 ] | |
356 (if (empty? (touch-topology geo)) | 89 (if (empty? (touch-topology geo)) |
357 nil | 90 nil |
358 (fn [node] | 91 (fn [node] |
359 (let [sensor-origins | 92 (let [sensor-origins |
360 (map | 93 (map |
377 (let [results (CollisionResults.)] | 110 (let [results (CollisionResults.)] |
378 (.collideWith node ray results) | 111 (.collideWith node ray results) |
379 (let [touch-objects | 112 (let [touch-objects |
380 (filter #(not (= geo (.getGeometry %))) | 113 (filter #(not (= geo (.getGeometry %))) |
381 results)] | 114 results)] |
382 (- 255 | 115 [(if (empty? touch-objects) |
383 (if (empty? touch-objects) 255 | 116 limit (.getDistance (first touch-objects))) |
384 (rem | 117 limit]))))))))))) |
385 (int | 118 |
386 (* 255 (/ (.getDistance | |
387 (first touch-objects)) limit))) | |
388 256)))))))))))))) | |
389 | |
390 (defn touch! | 119 (defn touch! |
391 "Endow the creature with the sense of touch. Returns a sequence of | 120 "Endow the creature with the sense of touch. Returns a sequence of |
392 functions, one for each body part with a tactile-sensor-proile, | 121 functions, one for each body part with a tactile-sensor-proile, |
393 each of which when called returns sensory data for that body part." | 122 each of which when called returns sensory data for that body part." |
394 [#^Node creature] | 123 [#^Node creature] |
395 (filter | 124 (filter |
396 (comp not nil?) | 125 (comp not nil?) |
397 (map touch-fn | 126 (map touch-kernel |
398 (filter #(isa? (class %) Geometry) | 127 (filter #(isa? (class %) Geometry) |
399 (node-seq creature))))) | 128 (node-seq creature))))) |
400 #+end_src | 129 #+end_src |
401 | 130 |
402 * Visualizing Touch | 131 * Visualizing Touch |
403 #+name: visualization | 132 #+name: visualization |
404 #+begin_src clojure | 133 #+begin_src clojure |
134 (in-ns 'cortex.touch) | |
135 | |
136 (defn touch->gray | |
137 "Convert a pair of [distance, max-distance] into a grayscale pixel" | |
138 [distance max-distance] | |
139 (gray | |
140 (- 255 | |
141 (rem | |
142 (int | |
143 (* 255 (/ distance max-distance))) | |
144 256)))) | |
145 | |
405 (defn view-touch | 146 (defn view-touch |
406 "Creates a function which accepts a list of touch sensor-data and | 147 "Creates a function which accepts a list of touch sensor-data and |
407 displays each element to the screen." | 148 displays each element to the screen." |
408 [] | 149 [] |
409 (view-sense | 150 (view-sense |
411 [[coords sensor-data]] | 152 [[coords sensor-data]] |
412 (let [image (points->image coords)] | 153 (let [image (points->image coords)] |
413 (dorun | 154 (dorun |
414 (for [i (range (count coords))] | 155 (for [i (range (count coords))] |
415 (.setRGB image ((coords i) 0) ((coords i) 1) | 156 (.setRGB image ((coords i) 0) ((coords i) 1) |
416 (gray (sensor-data i))))) | 157 (apply touch->gray (sensor-data i))))) |
417 image)))) | 158 image)))) |
418 #+end_src | 159 #+end_src |
160 | |
161 | |
162 | |
163 * Triangle Manipulation Functions | |
164 | |
165 The rigid bodies which make up a creature have an underlying | |
166 =Geometry=, which is a =Mesh= plus a =Material= and other important | |
167 data involved with displaying the body. | |
168 | |
169 A =Mesh= is composed of =Triangles=, and each =Triangle= has three | |
170 verticies which have coordinates in XYZ space and UV space. | |
171 | |
172 Here, =(triangles)= gets all the triangles which compose a mesh, and | |
173 =(triangle-UV-coord)= returns the the UV coordinates of the verticies | |
174 of a triangle. | |
175 | |
176 #+name: triangles-1 | |
177 #+begin_src clojure | |
178 (defn triangles | |
179 "Return a sequence of all the Triangles which compose a given | |
180 Geometry." | |
181 [#^Geometry geom] | |
182 (let | |
183 [mesh (.getMesh geom) | |
184 triangles (transient [])] | |
185 (dorun | |
186 (for [n (range (.getTriangleCount mesh))] | |
187 (let [tri (Triangle.)] | |
188 (.getTriangle mesh n tri) | |
189 ;; (.calculateNormal tri) | |
190 ;; (.calculateCenter tri) | |
191 (conj! triangles tri)))) | |
192 (persistent! triangles))) | |
193 | |
194 (defn mesh-triangle | |
195 "Get the triangle specified by triangle-index from the mesh within | |
196 bounds." | |
197 [#^Mesh mesh triangle-index] | |
198 (let [scratch (Triangle.)] | |
199 (.getTriangle mesh triangle-index scratch) | |
200 scratch)) | |
201 | |
202 (defn triangle-vertex-indices | |
203 "Get the triangle vertex indices of a given triangle from a given | |
204 mesh." | |
205 [#^Mesh mesh triangle-index] | |
206 (let [indices (int-array 3)] | |
207 (.getTriangle mesh triangle-index indices) | |
208 (vec indices))) | |
209 | |
210 (defn vertex-UV-coord | |
211 "Get the UV-coordinates of the vertex named by vertex-index" | |
212 [#^Mesh mesh vertex-index] | |
213 (let [UV-buffer | |
214 (.getData | |
215 (.getBuffer | |
216 mesh | |
217 VertexBuffer$Type/TexCoord))] | |
218 [(.get UV-buffer (* vertex-index 2)) | |
219 (.get UV-buffer (+ 1 (* vertex-index 2)))])) | |
220 | |
221 (defn triangle-UV-coord | |
222 "Get the UV-cooridnates of the triangle's verticies." | |
223 [#^Mesh mesh width height triangle-index] | |
224 (map (fn [[u v]] (vector (* width u) (* height v))) | |
225 (map (partial vertex-UV-coord mesh) | |
226 (triangle-vertex-indices mesh triangle-index)))) | |
227 #+end_src | |
228 | |
229 * Schrapnel Conversion Functions | |
230 | |
231 It is convienent to treat a =Triangle= as a sequence of verticies, and | |
232 a =Vector2f= and =Vector3f= as a sequence of floats. These conversion | |
233 functions make this easy. If these classes implemented =Iterable= then | |
234 this code would not be necessary. Hopefully they will in the future. | |
235 | |
236 #+name: triangles-2 | |
237 #+begin_src clojure | |
238 (defn triangle-seq [#^Triangle tri] | |
239 [(.get1 tri) (.get2 tri) (.get3 tri)]) | |
240 | |
241 (defn vector3f-seq [#^Vector3f v] | |
242 [(.getX v) (.getY v) (.getZ v)]) | |
243 | |
244 (defn point->vector2f [[u v]] | |
245 (Vector2f. u v)) | |
246 | |
247 (defn vector2f->vector3f [v] | |
248 (Vector3f. (.getX v) (.getY v) 0)) | |
249 | |
250 (defn map-triangle [f #^Triangle tri] | |
251 (Triangle. | |
252 (f 0 (.get1 tri)) | |
253 (f 1 (.get2 tri)) | |
254 (f 2 (.get3 tri)))) | |
255 | |
256 (defn points->triangle | |
257 "Convert a list of points into a triangle." | |
258 [points] | |
259 (apply #(Triangle. %1 %2 %3) | |
260 (map (fn [point] | |
261 (let [point (vec point)] | |
262 (Vector3f. (get point 0 0) | |
263 (get point 1 0) | |
264 (get point 2 0)))) | |
265 (take 3 points)))) | |
266 #+end_src | |
267 | |
268 * Triangle Affine Transforms | |
269 | |
270 The position of each hair is stored in a 2D image in UV | |
271 coordinates. To place the hair in 3D space we must convert from UV | |
272 coordinates to XYZ coordinates. Each =Triangle= has coordinates in | |
273 both UV-space and XYZ-space, which defines a unique [[http://mathworld.wolfram.com/AffineTransformation.html ][Affine Transform]] | |
274 for translating any coordinate within the UV triangle to the | |
275 cooresponding coordinate in the XYZ triangle. | |
276 | |
277 #+name: triangles-3 | |
278 #+begin_src clojure | |
279 (defn triangle->matrix4f | |
280 "Converts the triangle into a 4x4 matrix: The first three columns | |
281 contain the vertices of the triangle; the last contains the unit | |
282 normal of the triangle. The bottom row is filled with 1s." | |
283 [#^Triangle t] | |
284 (let [mat (Matrix4f.) | |
285 [vert-1 vert-2 vert-3] | |
286 ((comp vec map) #(.get t %) (range 3)) | |
287 unit-normal (do (.calculateNormal t)(.getNormal t)) | |
288 vertices [vert-1 vert-2 vert-3 unit-normal]] | |
289 (dorun | |
290 (for [row (range 4) col (range 3)] | |
291 (do | |
292 (.set mat col row (.get (vertices row)col)) | |
293 (.set mat 3 row 1)))) | |
294 mat)) | |
295 | |
296 (defn triangle-transformation | |
297 "Returns the affine transformation that converts each vertex in the | |
298 first triangle into the corresponding vertex in the second | |
299 triangle." | |
300 [#^Triangle tri-1 #^Triangle tri-2] | |
301 (.mult | |
302 (triangle->matrix4f tri-2) | |
303 (.invert (triangle->matrix4f tri-1)))) | |
304 #+end_src | |
305 | |
306 * Triangle Boundaries | |
307 | |
308 For efficiency's sake I will divide the UV-image into small squares | |
309 which inscribe each UV-triangle, then extract the points which lie | |
310 inside the triangle and map them to 3D-space using | |
311 =(triangle-transform)= above. To do this I need a function, | |
312 =(inside-triangle?)=, which determines whether a point is inside a | |
313 triangle in 2D UV-space. | |
314 | |
315 #+name: triangles-4 | |
316 #+begin_src clojure | |
317 (defn convex-bounds | |
318 "Returns the smallest square containing the given vertices, as a | |
319 vector of integers [left top width height]." | |
320 [uv-verts] | |
321 (let [xs (map first uv-verts) | |
322 ys (map second uv-verts) | |
323 x0 (Math/floor (apply min xs)) | |
324 y0 (Math/floor (apply min ys)) | |
325 x1 (Math/ceil (apply max xs)) | |
326 y1 (Math/ceil (apply max ys))] | |
327 [x0 y0 (- x1 x0) (- y1 y0)])) | |
328 | |
329 (defn same-side? | |
330 "Given the points p1 and p2 and the reference point ref, is point p | |
331 on the same side of the line that goes through p1 and p2 as ref is?" | |
332 [p1 p2 ref p] | |
333 (<= | |
334 0 | |
335 (.dot | |
336 (.cross (.subtract p2 p1) (.subtract p p1)) | |
337 (.cross (.subtract p2 p1) (.subtract ref p1))))) | |
338 | |
339 (defn inside-triangle? | |
340 "Is the point inside the triangle?" | |
341 {:author "Dylan Holmes"} | |
342 [#^Triangle tri #^Vector3f p] | |
343 (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] | |
344 (and | |
345 (same-side? vert-1 vert-2 vert-3 p) | |
346 (same-side? vert-2 vert-3 vert-1 p) | |
347 (same-side? vert-3 vert-1 vert-2 p)))) | |
348 #+end_src | |
349 | |
350 | |
351 | |
352 * Sensor Related Functions | |
353 | |
354 These functions analyze the touch-sensor-profile image convert the | |
355 location of each touch sensor from pixel coordinates to UV-coordinates | |
356 and XYZ-coordinates. | |
357 | |
358 #+name: sensors | |
359 #+begin_src clojure | |
360 (defn sensors-in-triangle | |
361 "Locate the touch sensors in the triangle, returning a map of their | |
362 UV and geometry-relative coordinates." | |
363 [image mesh tri-index] | |
364 (let [width (.getWidth image) | |
365 height (.getHeight image) | |
366 UV-vertex-coords (triangle-UV-coord mesh width height tri-index) | |
367 bounds (convex-bounds UV-vertex-coords) | |
368 | |
369 cutout-triangle (points->triangle UV-vertex-coords) | |
370 UV-sensor-coords | |
371 (filter (comp (partial inside-triangle? cutout-triangle) | |
372 (fn [[u v]] (Vector3f. u v 0))) | |
373 (white-coordinates image bounds)) | |
374 UV->geometry (triangle-transformation | |
375 cutout-triangle | |
376 (mesh-triangle mesh tri-index)) | |
377 geometry-sensor-coords | |
378 (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0))) | |
379 UV-sensor-coords)] | |
380 {:UV UV-sensor-coords :geometry geometry-sensor-coords})) | |
381 | |
382 (defn-memo locate-feelers | |
383 "Search the geometry's tactile UV profile for touch sensors, | |
384 returning their positions in geometry-relative coordinates." | |
385 [#^Geometry geo] | |
386 (let [mesh (.getMesh geo) | |
387 num-triangles (.getTriangleCount mesh)] | |
388 (if-let [image (tactile-sensor-profile geo)] | |
389 (map | |
390 (partial sensors-in-triangle image mesh) | |
391 (range num-triangles)) | |
392 (repeat (.getTriangleCount mesh) {:UV nil :geometry nil})))) | |
393 | |
394 (defn-memo touch-topology | |
395 "Return a sequence of vectors of the form [x y] describing the | |
396 \"topology\" of the tactile sensors. Points that are close together | |
397 in the touch-topology are generally close together in the simulation." | |
398 [#^Gemoetry geo] | |
399 (vec (collapse (reduce concat (map :UV (locate-feelers geo)))))) | |
400 | |
401 (defn-memo feeler-coordinates | |
402 "The location of the touch sensors in world-space coordinates." | |
403 [#^Geometry geo] | |
404 (vec (map :geometry (locate-feelers geo)))) | |
405 #+end_src | |
406 | |
407 * Physics Collision Objects | |
408 | |
409 The "hairs" are actually rays which extend from a point on a | |
410 =Triangle= in the =Mesh= normal to the =Triangle's= surface. | |
411 | |
412 #+name: rays | |
413 #+begin_src clojure | |
414 (defn get-ray-origin | |
415 "Return the origin which a Ray would have to have to be in the exact | |
416 center of a particular Triangle in the Geometry in World | |
417 Coordinates." | |
418 [geom tri] | |
419 (let [new (Vector3f.)] | |
420 (.calculateCenter tri) | |
421 (.localToWorld geom (.getCenter tri) new) new)) | |
422 | |
423 (defn get-ray-direction | |
424 "Return the direction which a Ray would have to have to be to point | |
425 normal to the Triangle, in coordinates relative to the center of the | |
426 Triangle." | |
427 [geom tri] | |
428 (let [n+c (Vector3f.)] | |
429 (.calculateNormal tri) | |
430 (.calculateCenter tri) | |
431 (.localToWorld | |
432 geom | |
433 (.add (.getCenter tri) (.getNormal tri)) n+c) | |
434 (.subtract n+c (get-ray-origin geom tri)))) | |
435 #+end_src | |
436 | |
437 | |
419 | 438 |
420 * Headers | 439 * Headers |
421 | 440 |
422 #+name: touch-header | 441 #+name: touch-header |
423 #+begin_src clojure | 442 #+begin_src clojure |
456 (fn [world] | 475 (fn [world] |
457 (light-up-everything world)) | 476 (light-up-everything world)) |
458 | 477 |
459 (fn [world tpf] | 478 (fn [world tpf] |
460 (touch-display (map #(% (.getRootNode world)) touch)))))) | 479 (touch-display (map #(% (.getRootNode world)) touch)))))) |
461 | |
462 #+end_src | 480 #+end_src |
463 | 481 |
464 * Source Listing | 482 * Source Listing |
465 * Next | 483 * Next |
466 | 484 |