Bug 12212 fixed: Export a polyline in 2D broke it into several segments 48/12548/2
Vincent COUVERT [Mon, 16 Sep 2013 10:34:02 +0000 (12:34 +0200)]
This reverts commit d20a172cff6af023d54b84fd4dddeb49a19543a0.

Change-Id: I8a34c7a4ba400164895e84616daabe9da84811df

scilab/CHANGES_5.5.X
scilab/modules/graphic_export/src/java/org/scilab/modules/graphic_export/Export.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/AbstractDrawable3DObject.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Clippable.java [new file with mode: 0644]
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/ConvexObject.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/G2DStroke.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Motor3D.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/PolyLine.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Scene.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Segment.java
scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Triangle.java

index d1f3098..5b99a7c 100644 (file)
@@ -514,6 +514,8 @@ Bug Fixes
 
 * Bug #12163 fixed - unzoom did not work with a single input argument.
 
+* Bug #12212 fixed - Export of a polyline in 2-D broke it into several segments.
+
 * Bug #12326 fixed - There was no way to set LaTeX font size in preview.
 
 * Bug #12349 fixed - In SciNotes, when the view was splitted, removing a char made the other view jump.
index e839190..bbe2781 100644 (file)
@@ -18,6 +18,7 @@ import java.awt.Graphics2D;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Ellipse2D;
+import java.awt.geom.Path2D;
 import java.awt.geom.PathIterator;
 import java.awt.image.BufferedImage;
 import java.io.BufferedOutputStream;
@@ -737,6 +738,7 @@ public class Export {
                         gen.writeln("/ReEncode { /MyEncoding exch def exch findfont dup length dict begin {def} forall /Encoding MyEncoding def currentdict end definefont } def");
                         gen.writeln("/Helvetica /HelveticaLatin1 ISOLatin1Encoding ReEncode");
                         gen.writeln("/Times /TimesLatin1 ISOLatin1Encoding ReEncode");
+                        gen.writeln("/DP {/Points exch def N Points 0 get Points 1 get M 2 2 Points length 1 sub {/i exch def Points i get Points i 1 add get L}for} def");
                     }
 
                     @Override
@@ -803,6 +805,33 @@ public class Export {
 
                                 return PathIterator.WIND_NON_ZERO;
                             }
+                        } else if (s instanceof Path2D) {
+                            StringBuilder buffer = new StringBuilder();
+                            double[] coords = new double[2];
+                            PathIterator it = ((Path2D) s).getPathIterator(new AffineTransform());
+                            if (!it.isDone()) {
+                                int type = it.currentSegment(coords);
+                                if (type == PathIterator.SEG_MOVETO) {
+                                    buffer.append("[").append(gen.formatDouble(coords[0])).append(" ").append(gen.formatDouble(coords[1]));
+                                    it.next();
+                                } else {
+                                    return super.processShape(s);
+                                }
+                            } else {
+                                return super.processShape(s);
+                            }
+
+                            for (; !it.isDone(); it.next()) {
+                                int type = it.currentSegment(coords);
+                                if (type == PathIterator.SEG_LINETO) {
+                                    buffer.append(" ").append(gen.formatDouble(coords[0])).append(" ").append(gen.formatDouble(coords[1]));
+                                } else {
+                                    return super.processShape(s);
+                                }
+                            }
+                            buffer.append("] DP");
+                            gen.writeln(buffer.toString());
+                            return PathIterator.WIND_NON_ZERO;
                         }
 
                         return super.processShape(s);
@@ -869,6 +898,7 @@ public class Export {
                         gen.writeln("/ReEncode { /MyEncoding exch def exch findfont dup length dict begin {def} forall /Encoding MyEncoding def currentdict end definefont } def");
                         gen.writeln("/Helvetica /HelveticaLatin1 ISOLatin1Encoding ReEncode");
                         gen.writeln("/Times /TimesLatin1 ISOLatin1Encoding ReEncode");
+                        gen.writeln("/DP {/Points exch def Points 0 get Points 1 get M 2 2 Points length 1 sub {/i exch def Points i get Points i 1 add get L}for} def");
                     }
 
                     @Override
@@ -935,6 +965,33 @@ public class Export {
 
                                 return PathIterator.WIND_NON_ZERO;
                             }
