001/* =========================================================== 002 * Orson Charts : a 3D chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C)opyright 2013-2016, by Object Refinery Limited. All rights reserved. 006 * 007 * http://www.object-refinery.com/orsoncharts/index.html 008 * 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published by 011 * the Free Software Foundation, either version 3 of the License, or 012 * (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with this program. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 023 * Other names may be trademarks of their respective owners.] 024 * 025 * If you do not wish to be bound by the terms of the GPL, an alternative 026 * commercial license can be purchased. For details, please see visit the 027 * Orson Charts home page: 028 * 029 * http://www.object-refinery.com/orsoncharts/index.html 030 * 031 */ 032 033package com.orsoncharts.graphics3d; 034 035import java.awt.geom.Point2D; 036import java.util.ArrayList; 037import java.util.Collection; 038import java.util.List; 039import java.util.Map; 040import java.util.Map.Entry; 041import com.orsoncharts.util.ArgChecks; 042 043/** 044 * A world is a model containing a collection of objects in 3D space and a 045 * direction vector for the sunlight. A viewing point ({@link ViewPoint3D}) is 046 * specified externally. Objects in the world are assigned to a partition, 047 * providing the ability to group objects. 048 */ 049public class World { 050 051 /** 052 * The default partition key. All objects in the world are added with 053 * a partition key. There always exists at least one partition (the 054 * default partition). 055 * 056 * @since 1.2 057 */ 058 public static final String DEFAULT_PARTITION_KEY = "default"; 059 060 /** The sunlight vector. */ 061 private double sunX; 062 private double sunY; 063 private double sunZ; 064 065 /** 066 * Storage for the objects in the world. A map is used to store 067 * one or more lists of objects (the partitioning is useful so 068 * that updates can be made to subsets of the world). 069 */ 070 private Map<String, List<Object3D>> objects; 071 072 /** 073 * Creates a new empty world. 074 */ 075 public World() { 076 this.objects = new java.util.TreeMap<String, List<Object3D>>(); 077 this.objects.put(DEFAULT_PARTITION_KEY, new ArrayList<Object3D>()); 078 setSunSource(new Point3D(2, -1, 10)); 079 } 080 081 082 /** 083 * Returns the x-component of the sunlight vector. 084 * 085 * @return The x-component of the sunlight vector. 086 */ 087 public double getSunX() { 088 return this.sunX; 089 } 090 091 /** 092 * Returns the y-component of the sunlight vector. 093 * 094 * @return The y-component of the sunlight vector. 095 */ 096 public double getSunY() { 097 return this.sunY; 098 } 099 100 /** 101 * Returns the z-component of the sunlight vector. 102 * 103 * @return The z-component of the sunlight vector. 104 */ 105 public double getSunZ() { 106 return this.sunZ; 107 } 108 109 /** 110 * Sets the light source point. 111 * 112 * @param x the x-coordinate. 113 * @param y the y-coordinate. 114 * @param z the z-coordinate. 115 * 116 * @since 1.2 117 */ 118 public final void setSunSource(double x, double y, double z) { 119 setSunSource(new Point3D(x, y, z)); 120 } 121 122 /** 123 * Sets the light source point. 124 * 125 * @param p the point ({@code null} not permitted). 126 * 127 * @since 1.2 128 */ 129 public final void setSunSource(Point3D p) { 130 ArgChecks.nullNotPermitted(p, "p"); 131 Point3D normal = Utils3D.normalise(p); 132 this.sunX = normal.getX(); 133 this.sunY = normal.getY(); 134 this.sunZ = normal.getZ(); 135 } 136 137 /** 138 * Adds an object to the world in the default partition. 139 * 140 * @param object the object ({@code null} not permitted). 141 */ 142 public void add(Object3D object) { 143 // defer argument checking 144 add(DEFAULT_PARTITION_KEY, object); 145 } 146 147 /** 148 * Adds an object to a specific partition. 149 * 150 * @param partition the partition ({@code null} not permitted). 151 * @param object the object ({@code null} not permitted). 152 * 153 * @since 1.2 154 */ 155 public void add(String partition, Object3D object) { 156 ArgChecks.nullNotPermitted(partition, "partition"); 157 ArgChecks.nullNotPermitted(object, "object"); 158 List<Object3D> list = this.objects.get(partition); 159 if (list == null) { 160 list = new ArrayList<Object3D>(); 161 this.objects.put(partition, list); 162 } 163 list.add(object); 164 } 165 166 /** 167 * Adds a collection of objects to the world (in the default 168 * partition). 169 * 170 * @param objects the objects ({@code null} not permitted). 171 */ 172 public void addAll(Collection<Object3D> objects) { 173 ArgChecks.nullNotPermitted(objects, "objects"); 174 for (Object3D object : objects) { 175 add(object); 176 } 177 } 178 179 /** 180 * Clears any objects belonging to the specified partition. 181 * 182 * @param partitionKey the partition key ({@code null} not permitted). 183 * 184 * @since 1.2 185 */ 186 public void clear(String partitionKey) { 187 ArgChecks.nullNotPermitted(partitionKey, "partitionKey"); 188 this.objects.put(partitionKey, null); 189 } 190 191 /** 192 * Returns the total number of vertices for all objects in this world. 193 * 194 * @return The total number of vertices. 195 */ 196 public int getVertexCount() { 197 int count = 0; 198 for (Entry<String, List<Object3D>> entry : this.objects.entrySet()) { 199 List<Object3D> objs = entry.getValue(); 200 for (Object3D object: objs) { 201 count += object.getVertexCount(); 202 } 203 } 204 return count; 205 } 206 207 /** 208 * Returns an array containing the vertices for all objects in this 209 * world, transformed to eye coordinates. 210 * 211 * @param vp the view point ({@code null} not permitted). 212 * 213 * @return The eye coordinates. 214 */ 215 public Point3D[] calculateEyeCoordinates(ViewPoint3D vp) { 216 Point3D[] result = new Point3D[getVertexCount()]; 217 int index = 0; 218 for (Entry<String, List<Object3D>> entry : this.objects.entrySet()) { 219 List<Object3D> objs = entry.getValue(); 220 for (Object3D object : objs) { 221 Point3D[] vertices = object.calculateEyeCoordinates(vp); 222 System.arraycopy(vertices, 0, result, index, vertices.length); 223 index = index + vertices.length; 224 } 225 } 226 return result; 227 } 228 229 /** 230 * Calculates the projected points in 2D-space for all the vertices of the 231 * objects in the world. 232 * 233 * @param vp the view point ({@code null} not permitted). 234 * @param d the distance. 235 * 236 * @return The projected points. 237 */ 238 public Point2D[] calculateProjectedPoints(ViewPoint3D vp, double d) { 239 Point2D[] result = new Point2D[getVertexCount()]; 240 int index = 0; 241 for (Entry<String, List<Object3D>> entry : this.objects.entrySet()) { 242 List<Object3D> objs = entry.getValue(); 243 for (Object3D object : objs) { 244 Point2D[] pts = object.calculateProjectedPoints(vp, d); 245 System.arraycopy(pts, 0, result, index, pts.length); 246 index = index + pts.length; 247 } 248 } 249 return result; 250 } 251 252 /** 253 * Fetches the faces for all the objects in this world, updating the 254 * offset to match the current position. 255 * 256 * @return A list of faces. 257 */ 258 public List<Face> getFaces() { 259 List<Face> result = new java.util.ArrayList<Face>(); 260 int offset = 0; 261 for (Entry<String, List<Object3D>> entry : this.objects.entrySet()) { 262 List<Object3D> objs = entry.getValue(); 263 for (Object3D object : objs) { 264 for (Face f : object.getFaces()) { 265 f.setOffset(offset); 266 } 267 offset += object.getVertexCount(); 268 result.addAll(object.getFaces()); 269 } 270 } 271 return result; 272 } 273 274 /** 275 * Returns a newly created list containing all the objects in the world 276 * model. 277 * 278 * @return The list of objects. 279 * 280 * @since 1.2 281 */ 282 public List<Object3D> getObjects() { 283 List<Object3D> result = new ArrayList<Object3D>(); 284 for (Entry<String, List<Object3D>> entry : this.objects.entrySet()) { 285 List<Object3D> objs = entry.getValue(); 286 result.addAll(objs); 287 } 288 return result; 289 } 290 291}