001package icy.type.geom; 002 003import icy.type.point.Point3D; 004import icy.type.rectangle.Rectangle3D; 005 006import java.util.ArrayList; 007import java.util.List; 008 009public class Polyline3D implements Shape3D, Cloneable 010{ 011 /** 012 * The total number of points. The value of <code>npoints</code> represents the number of points in this 013 * <code>Polyline3D</code>. 014 */ 015 public int npoints; 016 017 /** 018 * The array of <i>x</i> coordinates. The value of {@link #npoints} is equal to the 019 * number of points in this <code>Polyline3D</code>. 020 */ 021 public double[] xpoints; 022 023 /** 024 * The array of <i>y</i> coordinates. The value of {@link #npoints} is equal to the 025 * number of points in this <code>Polyline3D</code>. 026 */ 027 public double[] ypoints; 028 /** 029 * The array of <i>z</i> coordinates. The value of {@link #npoints} is equal to the 030 * number of points in this <code>Polyline3D</code>. 031 */ 032 public double[] zpoints; 033 034 /** 035 * Bounds of the Polyline3D. 036 * 037 * @see #getBounds() 038 */ 039 protected Rectangle3D bounds; 040 041 protected List<Line3D> lines; 042 043 /** 044 * Creates an empty Polyline3D. 045 */ 046 public Polyline3D() 047 { 048 super(); 049 050 reset(); 051 } 052 053 /** 054 * Constructs and initializes a <code>Polyline3D</code> from the specified parameters. 055 * 056 * @param xpoints 057 * an array of <i>x</i> coordinates 058 * @param ypoints 059 * an array of <i>y</i> coordinates 060 * @param zpoints 061 * an array of <i>z</i> coordinates 062 * @param npoints 063 * the total number of points in the <code>Polyline3D</code> 064 * @exception NegativeArraySizeException 065 * if the value of <code>npoints</code> is negative. 066 * @exception IndexOutOfBoundsException 067 * if <code>npoints</code> is greater than the length of points array. 068 * @exception NullPointerException 069 * if one of the points array is <code>null</code>. 070 */ 071 public Polyline3D(double[] xpoints, double[] ypoints, double[] zpoints, int npoints) 072 { 073 super(); 074 075 if (npoints > xpoints.length || npoints > ypoints.length || npoints > zpoints.length) 076 throw new IndexOutOfBoundsException("npoints > points.length"); 077 078 this.npoints = npoints; 079 this.xpoints = new double[npoints]; 080 this.ypoints = new double[npoints]; 081 this.zpoints = new double[npoints]; 082 083 System.arraycopy(xpoints, 0, this.xpoints, 0, npoints); 084 System.arraycopy(ypoints, 0, this.ypoints, 0, npoints); 085 System.arraycopy(zpoints, 0, this.zpoints, 0, npoints); 086 087 calculateLines(); 088 } 089 090 /** 091 * Constructs and initializes a <code>Polyline3D</code> from the specified parameters. 092 * 093 * @param xpoints 094 * an array of <i>x</i> coordinates 095 * @param ypoints 096 * an array of <i>y</i> coordinates 097 * @param zpoints 098 * an array of <i>z</i> coordinates 099 * @param npoints 100 * the total number of points in the <code>Polyline3D</code> 101 * @exception NegativeArraySizeException 102 * if the value of <code>npoints</code> is negative. 103 * @exception IndexOutOfBoundsException 104 * if <code>npoints</code> is greater than the length of points array. 105 * @exception NullPointerException 106 * if one of the points array is <code>null</code>. 107 */ 108 public Polyline3D(int[] xpoints, int[] ypoints, int[] zpoints, int npoints) 109 { 110 super(); 111 112 if (npoints > xpoints.length || npoints > ypoints.length || npoints > zpoints.length) 113 throw new IndexOutOfBoundsException("npoints > points.length"); 114 115 this.npoints = npoints; 116 this.xpoints = new double[npoints]; 117 this.ypoints = new double[npoints]; 118 this.zpoints = new double[npoints]; 119 120 for (int i = 0; i < npoints; i++) 121 { 122 this.xpoints[i] = xpoints[i]; 123 this.ypoints[i] = ypoints[i]; 124 this.zpoints[i] = zpoints[i]; 125 } 126 127 calculateLines(); 128 } 129 130 public Polyline3D(Line3D line) 131 { 132 super(); 133 134 npoints = 2; 135 xpoints = new double[2]; 136 ypoints = new double[2]; 137 zpoints = new double[2]; 138 139 xpoints[0] = line.getX1(); 140 xpoints[1] = line.getX2(); 141 ypoints[0] = line.getY1(); 142 ypoints[1] = line.getY2(); 143 zpoints[0] = line.getZ1(); 144 zpoints[1] = line.getZ2(); 145 146 calculateLines(); 147 } 148 149 /** 150 * Resets this <code>Polyline3D</code> object to an empty polygon. 151 * The coordinate arrays and the data in them are left untouched 152 * but the number of points is reset to zero to mark the old 153 * vertex data as invalid and to start accumulating new vertex 154 * data at the beginning. 155 * All internally-cached data relating to the old vertices 156 * are discarded. 157 * Note that since the coordinate arrays from before the reset 158 * are reused, creating a new empty <code>Polyline3D</code> might 159 * be more memory efficient than resetting the current one if 160 * the number of vertices in the new polyline data is significantly 161 * smaller than the number of vertices in the data from before the 162 * reset. 163 */ 164 public void reset() 165 { 166 npoints = 0; 167 xpoints = new double[0]; 168 ypoints = new double[0]; 169 zpoints = new double[0]; 170 bounds = new Rectangle3D.Double(); 171 lines = new ArrayList<Line3D>(); 172 } 173 174 @Override 175 public Object clone() 176 { 177 Polyline3D pol = new Polyline3D(); 178 179 for (int i = 0; i < npoints; i++) 180 pol.addPoint(xpoints[i], ypoints[i], zpoints[i]); 181 182 return pol; 183 } 184 185 public void calculateLines() 186 { 187 final List<Line3D> newLines = new ArrayList<Line3D>(); 188 double xmin, ymin, zmin; 189 double xmax, ymax, zmax; 190 191 if (npoints > 0) 192 { 193 // first point 194 Point3D pos = new Point3D.Double(xpoints[0], ypoints[0], zpoints[0]); 195 196 // init bounds 197 xmin = xmax = pos.getX(); 198 ymin = ymax = pos.getY(); 199 zmin = zmax = pos.getZ(); 200 201 // special case 202 if (npoints == 1) 203 newLines.add(new Line3D(pos, pos)); 204 else 205 { 206 for (int i = 1; i < npoints; i++) 207 { 208 final double x = xpoints[i]; 209 final double y = ypoints[i]; 210 final double z = zpoints[i]; 211 final Point3D newPos = new Point3D.Double(x, y, z); 212 213 if (x < xmin) 214 xmin = x; 215 if (y < ymin) 216 ymin = y; 217 if (z < zmin) 218 zmin = z; 219 if (x > xmax) 220 xmax = x; 221 if (y > ymax) 222 ymax = y; 223 if (z > zmax) 224 zmax = z; 225 226 newLines.add(new Line3D(pos, newPos)); 227 pos = newPos; 228 } 229 } 230 } 231 else 232 { 233 xmin = ymin = zmin = 0d; 234 xmax = ymax = zmax = 0d; 235 } 236 237 bounds = new Rectangle3D.Double(xmin, ymin, zmin, xmax - xmin, ymax - ymin, zmax - zmin); 238 lines = newLines; 239 } 240 241 protected void updateLines(double x, double y, double z) 242 { 243 if (lines.isEmpty()) 244 { 245 lines.add(new Line3D(x, y, z, x, y, z)); 246 bounds = new Rectangle3D.Double(x, y, z, 0d, 0d, 0d); 247 } 248 else 249 { 250 final Line3D lastLine = lines.get(lines.size() - 1); 251 final Line3D newLine = new Line3D(lastLine.getX2(), lastLine.getY2(), lastLine.getZ2(), x, y, z); 252 lines.add(newLine); 253 bounds.add(newLine.getBounds()); 254 } 255 } 256 257 /** 258 * Appends the specified coordinates to this <code>Polyline3D</code>. 259 * <p> 260 * If an operation that calculates the bounding box of this <code>Polyline3D</code> has already been performed, such 261 * as <code>getBounds</code> or <code>contains</code>, then this method updates the bounding box. 262 * 263 * @param p 264 * the point to add 265 */ 266 public void addPoint(Point3D p) 267 { 268 addPoint(p.getX(), p.getY(), p.getZ()); 269 } 270 271 /** 272 * Appends the specified coordinates to this <code>Polyline3D</code>. 273 * <p> 274 * If an operation that calculates the bounding box of this <code>Polyline3D</code> has already been performed, such 275 * as <code>getBounds</code> or <code>contains</code>, then this method updates the bounding box. 276 * 277 * @param x 278 * the specified x coordinate 279 * @param y 280 * the specified y coordinate 281 * @param z 282 * the specified z coordinate 283 */ 284 public void addPoint(double x, double y, double z) 285 { 286 if (npoints == xpoints.length) 287 { 288 double[] tmp; 289 290 tmp = new double[(npoints * 2) + 1]; 291 System.arraycopy(xpoints, 0, tmp, 0, npoints); 292 xpoints = tmp; 293 294 tmp = new double[(npoints * 2) + 1]; 295 System.arraycopy(ypoints, 0, tmp, 0, npoints); 296 ypoints = tmp; 297 298 tmp = new double[(npoints * 2) + 1]; 299 System.arraycopy(zpoints, 0, tmp, 0, npoints); 300 zpoints = tmp; 301 } 302 303 xpoints[npoints] = x; 304 ypoints[npoints] = y; 305 zpoints[npoints] = z; 306 npoints++; 307 308 updateLines(x, y, z); 309 } 310 311 @Override 312 public Rectangle3D getBounds() 313 { 314 return (Rectangle3D) bounds.clone(); 315 } 316 317 @Override 318 public boolean contains(Point3D p) 319 { 320 return false; 321 } 322 323 @Override 324 public boolean contains(double x, double y, double z) 325 { 326 return false; 327 } 328 329 @Override 330 public boolean intersects(double x, double y, double z, double sizeX, double sizeY, double sizeZ) 331 { 332 return intersects(new Rectangle3D.Double(x, y, z, sizeX, sizeY, sizeZ)); 333 } 334 335 @Override 336 public boolean intersects(Rectangle3D r) 337 { 338 if (lines.isEmpty() || !bounds.intersects(r)) 339 return false; 340 341 for (Line3D line : lines) 342 if (line.intersects(r)) 343 return true; 344 345 return false; 346 } 347 348 @Override 349 public boolean contains(double x, double y, double z, double sizeX, double sizeY, double sizeZ) 350 { 351 return false; 352 } 353 354 @Override 355 public boolean contains(Rectangle3D r) 356 { 357 return false; 358 } 359}