+                        } else if (s instanceof Path2D) {
+                            StringBuilder buffer = new StringBuilder();
+                            double[] coords = new double[2];
+                            PathIterator it = ((Path2D) s).getPathIterator(new AffineTransform());
+                            if (!it.isDone()) {
+                                int type = it.currentSegment(coords);
+                                if (type == PathIterator.SEG_MOVETO) {
+                                    buffer.append("[").append(gen.formatDouble(coords[0])).append(" ").append(gen.formatDouble(coords[1]));
+                                    it.next();
+                                } else {
+                                    return super.processShape(s);
+                                }
+                            } else {
+                                return super.processShape(s);
+                            }
+
+                            for (; !it.isDone(); it.next()) {
+                                int type = it.currentSegment(coords);
+                                if (type == PathIterator.SEG_LINETO) {
+                                    buffer.append(" ").append(gen.formatDouble(coords[0])).append(" ").append(gen.formatDouble(coords[1]));
+                                } else {
+                                    return super.processShape(s);
+                                }
+                            }
+                            buffer.append("] DP");
+                            gen.writeln(buffer.toString());
+                            return PathIterator.WIND_NON_ZERO;
                         }
 
                         return super.processShape(s);
index 30c88ce..fdda155 100644 (file)
@@ -50,7 +50,7 @@ public abstract class AbstractDrawable3DObject {
      */
     public AbstractDrawable3DObject(Vector3d[] vertices, Color[] colors) throws InvalidPolygonException {
         if (vertices == null || vertices.length == 0) {
-            throw new InvalidPolygonException("Invalid 3D Object: no vertices was givenl");
+            throw new InvalidPolygonException("Invalid 3D Object: no vertices was given");
         }
         this.vertices = vertices;
         this.colors = colors;
diff --git a/scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Clippable.java b/scilab/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Clippable.java
new file mode 100644 (file)
index 0000000..9e507e8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.util.List;
+
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+
+/**
+ * @author Calixte DENIZET
+ *
+ * Interface to represent a clippable object.
+ */
+public interface Clippable {
+
+    /**
+     * Break this ConvexObject against a plane
+     * @param v plane definition
+     * @return a list of ConvexObject.
+     */
+    public List<ConvexObject> breakObject(Vector4d v);
+
+}
\ No newline at end of file
index 4b2a96c..60b6f1d 100644 (file)
@@ -27,7 +27,7 @@ import org.scilab.forge.scirenderer.tranformations.Vector4d;
  * Collision and relative positions of convexs object are relatively easy to determinate.
  * About the method isBehind, it could be interesting to use the algorithm of Chung-Wang.
  */
-public abstract class ConvexObject extends AbstractDrawable3DObject {
+public abstract class ConvexObject extends AbstractDrawable3DObject implements Clippable {
 
     private List<ConvexObject> areas;
 
@@ -49,10 +49,7 @@ public abstract class ConvexObject extends AbstractDrawable3DObject {
     public abstract List<ConvexObject> breakObject(ConvexObject o);
 
     /**
-     * Abstract method
-     * Break this ConvexObject against a plane
-     * @param v plane definition
-     * @return a list of ConvexObject.
+     * {@inheritDoc}
      */
     public abstract List<ConvexObject> breakObject(Vector4d v);
 
index f8c702b..cbb1965 100644 (file)
@@ -24,13 +24,13 @@ import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
 public class G2DStroke extends BasicStroke {
 
     private static final int[] array = new int[16];
-    private static final Stroke BASIC = new G2DStroke(1, null, 0);
+    private static final G2DStroke BASIC = new G2DStroke(1, null, 0);
 
     public G2DStroke(float lineWidth, float[] dash, float phase) {
         super(lineWidth, CAP_BUTT, JOIN_MITER, 10.0f, dash, phase);
     }
 
-    public static Stroke getStroke(Appearance appearance, double dashPhase) {
+    public static G2DStroke getStroke(Appearance appearance, double dashPhase) {
         Appearance usedAppearance;
         if (appearance == null) {
             usedAppearance = new Appearance();
index 75cbc11..c403950 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
- * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ * Copyright (C) 2012-2013 - Scilab Enterprises - Calixte Denizet
  *
  * This file must be used under the terms of the CeCILL.
  * This source file is licensed as described in the file COPYING, which
@@ -250,6 +250,10 @@ public class Motor3D {
         Scene.addToRoot(is2DView(), sprite);
     }
 
+    private void add(PolyLine p) {
+        Scene.addToRoot(is2DView(), p);
+    }
+
     /**
      * Get arrays from Buffer
      * @param vertices a buffer containing vertices
@@ -283,7 +287,7 @@ public class Motor3D {
             }
             colorsArray = getMultiColors(buffer);
         } else {
-            colorsArray = new Color[vertices.limit()];
+            colorsArray = new Color[vertices.limit() / G2DElementsBuffer.ELEMENT_SIZE];
             Arrays.fill(colorsArray, defaultColor);
         }
 
@@ -351,34 +355,48 @@ public class Motor3D {
 
         switch (drawingMode) {
             case SEGMENTS_STRIP :
-                for (int i = 0; i < verticesArray.length - 1; i++) {
-                    v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
-                    c = new Color[] {colorsArray[i], colorsArray[i + 1]};
-                    try {
-                        add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength)));
-                        cumLength += Segment.getLength(v);
-                    } catch (InvalidPolygonException e) {
-                        cumLength = 0;
+                if (is2DView()) {
+                    List<PolyLine> list = PolyLine.getPolyLines(verticesArray, colorsArray, G2DStroke.getStroke(appearance, 0), false);
+                    for (PolyLine p : list) {
+                        add(p);
+                    }
+                } else {
+                    for (int i = 0; i < verticesArray.length - 1; i++) {
+                        v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
+                        c = new Color[] {colorsArray[i], colorsArray[i + 1]};
+                        try {
+                            add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength)));
+                            cumLength += Segment.getLength(v);
+                        } catch (InvalidPolygonException e) {
+                            cumLength = 0;
+                        }
                     }
                 }
                 break;
             case SEGMENTS_LOOP :
-                for (int i = 0; i < verticesArray.length - 1; i++) {
-                    v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
-                    c = new Color[] {colorsArray[i], colorsArray[i + 1]};
+                if (is2DView()) {
+                    List<PolyLine> list = PolyLine.getPolyLines(verticesArray, colorsArray, G2DStroke.getStroke(appearance, 0), true);
+                    for (PolyLine p : list) {
+                        add(p);
+                    }
+                } else {
+                    for (int i = 0; i < verticesArray.length - 1; i++) {
+                        v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
+                        c = new Color[] {colorsArray[i], colorsArray[i + 1]};
+                        try {
+                            add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength)));
+                            cumLength += Segment.getLength(v);
+                        } catch (InvalidPolygonException e) {
+                            cumLength = 0;
+                        }
+                    }
+                    int n = verticesArray.length - 1;
+                    v = new Vector3d[] {verticesArray[n], verticesArray[0]};
+                    c = new Color[] {colorsArray[n], colorsArray[0]};
                     try {
                         add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength)));
-                        cumLength += Segment.getLength(v);
-                    } catch (InvalidPolygonException e) {
-                        cumLength = 0;
-                    }
+                    } catch (InvalidPolygonException e) { }
                 }
-                int n = verticesArray.length - 1;
-                v = new Vector3d[] {verticesArray[n], verticesArray[0]};
-                c = new Color[] {colorsArray[n], colorsArray[0]};
-                try {
-                    add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength)));
-                } catch (InvalidPolygonException e) { }
                 break;
             case SEGMENTS :
             default :
index 705a484..f3016b0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
- * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte Denizet
  *
  * This file must be used under the terms of the CeCILL.
  * This source file is licensed as described in the file COPYING, which
 
 package org.scilab.forge.scirenderer.implementation.g2d.motor;
 
-import java.awt.*;
 import java.awt.Color;
+import java.awt.Stroke;
+import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
 import java.awt.Graphics2D;
 import java.util.ArrayList;
 import java.util.List;
-import org.scilab.forge.scirenderer.implementation.g2d.*;
 
 import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
 
 /**
+ * Class to represent a polyline object. This is used only in 2D (in 3D, a line could begin
+ * on front of a face and could end behind it).
+ * This allows to draw a polyline like a polyline ! and not as a set of segments.
+ * Notice that a PolyLine is NOT a convex object... but in 2D it does not matter, algorithms
+ * which use the convexity are not applyed.
+ *
  * @author Calixte DENIZET
  */
-public class PolyLine {
-    /* extends AbstractDrawable3DObject {
+public class PolyLine extends ConvexObject {
 
     private boolean monochromatic;
-    private Stroke stroke;
-    private Shape clip;
-
-    public PolyLine(Vector3d[] vertices, Color[] colors, Stroke stroke, Shape clip) throws InvalidPolygonException {
-    super(vertices, colors);
-    this.monochromatic = isMonochromatic(colors);
-    this.stroke = stroke;
-    this.clip = clip;
-    }
+    private G2DStroke stroke;
 
-    @Override
-    protected Path2D getProjectedPolyLine() {
-    int i;
-    Path2D.Double path = new Path2D.Double();
+    /**
+     * Default constructor
+     * @param vertices the polyline vertices
+     * @param colors the vertices color
+     * @param stroke the stroke to used
+     */
+    public PolyLine(Vector3d[] vertices, Color[] colors, G2DStroke stroke) throws InvalidPolygonException {
+        super(vertices, colors);
+        if (vertices.length <= 1) {
+            throw new InvalidPolygonException("A polyline cannot have one or zero point");
+        }
 
-    // Trim on the left
-    for (i = 0; i < vertices.length; i++) {
-    if (!AbstractDrawable3DObject.isNanOrInf(vertices[i])) {
-    break;
+        this.monochromatic = isMonochromatic(colors);
+        this.stroke = stroke;
     }
+
+    /**
+     * Get a set of polylines. The Nan of Inf vectors are removed and so the polyline is splitted.
+     * @param vertices the polyline vertices
+     * @param colors the vertices color
+     * @param stroke the stroke to used
+     * @param loop if true a looping polyline is created
+     * @return a set of polylines
+     */
+    public static List<PolyLine> getPolyLines(Vector3d[] vertices, Color[] colors, G2DStroke stroke, boolean loop) {
+        if (loop) {
+            Vector3d[] v = new Vector3d[vertices.length + 1];
+            Color[] c = new Color[vertices.length + 1];
+            for (int i = 0; i < vertices.length; i++) {
+                v[i] = vertices[i];
+                c[i] = colors[i];
+            }
+            v[vertices.length] = v[0];
+            c[vertices.length] = c[0];
+            vertices = v;
+            colors = c;
+        }
+
+        int pos = 0;
+        List<PolyLine> list = new ArrayList<PolyLine>(1);
+        while ((pos = trimLeft(vertices, pos)) != -1) {
+            final int second = findNanOrInf(vertices, pos + 1);
+            final int len = second - pos;
+            final Vector3d[] newVertices = new Vector3d[len];
+            final Color[] newColors = new Color[len];
+            for (int i = 0; i < len; i++) {
+                newVertices[i] = vertices[pos + i];
+                newColors[i] = colors[pos + i];
+            }
+            pos = second + 1;
+            try {
+                list.add(new PolyLine(newVertices, newColors, stroke));
+            } catch (InvalidPolygonException e) { }
+        }
+
+        return list;
     }
 
-    if (i < vertices.length) {
-    path.moveTo(vertices[i].getX(), vertices[i].getY());
-    i++;
-    boolean broken = false;
-    for (; i < vertices.length; i++) {
-    if (AbstractDrawable3DObject.isNanOrInf(vertices[i])) {
-    if (!broken) {
-    broken = true;
+    /**
+     * {@inheritDoc}
+     */
+    public List<ConvexObject> breakObject(Vector4d v) {
+        final double[] vv = v.getData();
+        final Vector3d np = new Vector3d(vv);
+        final List<ConvexObject> list = new ArrayList<ConvexObject>(1);
+
+        int pos = 0;
+        boolean prev = false;
+
+        for (int i = 0; i < vertices.length; i++) {
+            final boolean b = isBehind(vertices[i], np, vv[3]);
+            if (b && !prev) {
+                pos = i;
+                prev = true;
+            } else if (!b && prev) {
+                prev = false;
+                try {
+                    list.add(cut(pos, i, np, vv[3]));
+                } catch (InvalidPolygonException e) { }
+            }
+        }
+
+        if (prev) {
+            try {
+                list.add(cut(pos, vertices.length, np, vv[3]));
+            } catch (InvalidPolygonException e) { }
+        }
+
+        return list;
     }
-    } else {
-    if (broken) {
-    broken = false;
-    path.moveTo(vertices[i].getX(), vertices[i].getY());
-    } else {
-    path.lineTo(vertices[i].getX(), vertices[i].getY());
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<ConvexObject> breakObject(ConvexObject o) {
+        return null;
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected boolean isDegenerate() {
+        return false;
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected boolean isNanOrInf() {
+        return false;
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Vector3d getNormal() {
+        // Never used
+        return null;
     }
 
-    return path;
+    /**
+     * {@inheritDoc}
+     */
+    protected boolean isPlanar() {
+        // Never used
+        return true;
     }
 
-    public void draw(Graphics2D g2d) {
-    Shape oldClip = g2d.getClip();
-    Stroke oldStroke = g2d.getStroke();
-
-    g2d.clip(clip);
-
-    if (monochromatic) {
-    g2d.setColor(colors[0]);
-    g2d.setStroke(stroke);
-    g2d.draw(getProjectedPolyLine());
-    } else {
-    Vector3D start = null;
-    Color color = null;
-    double cumLen = 0;
-    float[] dashArray = stroke.getDashArray();
-    float lwidth = stroke.getLineWidth();
-    for (int i = 0; i < vertices.length; i++) {
-    if (AbstractDrawable3DObject.isNanOrInf(vertices[i])) {
-    start = null;
-    } else {
-    if (start == null) {
-    start = vertices[i];
-    color = colors[i];
-    } else {
-    Stroke nstroke = new G2DStroke(lwidth, dashArray, cumLen);
-    g2d.setStroke(nstroke);
-    g2d.setColor(color);
-    g2d.draw(new Line2D.Double(start.getX(), start.getY(), vertices[i].getX(), vertices[i].getY()));
-    cumLen += Math.hypot(start.getX() - vertices[i].getX(), start.getY() - vertices[i].getY());
+    /**
+     * Cut a polyline on a clipping plane
+     * @param first the first vertex position
+     * @param second the second vertex position
+     * @param np the normal vector of the clipping plane
+     * @param C the constant part of the hyperplane
+     * @return a cutted PolyLine
+     */
+    private PolyLine cut(int first, int second, Vector3d np, double C) throws InvalidPolygonException {
+        final boolean cutAtBegin = first != 0;
+        final boolean cutAtEnd = second != vertices.length;
+
+        if (!cutAtBegin && !cutAtEnd) {
+            return this;
+        }
+
+        if (cutAtBegin && cutAtEnd) {
+            final int len = second - first + 2;
+
+            Vector3d[] newVertices = new Vector3d[len];
+            Color[] newColors = new Color[len];
+
+            for (int i = 1; i < len - 1; i++) {
+                newVertices[i] = vertices[first + i - 1];
+                newColors[i] = colors[first + i - 1];
+            }
+
+            double c = (C + vertices[first].scalar(np)) / vertices[first].minus(vertices[first - 1]).scalar(np);
+            newVertices[0] = Vector3d.getBarycenter(vertices[first - 1], vertices[first], c, 1 - c);
+            newColors[0] = getColorsBarycenter(colors[first - 1], colors[first], c, 1 - c);
+
+            c = (C + vertices[second].scalar(np)) / vertices[second].minus(vertices[second - 1]).scalar(np);
+            newVertices[len - 1] = Vector3d.getBarycenter(vertices[second - 1], vertices[second], c, 1 - c);
+            newColors[len - 1] = getColorsBarycenter(colors[second - 1], colors[second], c, 1 - c);
+
+            return new PolyLine(newVertices, newColors, this.stroke);
+        }
+
+        if (cutAtBegin) {
+            final double c = (C + vertices[first].scalar(np)) / vertices[first].minus(vertices[first - 1]).scalar(np);
+            final int len = second - first + 1;
+
+            Vector3d[] newVertices = new Vector3d[len];
+            Color[] newColors = new Color[len];
+
+            for (int i = 1; i < len; i++) {
+                newVertices[i] = vertices[first + i - 1];
+                newColors[i] = colors[first + i - 1];
+            }
+
+            newVertices[0] = Vector3d.getBarycenter(vertices[first - 1], vertices[first], c, 1 - c);
+            newColors[0] = getColorsBarycenter(colors[first - 1], colors[first], c, 1 - c);
+
+            return new PolyLine(newVertices, newColors, this.stroke);
+        } else {
+            final double c = (C + vertices[second].scalar(np)) / vertices[second].minus(vertices[second - 1]).scalar(np);
+            final int len = second - first + 1;
+
+            Vector3d[] newVertices = new Vector3d[len];
+            Color[] newColors = new Color[len];
+
+            for (int i = 0; i < len - 1; i++) {
+                newVertices[i] = vertices[first + i];
+                newColors[i] = colors[first + i];
+            }
+
+            newVertices[len - 1] = Vector3d.getBarycenter(vertices[second - 1], vertices[second], c, 1 - c);
+            newColors[len - 1] = getColorsBarycenter(colors[second - 1], colors[second], c, 1 - c);
+            return new PolyLine(newVertices, newColors, this.stroke);
+        }
     }
+
+
+    @Override
+    protected Path2D getProjectedPolyLine() {
+        Path2D.Double path = new Path2D.Double();
+
+        path.moveTo(vertices[0].getX(), vertices[0].getY());
+        for (int i = 1; i < vertices.length; i++) {
+            path.lineTo(vertices[i].getX(), vertices[i].getY());
+        }
+
+        return path;
     }
+
+    @Override
+    public void draw(Graphics2D g2d) {
+        Stroke oldStroke = g2d.getStroke();
+
+        if (monochromatic) {
+            g2d.setColor(colors[0]);
+            g2d.setStroke(stroke);
+            g2d.draw(getProjectedPolyLine());
+        } else {
+            // on peut surement faire mieux ici
+            // avec un LinearGradientPaint
+            Vector3d start = vertices[0];
+            Color color = colors[0];
+            double cumLen = 0;
+            float[] dashArray = stroke.getDashArray();
+            float lwidth = stroke.getLineWidth();
+            for (int i = 1; i < vertices.length; i++) {
+                Stroke nstroke = new G2DStroke(lwidth, dashArray, (float) cumLen);
+                g2d.setStroke(nstroke);
+                g2d.setColor(color);
+                g2d.draw(new Line2D.Double(start.getX(), start.getY(), vertices[i].getX(), vertices[i].getY()));
+                cumLen += Math.hypot(start.getX() - vertices[i].getX(), start.getY() - vertices[i].getY());
+            }
+        }
+
+        g2d.setStroke(oldStroke);
     }
+
+    /**
+     * Get first non Nan (or Inf) vector position
+     * @param v the array to trim
+     * @param start the starting position
+     * @return index of the first non Nan vector or -1 if not found
+     */
+    private static int trimLeft(Vector3d[] v, int start) {
+        for (int i = start; i < v.length; i++) {
+            if (!isNanOrInf(v[i])) {
+                return i;
+            }
+        }
+
+        return -1;
     }
 
-    g2d.setClip(oldClip);
-    g2d.setStroke(oldStroke);
-    }*/
+    /**
+     * Get first Nan (or Inf) vector position
+     * @param v the array to trim
+     * @param start the starting position
+     * @return index of the first Nan vector
+     */
+    private static int findNanOrInf(Vector3d[] v, int start) {
+        for (int i = start; i < v.length; i++) {
+            if (isNanOrInf(v[i])) {
+                return i;
+            }
+        }
+
+        return v.length;
+    }
 }
index beb303b..3bafa08 100644 (file)
@@ -47,6 +47,7 @@ final class Scene {
     private List<Scene> onfront;
     private ConvexObject object;
     private boolean drawn;
+    private boolean is2d;
 
     private Scene(final ConvexObject object) {
         this.object = object;
@@ -57,8 +58,8 @@ final class Scene {
     }
 
     private static final List<ConvexObject> breakOnClippingPlane(ConvexObject o) {
-        List<ConvexObject> list = new ArrayList<ConvexObject>();
-        List<ConvexObject> tmp = new ArrayList<ConvexObject>();
+        List<ConvexObject> list = new ArrayList<ConvexObject>(8);
+        List<ConvexObject> tmp = new ArrayList<ConvexObject>(8);
         list.add(o);
         if (clippingPlanes != null) {
             for (ClippingPlane clip : clippingPlanes) {
@@ -68,6 +69,9 @@ final class Scene {
                         List<ConvexObject> l = co.breakObject(clip.getEquation());
                         if (l != null) {
                             tmp.addAll(l);
+                        } else {
+                            list.clear();
+                            return list;
                         }
                     }
                     list.clear();
@@ -82,9 +86,13 @@ final class Scene {
     }
 
     static final void addToRoot(final boolean is2D, final ConvexObject co) {
-        List<ConvexObject> broken = breakOnClippingPlane(co);
-        for (ConvexObject object : broken) {
-            add(is2D, object);
+        try {
+            List<ConvexObject> broken = breakOnClippingPlane(co);
+            for (ConvexObject object : broken) {
+                add(is2D, object);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
         }
     }
 
@@ -92,6 +100,7 @@ final class Scene {
         synchronized (faces) {
             Scene st = new Scene(object);
             if (is2D) {
+                st.is2d = true;
                 faces2d.add(st);
             } else {
                 Set<Scene> toRemove = new HashSet<Scene>();
index 4b05c5f..8033500 100644 (file)
@@ -25,15 +25,17 @@ import org.scilab.forge.scirenderer.tranformations.Vector3d;
 import org.scilab.forge.scirenderer.tranformations.Vector4d;
 
 /**
+ * Segment object (for info, when modify rendering check for PolyLine too).
+ *
  * @author Calixte DENIZET
  */
 public class Segment extends ConvexObject implements Comparable<Segment> {
 
     private Integer hash;
-    protected Stroke stroke;
+    protected G2DStroke stroke;
     protected List<ConvexObject> segmentOn;
 
-    public Segment(Vector3d[] vertices, Color[] colors, Stroke stroke) throws InvalidPolygonException {
+    public Segment(Vector3d[] vertices, Color[] colors, G2DStroke stroke) throws InvalidPolygonException {
         super(vertices, colors);
         if (vertices.length != 2) {
             throw new InvalidPolygonException("Invalid segment: must have 2 vertices.");
@@ -45,7 +47,7 @@ public class Segment extends ConvexObject implements Comparable<Segment> {
         this(vertices, colors, null);
     }
 
-    public void setStroke(Stroke stroke) {
+    public void setStroke(G2DStroke stroke) {
         this.stroke = stroke;
     }
 
@@ -146,22 +148,17 @@ public class Segment extends ConvexObject implements Comparable<Segment> {
         double c = (vv[3] + vertices[1].scalar(np)) / v0.scalar(np);
         Vector3d p = Vector3d.getBarycenter(vertices[0], vertices[1], c, 1 - c);
         Color color = getColorsBarycenter(colors[0], colors[1], c, 1 - c);
-        Vector3d[] vs = null;
-        Color[] cs = null;
-
-        if (a) {
-            vs = new Vector3d[] {vertices[0], p};
-            cs = new Color[] {colors[0], color};
-        }
-
-        if (b) {
-            vs = new Vector3d[] {p, vertices[1]};
-            cs = new Color[] {color, colors[1]};
-        }
+        Segment s;
 
         try {
+            if (a) {
+                s = new Segment(new Vector3d[] {vertices[0], p}, new Color[] {colors[0], color}, this.stroke);
+            } else {
+                s = new Segment(new Vector3d[] {p, vertices[1]}, new Color[] {color, colors[1]}, this.stroke);
+            }
+
             List<ConvexObject> list = new ArrayList<ConvexObject>(1);
-            list.add(new Segment(vs, cs, this.stroke));
+            list.add(s);
 
             return list;
         } catch (InvalidPolygonException e) { }
index ffaccba..e5bc01b 100644 (file)
@@ -193,6 +193,10 @@ public class Triangle extends ConvexObject {
             Path2D contour = getProjectedContour();
             Area area = new Area(contour);
             // Trick to paint the triangle and its outline
+            // TODO: the newly created Area contains in fact two areas
+            // it should be better to have one area where its border
+            // is the external outline of the contour...
+            // (it would reduce eps/ps/pdf/svg file size)
             area.add(new Area(stroke.createStrokedShape(contour)));
             g2d.setStroke(EMPTYSTROKE);
             g2d.setColor(colors[0]);