001/* =========================================================== 002 * Orson Charts : a 3D chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C)opyright 2013-2022, by David Gilbert. All rights reserved. 006 * 007 * https://github.com/jfree/orson-charts 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 org.jfree.chart3d.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 org.jfree.chart3d.graphics3d.internal.Utils3D; 042import org.jfree.chart3d.internal.Args; 043 044/** 045 * A world is a model containing a collection of objects in 3D space and a 046 * direction vector for the sunlight. A viewing point ({@link ViewPoint3D}) is 047 * specified externally. Objects in the world are assigned to a partition, 048 * providing the ability to group objects. 049 */ 050public class World { 051 052 /** 053 * The default partition key. All objects in the world are added with 054 * a partition key. There always exists at least one partition (the 055 * default partition). 056 * 057 * @since 1.2 058 */ 059 public static final String DEFAULT_PARTITION_KEY = "default"; 060 061 /** The sunlight vector. */ 062 private double sunX; 063 private double sunY; 064 private double sunZ; 065 066 /** 067 * Storage for the objects in the world. A map is used to store 068 * one or more lists of objects (the partitioning is useful so 069 * that updates can be made to subsets of the world). 070 */ 071 private Map<String, List<Object3D>> objects; 072 073 /** 074 * Creates a new empty world. 075 */ 076 public World() { 077 this.objects = new java.util.TreeMap<>(); 078 this.objects.put(DEFAULT_PARTITION_KEY, new ArrayList<>()); 079 setSunSource(new Point3D(2, -1, 10)); 080 } 081 082 083 /** 084 * Returns the x-component of the sunlight vector. 085 * 086 * @return The x-component of the sunlight vector. 087 */ 088 public double getSunX() { 089 return this.sunX; 090 } 091 092 /** 093 * Returns the y-component of the sunlight vector. 094 * 095 * @return The y-component of the sunlight vector. 096 */ 097 public double getSunY() { 098 return this.sunY; 099 } 100 101 /** 102 * Returns the z-component of the sunlight vector. 103 * 104 * @return The z-component of the sunlight vector. 105 */ 106 public double getSunZ() { 107 return this.sunZ; 108 } 109 110 /** 111 * Sets the light source point. 112 * 113 * @param x the x-coordinate. 114 * @param y the y-coordinate. 115 * @param z the z-coordinate. 116 * 117 * @since 1.2 118 */ 119 public final void setSunSource(double x, double y, double z) { 120 setSunSource(new Point3D(x, y, z)); 121 } 122 123 /** 124 * Sets the light source point. 125 * 126 * @param p the point ({@code null} not permitted). 127 * 128 * @since 1.2 129 */ 130 public final void setSunSource(Point3D p) { 131 Args.nullNotPermitted(p, "p"); 132 Point3D normal = Utils3D.normalise(p); 133 this.sunX = normal.getX(); 134 this.sunY = normal.getY(); 135 this.sunZ = normal.getZ(); 136 } 137 138 /** 139 * Adds an object to the world in the default partition. 140 * 141 * @param object the object ({@code null} not permitted). 142 */ 143 public void add(Object3D object) { 144 // defer argument checking 145 add(DEFAULT_PARTITION_KEY, object); 146 } 147 148 /** 149 * Adds an object to a specific partition. 150 * 151 * @param partition the partition ({@code null} not permitted). 152 * @param object the object ({@code null} not permitted). 153 * 154 * @since 1.2 155 */ 156 public void add(String partition, Object3D object) { 157 Args.nullNotPermitted(partition, "partition"); 158 Args.nullNotPermitted(object, "object"); 159 List<Object3D> list = this.objects.get(partition); 160 if (list == null) { 161 list = new ArrayList<>(); 162 this.objects.put(partition, list); 163 } 164 list.add(object); 165 } 166 167 /** 168 * Adds a collection of objects to the world (in the default 169 * partition). 170 * 171 * @param objects the objects ({@code null} not permitted). 172 */ 173 public void addAll(Collection<Object3D> objects) { 174 Args.nullNotPermitted(objects, "objects"); 175 for (Object3D object : objects) { 176 add(object); 177 } 178 } 179 180 /** 181 * Clears any objects belonging to the specified partition. 182 * 183 * @param partitionKey the partition key ({@code null} not permitted). 184 * 185 * @since 1.2 186 */ 187 public void clear(String partitionKey) { 188 Args.nullNotPermitted(partitionKey, "partitionKey"); 189 this.objects.put(partitionKey, null); 190 } 191 192 /** 193 * Returns the total number of vertices for all objects in this world. 194 * 195 * @return The total number of vertices. 196 */ 197 public int getVertexCount() { 198 int count = 0; 199 for (Entry<String, List<Object3D>> entry : this.objects.entrySet()) { 200 List<Object3D> objs = entry.getValue(); 201 for (Object3D object: objs) { 202 count += object.getVertexCount(); 203 } 204 } 205 return count; 206 } 207 208 /** 209 * Returns an array containing the vertices for all objects in this 210 * world, transformed to eye coordinates. 211 * 212 * @param vp the view point ({@code null} not permitted). 213 * 214 * @return The eye coordinates. 215 */ 216 public Point3D[] calculateEyeCoordinates(ViewPoint3D vp) { 217 Point3D[] result = new Point3D[getVertexCount()]; 218 int index = 0; 219 for (Entry<String, List<Object3D>> entry : this.objects.entrySet()) { 220 List<Object3D> objs = entry.getValue(); 221 for (Object3D object : objs) { 222 Point3D[] vertices = object.calculateEyeCoordinates(vp); 223 System.arraycopy(vertices, 0, result, index, vertices.length); 224 index = index + vertices.length; 225 } 226 } 227 return result; 228 } 229 230 /** 231 * Calculates the projected points in 2D-space for all the vertices of the 232 * objects in the world. 233 * 234 * @param vp the view point ({@code null} not permitted). 235 * @param d the distance. 236 * 237 * @return The projected points. 238 */ 239 public Point2D[] calculateProjectedPoints(ViewPoint3D vp, double d) { 240 Point2D[] result = new Point2D[getVertexCount()]; 241 int index = 0; 242 for (Entry<String, List<Object3D>> entry : this.objects.entrySet()) { 243 List<Object3D> objs = entry.getValue(); 244 for (Object3D object : objs) { 245 Point2D[] pts = object.calculateProjectedPoints(vp, d); 246 System.arraycopy(pts, 0, result, index, pts.length); 247 index = index + pts.length; 248 } 249 } 250 return result; 251 } 252 253 /** 254 * Fetches the faces for all the objects in this world, updating the 255 * offset to match the current position. 256 * 257 * @return A list of faces. 258 */ 259 public List<Face> getFaces() { 260 List<Face> result = new java.util.ArrayList<>(); 261 int offset = 0; 262 for (Entry<String, List<Object3D>> entry : this.objects.entrySet()) { 263 List<Object3D> objs = entry.getValue(); 264 for (Object3D object : objs) { 265 for (Face f : object.getFaces()) { 266 f.setOffset(offset); 267 } 268 offset += object.getVertexCount(); 269 result.addAll(object.getFaces()); 270 } 271 } 272 return result; 273 } 274 275 /** 276 * Returns a newly created list containing all the objects in the world 277 * model. 278 * 279 * @return The list of objects. 280 * 281 * @since 1.2 282 */ 283 public List<Object3D> getObjects() { 284 List<Object3D> result = new ArrayList<>(); 285 for (Entry<String, List<Object3D>> entry : this.objects.entrySet()) { 286 List<Object3D> objs = entry.getValue(); 287 result.addAll(objs); 288 } 289 return result; 290 } 291 292}