Add a way to precise mark border color for scatter plots
[scilab.git] / scilab / modules / scirenderer / src / org / scilab / forge / scirenderer / implementation / g2d / motor / SpritedRectangle.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
4  *
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
10  */
11
12 package org.scilab.forge.scirenderer.implementation.g2d.motor;
13
14 import java.awt.Color;
15 import java.awt.Dimension;
16 import java.awt.Graphics2D;
17 import java.awt.RenderingHints;
18 import java.awt.Stroke;
19 import java.awt.geom.AffineTransform;
20 import java.awt.geom.Path2D;
21 import java.awt.image.BufferedImage;
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.scilab.forge.scirenderer.implementation.g2d.texture.G2DTextureDrawingTools;
26 import org.scilab.forge.scirenderer.texture.Texture;
27 import org.scilab.forge.scirenderer.texture.AnchorPosition;
28 import org.scilab.forge.scirenderer.tranformations.Transformation;
29 import org.scilab.forge.scirenderer.tranformations.Vector3d;
30 import org.scilab.forge.scirenderer.tranformations.Vector4d;
31
32 /**
33  * @author Calixte DENIZET
34  */
35 public class SpritedRectangle extends ConvexObject {
36
37     private static final Color[] COLORS = new Color[] {Color.BLACK, Color.BLACK, Color.BLACK};
38
39     private Texture sprite;
40     private BufferedImage image;
41     private G2DTextureDrawingTools drawingTools;
42     private double rotationAngle;
43     private Texture.Filter filter;
44     private Vector3d position;
45     private Color fillColor;
46     private Color borderColor;
47
48     public SpritedRectangle(Vector3d vertex, Texture sprite, AnchorPosition anchor, G2DTextureDrawingTools drawingTools, double rotationAngle, Color borderColor, Color fillColor) throws InvalidPolygonException {
49         super(getSpriteVertices(vertex, sprite, anchor, rotationAngle), null);
50         this.sprite = sprite;
51         this.drawingTools = drawingTools;
52         this.rotationAngle = rotationAngle;
53         this.position = vertex;
54         this.fillColor = fillColor;
55         this.borderColor = borderColor;
56     }
57
58     public SpritedRectangle(Vector3d vertex, Transformation transf, BufferedImage image, Texture.Filter filter) throws InvalidPolygonException {
59         super(getSpriteVertices(vertex, transf, image), null);
60         this.image = image;
61         this.filter = filter;
62         this.position = vertex;
63     }
64
65     @Override
66     public List<ConvexObject> breakObject(ConvexObject o) {
67         if (o instanceof Triangle) {
68             return breakObject((Triangle) o);
69         } else if (o instanceof Segment) {
70             return breakObject((Segment) o);
71         } else if (o instanceof SpritedRectangle) {
72             return breakObject((SpritedRectangle) o);
73         }
74         return null;
75     }
76
77     public List<ConvexObject> breakObject(Triangle o) {
78         try {
79             Vector3d[] v1 = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
80             Vector3d[] v2 = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
81             Triangle t1 = new Triangle(v1, COLORS);
82             Triangle t2 = new Triangle(v2, COLORS);
83             t1.setSprite(this);
84             t2.setSprite(this);
85             List<ConvexObject> list = new ArrayList<ConvexObject>();
86             if (o.isBehind(t1) == 2) {
87                 List<ConvexObject> list2 = o.breakObject(t1);
88                 if (list2 != null) {
89                     list.addAll(list2);
90                 }
91             } else {
92                 list.add(t1);
93             }
94             if (o.isBehind(t2) == 2) {
95                 List<ConvexObject> list2 = o.breakObject(t2);
96                 if (list2 != null) {
97                     list.addAll(list2);
98                 }
99             } else {
100                 list.add(t2);
101             }
102
103             return list;
104         } catch (InvalidPolygonException e) { }
105
106         return null;
107     }
108
109     public List<ConvexObject> breakObject(Segment o) {
110         try {
111             Vector3d[] v = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
112             Triangle t1 = new Triangle(v, COLORS);
113             t1.setSprite(this);
114             v = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
115             Triangle t2 = new Triangle(v, COLORS);
116             t2.setSprite(this);
117             List<ConvexObject> list = t1.breakObject(o);
118             if (list != null) {
119                 list.add(t2);
120                 return list;
121             }
122
123             list = t2.breakObject(o);
124             if (list != null) {
125                 list.add(t1);
126                 return list;
127             }
128         } catch (InvalidPolygonException e) { }
129
130         return null;
131     }
132
133     public List<ConvexObject> breakObject(SpritedRectangle o) {
134         try {
135             Vector3d[] v1 = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
136             Vector3d[] v2 = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
137             Triangle t1 = new Triangle(v1, COLORS);
138             Triangle t2 = new Triangle(v2, COLORS);
139             t1.setSprite(this);
140             t2.setSprite(this);
141             List<ConvexObject> list = o.breakObject(t1);
142             if (list == null) {
143                 list = o.breakObject(t2);
144             } else {
145                 List<ConvexObject> list2 = o.breakObject(t2);
146                 if (list2 != null) {
147                     list.addAll(list2);
148                 }
149             }
150
151             return list;
152         } catch (InvalidPolygonException e) { }
153
154         return null;
155     }
156
157     public List<ConvexObject> breakObject(Vector4d v) {
158         try {
159             double[] vv = v.getData();
160             Vector3d np = new Vector3d(vv);
161             int ret = isBehind(np, vv[3]);
162             if (ret == 1) {
163                 List<ConvexObject> list = new ArrayList<ConvexObject>();
164                 list.add(this);
165                 return list;
166             } else if (ret == -1) {
167                 return null;
168             }
169
170             Vector3d[] v1 = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
171             Vector3d[] v2 = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
172             Triangle t1 = new Triangle(v1, COLORS);
173             Triangle t2 = new Triangle(v2, COLORS);
174             t1.setSprite(this);
175             t2.setSprite(this);
176             List<ConvexObject> list = t1.breakObject(v);
177             if (list != null) {
178                 List<ConvexObject> list2 = t2.breakObject(v);
179                 if (list2 != null) {
180                     list.addAll(list2);
181                 }
182                 return list;
183             } else {
184                 return t2.breakObject(v);
185             }
186         } catch (InvalidPolygonException e) { }
187
188         return null;
189     }
190
191     private static Vector3d[] getSpriteVertices(Vector3d vertex, Transformation transf, BufferedImage image) {
192         int w = image.getWidth();
193         int h = image.getHeight();
194         double x = vertex.getX();
195         double y = vertex.getY();
196         double z = vertex.getZ();
197
198         return new Vector3d[] {transf.project(new Vector3d(x, y, z)), transf.project(new Vector3d(x + w, y, z)), transf.project(new Vector3d(x + w, y + h, z)), transf.project(new Vector3d(x, y + h, z))};
199     }
200
201     private static Vector3d[] getSpriteVertices(Vector3d vertex, Texture sprite, AnchorPosition anchor) {
202         Dimension d = sprite.getDataProvider().getTextureSize();
203         double spriteWidth = d.getWidth();
204         double spriteHeight = d.getHeight();
205         double deltaX = 0;
206         double deltaY = 0;
207
208         switch (anchor) {
209             case LEFT:
210                 deltaX = spriteWidth / 2;
211                 break;
212             case LOWER_LEFT:
213                 deltaX = spriteWidth / 2;
214                 deltaY = spriteHeight / 2;
215                 break;
216             case UPPER_LEFT:
217                 deltaX = spriteWidth / 2;
218                 deltaY = -spriteHeight / 2;
219                 break;
220             case UP:
221                 deltaY = -spriteHeight / 2;
222                 break;
223             case CENTER:
224                 break;
225             case DOWN:
226                 deltaY = spriteHeight / 2;
227                 break;
228             case RIGHT:
229                 deltaX = -spriteWidth / 2;
230                 break;
231             case LOWER_RIGHT:
232                 deltaX = -spriteWidth / 2;
233                 deltaY = spriteHeight / 2;
234                 break;
235             case UPPER_RIGHT:
236                 deltaX = -spriteWidth / 2;
237                 deltaY = -spriteHeight / 2;
238                 break;
239             default:
240         }
241
242         double x = deltaX;
243         double y = -deltaY;
244         double z = vertex.getZ();
245
246         return new Vector3d[] {new Vector3d(x - spriteWidth / 2, y - spriteHeight / 2, z),
247                    new Vector3d(x - spriteWidth / 2, y + spriteHeight / 2, z),
248                    new Vector3d(x + spriteWidth / 2, y + spriteHeight / 2, z),
249                    new Vector3d(x + spriteWidth / 2, y - spriteHeight / 2, z)
250         };
251     }
252
253     private static Vector3d[] getSpriteVertices(Vector3d vertex, Texture sprite, AnchorPosition anchor, double rotationAngle) {
254         Vector3d[] points = getSpriteVertices(vertex, sprite, anchor);
255
256         if (rotationAngle != 0) {
257             final double a = -rotationAngle * Math.PI / 180;
258             final double ca = Math.cos(a);
259             final double sa = Math.sin(a);
260
261             for (int i = 0; i < 4; i++) {
262                 points[i] = new Vector3d(vertex.getX() + ca * points[i].getX() - sa * points[i].getY(), vertex.getY() + sa * points[i].getX() + ca * points[i].getY(), vertex.getZ());
263             }
264         } else {
265             for (int i = 0; i < 4; i++) {
266                 points[i] = new Vector3d(vertex.getX() + points[i].getX(), vertex.getY() + points[i].getY(), vertex.getZ());
267             }
268         }
269
270         return points;
271     }
272
273     private static Vector3d unrotate(Vector3d v, Vector3d t, double rotationAngle) {
274         v = v.minus(t);
275         final double a = rotationAngle * Math.PI / 180;
276         final double ca = Math.cos(a);
277         final double sa = Math.sin(a);
278
279         return new Vector3d(ca * v.getX() - sa * v.getY(), sa * v.getX() + ca * v.getY(), v.getZ());
280     }
281
282     public Texture getSprite() {
283         return sprite;
284     }
285
286     @Override
287     public void draw(Graphics2D g2d) {
288         if (sprite != null) {
289             Path2D contour = getProjectedContour();
290             AffineTransform oldTransf = g2d.getTransform();
291             Stroke oldStroke = g2d.getStroke();
292
293             if (rotationAngle != 0) {
294                 g2d.translate(position.getX(), position.getY());
295                 g2d.rotate(-rotationAngle * Math.PI / 180);
296                 Vector3d v = unrotate(vertices[0], position, rotationAngle);
297                 g2d.translate(v.getX(), v.getY());
298             } else {
299                 g2d.translate(vertices[0].getX(), vertices[0].getY());
300             }
301
302             drawingTools.accept(sprite, borderColor, fillColor);
303             g2d.setTransform(oldTransf);
304             g2d.setStroke(oldStroke);
305         } else {
306             Object key = filter == Texture.Filter.LINEAR ? RenderingHints.VALUE_INTERPOLATION_BILINEAR : RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
307             DrawTools.drawParallelogramTexture(g2d, image, new double[] {0, 1, 1, 0}, new double[] {0, 0, 1, 1},
308                                                new double[] {vertices[3].getX(), vertices[2].getX(), vertices[1].getX(), vertices[0].getX()},
309                                                new double[] {vertices[3].getY(), vertices[2].getY(), vertices[1].getY(), vertices[0].getY()}, key);
310         }
311     }
312
313     public String toString() {
314         return "SpritedRectangle: " + vertices[0].toString() + " " + vertices[1].toString() + " " + vertices[2].toString() + " " + vertices[3].toString() + "\nPrecedence: " + precedence;
315     }
316 }