001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.demos.hardware; 031 032import java.util.ArrayList; 033import java.util.Arrays; 034import java.util.List; 035 036import org.openimaj.image.MBFImage; 037import org.openimaj.image.typography.hershey.HersheyFont; 038import org.openimaj.math.geometry.point.Point2dImpl; 039 040import Jama.Matrix; 041 042/** 043 * Very crude orthographic wireframe renderer 044 * 045 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 046 * 047 */ 048public class Simple3D { 049 /** 050 * Simple interface to describe a primative 051 * 052 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 053 */ 054 public static interface Primative { 055 /** 056 * Render the primative 057 * 058 * @param transform 059 * @param tx 060 * @param ty 061 * @param image 062 */ 063 public void renderOrtho(Matrix transform, int tx, int ty, MBFImage image); 064 065 /** 066 * Translate the primative 067 * 068 * @param x 069 * @param y 070 * @param z 071 */ 072 public void translate(int x, int y, int z); 073 } 074 075 /** 076 * A 3D point 077 * 078 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 079 * 080 */ 081 public static class Point3D implements Primative { 082 Matrix pt; 083 private Float[] colour; 084 private int size; 085 086 /** 087 * Construct 088 * 089 * @param x 090 * @param y 091 * @param z 092 * @param colour 093 * @param size 094 */ 095 public Point3D(double x, double y, double z, Float[] colour, int size) { 096 pt = new Matrix(3, 1); 097 pt.set(0, 0, x); 098 pt.set(1, 0, y); 099 pt.set(2, 0, z); 100 this.colour = colour; 101 this.size = size; 102 } 103 104 @Override 105 public void renderOrtho(Matrix transform, int tx, int ty, MBFImage image) { 106 final Point2dImpl pt1 = projectOrtho(transform.times(pt)); 107 pt1.x += tx; 108 pt1.y += ty; 109 pt1.y = image.getHeight() - pt1.y; 110 image.drawPoint(pt1, colour, size); 111 } 112 113 @Override 114 public void translate(int x, int y, int z) { 115 pt.set(0, 0, pt.get(0, 0) + x); 116 pt.set(1, 0, pt.get(1, 0) + y); 117 pt.set(2, 0, pt.get(2, 0) + z); 118 } 119 } 120 121 /** 122 * 3D Text 123 * 124 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 125 * 126 */ 127 public static class Text3D implements Primative { 128 Matrix pt; 129 private Float[] colour; 130 private int size; 131 private String text; 132 133 /** 134 * Construct 135 * 136 * @param x 137 * @param y 138 * @param z 139 * @param colour 140 * @param size 141 * @param text 142 */ 143 public Text3D(double x, double y, double z, Float[] colour, int size, String text) { 144 pt = new Matrix(3, 1); 145 pt.set(0, 0, x); 146 pt.set(1, 0, y); 147 pt.set(2, 0, z); 148 this.colour = colour; 149 this.size = size; 150 this.text = text; 151 } 152 153 @Override 154 public void renderOrtho(Matrix transform, int tx, int ty, MBFImage image) { 155 final Point2dImpl pt1 = projectOrtho(transform.times(pt)); 156 pt1.x += tx; 157 pt1.y += ty; 158 pt1.y = image.getHeight() - pt1.y; 159 image.drawText(text, pt1, HersheyFont.ROMAN_DUPLEX, size, colour); 160 } 161 162 @Override 163 public void translate(int x, int y, int z) { 164 pt.set(0, 0, pt.get(0, 0) + x); 165 pt.set(1, 0, pt.get(1, 0) + y); 166 pt.set(2, 0, pt.get(2, 0) + z); 167 } 168 } 169 170 /** 171 * 3D line 172 * 173 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 174 * 175 */ 176 public static class Line3D implements Primative { 177 Matrix pt1; 178 Matrix pt2; 179 private Float[] colour; 180 private int thickness; 181 182 /** 183 * Construct 184 * 185 * @param x1 186 * @param y1 187 * @param z1 188 * @param x2 189 * @param y2 190 * @param z2 191 * @param colour 192 * @param size 193 */ 194 public Line3D(double x1, double y1, double z1, double x2, double y2, double z2, Float[] colour, int size) { 195 pt1 = new Matrix(3, 1); 196 pt1.set(0, 0, x1); 197 pt1.set(1, 0, y1); 198 pt1.set(2, 0, z1); 199 pt2 = new Matrix(3, 1); 200 pt2.set(0, 0, x2); 201 pt2.set(1, 0, y2); 202 pt2.set(2, 0, z2); 203 this.colour = colour; 204 this.thickness = size; 205 } 206 207 @Override 208 public void renderOrtho(Matrix transform, int tx, int ty, MBFImage image) { 209 final Point2dImpl p1 = projectOrtho(transform.times(pt1)); 210 p1.translate(tx, ty); 211 p1.y = image.getHeight() - p1.y; 212 213 final Point2dImpl p2 = projectOrtho(transform.times(pt2)); 214 p2.translate(tx, ty); 215 p2.y = image.getHeight() - p2.y; 216 217 image.drawLine(p1, p2, thickness, colour); 218 } 219 220 @Override 221 public void translate(int x, int y, int z) { 222 pt1.set(0, 0, pt1.get(0, 0) + x); 223 pt1.set(1, 0, pt1.get(1, 0) + y); 224 pt1.set(2, 0, pt1.get(2, 0) + z); 225 pt2.set(0, 0, pt2.get(0, 0) + x); 226 pt2.set(1, 0, pt2.get(1, 0) + y); 227 pt2.set(2, 0, pt2.get(2, 0) + z); 228 } 229 } 230 231 /** 232 * A scene consisting of primatives 233 * 234 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 235 * 236 */ 237 public static class Scene { 238 List<Primative> primatives = new ArrayList<Primative>(); 239 240 /** 241 * Construct 242 */ 243 public Scene() { 244 } 245 246 /** 247 * Construct 248 * 249 * @param primatives 250 */ 251 public Scene(List<Primative> primatives) { 252 this.primatives.addAll(primatives); 253 } 254 255 /** 256 * Construct 257 * 258 * @param primatives 259 */ 260 public Scene(Primative... primatives) { 261 this.primatives.addAll(Arrays.asList(primatives)); 262 } 263 264 /** 265 * Add a primative to the scene 266 * 267 * @param p 268 * @return the scene 269 */ 270 public Scene addPrimative(Primative p) { 271 primatives.add(p); 272 return this; 273 } 274 275 /** 276 * Render the scene 277 * 278 * @param transform 279 * @param image 280 */ 281 public void renderOrtho(Matrix transform, MBFImage image) { 282 for (final Primative p : primatives) 283 p.renderOrtho(transform, image.getWidth() / 2, image.getHeight() / 2, image); 284 } 285 286 /** 287 * Translate the scene 288 * 289 * @param x 290 * @param y 291 * @param z 292 */ 293 public void translate(int x, int y, int z) { 294 for (final Primative p : primatives) { 295 p.translate(x, y, z); 296 } 297 } 298 } 299 300 /** 301 * @param pt 302 * @return 303 */ 304 static Point2dImpl projectOrtho(Matrix pt) { 305 final Point2dImpl po = new Point2dImpl(); 306 307 po.x = (float) pt.get(0, 0); 308 po.y = (float) pt.get(1, 0); 309 310 return po; 311 } 312 313 /** 314 * @param pitch 315 * @param yaw 316 * @param roll 317 * @return 318 */ 319 static Matrix euler2Rot(final double pitch, final double yaw, final double roll) 320 { 321 Matrix R; 322 R = new Matrix(3, 3); 323 324 final double sina = Math.sin(pitch), sinb = Math.sin(yaw), sinc = Math 325 .sin(roll); 326 final double cosa = Math.cos(pitch), cosb = Math.cos(yaw), cosc = Math 327 .cos(roll); 328 R.set(0, 0, cosb * cosc); 329 R.set(0, 1, -cosb * sinc); 330 R.set(0, 2, sinb); 331 R.set(1, 0, cosa * sinc + sina * sinb * cosc); 332 R.set(1, 1, cosa * cosc - sina * sinb * sinc); 333 R.set(1, 2, -sina * cosb); 334 R.set(2, 0, R.get(0, 1) * R.get(1, 2) - R.get(0, 2) * R.get(1, 1)); 335 R.set(2, 1, R.get(0, 2) * R.get(1, 0) - R.get(0, 0) * R.get(1, 2)); 336 R.set(2, 2, R.get(0, 0) * R.get(1, 1) - R.get(0, 1) * R.get(1, 0)); 337 338 return R; 339 } 340}