]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/elementclass/operationsymbols/OperationSymbols.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / elementclass / operationsymbols / OperationSymbols.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.g2d.elementclass.operationsymbols;
13
14 import java.awt.BasicStroke;
15 import java.awt.Color;
16 import java.awt.Font;
17 import java.awt.Graphics2D;
18 import java.awt.Polygon;
19 import java.awt.Shape;
20 import java.awt.Stroke;
21 import java.awt.geom.Ellipse2D;
22 import java.awt.geom.Path2D;
23 import java.awt.geom.Rectangle2D;
24 import java.util.EnumSet;
25
26 import org.simantics.g2d.image.Image;
27 import org.simantics.g2d.image.impl.Shadow;
28 import org.simantics.g2d.image.impl.Shadow.ShadowParameters;
29 import org.simantics.g2d.utils.GeometryUtils;
30 import org.simantics.g2d.utils.PathUtils;
31 import org.simantics.scenegraph.Node;
32 import org.simantics.scenegraph.g2d.G2DParentNode;
33 import org.simantics.utils.ObjectUtils;
34
35 /**
36  * @author Toni Kalajainen
37  */
38 public class OperationSymbols {
39
40     static final double SHADOW_SIZE = 100;
41     static final Color BORDER_COLOR = Color.GRAY;
42     static final Color FILL_COLOR = Color.GRAY;
43     static final Color SECONDARY_COLOR = Color.GREEN;
44     static final ShadowParameters SHADOW = new ShadowParameters(0.5, Color.BLACK, 2);
45
46     static final Color HOT = new Color(50, 50, 200);
47     static final Color COLD = new Color(190, 190, 255);
48
49     public static final BoilerHeatExchanger[] BOILER_HES = new BoilerHeatExchanger[] {
50         new BoilerHeatExchanger(null, HOT, HOT, null, HOT),
51         new BoilerHeatExchanger(HOT, null, COLD, COLD, HOT),
52         new BoilerHeatExchanger(HOT, null, COLD, null, HOT),
53         new BoilerHeatExchanger(HOT, null, null, HOT, HOT)
54     };
55
56     public static final Image BOILER_SYMBOL = new BoilerSymbol2(FILL_COLOR, FILL_COLOR, BOILER_HES);
57     public static final Image BOILER_SHADOW = new Shadow(BOILER_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
58
59     public static final Image COMPRESSOR_SYMBOL = new CompressorSymbol(FILL_COLOR, BORDER_COLOR);
60     public static final Image COMPRESSOR_SHADOW = new Shadow(COMPRESSOR_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
61
62     public static final Image NO_SPIN_SYMBOL = new NoSpinSymbol(FILL_COLOR, BORDER_COLOR);
63     public static final Image NO_SPIN_SHADOW = new Shadow(NO_SPIN_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
64
65     public static final Image CONTROLVALVE_SYMBOL = new ControlValveSymbol(BORDER_COLOR, FILL_COLOR);
66     public static final Image CONTROLVALVE_SHADOW = new Shadow(CONTROLVALVE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
67
68     public static final Image THREEWAYVALVE_SYMBOL = new ThreeWayValveSymbol(BORDER_COLOR, FILL_COLOR);
69     public static final Image THREEWAYVALVE_SHADOW = new Shadow(THREEWAYVALVE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
70
71     public static final Image HEATEXCHANGER_SYMBOL = new HeatExchangerSymbol(BORDER_COLOR, FILL_COLOR);
72     public static final Image HEATEXCHANGER_SHADOW = new Shadow(HEATEXCHANGER_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
73
74     public static final Image PUMP_SYMBOL = new PumpSymbol(BORDER_COLOR, FILL_COLOR);
75     public static final Image PUMP_SHADOW = new Shadow(PUMP_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
76
77     public static final Image SHUTOFFVALVE_SYMBOL = new ShutoffValveSymbol(BORDER_COLOR, FILL_COLOR);
78     public static final Image SHUTOFFVALVE_SHADOW = new Shadow(SHUTOFFVALVE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
79
80     public static final Image SWITCH_SYMBOL = new SwitchSymbol(BORDER_COLOR);
81     public static final Image SWITCH_SHADOW = new Shadow(SWITCH_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
82
83     public static final Image TURBINE_SYMBOL = new TurbineSymbol(BORDER_COLOR, FILL_COLOR);
84     public static final Image TURBINE_SHADOW = new Shadow(TURBINE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
85
86     public static final Image VOLTAGETRANSFORMER_SYMBOL = new VoltageTransformerSymbol(SECONDARY_COLOR, BORDER_COLOR);
87     public static final Image VOLTAGETRANSFORMER_SHADOW = new Shadow(VOLTAGETRANSFORMER_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
88
89     public static final Image CHIMNEY_SYMBOL = new ChimneySymbol(SECONDARY_COLOR, BORDER_COLOR);
90     public static final Image CHIMNEY_SHADOW = new Shadow(CHIMNEY_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
91
92     public static final Image GENERATOR_SYMBOL = new GeneratorSymbol(SECONDARY_COLOR, BORDER_COLOR);
93     public static final Image GENERATOR_SHADOW = new Shadow(GENERATOR_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
94
95     public static final Image TANK_SYMBOL = new TankSymbol(new Rectangle2D.Double(0,0, 20.0, 8.0), 2.0, SECONDARY_COLOR, BORDER_COLOR);
96     public static final Image TANK_SHADOW = new Shadow(TANK_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
97
98     public static final Image TANK2_SYMBOL = new Tank2Symbol(new Rectangle2D.Double(0,0, 20.0, 8.0), 2.0, SECONDARY_COLOR, BORDER_COLOR, HOT);
99     public static final Image TANK2_SHADOW = new Shadow(TANK2_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
100
101     public static class BoilerSymbol extends PS implements Image {
102         public static final int DIM = 10;
103         public static final Polygon SHAPE =
104             new Polygon(new int[] {-DIM, -DIM, 0, DIM, DIM, 0}, new int[] {2*DIM, -2*DIM, -3*DIM, -2*DIM, 2*DIM, 3*DIM}, 6);
105         public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
106
107         public BoilerSymbol(Color bc, Color fc) {
108             super(SHAPE.getBounds2D(), bc, fc, null, null);
109         }
110         @Override
111         public void paint(Graphics2D g) {
112 //                      if (fc!=null) {
113 //                              g.setColor(fc);
114 //                              g.fill(SHAPE);
115 //                      }
116 //                      if (bc!=null) {
117 //                              g.setColor(bc);
118 //                              g.draw(SHAPE);
119 //                      }
120         }
121     }
122
123     public static class BoilerHeatExchanger {
124         public final Color color;
125         public final Color topLeft, topRight, bottomLeft, bottomRight;
126         public BoilerHeatExchanger(Color topLeft, Color topRight,
127                 Color bottomLeft, Color bottomRight,
128                 Color color) {
129             this.bottomLeft = bottomLeft;
130             this.bottomRight = bottomRight;
131             this.color = color;
132             this.topLeft = topLeft;
133             this.topRight = topRight;
134         }
135     }
136
137     public static class BoilerSymbol2 extends PS implements Image {
138
139         public static Path2D HE = PathUtils.path(10,0, 0,0, 0,5, 5,10, -5,10, 0,15, 0,20);
140
141         public static Rectangle2D getBoilerRect(BoilerHeatExchanger ... hes)
142         {
143             return new Rectangle2D.Double(-10, 0, 20, hes.length*25+25);
144         }
145
146         public static Shape getBoilerShape(BoilerHeatExchanger ... hes)
147         {
148             Path2D p = new Path2D.Double();
149             p.moveTo(-10, 10);
150             p.lineTo(  0,  0);
151             p.lineTo( 10, 10);
152             double h = hes.length * 25;
153             p.lineTo( 10, h+15);
154             p.lineTo(  0, h+25);
155             p.lineTo(-10, h+15);
156             p.closePath();
157             return p;
158         }
159
160         private final Shape shape;
161         private final BoilerHeatExchanger [] hes;
162
163         public BoilerSymbol2(Color fc, Color bc, BoilerHeatExchanger ... hes) {
164             super( getBoilerRect(hes), bc, fc, null, null);
165             shape = getBoilerShape(hes);
166             this.hes = hes;
167         }
168
169         @Override
170         public void paint(Graphics2D g) {
171             if (fc!=null) {
172                 g.setColor(fc);
173                 g.fill(shape);
174             }
175             if (bc!=null) {
176                 g.setColor(bc);
177                 g.draw(shape);
178             }
179             // paint heat exchangers
180             g.translate(0, 15);
181             for (BoilerHeatExchanger he : hes)
182             {
183                 g.setColor(he.color);
184                 g.draw(HE);
185                 if (he.topLeft!=null) {
186                     g.setColor(he.topLeft);
187                     g.drawLine(-10, 0, 0, 0);
188                 }
189                 if (he.topRight!=null) {
190                     g.setColor(he.topRight);
191                     g.drawLine(0, 0, 10, 0);
192                 }
193                 if (he.bottomLeft!=null) {
194                     g.setColor(he.bottomLeft);
195                     g.drawLine(-10, 20, 0, 20);
196                 }
197                 if (he.bottomRight!=null) {
198                     g.setColor(he.bottomRight);
199                     g.drawLine(0, 20, 10, 20);
200                 }
201                 g.translate(0, 25);
202             }
203         }
204     }
205
206     public static class ChimneySymbol extends PS implements Image {
207
208         public static final int DIM = 10;
209         public static final int D2 = 8;
210         public static final Shape C1 = new Ellipse2D.Double(-DIM, -DIM, DIM*2, DIM*2);
211         public static final Shape C2 = new Ellipse2D.Double(-D2, -D2, D2*2, D2*2);
212
213         public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-10, -10, 20, 40);
214
215         public ChimneySymbol(Color fc, Color bc) {
216             super( BOUNDS, bc, fc, null, null);
217             assert(bc!=null);
218         }
219
220         @Override
221         public void paint(Graphics2D g) {
222             g.setColor(fc);
223             g.fill(C2);
224             g.fillRect(-5, 14, 10, 8);
225             g.setColor(bc);
226             g.draw(C1);
227             g.draw(C2);
228
229             g.drawLine(0, DIM, 0, 15);
230             g.drawRect(-5, 14, 10, 8);
231             g.drawLine(-5, 14, 5, 22);
232         }
233     }
234
235
236     public static class GeneratorSymbol extends PS implements Image {
237
238         public static final int DIM = 10;
239         public static final Shape C1 = new Ellipse2D.Double(-DIM, -DIM, DIM*2, DIM*2);
240
241         public static final Rectangle2D BOUNDS = C1.getBounds2D();
242         private final static Font FONT = Font.decode("Serif-12");
243
244         public GeneratorSymbol(Color fc, Color bc) {
245             super( BOUNDS, bc, fc, null, null);
246             assert(bc!=null && fc!=null);
247         }
248
249         @Override
250         public void paint(Graphics2D g) {
251             g.setColor(fc);
252             g.fill(C1);
253             g.setColor(bc);
254             g.draw(C1);
255             g.setFont(FONT);
256             g.drawString("G", -4, 4);
257         }
258     }
259
260     public static class NoSpinSymbol extends PS {
261         public NoSpinSymbol(Color fc, Color bc) {
262             super(BOUNDS, bc, fc, null, null);
263         }
264         public static final Stroke STROKE = new BasicStroke(1.5f);
265         public static final int DIM = 10;
266         public static final int D2 = 8;
267         public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-DIM, -DIM, 2*DIM, 2*DIM);
268         public static final Shape CIRCLE = new Ellipse2D.Double(-D2, -D2, D2*2, D2*2);
269
270         @Override
271         public void paint(Graphics2D g) {
272             g.setStroke(STROKE);
273             g.setColor(fc);
274             g.fillRect(-DIM, -DIM, DIM*2, DIM*2);
275             g.setColor(bc);
276             g.drawRect(-DIM, -DIM, DIM*2, DIM*2);
277             g.draw(CIRCLE);
278             g.drawLine(-DIM/3, -DIM/3, DIM/3, DIM/3);
279             g.drawLine(DIM/3, -DIM/3, -DIM/3, DIM/3);
280         }
281     }
282
283     public static class ControlValveSymbol extends PS implements Image {
284
285         public static final Stroke STROKE = new BasicStroke(1.5f);
286         public static final int D = 10;
287         public static final Path2D SHAPE =
288             PathUtils.closedPath(-D,-D, -D,D, D,-D, D,D );
289         public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
290
291         public ControlValveSymbol(Color bc, Color fc) {
292             super(BOUNDS, bc, fc, null, null);
293         }
294         @Override
295         public void paint(Graphics2D g) {
296             if (fc!=null) {
297                 g.setColor(fc);
298                 g.fill(SHAPE);
299             }
300             if (bc!=null) {
301                 g.setColor(bc);
302                 g.draw(SHAPE);
303             }
304         }
305     }
306
307     public static class ThreeWayValveSymbol extends PS implements Image {
308
309         public static final Stroke STROKE = new BasicStroke(1.5f);
310         public static final int D = 10;
311         public static final Path2D SHAPE =
312             PathUtils.closedPath(-D,D*2/3, -D,-D*2/3, 0,0, -D*2/3,-D, D*2/3,-D, 0,0, D,D*2/3, D,-D*2/3, 0,0 );
313         public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
314
315         public ThreeWayValveSymbol(Color bc, Color fc) {
316             super(BOUNDS, bc, fc, null, null);
317         }
318         @Override
319         public void paint(Graphics2D g) {
320             if (fc!=null) {
321                 g.setColor(fc);
322                 g.fill(SHAPE);
323             }
324             if (bc!=null) {
325                 g.setColor(bc);
326                 g.draw(SHAPE);
327             }
328         }
329     }
330
331
332     public static class HeatExchangerSymbol extends PS {
333
334         public HeatExchangerSymbol(Color bc, Color fc) {
335             super(BOUNDS, bc, fc, null, null);
336         }
337         public static final Stroke STROKE = new BasicStroke(1.5f);
338         public static final int D = 10;
339         public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-D, -D, 2*D, 2*D);
340         public static final int xPoints[] = new int [] {-D, 0, 0, -D/2, D/2, 0, 0, D};
341         public static final int yPoints[] = new int [] {D/2, D/2, D/8, 0, 0, -D/8, -D/2, -D/2};
342
343         @Override
344         public void paint(Graphics2D g) {
345             g.setColor(fc);
346             g.fill(BOUNDS);
347             g.setColor(bc);
348             g.draw(BOUNDS);
349             g.setStroke(STROKE);
350             g.drawPolyline(xPoints, yPoints, xPoints.length);
351         }
352     }
353
354     public static class PumpSymbol extends PS {
355
356         public PumpSymbol(Color bc, Color fc) {
357             super(BOUNDS, bc, fc, null, null);
358         }
359         public static final Stroke STROKE = new BasicStroke(1.5f);
360         public static final int DIM = 10;
361         public static final int D2 = 12;
362         public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-D2, -D2, 2*D2, 2*D2);
363         public static final Shape CIRCLE = new Ellipse2D.Double(-D2, -D2, D2*2, D2*2);
364         public static final Polygon SHAPE =
365             new Polygon(new int[] {-DIM, -DIM, 0, 0, DIM, 0, 0}, new int[] {DIM/4, -DIM/4, -DIM/4, -DIM, 0, DIM, DIM/4}, 7);
366
367         @Override
368         public void paint(Graphics2D g) {
369             g.setColor(fc);
370             g.fill(CIRCLE);
371             g.setColor(bc);
372             g.setStroke( STROKE );
373             g.draw(CIRCLE);
374             g.draw(SHAPE);
375         }
376     }
377
378
379     public static class ShutoffValveSymbol extends PS implements Image {
380
381         public static final Stroke STROKE = new BasicStroke(1.5f);
382         public static final int DIM = 10;
383         public static final Path2D SHAPE =
384             PathUtils.closedPath(-DIM,-DIM, -DIM,DIM, DIM,-DIM, DIM,DIM );
385         public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
386
387         public ShutoffValveSymbol(Color bc, Color fc) {
388             super(BOUNDS, bc, fc, null, null);
389         }
390         @Override
391         public void paint(Graphics2D g) {
392             if (fc!=null) {
393                 g.setColor(fc);
394                 g.fill(SHAPE);
395             }
396             if (bc!=null) {
397                 g.setColor(bc);
398                 g.draw(SHAPE);
399                 g.drawLine(0, -DIM, 0, DIM);
400             }
401         }
402     }
403
404
405     public static class SwitchSymbol extends PS {
406
407         public SwitchSymbol(Color bc) {
408             super(BOUNDS, bc, null, null, null);
409         }
410         public static final Stroke STROKE = new BasicStroke(1.5f);
411         public static final int D = 10;
412         public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-D, -D, 2*D, 2*D);
413
414         @Override
415         public void paint(Graphics2D g) {
416             g.setColor(bc);
417             g.setStroke(STROKE);
418
419             g.drawLine(0, -D, 0, D);
420             g.drawLine(-D/4, -D/2, D/4, -D/2);
421             g.drawLine(-D, 0, D, 0);
422             g.drawLine(-D/4, D/2, D/4, D/2);
423         }
424     }
425
426
427     public static class TurbineSymbol extends PS implements Image {
428
429         public static final int DIM = 10;
430         public static final Polygon SHAPE =
431             new Polygon(new int[] {-DIM, -DIM, DIM, DIM}, new int[] {-DIM, DIM, DIM*2, -DIM*2}, 4);
432         public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
433
434         public TurbineSymbol(Color bc, Color fc) {
435             super(BOUNDS, bc, fc, null, null);
436         }
437         @Override
438         public void paint(Graphics2D g) {
439             if (fc!=null) {
440                 g.setColor(fc);
441                 g.fill(SHAPE);
442             }
443             if (bc!=null) {
444                 g.setColor(bc);
445                 g.draw(SHAPE);
446             }
447         }
448     }
449
450     public static class CompressorSymbol extends PS implements Image {
451
452         public static final int DIM = 10;
453         public static final Polygon SHAPE =
454             new Polygon(new int[] {DIM, DIM, -DIM, -DIM}, new int[] {-DIM, DIM, DIM*2, -DIM*2}, 4);
455         public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
456
457         public CompressorSymbol(Color bc, Color fc) {
458             super(BOUNDS, bc, fc, null, null);
459         }
460         @Override
461         public void paint(Graphics2D g) {
462             if (fc!=null) {
463                 g.setColor(fc);
464                 g.fill(SHAPE);
465             }
466             if (bc!=null) {
467                 g.setColor(bc);
468                 g.draw(SHAPE);
469             }
470         }
471     }
472
473     public static class VoltageTransformerSymbol extends PS implements Image {
474
475         public static final Stroke STROKE = new BasicStroke(1.5f);
476         public static final int DIM = 10;
477         public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-DIM, -DIM*1.7, 2*DIM, 2*DIM*1.7);
478         public static final Shape CIRCLE = new Ellipse2D.Double(-DIM, -DIM, DIM*2, DIM*2);
479
480         public VoltageTransformerSymbol(Color c1, Color c2) {
481             super(BOUNDS, null, null, c1, c2);
482         }
483         @Override
484         public void paint(Graphics2D g) {
485             g.setStroke(STROKE);
486             Graphics2D sg = (Graphics2D) g.create();
487
488             sg.clipRect(-DIM*2, -DIM*2, DIM*4, DIM*2);
489             sg.setColor(c1);
490             sg.translate(0, -0.7*DIM);
491             sg.draw(CIRCLE);
492             sg.setColor(c2);
493             sg.translate(0, 1.4*DIM);
494             sg.draw(CIRCLE);
495             sg.dispose();
496
497             g.clipRect(-DIM*2, 0, DIM*4, DIM*2);
498             g.setColor(c2);
499             g.translate(0, 0.7*DIM);
500             g.draw(CIRCLE);
501             g.setColor(c1);
502             g.translate(0, -1.4*DIM);
503             g.draw(CIRCLE);
504         }
505     }
506
507     public static class TankSymbol extends PS implements Image {
508
509         /**
510          * Create tank shape.
511          * @param r rectangle
512          * @param cap cap size
513          * @return tank shape
514          */
515         public static Path2D createTankShape(Rectangle2D r, double cap)
516         {
517             double x1 = r.getMinX();
518             double y1 = r.getMinY();
519             double x2 = r.getMaxX();
520             double y2 = r.getMaxY();
521             Path2D p = new Path2D.Double();
522             p.moveTo(x1+cap, y1);
523             p.lineTo(x2-cap, y1);
524             p.quadTo(x2,y1, x2,y1+cap);
525             p.lineTo(x2, y2-cap);
526             p.quadTo(x2, y2, x2-cap, y2);
527             p.lineTo(x1+cap, y2);
528             p.quadTo(x1, y2, x1, y2-cap);
529             p.lineTo(x1, y1+cap);
530             p.quadTo(x1, y1, x1+cap, y1);
531             return p;
532         }
533
534         Path2D shape;
535
536         public TankSymbol(Rectangle2D rect, double cap, Color bc, Color fc) {
537             super(rect, bc, fc, null, null);
538             shape = createTankShape(rect, cap);
539         }
540
541         @Override
542         public void paint(Graphics2D g) {
543             g.setColor(fc);
544             g.setStroke(GeometryUtils.BASIC_STROKE);
545             g.fill(shape);
546             if (bc!=null) {
547                 g.setColor(bc);
548                 g.draw(shape);
549             }
550         }
551
552     }
553
554     public static class Tank2Symbol extends PS implements Image {
555
556         public static Path2D createWShape()
557         {
558             Path2D p = new Path2D.Double();
559             double k = Math.sqrt(2);
560             p.moveTo(-1, -1);
561             p.quadTo(0, -k, 1, -1);
562             p.quadTo(k, 0, 1, 1);
563             p.quadTo(0, k, -1, 1);
564             p.quadTo(-k, 0, -1, -1);
565             p.lineTo(-1, 1);
566             p.lineTo(0,0);
567             p.lineTo(1, 1);
568             p.lineTo(1, -1);
569             return p;
570         }
571
572         Path2D shape;
573         Path2D shape2;
574
575         public Tank2Symbol(Rectangle2D rect, double cap, Color bc, Color fc, Color a1) {
576             super(rect, bc, fc, a1, null);
577             shape = TankSymbol.createTankShape(rect, cap);
578             shape2 = createWShape();
579         }
580
581         @Override
582         public void paint(Graphics2D g) {
583             g.setColor(fc);
584             g.setStroke(GeometryUtils.BASIC_STROKE);
585             g.setStroke(new BasicStroke(0.3f));
586             g.fill(shape);
587             if (bc!=null) {
588                 g.setColor(bc);
589                 g.draw(shape);
590             }
591             g.setColor(c1);
592             double d = Math.min(bounds.getHeight(), bounds.getWidth());
593             g.translate(bounds.getMinX()+d/2, bounds.getMinY()+d/2);
594             g.scale(d/3, d/3);
595             g.draw(shape2);
596         }
597
598     }
599
600     private abstract static class PS implements Image {
601
602
603         public final Rectangle2D bounds;
604         public final Color c1;
605         public final Color c2;
606         public final Color bc;
607         public final Color fc;
608         private final int hash;
609         public PS(Rectangle2D bounds, Color bc, Color fc, Color c1, Color c2) {
610             this.bounds = bounds;
611             this.bc = bc;
612             this.fc = fc;
613             this.c1 = c1;
614             this.c2 = c2;
615             int hash = this.getClass().hashCode();
616             if (bc!=null) hash += 3 * bc.hashCode();
617             if (fc!=null) hash += 5 * fc.hashCode();
618             if (c1!=null) hash += 7 * c1.hashCode();
619             if (c2!=null) hash += 11 * c2.hashCode();
620             this.hash = hash;
621         }
622
623         @Override
624         public int hashCode() {
625             return hash;
626         }
627
628         @Override
629         public boolean equals(Object obj) {
630             if (!obj.getClass().equals(getClass()))return false;
631             PS other = (PS) obj;
632             return
633             ObjectUtils.objectEquals(other.c1, c1) &&
634             ObjectUtils.objectEquals(other.c2, c2) &&
635             ObjectUtils.objectEquals(other.fc, fc) &&
636             ObjectUtils.objectEquals(other.bc, bc);
637         }
638         @Override
639         public Rectangle2D getBounds() {
640             return bounds;
641         }
642
643         @Override
644         public Shape getOutline() {
645             return bounds;
646         }
647
648         @Override
649         public Node init(G2DParentNode g) {
650 //                      return init(g);
651             return null;
652         }
653
654         public void paint(Graphics2D g2d) { // FIXME: get rid of this
655
656         }
657
658         @Override
659         public void addImageListener(ImageListener listener) {
660         }
661
662         static EnumSet<Feature> caps = EnumSet.of(Feature.Vector);
663         @Override
664         public EnumSet<Feature> getFeatures() {
665             return caps;
666         }
667
668         @Override
669         public void removeImageListener(ImageListener listener) {
670         }
671
672     }
673
674 }