2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
12 package org.scilab.forge.scirenderer.implementation.g2d.motor;
14 import java.awt.Color;
15 import java.awt.Graphics2D;
16 import java.awt.geom.Path2D;
17 import java.util.HashSet;
20 import org.scilab.forge.scirenderer.tranformations.Vector3d;
23 * @author Calixte DENIZET
25 public abstract class AbstractDrawable3DObject {
27 public static final double PRECISION = 1e-8;
29 private static int defaultPrecedence = 0;
31 protected final Vector3d[] vertices;
33 protected final Color[] colors;
34 protected int precedence;
35 protected Boolean is2d;
36 protected Double zindex;
37 protected Vector3d v0;
38 protected Vector3d v1;
39 protected Vector3d v0v1;
40 protected double nv0v1;
41 protected Vector3d normal;
42 protected BoundingBox bbox;
43 protected boolean marked;
44 protected boolean marked2;
45 protected Boolean degenerated;
49 * @param vertices the vertices
51 public AbstractDrawable3DObject(Vector3d[] vertices, Color[] colors) throws InvalidPolygonException {
52 if (vertices == null || vertices.length == 0) {
53 throw new InvalidPolygonException("Invalid 3D Object: no vertices was givenl");
55 this.vertices = vertices;
58 throw new InvalidPolygonException("Invalid 3D Object: two vertices are the same");
61 throw new InvalidPolygonException("Invalid 3D Object: contains NaN or Inf coordinates");
63 setPrecedence(defaultPrecedence++);
68 * Get the bounding box
69 * @return the bounding box
71 final BoundingBox getBBox() {
73 bbox = BoundingBox.getBoundingBox(this);
80 * Test if an array of colors contains only one color or not
81 * @param colors the colors array
82 * @return true if the array is monochromatic
84 public static boolean isMonochromatic(Color[] colors) {
85 if (colors != null && colors.length > 0) {
87 for (int i = 1; i < colors.length; i++) {
88 if (!c.equals(colors[i])) {
98 * Draw this object on a Graphics2D object
99 * @param g2d the Graphics2d object where to draw
101 public abstract void draw(Graphics2D g2d);
104 * Reset the default precedence
106 public static void resetDefaultPrecedence() {
107 defaultPrecedence = 0;
111 * Set the precedence of this object.
112 * @param precedence the precedence of this object
114 public void setPrecedence(int precedence) {
115 this.precedence = precedence;
119 * Get the precedence of this object, i.e. its position in the list of the draw objects.
120 * The first object has a precedence of 0, the second has a precedence of 1, ...
121 * @param the precedence
123 public int getPrecedence() {
128 * Determinates if this object is 2D in looking at the z coordinates
129 * (when all the drawn objects are 2D, we can avoid the projection)
131 public boolean is2D() {
133 for (Vector3d v : vertices) {
135 is2d = Boolean.FALSE;
146 * Get the normal vector.
147 * If no normal vector has been set then it is calculated in using the cross product of the first two vectors.
148 * @return the normal vector.
150 public Vector3d getProvidedNormal() {
155 * Get the normal vector.
156 * If no normal vector has been set then it is calculated in using the cross product of the first two vectors.
157 * @return the normal vector.
159 public Vector3d getNormal() {
168 * Set the normal vector
170 protected void setNormal() {
171 v0 = vertices[1].minus(vertices[0]);
172 if (vertices.length >= 3) {
173 v1 = vertices[2].minus(vertices[0]);
174 v0v1 = Vector3d.product(v0, v1);
175 nv0v1 = v0v1.getNorm();
176 v0v1 = v0v1.times(1 / nv0v1);;
178 v0v1 = new Vector3d(0, 0, 0);
183 * Determinates if the object is contained into a plane
184 * @return true if the object is planar
186 protected boolean isPlanar() {
187 Vector3d n = getNormal();
188 if (n.isZero() || vertices.length == 3) {
192 for (int i = 1; i < vertices.length; i++) {
193 if (!isNull(n.scalar(vertices[0].minus(vertices[i])))) {
201 public int isBehind(Vector3d v, double a) {
202 double[] mM = minmax3D(this, v);
204 if (isPositiveOrNull(mM[0] + a)) {
214 public static boolean isBehind(Vector3d M, Vector3d v, double a) {
215 return isPositiveOrNull(M.scalar(v) + a);
219 * Get the projected polyline of this object
222 protected Path2D getProjectedPolyLine() {
223 Path2D.Double path = new Path2D.Double();
224 path.moveTo(vertices[0].getX(), vertices[0].getY());
225 for (int i = 1; i < vertices.length; i++) {
226 path.lineTo(vertices[i].getX(), vertices[i].getY());
233 * Get the projected contour (i.e. a closed polyline) of this object
236 protected Path2D getProjectedContour() {
237 Path2D path = getProjectedPolyLine();
245 * @return true if d is near zero
247 protected final static boolean isNull(final double d) {
248 return Math.abs(d) <= PRECISION;
253 * @return true if d is greater than zero
255 protected final static boolean isPositiveOrNull(final double d) {
256 return d >= 0 || isNull(d);
261 * @return true if d is greater than zero
263 protected final static boolean isNegativeOrNull(final double d) {
264 return d <= 0 || isNull(d);
270 * @return true if d1 is greater than d2
272 protected final static boolean isGreaterOrEqual(final double d1, final double d2) {
273 return isPositiveOrNull(d1 - d2);
279 * @return true if d1 is lower than d2
281 protected final static boolean isLowerOrEqual(final double d1, final double d2) {
282 return isPositiveOrNull(d2 - d1);
288 * @return true if d1 is equal to d2
290 protected final static boolean isEqual(final double d1, final double d2) {
291 return isNull(d1 - d2);
295 * Get min-max of the projections of the vertices of o on v
298 * @return an array of size 2 containing min-max.
300 protected static final double[] minmax3D(final AbstractDrawable3DObject o, final Vector3d v) {
301 double min = v.scalar(o.vertices[0]);
304 for (int i = 1; i < o.vertices.length; i++) {
305 double s = v.scalar(o.vertices[i]);
308 } else if (s > max) {
313 return new double[] {min, max};
317 * Get min-max of the projections of the vertices of o on v
320 * @return an array of size 2 containing min-max.
322 protected static final double[] minmax2D(final AbstractDrawable3DObject o, final double x, final double y) {
323 double min = x * o.vertices[0].getX() + y * o.vertices[0].getY();
326 for (int i = 1; i < o.vertices.length; i++) {
327 double s = x * o.vertices[i].getX() + y * o.vertices[i].getY();
330 } else if (s > max) {
335 return new double[] {min, max};
338 protected static final Color getColorsBarycenter(final Color c1, final Color c2, final double w1, final double w2) {
339 if (c1 != null && c2 != null && !c1.equals(c2)) {
340 float[] comp1 = c1.getComponents(null);
341 float[] comp2 = c2.getComponents(null);
343 return new Color((float) (comp1[0] * w1 + comp2[0] * w2),
344 (float) (comp1[1] * w1 + comp2[1] * w2),
345 (float) (comp1[2] * w1 + comp2[2] * w2),
346 (float) (comp1[3] * w1 + comp2[3] * w2));
353 * @return true if there are two vertices which are indentical
355 protected boolean isDegenerate() {
356 if (degenerated == null) {
357 Set<Vector3d> set = new HashSet<Vector3d>();
358 for (Vector3d v : vertices) {
362 degenerated = set.size() != vertices.length;
368 protected boolean isNanOrInf() {
369 for (Vector3d v : vertices) {
378 public static final boolean isNanOrInf(final Vector3d v) {
379 final double x = v.getX();
380 if (Double.isNaN(x) || Double.isInfinite(x)) {
383 final double y = v.getY();
384 if (Double.isNaN(y) || Double.isInfinite(y)) {
387 final double z = v.getZ();
388 if (Double.isNaN(z) || Double.isInfinite(z)) {