view org/sense.org @ 197:16cbce075a0b

reorganizing for website
author Robert McIntyre <rlm@mit.edu>
date Sun, 05 Feb 2012 06:55:41 -0700
parents 22548d48cc85
children fc0bf33bded2
line wrap: on
line source
1 #+title: General Sense/Effector Utilities
2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu
4 #+description: sensory utilities
5 #+keywords: simulation, jMonkeyEngine3, clojure, simulated senses
6 #+SETUPFILE: ../../aurellem/org/setup.org
7 #+INCLUDE: ../../aurellem/org/level-0.org
9 * Namespace/Imports
10 #+name header
11 #+begin_src clojure
12 (ns cortex.sense
13 "Here are functions useful in the construction of two or more
14 sensors/effectors."
15 {:author "Robert McInytre"}
16 (:use (cortex world util))
17 (:import ij.process.ImageProcessor)
18 (:import jme3tools.converters.ImageToAwt)
19 (:import java.awt.image.BufferedImage)
20 (:import com.jme3.collision.CollisionResults)
21 (:import com.jme3.bounding.BoundingBox)
22 (:import (com.jme3.scene Node Spatial))
23 (:import com.jme3.scene.control.AbstractControl)
24 (:import (com.jme3.math Quaternion Vector3f)))
25 #+end_src
27 * Blender Utilities
28 #+name: blender
29 #+begin_src clojure
30 (defn meta-data
31 "Get the meta-data for a node created with blender."
32 [blender-node key]
33 (if-let [data (.getUserData blender-node "properties")]
34 (.findValue data key)
35 nil))
37 (defn jme-to-blender
38 "Convert from JME coordinates to Blender coordinates"
39 [#^Vector3f in]
40 (Vector3f. (.getX in)
41 (- (.getZ in))
42 (.getY in)))
44 (defn blender-to-jme
45 "Convert from Blender coordinates to JME coordinates"
46 [#^Vector3f in]
47 (Vector3f. (.getX in)
48 (.getZ in)
49 (- (.getY in))))
50 #+end_src
52 * Topology Related stuff
53 #+name: topology
54 #+begin_src clojure
55 (defn load-image
56 "Load an image as a BufferedImage using the asset-manager system."
57 [asset-relative-path]
58 (ImageToAwt/convert
59 (.getImage (.loadTexture (asset-manager) asset-relative-path))
60 false false 0))
62 (def white 0xFFFFFF)
64 (defn white? [rgb]
65 (= (bit-and white rgb) white))
67 (defn filter-pixels
68 "List the coordinates of all pixels matching pred, within the bounds
69 provided.
70 bounds -> [x0 y0 width height]"
71 {:author "Dylan Holmes"}
72 ([pred #^BufferedImage image]
73 (filter-pixels pred image [0 0 (.getWidth image) (.getHeight image)]))
74 ([pred #^BufferedImage image [x0 y0 width height]]
75 ((fn accumulate [x y matches]
76 (cond
77 (>= y (+ height y0)) matches
78 (>= x (+ width x0)) (recur 0 (inc y) matches)
79 (pred (.getRGB image x y))
80 (recur (inc x) y (conj matches [x y]))
81 :else (recur (inc x) y matches)))
82 x0 y0 [])))
84 (defn white-coordinates
85 "Coordinates of all the white pixels in a subset of the image."
86 ([#^BufferedImage image bounds]
87 (filter-pixels white? image bounds))
88 ([#^BufferedImage image]
89 (filter-pixels white? image)))
91 (defn points->image
92 "Take a sparse collection of points and visuliaze it as a
93 BufferedImage."
94 [points]
95 (if (empty? points)
96 (BufferedImage. 1 1 BufferedImage/TYPE_BYTE_BINARY)
97 (let [xs (vec (map first points))
98 ys (vec (map second points))
99 x0 (apply min xs)
100 y0 (apply min ys)
101 width (- (apply max xs) x0)
102 height (- (apply max ys) y0)
103 image (BufferedImage. (inc width) (inc height)
104 BufferedImage/TYPE_INT_RGB)]
105 (dorun
106 (for [x (range (.getWidth image))
107 y (range (.getHeight image))]
108 (.setRGB image x y 0xFF0000)))
109 (dorun
110 (for [index (range (count points))]
111 (.setRGB image (- (xs index) x0) (- (ys index) y0) -1)))
112 image)))
114 (defn average [coll]
115 (/ (reduce + coll) (count coll)))
117 (defn collapse-1d
118 "One dimensional analogue of collapse."
119 [center line]
120 (let [length (count line)
121 num-above (count (filter (partial < center) line))
122 num-below (- length num-above)]
123 (range (- center num-below)
124 (+ center num-above))))
126 (defn collapse
127 "Take a set of pairs of integers and collapse them into a
128 contigous bitmap with no \"holes\"."
129 [points]
130 (if (empty? points) []
131 (let
132 [num-points (count points)
133 center (vector
134 (int (average (map first points)))
135 (int (average (map first points))))
136 flattened
137 (reduce
138 concat
139 (map
140 (fn [column]
141 (map vector
142 (map first column)
143 (collapse-1d (second center)
144 (map second column))))
145 (partition-by first (sort-by first points))))
146 squeezed
147 (reduce
148 concat
149 (map
150 (fn [row]
151 (map vector
152 (collapse-1d (first center)
153 (map first row))
154 (map second row)))
155 (partition-by second (sort-by second flattened))))
156 relocated
157 (let [min-x (apply min (map first squeezed))
158 min-y (apply min (map second squeezed))]
159 (map (fn [[x y]]
160 [(- x min-x)
161 (- y min-y)])
162 squeezed))]
163 relocated)))
165 #+end_src
167 * Node level stuff
168 #+name: node
169 #+begin_src clojure
170 (defn closest-node
171 "Return the node in creature which is closest to the given node."
172 [#^Node creature #^Node eye]
173 (loop [radius (float 0.01)]
174 (let [results (CollisionResults.)]
175 (.collideWith
176 creature
177 (BoundingBox. (.getWorldTranslation eye)
178 radius radius radius)
179 results)
180 (if-let [target (first results)]
181 (.getGeometry target)
182 (recur (float (* 2 radius)))))))
184 (defn bind-sense
185 "Bind the sense to the Spatial such that it will maintain its
186 current position relative to the Spatial no matter how the spatial
187 moves. 'sense can be either a Camera or Listener object."
188 [#^Spatial obj sense]
189 (let [sense-offset (.subtract (.getLocation sense)
190 (.getWorldTranslation obj))
191 initial-sense-rotation (Quaternion. (.getRotation sense))
192 base-anti-rotation (.inverse (.getWorldRotation obj))]
193 (.addControl
194 obj
195 (proxy [AbstractControl] []
196 (controlUpdate [tpf]
197 (let [total-rotation
198 (.mult base-anti-rotation (.getWorldRotation obj))]
199 (.setLocation
200 sense
201 (.add
202 (.mult total-rotation sense-offset)
203 (.getWorldTranslation obj)))
204 (.setRotation
205 sense
206 (.mult total-rotation initial-sense-rotation))))
207 (controlRender [_ _])))))
209 (defn world-to-local
210 "Convert the world coordinates into coordinates relative to the
211 object (i.e. local coordinates), taking into account the rotation
212 of object."
213 [#^Spatial object world-coordinate]
214 (.worldToLocal object world-coordinate nil))
216 (defn local-to-world
217 "Convert the local coordinates into world relative coordinates"
218 [#^Spatial object local-coordinate]
219 (.localToWorld object local-coordinate nil))
221 (defn sense-nodes
222 "For each sense there is a special blender node whose children are
223 considered markers for an instance of a that sense. This function
224 generates functions to find those children, given the name of the
225 special parent node."
226 [parent-name]
227 (fn [#^Node creature]
228 (if-let [sense-node (.getChild creature parent-name)]
229 (seq (.getChildren sense-node))
230 (do (println-repl "could not find" parent-name "node") []))))
231 #+end_src
233 * Viewing Senses
234 #+name view-senses
235 #+begin_src clojure
236 (defn view-sense
237 "Take a kernel that produces a BufferedImage from some sense data
238 and return a function which takes a list of sense data, uses the
239 kernem to convert to images, and displays those images, each in
240 its own JFrame."
241 [sense-display-kernel]
242 (let [windows (atom [])]
243 (fn [data]
244 (if (> (count data) (count @windows))
245 (reset!
246 windows (map (fn [_] (view-image)) (range (count data)))))
247 (dorun
248 (map
249 (fn [display datum]
250 (display (sense-display-kernel datum)))
251 @windows data)))))
253 (defn gray
254 "Create a gray RGB pixel with R, G, and B set to num. num must be
255 between 0 and 255."
256 [num]
257 (+ num
258 (bit-shift-left num 8)
259 (bit-shift-left num 16)))
260 #+end_src
262 * COMMENT generate source
263 #+begin_src clojure :tangle ../src/cortex/sense.clj
264 <<header>>
265 <<blender>>
266 <<topology>>
267 <<node>>
268 <<view-senses>>
269 #+end_src