# HG changeset patch # User Robert McIntyre # Date 1328366986 25200 # Node ID 446b115bddc2de3c99adfa113fdd22e889018fe5 # Parent f2552d61e8df567a2134b0a2ea14b8808b99de24 renamed sense-util.org to sense.org. diff -r f2552d61e8df -r 446b115bddc2 org/sense-util.org --- a/org/sense-util.org Sat Feb 04 07:44:48 2012 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -#+title: General sense/effector utilities -#+author: Robert McIntyre -#+email: rlm@mit.edu -#+description: sensory utilities -#+keywords: simulation, jMonkeyEngine3, clojure, simulated senses -#+SETUPFILE: ../../aurellem/org/setup.org -#+INCLUDE: ../../aurellem/org/level-0.org - -#+name: sense-util -#+begin_src clojure -(ns cortex.sense - "Here are functions usefull in the construction of two or more - senses/effectors." - {:author "Robert McInytre"} - (:use (cortex world util)) - (:import ij.process.ImageProcessor) - (:import jme3tools.converters.ImageToAwt) - (:import java.awt.image.BufferedImage) - (:import com.jme3.collision.CollisionResults) - (:import com.jme3.bounding.BoundingBox) - (:import (com.jme3.scene Node Spatial)) - (:import com.jme3.scene.control.AbstractControl) - (:import (com.jme3.math Quaternion Vector3f))) - -(defn meta-data - "Get the meta-data for a node created with blender." - [blender-node key] - (if-let [data (.getUserData blender-node "properties")] - (.findValue data key) - nil)) - -(defn closest-node - "Return the node in creature which is closest to the given node." - [#^Node creature #^Node eye] - (loop [radius (float 0.01)] - (let [results (CollisionResults.)] - (.collideWith - creature - (BoundingBox. (.getWorldTranslation eye) - radius radius radius) - results) - (if-let [target (first results)] - (.getGeometry target) - (recur (float (* 2 radius))))))) - -(defn bind-sense - "Bind the sense to the Spatial such that it will maintain its - current position relative to the Spatial no matter how the spatial - moves. 'sense can be either a Camera or Listener object." - [#^Spatial obj sense] - (let [sense-offset (.subtract (.getLocation sense) - (.getWorldTranslation obj)) - initial-sense-rotation (Quaternion. (.getRotation sense)) - base-anti-rotation (.inverse (.getWorldRotation obj))] - (.addControl - obj - (proxy [AbstractControl] [] - (controlUpdate [tpf] - (let [total-rotation - (.mult base-anti-rotation (.getWorldRotation obj))] - (.setLocation - sense - (.add - (.mult total-rotation sense-offset) - (.getWorldTranslation obj))) - (.setRotation - sense - (.mult total-rotation initial-sense-rotation)))) - (controlRender [_ _]))))) - -(def white 0xFFFFFF) - -(defn white? [rgb] - (= (bit-and white rgb) white)) - -(defn filter-pixels - "List the coordinates of all pixels matching pred, within the bounds - provided. - bounds -> [x0 y0 width height]" - {:author "Dylan Holmes"} - ([pred #^BufferedImage image] - (filter-pixels pred image [0 0 (.getWidth image) (.getHeight image)])) - ([pred #^BufferedImage image [x0 y0 width height]] - ((fn accumulate [x y matches] - (cond - (>= y (+ height y0)) matches - (>= x (+ width x0)) (recur 0 (inc y) matches) - (pred (.getRGB image x y)) - (recur (inc x) y (conj matches [x y])) - :else (recur (inc x) y matches))) - x0 y0 []))) - -(defn white-coordinates - "Coordinates of all the white pixels in a subset of the image." - ([#^BufferedImage image bounds] - (filter-pixels white? image bounds)) - ([#^BufferedImage image] - (filter-pixels white? image))) - -(defn points->image - "Take a sparse collection of points and visuliaze it as a - BufferedImage." - [points] - (if (empty? points) - (BufferedImage. 1 1 BufferedImage/TYPE_BYTE_BINARY) - (let [xs (vec (map first points)) - ys (vec (map second points)) - x0 (apply min xs) - y0 (apply min ys) - width (- (apply max xs) x0) - height (- (apply max ys) y0) - image (BufferedImage. (inc width) (inc height) - BufferedImage/TYPE_INT_RGB)] - (dorun - (for [x (range (.getWidth image)) - y (range (.getHeight image))] - (.setRGB image x y 0xFF0000))) - (dorun - (for [index (range (count points))] - (.setRGB image (- (xs index) x0) (- (ys index) y0) -1))) - image))) - -(defn average [coll] - (/ (reduce + coll) (count coll))) - -(defn collapse-1d - "One dimensional analogue of collapse." - [center line] - (let [length (count line) - num-above (count (filter (partial < center) line)) - num-below (- length num-above)] - (range (- center num-below) - (+ center num-above)))) - -(defn collapse - "Take a set of pairs of integers and collapse them into a - contigous bitmap with no \"holes\"." - [points] - (if (empty? points) [] - (let - [num-points (count points) - center (vector - (int (average (map first points))) - (int (average (map first points)))) - flattened - (reduce - concat - (map - (fn [column] - (map vector - (map first column) - (collapse-1d (second center) - (map second column)))) - (partition-by first (sort-by first points)))) - squeezed - (reduce - concat - (map - (fn [row] - (map vector - (collapse-1d (first center) - (map first row)) - (map second row))) - (partition-by second (sort-by second flattened)))) - relocated - (let [min-x (apply min (map first squeezed)) - min-y (apply min (map second squeezed))] - (map (fn [[x y]] - [(- x min-x) - (- y min-y)]) - squeezed))] - relocated))) - -(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 world relative coordinates" - [#^Spatial object local-coordinate] - (.localToWorld object local-coordinate nil)) - -(defn sense-nodes - "For each sense there is a special blender node whose children are - considered markers for an instance of a that sense. This function - generates functions to find those children, given the name of the - special parent node." - [parent-name] - (fn [#^Node creature] - (if-let [sense-node (.getChild creature parent-name)] - (seq (.getChildren sense-node)) - (do (println-repl "could not find" parent-name "node") [])))) - -(defn load-image - "Load an image as a BufferedImage using the asset-manager system." - [asset-relative-path] - (ImageToAwt/convert - (.getImage (.loadTexture (asset-manager) asset-relative-path)) - false false 0)) - -(defn jme-to-blender - "Convert from JME coordinates to Blender coordinates" - [#^Vector3f in] - (Vector3f. (.getX in) - (- (.getZ in)) - (.getY in))) - -(defn blender-to-jme - "Convert from Blender coordinates to JME coordinates" - [#^Vector3f in] - (Vector3f. (.getX in) - (.getZ in) - (- (.getY in)))) -#+end_src - -#+results: sense-util -: #'cortex.sense/meta-data - - - -* COMMENT generate source -#+begin_src clojure :tangle ../src/cortex/sense.clj -<> -#+end_src diff -r f2552d61e8df -r 446b115bddc2 sense.org --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sense.org Sat Feb 04 07:49:46 2012 -0700 @@ -0,0 +1,223 @@ +#+title: General sense/effector utilities +#+author: Robert McIntyre +#+email: rlm@mit.edu +#+description: sensory utilities +#+keywords: simulation, jMonkeyEngine3, clojure, simulated senses +#+SETUPFILE: ../../aurellem/org/setup.org +#+INCLUDE: ../../aurellem/org/level-0.org + +#+name: sense +#+begin_src clojure +(ns cortex.sense + "Here are functions useful in the construction of two or more + sensors/effectors." + {:author "Robert McInytre"} + (:use (cortex world util)) + (:import ij.process.ImageProcessor) + (:import jme3tools.converters.ImageToAwt) + (:import java.awt.image.BufferedImage) + (:import com.jme3.collision.CollisionResults) + (:import com.jme3.bounding.BoundingBox) + (:import (com.jme3.scene Node Spatial)) + (:import com.jme3.scene.control.AbstractControl) + (:import (com.jme3.math Quaternion Vector3f))) + +(defn meta-data + "Get the meta-data for a node created with blender." + [blender-node key] + (if-let [data (.getUserData blender-node "properties")] + (.findValue data key) + nil)) + +(defn closest-node + "Return the node in creature which is closest to the given node." + [#^Node creature #^Node eye] + (loop [radius (float 0.01)] + (let [results (CollisionResults.)] + (.collideWith + creature + (BoundingBox. (.getWorldTranslation eye) + radius radius radius) + results) + (if-let [target (first results)] + (.getGeometry target) + (recur (float (* 2 radius))))))) + +(defn bind-sense + "Bind the sense to the Spatial such that it will maintain its + current position relative to the Spatial no matter how the spatial + moves. 'sense can be either a Camera or Listener object." + [#^Spatial obj sense] + (let [sense-offset (.subtract (.getLocation sense) + (.getWorldTranslation obj)) + initial-sense-rotation (Quaternion. (.getRotation sense)) + base-anti-rotation (.inverse (.getWorldRotation obj))] + (.addControl + obj + (proxy [AbstractControl] [] + (controlUpdate [tpf] + (let [total-rotation + (.mult base-anti-rotation (.getWorldRotation obj))] + (.setLocation + sense + (.add + (.mult total-rotation sense-offset) + (.getWorldTranslation obj))) + (.setRotation + sense + (.mult total-rotation initial-sense-rotation)))) + (controlRender [_ _]))))) + +(def white 0xFFFFFF) + +(defn white? [rgb] + (= (bit-and white rgb) white)) + +(defn filter-pixels + "List the coordinates of all pixels matching pred, within the bounds + provided. + bounds -> [x0 y0 width height]" + {:author "Dylan Holmes"} + ([pred #^BufferedImage image] + (filter-pixels pred image [0 0 (.getWidth image) (.getHeight image)])) + ([pred #^BufferedImage image [x0 y0 width height]] + ((fn accumulate [x y matches] + (cond + (>= y (+ height y0)) matches + (>= x (+ width x0)) (recur 0 (inc y) matches) + (pred (.getRGB image x y)) + (recur (inc x) y (conj matches [x y])) + :else (recur (inc x) y matches))) + x0 y0 []))) + +(defn white-coordinates + "Coordinates of all the white pixels in a subset of the image." + ([#^BufferedImage image bounds] + (filter-pixels white? image bounds)) + ([#^BufferedImage image] + (filter-pixels white? image))) + +(defn points->image + "Take a sparse collection of points and visuliaze it as a + BufferedImage." + [points] + (if (empty? points) + (BufferedImage. 1 1 BufferedImage/TYPE_BYTE_BINARY) + (let [xs (vec (map first points)) + ys (vec (map second points)) + x0 (apply min xs) + y0 (apply min ys) + width (- (apply max xs) x0) + height (- (apply max ys) y0) + image (BufferedImage. (inc width) (inc height) + BufferedImage/TYPE_INT_RGB)] + (dorun + (for [x (range (.getWidth image)) + y (range (.getHeight image))] + (.setRGB image x y 0xFF0000))) + (dorun + (for [index (range (count points))] + (.setRGB image (- (xs index) x0) (- (ys index) y0) -1))) + image))) + +(defn average [coll] + (/ (reduce + coll) (count coll))) + +(defn collapse-1d + "One dimensional analogue of collapse." + [center line] + (let [length (count line) + num-above (count (filter (partial < center) line)) + num-below (- length num-above)] + (range (- center num-below) + (+ center num-above)))) + +(defn collapse + "Take a set of pairs of integers and collapse them into a + contigous bitmap with no \"holes\"." + [points] + (if (empty? points) [] + (let + [num-points (count points) + center (vector + (int (average (map first points))) + (int (average (map first points)))) + flattened + (reduce + concat + (map + (fn [column] + (map vector + (map first column) + (collapse-1d (second center) + (map second column)))) + (partition-by first (sort-by first points)))) + squeezed + (reduce + concat + (map + (fn [row] + (map vector + (collapse-1d (first center) + (map first row)) + (map second row))) + (partition-by second (sort-by second flattened)))) + relocated + (let [min-x (apply min (map first squeezed)) + min-y (apply min (map second squeezed))] + (map (fn [[x y]] + [(- x min-x) + (- y min-y)]) + squeezed))] + relocated))) + +(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 world relative coordinates" + [#^Spatial object local-coordinate] + (.localToWorld object local-coordinate nil)) + +(defn sense-nodes + "For each sense there is a special blender node whose children are + considered markers for an instance of a that sense. This function + generates functions to find those children, given the name of the + special parent node." + [parent-name] + (fn [#^Node creature] + (if-let [sense-node (.getChild creature parent-name)] + (seq (.getChildren sense-node)) + (do (println-repl "could not find" parent-name "node") [])))) + +(defn load-image + "Load an image as a BufferedImage using the asset-manager system." + [asset-relative-path] + (ImageToAwt/convert + (.getImage (.loadTexture (asset-manager) asset-relative-path)) + false false 0)) + +(defn jme-to-blender + "Convert from JME coordinates to Blender coordinates" + [#^Vector3f in] + (Vector3f. (.getX in) + (- (.getZ in)) + (.getY in))) + +(defn blender-to-jme + "Convert from Blender coordinates to JME coordinates" + [#^Vector3f in] + (Vector3f. (.getX in) + (.getZ in) + (- (.getY in)))) +#+end_src + + +* COMMENT generate source +#+begin_src clojure :tangle ../src/cortex/sense.clj +<> +#+end_src