# HG changeset patch # User Robert McIntyre # Date 1328274934 25200 # Node ID e8df6e76c3e5f02c6c3922ce2a146e4118026d58 # Parent 95bf556142116917946f069b48b321eb341bb985 refactored touch diff -r 95bf55614211 -r e8df6e76c3e5 org/sense-util.org --- a/org/sense-util.org Fri Feb 03 06:04:30 2012 -0700 +++ b/org/sense-util.org Fri Feb 03 06:15:34 2012 -0700 @@ -161,6 +161,19 @@ squeezed))] relocate))) +(defn world-to-local + "Convert the world coordinates into coordinates relative to the + object (i.e. local coordinates), taking into account the rotation + of object." + [#^Spatial object world-coordinate] + (.worldToLocal object world-coordinate nil)) + +(defn local-to-world + "Convert the local coordinates into coordinates into world relative + coordinates" + [#^Spatial object local-coordinate] + (.localToWorld object local-coordinate nil)) + #+end_src #+results: sense-util diff -r 95bf55614211 -r e8df6e76c3e5 org/skin.org --- a/org/skin.org Fri Feb 03 06:04:30 2012 -0700 +++ b/org/skin.org Fri Feb 03 06:15:34 2012 -0700 @@ -25,11 +25,15 @@ density of triangles along the surface of the Geometry. Enables a Geometry to know what parts of itself are touching nearby objects." {:author "Robert McIntyre"} - (:use (cortex world util)) + (:use (cortex world util sense)) (:import com.jme3.scene.Geometry) (:import com.jme3.collision.CollisionResults) + (:import jme3tools.converters.ImageToAwt) (:import (com.jme3.math Triangle Vector3f Ray))) +(use 'clojure.contrib.def) +(cortex.import/mega-import-jme3) + (defn triangles "Return a sequence of all the Triangles which compose a given Geometry." @@ -56,8 +60,7 @@ (.localToWorld geom (.getCenter tri) new) new)) (defn get-ray-direction - "Return the direction which a Ray would have to have to be in the - exact center of a particular Triangle in the Geometry, pointing + "Return the direction which a Ray would have to have to be to point normal to the Triangle, in coordinates relative to the center of the Triangle." [geom tri] @@ -69,37 +72,239 @@ (.add (.getCenter tri) (.getNormal tri)) n+c) (.subtract n+c (get-ray-origin geom tri)))) -(defn normal-rays - "For each Triangle which comprises the Geometry, returns a Ray which - is centered on that Triangle, points outward in a normal direction, - and extends for =limit= distance." - [limit #^Geometry geom] - (vec - (map - (fn [tri] - (doto - (Ray. (get-ray-origin geom tri) - (get-ray-direction geom tri)) - (.setLimit limit))) - (triangles geom)))) +;; Every Mesh has many triangles, each with its own index. +;; Every vertex has its own index as well. -(defn touch-percieve - "Augment a Geometry with the sense of touch. Returns a sequence of - non-negative integers, one for each triangle, with the value of the - integer describing how many objects a ray of length =limit=, normal - to the triangle and originating from its center, encountered. The - Geometry itself is not counted among the results." - [limit geom node] - (let [normals (normal-rays limit geom)] - (doall - (for [ray normals] +(defn tactile-sensor-image + "Return the touch-sensor distribution image in BufferedImage format, + or nil if it does not exist." + [#^Geometry obj] + (if-let [image-path (meta-data obj "touch")] + (ImageToAwt/convert + (.getImage + (.loadTexture + (asset-manager) + image-path)) + false false 0))) + + + +(defn triangle + "Get the triangle specified by triangle-index from the mesh within + bounds." + [#^Mesh mesh triangle-index] + (let [scratch (Triangle.)] + (.getTriangle mesh triangle-index scratch) + scratch)) + +(defn triangle-vertex-indices + "Get the triangle vertex indices of a given triangle from a given + mesh." + [#^Mesh mesh triangle-index] + (let [indices (int-array 3)] + (.getTriangle mesh triangle-index indices) + (vec indices))) + +(defn vertex-UV-coord + "Get the uv-coordinates of the vertex named by vertex-index" + [#^Mesh mesh vertex-index] + (let [UV-buffer + (.getData + (.getBuffer + mesh + VertexBuffer$Type/TexCoord))] + [(.get UV-buffer (* vertex-index 2)) + (.get UV-buffer (+ 1 (* vertex-index 2)))])) + +(defn triangle-UV-coord + "Get the uv-cooridnates of the triangle's verticies." + [#^Mesh mesh width height triangle-index] + (map (fn [[u v]] (vector (* width u) (* height v))) + (map (partial vertex-UV-coord mesh) + (triangle-vertex-indices mesh triangle-index)))) + +(defn same-side? + "Given the points p1 and p2 and the reference point ref, is point p + on the same side of the line that goes through p1 and p2 as ref is?" + [p1 p2 ref p] + (<= + 0 + (.dot + (.cross (.subtract p2 p1) (.subtract p p1)) + (.cross (.subtract p2 p1) (.subtract ref p1))))) + +(defn triangle-seq [#^Triangle tri] + [(.get1 tri) (.get2 tri) (.get3 tri)]) + +(defn vector3f-seq [#^Vector3f v] + [(.getX v) (.getY v) (.getZ v)]) + +(defn inside-triangle? + "Is the point inside the triangle?" + {:author "Dylan Holmes"} + [#^Triangle tri #^Vector3f p] + (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] + (and + (same-side? vert-1 vert-2 vert-3 p) + (same-side? vert-2 vert-3 vert-1 p) + (same-side? vert-3 vert-1 vert-2 p)))) + +(defn triangle->matrix4f + "Converts the triangle into a 4x4 matrix: The first three columns + contain the vertices of the triangle; the last contains the unit + normal of the triangle. The bottom row is filled with 1s." + [#^Triangle t] + (let [mat (Matrix4f.) + [vert-1 vert-2 vert-3] + ((comp vec map) #(.get t %) (range 3)) + unit-normal (do (.calculateNormal t)(.getNormal t)) + vertices [vert-1 vert-2 vert-3 unit-normal]] + (dorun + (for [row (range 4) col (range 3)] (do - (let [results (CollisionResults.)] - (.collideWith node ray results) - (let [touch-objects - (set (filter #(not (= geom %)) - (map #(.getGeometry %) results)))] - (count touch-objects)))))))) + (.set mat col row (.get (vertices row)col)) + (.set mat 3 row 1)))) + mat)) + +(defn triangle-transformation + "Returns the affine transformation that converts each vertex in the + first triangle into the corresponding vertex in the second + triangle." + [#^Triangle tri-1 #^Triangle tri-2] + (.mult + (triangle->matrix4f tri-2) + (.invert (triangle->matrix4f tri-1)))) + +(defn point->vector2f [[u v]] + (Vector2f. u v)) + +(defn vector2f->vector3f [v] + (Vector3f. (.getX v) (.getY v) 0)) + +(defn map-triangle [f #^Triangle tri] + (Triangle. + (f 0 (.get1 tri)) + (f 1 (.get2 tri)) + (f 2 (.get3 tri)))) + +(defn points->triangle + "Convert a list of points into a triangle." + [points] + (apply #(Triangle. %1 %2 %3) + (map (fn [point] + (let [point (vec point)] + (Vector3f. (get point 0 0) + (get point 1 0) + (get point 2 0)))) + (take 3 points)))) + +(defn convex-bounds + ;;dylan + "Returns the smallest square containing the given +vertices, as a vector of integers [left top width height]." + ;; "Dimensions of the smallest integer bounding square of the list of + ;; 2D verticies in the form: [x y width height]." + [uv-verts] + (let [xs (map first uv-verts) + ys (map second uv-verts) + x0 (Math/floor (apply min xs)) + y0 (Math/floor (apply min ys)) + x1 (Math/ceil (apply max xs)) + y1 (Math/ceil (apply max ys))] + [x0 y0 (- x1 x0) (- y1 y0)])) + +(defn sensors-in-triangle + ;;dylan + "Locate the touch sensors in the triangle, returning a map of their UV and geometry-relative coordinates." + ;;"Find the locations of the touch sensors within a triangle in both + ;; UV and gemoetry relative coordinates." + [image mesh tri-index] + (let [width (.getWidth image) + height (.getHeight image) + UV-vertex-coords (triangle-UV-coord mesh width height tri-index) + bounds (convex-bounds UV-vertex-coords) + + cutout-triangle (points->triangle UV-vertex-coords) + UV-sensor-coords + (filter (comp (partial inside-triangle? cutout-triangle) + (fn [[u v]] (Vector3f. u v 0))) + (white-coordinates image bounds)) + UV->geometry (triangle-transformation + cutout-triangle + (triangle mesh tri-index)) + geometry-sensor-coords + (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0))) + UV-sensor-coords)] + {:UV UV-sensor-coords :geometry geometry-sensor-coords})) + +(defn-memo locate-feelers + "Search the geometry's tactile UV image for touch sensors, returning + their positions in geometry-relative coordinates." + [#^Geometry geo] + (let [mesh (.getMesh geo) + num-triangles (.getTriangleCount mesh)] + (if-let [image (tactile-sensor-image geo)] + (map + (partial sensors-in-triangle image mesh) + (range num-triangles)) + (repeat (.getTriangleCount mesh) {:UV nil :geometry nil})))) + + + +(defn-memo touch-topology [#^Gemoetry geo] + (vec (collapse (reduce concat (map :UV (locate-feelers geo)))))) + +(defn-memo feeler-coordinates [#^Geometry geo] + (vec (map :geometry (locate-feelers geo)))) + +(defn enable-touch [#^Geometry geo] + (let [feeler-coords (feeler-coordinates geo) + tris (triangles geo) + limit 0.1 + ;;results (CollisionResults.) + ] + (if (empty? (touch-topology geo)) + nil + (fn [node] + (let [sensor-origins + (map + #(map (partial local-to-world geo) %) + feeler-coords) + triangle-normals + (map (partial get-ray-direction geo) + tris) + rays + (flatten + (map (fn [origins norm] + (map #(doto (Ray. % norm) + (.setLimit limit)) origins)) + sensor-origins triangle-normals))] + (vector + (touch-topology geo) + (vec + (for [ray rays] + (do + (let [results (CollisionResults.)] + (.collideWith node ray results) + (let [touch-objects + (filter #(not (= geo (.getGeometry %))) + results)] + (- 255 + (if (empty? touch-objects) 255 + (rem + (int + (* 255 (/ (.getDistance + (first touch-objects)) limit))) + 256)))))))))))))) + + +(defn touch [#^Node pieces] + (filter (comp not nil?) + (map enable-touch + (filter #(isa? (class %) Geometry) + (node-seq pieces))))) + + #+end_src diff -r 95bf55614211 -r e8df6e76c3e5 org/test-creature.org --- a/org/test-creature.org Fri Feb 03 06:04:30 2012 -0700 +++ b/org/test-creature.org Fri Feb 03 06:15:34 2012 -0700 @@ -77,18 +77,6 @@ (.getZ in) (- (.getY in)))) -(defn world-to-local - "Convert the world coordinates into coordinates relative to the - object (i.e. local coordinates), taking into account the rotation - of object." - [#^Spatial object world-coordinate] - (.worldToLocal object world-coordinate nil)) - -(defn local-to-world - "Convert the local coordinates into coordinates into world relative - coordinates" - [#^Spatial object local-coordinate] - (.localToWorld object local-coordinate nil)) (defmulti joint-dispatch "Translate blender pseudo-joints into real JME joints." @@ -245,8 +233,6 @@ (def worm "Models/creature1/try-again.blend") -(def touch "Models/creature1/touch.blend") - (defn worm-model [] (load-blender-model worm)) (defn x-ray [#^ColorRGBA color] @@ -263,237 +249,6 @@ (import ij.ImagePlus) -;; Every Mesh has many triangles, each with its own index. -;; Every vertex has its own index as well. - -(defn tactile-sensor-image - "Return the touch-sensor distribution image in BufferedImage format, - or nil if it does not exist." - [#^Geometry obj] - (if-let [image-path (meta-data obj "touch")] - (ImageToAwt/convert - (.getImage - (.loadTexture - (asset-manager) - image-path)) - false false 0))) - - - -(defn triangle - "Get the triangle specified by triangle-index from the mesh within - bounds." - [#^Mesh mesh triangle-index] - (let [scratch (Triangle.)] - (.getTriangle mesh triangle-index scratch) - scratch)) - -(defn triangle-vertex-indices - "Get the triangle vertex indices of a given triangle from a given - mesh." - [#^Mesh mesh triangle-index] - (let [indices (int-array 3)] - (.getTriangle mesh triangle-index indices) - (vec indices))) - -(defn vertex-UV-coord - "Get the uv-coordinates of the vertex named by vertex-index" - [#^Mesh mesh vertex-index] - (let [UV-buffer - (.getData - (.getBuffer - mesh - VertexBuffer$Type/TexCoord))] - [(.get UV-buffer (* vertex-index 2)) - (.get UV-buffer (+ 1 (* vertex-index 2)))])) - -(defn triangle-UV-coord - "Get the uv-cooridnates of the triangle's verticies." - [#^Mesh mesh width height triangle-index] - (map (fn [[u v]] (vector (* width u) (* height v))) - (map (partial vertex-UV-coord mesh) - (triangle-vertex-indices mesh triangle-index)))) - -(defn same-side? - "Given the points p1 and p2 and the reference point ref, is point p - on the same side of the line that goes through p1 and p2 as ref is?" - [p1 p2 ref p] - (<= - 0 - (.dot - (.cross (.subtract p2 p1) (.subtract p p1)) - (.cross (.subtract p2 p1) (.subtract ref p1))))) - -(defn triangle-seq [#^Triangle tri] - [(.get1 tri) (.get2 tri) (.get3 tri)]) - -(defn vector3f-seq [#^Vector3f v] - [(.getX v) (.getY v) (.getZ v)]) - -(defn inside-triangle? - "Is the point inside the triangle?" - {:author "Dylan Holmes"} - [#^Triangle tri #^Vector3f p] - (let [[vert-1 vert-2 vert-3] (triangle-seq tri)] - (and - (same-side? vert-1 vert-2 vert-3 p) - (same-side? vert-2 vert-3 vert-1 p) - (same-side? vert-3 vert-1 vert-2 p)))) - -(defn triangle->matrix4f - "Converts the triangle into a 4x4 matrix: The first three columns - contain the vertices of the triangle; the last contains the unit - normal of the triangle. The bottom row is filled with 1s." - [#^Triangle t] - (let [mat (Matrix4f.) - [vert-1 vert-2 vert-3] - ((comp vec map) #(.get t %) (range 3)) - unit-normal (do (.calculateNormal t)(.getNormal t)) - vertices [vert-1 vert-2 vert-3 unit-normal]] - (dorun - (for [row (range 4) col (range 3)] - (do - (.set mat col row (.get (vertices row)col)) - (.set mat 3 row 1)))) - mat)) - -(defn triangle-transformation - "Returns the affine transformation that converts each vertex in the - first triangle into the corresponding vertex in the second - triangle." - [#^Triangle tri-1 #^Triangle tri-2] - (.mult - (triangle->matrix4f tri-2) - (.invert (triangle->matrix4f tri-1)))) - -(defn point->vector2f [[u v]] - (Vector2f. u v)) - -(defn vector2f->vector3f [v] - (Vector3f. (.getX v) (.getY v) 0)) - -(defn map-triangle [f #^Triangle tri] - (Triangle. - (f 0 (.get1 tri)) - (f 1 (.get2 tri)) - (f 2 (.get3 tri)))) - -(defn points->triangle - "Convert a list of points into a triangle." - [points] - (apply #(Triangle. %1 %2 %3) - (map (fn [point] - (let [point (vec point)] - (Vector3f. (get point 0 0) - (get point 1 0) - (get point 2 0)))) - (take 3 points)))) - -(defn convex-bounds - ;;dylan - "Returns the smallest square containing the given -vertices, as a vector of integers [left top width height]." - ;; "Dimensions of the smallest integer bounding square of the list of - ;; 2D verticies in the form: [x y width height]." - [uv-verts] - (let [xs (map first uv-verts) - ys (map second uv-verts) - x0 (Math/floor (apply min xs)) - y0 (Math/floor (apply min ys)) - x1 (Math/ceil (apply max xs)) - y1 (Math/ceil (apply max ys))] - [x0 y0 (- x1 x0) (- y1 y0)])) - -(defn sensors-in-triangle - ;;dylan - "Locate the touch sensors in the triangle, returning a map of their UV and geometry-relative coordinates." - ;;"Find the locations of the touch sensors within a triangle in both - ;; UV and gemoetry relative coordinates." - [image mesh tri-index] - (let [width (.getWidth image) - height (.getHeight image) - UV-vertex-coords (triangle-UV-coord mesh width height tri-index) - bounds (convex-bounds UV-vertex-coords) - - cutout-triangle (points->triangle UV-vertex-coords) - UV-sensor-coords - (filter (comp (partial inside-triangle? cutout-triangle) - (fn [[u v]] (Vector3f. u v 0))) - (white-coordinates image bounds)) - UV->geometry (triangle-transformation - cutout-triangle - (triangle mesh tri-index)) - geometry-sensor-coords - (map (fn [[u v]] (.mult UV->geometry (Vector3f. u v 0))) - UV-sensor-coords)] - {:UV UV-sensor-coords :geometry geometry-sensor-coords})) - -(defn-memo locate-feelers - "Search the geometry's tactile UV image for touch sensors, returning - their positions in geometry-relative coordinates." - [#^Geometry geo] - (let [mesh (.getMesh geo) - num-triangles (.getTriangleCount mesh)] - (if-let [image (tactile-sensor-image geo)] - (map - (partial sensors-in-triangle image mesh) - (range num-triangles)) - (repeat (.getTriangleCount mesh) {:UV nil :geometry nil})))) - -(use 'clojure.contrib.def) - -(defn-memo touch-topology [#^Gemoetry geo] - (vec (collapse (reduce concat (map :UV (locate-feelers geo)))))) - -(defn-memo feeler-coordinates [#^Geometry geo] - (vec (map :geometry (locate-feelers geo)))) - -(defn enable-touch [#^Geometry geo] - (let [feeler-coords (feeler-coordinates geo) - tris (triangles geo) - limit 0.1 - ;;results (CollisionResults.) - ] - (if (empty? (touch-topology geo)) - nil - (fn [node] - (let [sensor-origins - (map - #(map (partial local-to-world geo) %) - feeler-coords) - triangle-normals - (map (partial get-ray-direction geo) - tris) - rays - (flatten - (map (fn [origins norm] - (map #(doto (Ray. % norm) - (.setLimit limit)) origins)) - sensor-origins triangle-normals))] - (vector - (touch-topology geo) - (vec - (for [ray rays] - (do - (let [results (CollisionResults.)] - (.collideWith node ray results) - (let [touch-objects - (filter #(not (= geo (.getGeometry %))) - results)] - (- 255 - (if (empty? touch-objects) 255 - (rem - (int - (* 255 (/ (.getDistance - (first touch-objects)) limit))) - 256)))))))))))))) - - -(defn touch [#^Node pieces] - (filter (comp not nil?) - (map enable-touch - (filter #(isa? (class %) Geometry) - (node-seq pieces))))) (defn test-eye []