diff sense.org @ 183:446b115bddc2

renamed sense-util.org to sense.org.
author Robert McIntyre <rlm@mit.edu>
date Sat, 04 Feb 2012 07:49:46 -0700
parents org/sense-util.org@f2552d61e8df
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/sense.org	Sat Feb 04 07:49:46 2012 -0700
     1.3 @@ -0,0 +1,223 @@
     1.4 +#+title: General sense/effector utilities
     1.5 +#+author: Robert McIntyre
     1.6 +#+email: rlm@mit.edu
     1.7 +#+description: sensory utilities
     1.8 +#+keywords: simulation, jMonkeyEngine3, clojure, simulated senses
     1.9 +#+SETUPFILE: ../../aurellem/org/setup.org
    1.10 +#+INCLUDE: ../../aurellem/org/level-0.org
    1.11 +
    1.12 +#+name: sense
    1.13 +#+begin_src clojure 
    1.14 +(ns cortex.sense
    1.15 +  "Here are functions useful in the construction of two or more
    1.16 +   sensors/effectors."
    1.17 +  {:author "Robert McInytre"}
    1.18 +  (:use (cortex world util))
    1.19 +  (:import ij.process.ImageProcessor)
    1.20 +  (:import jme3tools.converters.ImageToAwt)
    1.21 +  (:import java.awt.image.BufferedImage)
    1.22 +  (:import com.jme3.collision.CollisionResults)
    1.23 +  (:import com.jme3.bounding.BoundingBox)
    1.24 +  (:import (com.jme3.scene Node Spatial))
    1.25 +  (:import com.jme3.scene.control.AbstractControl)
    1.26 +  (:import (com.jme3.math Quaternion Vector3f)))
    1.27 +
    1.28 +(defn meta-data
    1.29 +  "Get the meta-data for a node created with blender."
    1.30 +  [blender-node key]
    1.31 +  (if-let [data (.getUserData blender-node "properties")]
    1.32 +    (.findValue data key)
    1.33 +    nil))
    1.34 +
    1.35 +(defn closest-node
    1.36 +  "Return the node in creature which is closest to the given node."
    1.37 +  [#^Node creature #^Node eye]
    1.38 +  (loop [radius (float 0.01)]
    1.39 +    (let [results (CollisionResults.)]
    1.40 +      (.collideWith
    1.41 +       creature
    1.42 +       (BoundingBox. (.getWorldTranslation eye)
    1.43 +                     radius radius radius)
    1.44 +       results)
    1.45 +      (if-let [target (first results)]
    1.46 +        (.getGeometry target)
    1.47 +        (recur (float (* 2 radius)))))))
    1.48 +
    1.49 +(defn bind-sense
    1.50 +  "Bind the sense to the Spatial such that it will maintain its
    1.51 +   current position relative to the Spatial no matter how the spatial
    1.52 +   moves. 'sense can be either a Camera or Listener object."
    1.53 +  [#^Spatial obj sense]
    1.54 +  (let [sense-offset (.subtract (.getLocation sense)
    1.55 +                                (.getWorldTranslation obj))
    1.56 +        initial-sense-rotation (Quaternion. (.getRotation sense))
    1.57 +        base-anti-rotation (.inverse (.getWorldRotation obj))]
    1.58 +    (.addControl
    1.59 +     obj
    1.60 +     (proxy [AbstractControl] []
    1.61 +       (controlUpdate [tpf]
    1.62 +         (let [total-rotation
    1.63 +               (.mult base-anti-rotation (.getWorldRotation obj))]
    1.64 +           (.setLocation
    1.65 +            sense
    1.66 +            (.add
    1.67 +             (.mult total-rotation sense-offset)
    1.68 +             (.getWorldTranslation obj)))
    1.69 +           (.setRotation
    1.70 +            sense
    1.71 +            (.mult total-rotation initial-sense-rotation))))
    1.72 +       (controlRender [_ _])))))
    1.73 +
    1.74 +(def white 0xFFFFFF)
    1.75 +
    1.76 +(defn white? [rgb]
    1.77 +  (= (bit-and white rgb) white))
    1.78 +
    1.79 +(defn filter-pixels
    1.80 +  "List the coordinates of all pixels matching pred, within the bounds
    1.81 +   provided.
    1.82 +   bounds -> [x0 y0 width height]"
    1.83 +  {:author "Dylan Holmes"}
    1.84 +  ([pred #^BufferedImage image]
    1.85 +     (filter-pixels pred image [0 0 (.getWidth image) (.getHeight image)]))
    1.86 +  ([pred #^BufferedImage image [x0 y0 width height]]
    1.87 +     ((fn accumulate [x y matches]
    1.88 +        (cond
    1.89 +         (>= y (+ height y0)) matches
    1.90 +         (>= x (+ width x0)) (recur 0 (inc y) matches)
    1.91 +         (pred (.getRGB image x y))
    1.92 +         (recur (inc x) y (conj matches [x y]))
    1.93 +         :else (recur (inc x) y matches)))
    1.94 +      x0 y0 [])))
    1.95 +
    1.96 +(defn white-coordinates
    1.97 +  "Coordinates of all the white pixels in a subset of the image."
    1.98 +  ([#^BufferedImage image bounds]
    1.99 +     (filter-pixels white? image bounds))
   1.100 +  ([#^BufferedImage image]
   1.101 +     (filter-pixels white? image)))
   1.102 +
   1.103 +(defn points->image
   1.104 +  "Take a sparse collection of points and visuliaze it as a
   1.105 +   BufferedImage."
   1.106 +  [points]
   1.107 +  (if (empty? points)
   1.108 +    (BufferedImage. 1 1 BufferedImage/TYPE_BYTE_BINARY)
   1.109 +    (let [xs (vec (map first points))
   1.110 +          ys (vec (map second points))
   1.111 +          x0 (apply min xs)
   1.112 +          y0 (apply min ys)
   1.113 +          width (- (apply max xs) x0)
   1.114 +          height (- (apply max ys) y0)
   1.115 +          image (BufferedImage. (inc width) (inc height)
   1.116 +                                BufferedImage/TYPE_INT_RGB)]
   1.117 +      (dorun
   1.118 +       (for [x (range (.getWidth image))
   1.119 +             y (range (.getHeight image))]
   1.120 +         (.setRGB image x y 0xFF0000)))
   1.121 +      (dorun 
   1.122 +       (for [index (range (count points))]
   1.123 +         (.setRGB image (- (xs index) x0) (- (ys index) y0) -1)))
   1.124 +      image)))
   1.125 +
   1.126 +(defn average [coll]
   1.127 +  (/ (reduce + coll) (count coll)))
   1.128 +
   1.129 +(defn collapse-1d
   1.130 +  "One dimensional analogue of collapse."
   1.131 +  [center line]
   1.132 +  (let [length (count line)
   1.133 +        num-above (count (filter (partial < center) line))
   1.134 +        num-below (- length num-above)]
   1.135 +    (range (- center num-below)
   1.136 +           (+ center num-above))))
   1.137 +
   1.138 +(defn collapse
   1.139 +  "Take a set of pairs of integers and collapse them into a
   1.140 +   contigous bitmap with no \"holes\"."
   1.141 +  [points]
   1.142 +  (if (empty? points) []
   1.143 +      (let
   1.144 +          [num-points (count points)
   1.145 +           center (vector
   1.146 +                   (int (average (map first points)))
   1.147 +                   (int (average (map first points))))
   1.148 +           flattened
   1.149 +           (reduce
   1.150 +            concat 
   1.151 +            (map
   1.152 +             (fn [column]
   1.153 +               (map vector
   1.154 +                    (map first column)
   1.155 +                    (collapse-1d (second center)
   1.156 +                                 (map second column))))
   1.157 +             (partition-by first (sort-by first points))))
   1.158 +           squeezed
   1.159 +           (reduce
   1.160 +            concat 
   1.161 +            (map
   1.162 +             (fn [row]
   1.163 +               (map vector
   1.164 +                    (collapse-1d (first center)
   1.165 +                                 (map first row))
   1.166 +                    (map second row)))
   1.167 +             (partition-by second (sort-by second flattened))))
   1.168 +           relocated
   1.169 +           (let [min-x (apply min (map first squeezed))
   1.170 +                 min-y (apply min (map second squeezed))]
   1.171 +             (map (fn [[x y]]
   1.172 +                    [(- x min-x)
   1.173 +                     (- y min-y)])
   1.174 +                  squeezed))]
   1.175 +        relocated)))
   1.176 +
   1.177 +(defn world-to-local
   1.178 +  "Convert the world coordinates into coordinates relative to the 
   1.179 +   object (i.e. local coordinates), taking into account the rotation
   1.180 +   of object."
   1.181 +  [#^Spatial object world-coordinate]
   1.182 +  (.worldToLocal object world-coordinate nil))
   1.183 +
   1.184 +(defn local-to-world
   1.185 +  "Convert the local coordinates into world relative coordinates"
   1.186 +  [#^Spatial object local-coordinate]
   1.187 +  (.localToWorld object local-coordinate nil))
   1.188 +
   1.189 +(defn sense-nodes
   1.190 +  "For each sense there is a special blender node whose children are
   1.191 +   considered markers for an instance of a that sense. This function
   1.192 +   generates functions to find those children, given the name of the
   1.193 +   special parent node."
   1.194 +  [parent-name]
   1.195 +  (fn [#^Node creature]
   1.196 +    (if-let [sense-node (.getChild creature parent-name)]
   1.197 +      (seq (.getChildren sense-node))
   1.198 +      (do (println-repl "could not find" parent-name "node") []))))
   1.199 +
   1.200 +(defn load-image
   1.201 +  "Load an image as a BufferedImage using the asset-manager system." 
   1.202 +  [asset-relative-path]
   1.203 +  (ImageToAwt/convert
   1.204 +   (.getImage (.loadTexture (asset-manager) asset-relative-path))
   1.205 +   false false 0))
   1.206 +
   1.207 +(defn jme-to-blender
   1.208 +  "Convert from JME coordinates to Blender coordinates"
   1.209 +  [#^Vector3f in]
   1.210 +  (Vector3f. (.getX in)
   1.211 +             (- (.getZ in))
   1.212 +             (.getY in)))
   1.213 +
   1.214 +(defn blender-to-jme
   1.215 +  "Convert from Blender coordinates to JME coordinates"
   1.216 +  [#^Vector3f in]
   1.217 +  (Vector3f. (.getX in)
   1.218 +             (.getZ in)
   1.219 +             (- (.getY in))))
   1.220 +#+end_src
   1.221 +
   1.222 +
   1.223 +* COMMENT generate source
   1.224 +#+begin_src clojure :tangle ../src/cortex/sense.clj
   1.225 +<<sense>>
   1.226 +#+end_src