]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
index b057ef9f51ee06d23c2a6ad8e4731fbd04ba6eda..db8d6350e454f50d35f459918aa6c0f36820cd88 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.g2d.elementclass.operationsymbols;\r
-\r
-import java.awt.BasicStroke;\r
-import java.awt.Color;\r
-import java.awt.Font;\r
-import java.awt.Graphics2D;\r
-import java.awt.Polygon;\r
-import java.awt.Shape;\r
-import java.awt.Stroke;\r
-import java.awt.geom.Ellipse2D;\r
-import java.awt.geom.Path2D;\r
-import java.awt.geom.Rectangle2D;\r
-import java.util.EnumSet;\r
-\r
-import org.simantics.g2d.image.Image;\r
-import org.simantics.g2d.image.impl.Shadow;\r
-import org.simantics.g2d.image.impl.Shadow.ShadowParameters;\r
-import org.simantics.g2d.utils.GeometryUtils;\r
-import org.simantics.g2d.utils.PathUtils;\r
-import org.simantics.scenegraph.Node;\r
-import org.simantics.scenegraph.g2d.G2DParentNode;\r
-import org.simantics.utils.ObjectUtils;\r
-\r
-/**\r
- * @author Toni Kalajainen\r
- */\r
-public class OperationSymbols {\r
-\r
-    static final double SHADOW_SIZE = 100;\r
-    static final Color BORDER_COLOR = Color.GRAY;\r
-    static final Color FILL_COLOR = Color.GRAY;\r
-    static final Color SECONDARY_COLOR = Color.GREEN;\r
-    static final ShadowParameters SHADOW = new ShadowParameters(0.5, Color.BLACK, 2);\r
-\r
-    static final Color HOT = new Color(50, 50, 200);\r
-    static final Color COLD = new Color(190, 190, 255);\r
-\r
-    public static final BoilerHeatExchanger[] BOILER_HES = new BoilerHeatExchanger[] {\r
-        new BoilerHeatExchanger(null, HOT, HOT, null, HOT),\r
-        new BoilerHeatExchanger(HOT, null, COLD, COLD, HOT),\r
-        new BoilerHeatExchanger(HOT, null, COLD, null, HOT),\r
-        new BoilerHeatExchanger(HOT, null, null, HOT, HOT)\r
-    };\r
-\r
-    public static final Image BOILER_SYMBOL = new BoilerSymbol2(FILL_COLOR, FILL_COLOR, BOILER_HES);\r
-    public static final Image BOILER_SHADOW = new Shadow(BOILER_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image COMPRESSOR_SYMBOL = new CompressorSymbol(FILL_COLOR, BORDER_COLOR);\r
-    public static final Image COMPRESSOR_SHADOW = new Shadow(COMPRESSOR_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image NO_SPIN_SYMBOL = new NoSpinSymbol(FILL_COLOR, BORDER_COLOR);\r
-    public static final Image NO_SPIN_SHADOW = new Shadow(NO_SPIN_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image CONTROLVALVE_SYMBOL = new ControlValveSymbol(BORDER_COLOR, FILL_COLOR);\r
-    public static final Image CONTROLVALVE_SHADOW = new Shadow(CONTROLVALVE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image THREEWAYVALVE_SYMBOL = new ThreeWayValveSymbol(BORDER_COLOR, FILL_COLOR);\r
-    public static final Image THREEWAYVALVE_SHADOW = new Shadow(THREEWAYVALVE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image HEATEXCHANGER_SYMBOL = new HeatExchangerSymbol(BORDER_COLOR, FILL_COLOR);\r
-    public static final Image HEATEXCHANGER_SHADOW = new Shadow(HEATEXCHANGER_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image PUMP_SYMBOL = new PumpSymbol(BORDER_COLOR, FILL_COLOR);\r
-    public static final Image PUMP_SHADOW = new Shadow(PUMP_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image SHUTOFFVALVE_SYMBOL = new ShutoffValveSymbol(BORDER_COLOR, FILL_COLOR);\r
-    public static final Image SHUTOFFVALVE_SHADOW = new Shadow(SHUTOFFVALVE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image SWITCH_SYMBOL = new SwitchSymbol(BORDER_COLOR);\r
-    public static final Image SWITCH_SHADOW = new Shadow(SWITCH_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image TURBINE_SYMBOL = new TurbineSymbol(BORDER_COLOR, FILL_COLOR);\r
-    public static final Image TURBINE_SHADOW = new Shadow(TURBINE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image VOLTAGETRANSFORMER_SYMBOL = new VoltageTransformerSymbol(SECONDARY_COLOR, BORDER_COLOR);\r
-    public static final Image VOLTAGETRANSFORMER_SHADOW = new Shadow(VOLTAGETRANSFORMER_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image CHIMNEY_SYMBOL = new ChimneySymbol(SECONDARY_COLOR, BORDER_COLOR);\r
-    public static final Image CHIMNEY_SHADOW = new Shadow(CHIMNEY_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image GENERATOR_SYMBOL = new GeneratorSymbol(SECONDARY_COLOR, BORDER_COLOR);\r
-    public static final Image GENERATOR_SHADOW = new Shadow(GENERATOR_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image TANK_SYMBOL = new TankSymbol(new Rectangle2D.Double(0,0, 20.0, 8.0), 2.0, SECONDARY_COLOR, BORDER_COLOR);\r
-    public static final Image TANK_SHADOW = new Shadow(TANK_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static final Image TANK2_SYMBOL = new Tank2Symbol(new Rectangle2D.Double(0,0, 20.0, 8.0), 2.0, SECONDARY_COLOR, BORDER_COLOR, HOT);\r
-    public static final Image TANK2_SHADOW = new Shadow(TANK2_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);\r
-\r
-    public static class BoilerSymbol extends PS implements Image {\r
-        public static final int DIM = 10;\r
-        public static final Polygon SHAPE =\r
-            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);\r
-        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();\r
-\r
-        public BoilerSymbol(Color bc, Color fc) {\r
-            super(SHAPE.getBounds2D(), bc, fc, null, null);\r
-        }\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-//                     if (fc!=null) {\r
-//                             g.setColor(fc);\r
-//                             g.fill(SHAPE);\r
-//                     }\r
-//                     if (bc!=null) {\r
-//                             g.setColor(bc);\r
-//                             g.draw(SHAPE);\r
-//                     }\r
-        }\r
-    }\r
-\r
-    public static class BoilerHeatExchanger {\r
-        public final Color color;\r
-        public final Color topLeft, topRight, bottomLeft, bottomRight;\r
-        public BoilerHeatExchanger(Color topLeft, Color topRight,\r
-                Color bottomLeft, Color bottomRight,\r
-                Color color) {\r
-            this.bottomLeft = bottomLeft;\r
-            this.bottomRight = bottomRight;\r
-            this.color = color;\r
-            this.topLeft = topLeft;\r
-            this.topRight = topRight;\r
-        }\r
-    }\r
-\r
-    public static class BoilerSymbol2 extends PS implements Image {\r
-\r
-        public static Path2D HE = PathUtils.path(10,0, 0,0, 0,5, 5,10, -5,10, 0,15, 0,20);\r
-\r
-        public static Rectangle2D getBoilerRect(BoilerHeatExchanger ... hes)\r
-        {\r
-            return new Rectangle2D.Double(-10, 0, 20, hes.length*25+25);\r
-        }\r
-\r
-        public static Shape getBoilerShape(BoilerHeatExchanger ... hes)\r
-        {\r
-            Path2D p = new Path2D.Double();\r
-            p.moveTo(-10, 10);\r
-            p.lineTo(  0,  0);\r
-            p.lineTo( 10, 10);\r
-            double h = hes.length * 25;\r
-            p.lineTo( 10, h+15);\r
-            p.lineTo(  0, h+25);\r
-            p.lineTo(-10, h+15);\r
-            p.closePath();\r
-            return p;\r
-        }\r
-\r
-        private final Shape shape;\r
-        private final BoilerHeatExchanger [] hes;\r
-\r
-        public BoilerSymbol2(Color fc, Color bc, BoilerHeatExchanger ... hes) {\r
-            super( getBoilerRect(hes), bc, fc, null, null);\r
-            shape = getBoilerShape(hes);\r
-            this.hes = hes;\r
-        }\r
-\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            if (fc!=null) {\r
-                g.setColor(fc);\r
-                g.fill(shape);\r
-            }\r
-            if (bc!=null) {\r
-                g.setColor(bc);\r
-                g.draw(shape);\r
-            }\r
-            // paint heat exchangers\r
-            g.translate(0, 15);\r
-            for (BoilerHeatExchanger he : hes)\r
-            {\r
-                g.setColor(he.color);\r
-                g.draw(HE);\r
-                if (he.topLeft!=null) {\r
-                    g.setColor(he.topLeft);\r
-                    g.drawLine(-10, 0, 0, 0);\r
-                }\r
-                if (he.topRight!=null) {\r
-                    g.setColor(he.topRight);\r
-                    g.drawLine(0, 0, 10, 0);\r
-                }\r
-                if (he.bottomLeft!=null) {\r
-                    g.setColor(he.bottomLeft);\r
-                    g.drawLine(-10, 20, 0, 20);\r
-                }\r
-                if (he.bottomRight!=null) {\r
-                    g.setColor(he.bottomRight);\r
-                    g.drawLine(0, 20, 10, 20);\r
-                }\r
-                g.translate(0, 25);\r
-            }\r
-        }\r
-    }\r
-\r
-    public static class ChimneySymbol extends PS implements Image {\r
-\r
-        public static final int DIM = 10;\r
-        public static final int D2 = 8;\r
-        public static final Shape C1 = new Ellipse2D.Double(-DIM, -DIM, DIM*2, DIM*2);\r
-        public static final Shape C2 = new Ellipse2D.Double(-D2, -D2, D2*2, D2*2);\r
-\r
-        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-10, -10, 20, 40);\r
-\r
-        public ChimneySymbol(Color fc, Color bc) {\r
-            super( BOUNDS, bc, fc, null, null);\r
-            assert(bc!=null);\r
-        }\r
-\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            g.setColor(fc);\r
-            g.fill(C2);\r
-            g.fillRect(-5, 14, 10, 8);\r
-            g.setColor(bc);\r
-            g.draw(C1);\r
-            g.draw(C2);\r
-\r
-            g.drawLine(0, DIM, 0, 15);\r
-            g.drawRect(-5, 14, 10, 8);\r
-            g.drawLine(-5, 14, 5, 22);\r
-        }\r
-    }\r
-\r
-\r
-    public static class GeneratorSymbol extends PS implements Image {\r
-\r
-        public static final int DIM = 10;\r
-        public static final Shape C1 = new Ellipse2D.Double(-DIM, -DIM, DIM*2, DIM*2);\r
-\r
-        public static final Rectangle2D BOUNDS = C1.getBounds2D();\r
-        private final static Font FONT = Font.decode("Serif-12");\r
-\r
-        public GeneratorSymbol(Color fc, Color bc) {\r
-            super( BOUNDS, bc, fc, null, null);\r
-            assert(bc!=null && fc!=null);\r
-        }\r
-\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            g.setColor(fc);\r
-            g.fill(C1);\r
-            g.setColor(bc);\r
-            g.draw(C1);\r
-            g.setFont(FONT);\r
-            g.drawString("G", -4, 4);\r
-        }\r
-    }\r
-\r
-    public static class NoSpinSymbol extends PS {\r
-        public NoSpinSymbol(Color fc, Color bc) {\r
-            super(BOUNDS, bc, fc, null, null);\r
-        }\r
-        public static final Stroke STROKE = new BasicStroke(1.5f);\r
-        public static final int DIM = 10;\r
-        public static final int D2 = 8;\r
-        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-DIM, -DIM, 2*DIM, 2*DIM);\r
-        public static final Shape CIRCLE = new Ellipse2D.Double(-D2, -D2, D2*2, D2*2);\r
-\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            g.setStroke(STROKE);\r
-            g.setColor(fc);\r
-            g.fillRect(-DIM, -DIM, DIM*2, DIM*2);\r
-            g.setColor(bc);\r
-            g.drawRect(-DIM, -DIM, DIM*2, DIM*2);\r
-            g.draw(CIRCLE);\r
-            g.drawLine(-DIM/3, -DIM/3, DIM/3, DIM/3);\r
-            g.drawLine(DIM/3, -DIM/3, -DIM/3, DIM/3);\r
-        }\r
-    }\r
-\r
-    public static class ControlValveSymbol extends PS implements Image {\r
-\r
-        public static final Stroke STROKE = new BasicStroke(1.5f);\r
-        public static final int D = 10;\r
-        public static final Path2D SHAPE =\r
-            PathUtils.closedPath(-D,-D, -D,D, D,-D, D,D );\r
-        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();\r
-\r
-        public ControlValveSymbol(Color bc, Color fc) {\r
-            super(BOUNDS, bc, fc, null, null);\r
-        }\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            if (fc!=null) {\r
-                g.setColor(fc);\r
-                g.fill(SHAPE);\r
-            }\r
-            if (bc!=null) {\r
-                g.setColor(bc);\r
-                g.draw(SHAPE);\r
-            }\r
-        }\r
-    }\r
-\r
-    public static class ThreeWayValveSymbol extends PS implements Image {\r
-\r
-        public static final Stroke STROKE = new BasicStroke(1.5f);\r
-        public static final int D = 10;\r
-        public static final Path2D SHAPE =\r
-            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 );\r
-        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();\r
-\r
-        public ThreeWayValveSymbol(Color bc, Color fc) {\r
-            super(BOUNDS, bc, fc, null, null);\r
-        }\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            if (fc!=null) {\r
-                g.setColor(fc);\r
-                g.fill(SHAPE);\r
-            }\r
-            if (bc!=null) {\r
-                g.setColor(bc);\r
-                g.draw(SHAPE);\r
-            }\r
-        }\r
-    }\r
-\r
-\r
-    public static class HeatExchangerSymbol extends PS {\r
-\r
-        public HeatExchangerSymbol(Color bc, Color fc) {\r
-            super(BOUNDS, bc, fc, null, null);\r
-        }\r
-        public static final Stroke STROKE = new BasicStroke(1.5f);\r
-        public static final int D = 10;\r
-        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-D, -D, 2*D, 2*D);\r
-        public static final int xPoints[] = new int [] {-D, 0, 0, -D/2, D/2, 0, 0, D};\r
-        public static final int yPoints[] = new int [] {D/2, D/2, D/8, 0, 0, -D/8, -D/2, -D/2};\r
-\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            g.setColor(fc);\r
-            g.fill(BOUNDS);\r
-            g.setColor(bc);\r
-            g.draw(BOUNDS);\r
-            g.setStroke(STROKE);\r
-            g.drawPolyline(xPoints, yPoints, xPoints.length);\r
-        }\r
-    }\r
-\r
-    public static class PumpSymbol extends PS {\r
-\r
-        public PumpSymbol(Color bc, Color fc) {\r
-            super(BOUNDS, bc, fc, null, null);\r
-        }\r
-        public static final Stroke STROKE = new BasicStroke(1.5f);\r
-        public static final int DIM = 10;\r
-        public static final int D2 = 12;\r
-        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-D2, -D2, 2*D2, 2*D2);\r
-        public static final Shape CIRCLE = new Ellipse2D.Double(-D2, -D2, D2*2, D2*2);\r
-        public static final Polygon SHAPE =\r
-            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);\r
-\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            g.setColor(fc);\r
-            g.fill(CIRCLE);\r
-            g.setColor(bc);\r
-            g.setStroke( STROKE );\r
-            g.draw(CIRCLE);\r
-            g.draw(SHAPE);\r
-        }\r
-    }\r
-\r
-\r
-    public static class ShutoffValveSymbol extends PS implements Image {\r
-\r
-        public static final Stroke STROKE = new BasicStroke(1.5f);\r
-        public static final int DIM = 10;\r
-        public static final Path2D SHAPE =\r
-            PathUtils.closedPath(-DIM,-DIM, -DIM,DIM, DIM,-DIM, DIM,DIM );\r
-        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();\r
-\r
-        public ShutoffValveSymbol(Color bc, Color fc) {\r
-            super(BOUNDS, bc, fc, null, null);\r
-        }\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            if (fc!=null) {\r
-                g.setColor(fc);\r
-                g.fill(SHAPE);\r
-            }\r
-            if (bc!=null) {\r
-                g.setColor(bc);\r
-                g.draw(SHAPE);\r
-                g.drawLine(0, -DIM, 0, DIM);\r
-            }\r
-        }\r
-    }\r
-\r
-\r
-    public static class SwitchSymbol extends PS {\r
-\r
-        public SwitchSymbol(Color bc) {\r
-            super(BOUNDS, bc, null, null, null);\r
-        }\r
-        public static final Stroke STROKE = new BasicStroke(1.5f);\r
-        public static final int D = 10;\r
-        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-D, -D, 2*D, 2*D);\r
-\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            g.setColor(bc);\r
-            g.setStroke(STROKE);\r
-\r
-            g.drawLine(0, -D, 0, D);\r
-            g.drawLine(-D/4, -D/2, D/4, -D/2);\r
-            g.drawLine(-D, 0, D, 0);\r
-            g.drawLine(-D/4, D/2, D/4, D/2);\r
-        }\r
-    }\r
-\r
-\r
-    public static class TurbineSymbol extends PS implements Image {\r
-\r
-        public static final int DIM = 10;\r
-        public static final Polygon SHAPE =\r
-            new Polygon(new int[] {-DIM, -DIM, DIM, DIM}, new int[] {-DIM, DIM, DIM*2, -DIM*2}, 4);\r
-        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();\r
-\r
-        public TurbineSymbol(Color bc, Color fc) {\r
-            super(BOUNDS, bc, fc, null, null);\r
-        }\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            if (fc!=null) {\r
-                g.setColor(fc);\r
-                g.fill(SHAPE);\r
-            }\r
-            if (bc!=null) {\r
-                g.setColor(bc);\r
-                g.draw(SHAPE);\r
-            }\r
-        }\r
-    }\r
-\r
-    public static class CompressorSymbol extends PS implements Image {\r
-\r
-        public static final int DIM = 10;\r
-        public static final Polygon SHAPE =\r
-            new Polygon(new int[] {DIM, DIM, -DIM, -DIM}, new int[] {-DIM, DIM, DIM*2, -DIM*2}, 4);\r
-        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();\r
-\r
-        public CompressorSymbol(Color bc, Color fc) {\r
-            super(BOUNDS, bc, fc, null, null);\r
-        }\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            if (fc!=null) {\r
-                g.setColor(fc);\r
-                g.fill(SHAPE);\r
-            }\r
-            if (bc!=null) {\r
-                g.setColor(bc);\r
-                g.draw(SHAPE);\r
-            }\r
-        }\r
-    }\r
-\r
-    public static class VoltageTransformerSymbol extends PS implements Image {\r
-\r
-        public static final Stroke STROKE = new BasicStroke(1.5f);\r
-        public static final int DIM = 10;\r
-        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-DIM, -DIM*1.7, 2*DIM, 2*DIM*1.7);\r
-        public static final Shape CIRCLE = new Ellipse2D.Double(-DIM, -DIM, DIM*2, DIM*2);\r
-\r
-        public VoltageTransformerSymbol(Color c1, Color c2) {\r
-            super(BOUNDS, null, null, c1, c2);\r
-        }\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            g.setStroke(STROKE);\r
-            Graphics2D sg = (Graphics2D) g.create();\r
-\r
-            sg.clipRect(-DIM*2, -DIM*2, DIM*4, DIM*2);\r
-            sg.setColor(c1);\r
-            sg.translate(0, -0.7*DIM);\r
-            sg.draw(CIRCLE);\r
-            sg.setColor(c2);\r
-            sg.translate(0, 1.4*DIM);\r
-            sg.draw(CIRCLE);\r
-            sg.dispose();\r
-\r
-            g.clipRect(-DIM*2, 0, DIM*4, DIM*2);\r
-            g.setColor(c2);\r
-            g.translate(0, 0.7*DIM);\r
-            g.draw(CIRCLE);\r
-            g.setColor(c1);\r
-            g.translate(0, -1.4*DIM);\r
-            g.draw(CIRCLE);\r
-        }\r
-    }\r
-\r
-    public static class TankSymbol extends PS implements Image {\r
-\r
-        /**\r
-         * Create tank shape.\r
-         * @param r rectangle\r
-         * @param cap cap size\r
-         * @return tank shape\r
-         */\r
-        public static Path2D createTankShape(Rectangle2D r, double cap)\r
-        {\r
-            double x1 = r.getMinX();\r
-            double y1 = r.getMinY();\r
-            double x2 = r.getMaxX();\r
-            double y2 = r.getMaxY();\r
-            Path2D p = new Path2D.Double();\r
-            p.moveTo(x1+cap, y1);\r
-            p.lineTo(x2-cap, y1);\r
-            p.quadTo(x2,y1, x2,y1+cap);\r
-            p.lineTo(x2, y2-cap);\r
-            p.quadTo(x2, y2, x2-cap, y2);\r
-            p.lineTo(x1+cap, y2);\r
-            p.quadTo(x1, y2, x1, y2-cap);\r
-            p.lineTo(x1, y1+cap);\r
-            p.quadTo(x1, y1, x1+cap, y1);\r
-            return p;\r
-        }\r
-\r
-        Path2D shape;\r
-\r
-        public TankSymbol(Rectangle2D rect, double cap, Color bc, Color fc) {\r
-            super(rect, bc, fc, null, null);\r
-            shape = createTankShape(rect, cap);\r
-        }\r
-\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            g.setColor(fc);\r
-            g.setStroke(GeometryUtils.BASIC_STROKE);\r
-            g.fill(shape);\r
-            if (bc!=null) {\r
-                g.setColor(bc);\r
-                g.draw(shape);\r
-            }\r
-        }\r
-\r
-    }\r
-\r
-    public static class Tank2Symbol extends PS implements Image {\r
-\r
-        public static Path2D createWShape()\r
-        {\r
-            Path2D p = new Path2D.Double();\r
-            double k = Math.sqrt(2);\r
-            p.moveTo(-1, -1);\r
-            p.quadTo(0, -k, 1, -1);\r
-            p.quadTo(k, 0, 1, 1);\r
-            p.quadTo(0, k, -1, 1);\r
-            p.quadTo(-k, 0, -1, -1);\r
-            p.lineTo(-1, 1);\r
-            p.lineTo(0,0);\r
-            p.lineTo(1, 1);\r
-            p.lineTo(1, -1);\r
-            return p;\r
-        }\r
-\r
-        Path2D shape;\r
-        Path2D shape2;\r
-\r
-        public Tank2Symbol(Rectangle2D rect, double cap, Color bc, Color fc, Color a1) {\r
-            super(rect, bc, fc, a1, null);\r
-            shape = TankSymbol.createTankShape(rect, cap);\r
-            shape2 = createWShape();\r
-        }\r
-\r
-        @Override\r
-        public void paint(Graphics2D g) {\r
-            g.setColor(fc);\r
-            g.setStroke(GeometryUtils.BASIC_STROKE);\r
-            g.setStroke(new BasicStroke(0.3f));\r
-            g.fill(shape);\r
-            if (bc!=null) {\r
-                g.setColor(bc);\r
-                g.draw(shape);\r
-            }\r
-            g.setColor(c1);\r
-            double d = Math.min(bounds.getHeight(), bounds.getWidth());\r
-            g.translate(bounds.getMinX()+d/2, bounds.getMinY()+d/2);\r
-            g.scale(d/3, d/3);\r
-            g.draw(shape2);\r
-        }\r
-\r
-    }\r
-\r
-    private abstract static class PS implements Image {\r
-\r
-\r
-        public final Rectangle2D bounds;\r
-        public final Color c1;\r
-        public final Color c2;\r
-        public final Color bc;\r
-        public final Color fc;\r
-        private final int hash;\r
-        public PS(Rectangle2D bounds, Color bc, Color fc, Color c1, Color c2) {\r
-            this.bounds = bounds;\r
-            this.bc = bc;\r
-            this.fc = fc;\r
-            this.c1 = c1;\r
-            this.c2 = c2;\r
-            int hash = this.getClass().hashCode();\r
-            if (bc!=null) hash += 3 * bc.hashCode();\r
-            if (fc!=null) hash += 5 * fc.hashCode();\r
-            if (c1!=null) hash += 7 * c1.hashCode();\r
-            if (c2!=null) hash += 11 * c2.hashCode();\r
-            this.hash = hash;\r
-        }\r
-\r
-        @Override\r
-        public int hashCode() {\r
-            return hash;\r
-        }\r
-\r
-        @Override\r
-        public boolean equals(Object obj) {\r
-            if (!obj.getClass().equals(getClass()))return false;\r
-            PS other = (PS) obj;\r
-            return\r
-            ObjectUtils.objectEquals(other.c1, c1) &&\r
-            ObjectUtils.objectEquals(other.c2, c2) &&\r
-            ObjectUtils.objectEquals(other.fc, fc) &&\r
-            ObjectUtils.objectEquals(other.bc, bc);\r
-        }\r
-        @Override\r
-        public Rectangle2D getBounds() {\r
-            return bounds;\r
-        }\r
-\r
-        @Override\r
-        public Shape getOutline() {\r
-            return bounds;\r
-        }\r
-\r
-        @Override\r
-        public Node init(G2DParentNode g) {\r
-//                     return init(g);\r
-            return null;\r
-        }\r
-\r
-        public void paint(Graphics2D g2d) { // FIXME: get rid of this\r
-\r
-        }\r
-\r
-        @Override\r
-        public void addImageListener(ImageListener listener) {\r
-        }\r
-\r
-        static EnumSet<Feature> caps = EnumSet.of(Feature.Vector);\r
-        @Override\r
-        public EnumSet<Feature> getFeatures() {\r
-            return caps;\r
-        }\r
-\r
-        @Override\r
-        public void removeImageListener(ImageListener listener) {\r
-        }\r
-\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.g2d.elementclass.operationsymbols;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Polygon;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
+import java.util.EnumSet;
+
+import org.simantics.g2d.image.Image;
+import org.simantics.g2d.image.impl.Shadow;
+import org.simantics.g2d.image.impl.Shadow.ShadowParameters;
+import org.simantics.g2d.utils.GeometryUtils;
+import org.simantics.g2d.utils.PathUtils;
+import org.simantics.scenegraph.Node;
+import org.simantics.scenegraph.g2d.G2DParentNode;
+import org.simantics.utils.ObjectUtils;
+
+/**
+ * @author Toni Kalajainen
+ */
+public class OperationSymbols {
+
+    static final double SHADOW_SIZE = 100;
+    static final Color BORDER_COLOR = Color.GRAY;
+    static final Color FILL_COLOR = Color.GRAY;
+    static final Color SECONDARY_COLOR = Color.GREEN;
+    static final ShadowParameters SHADOW = new ShadowParameters(0.5, Color.BLACK, 2);
+
+    static final Color HOT = new Color(50, 50, 200);
+    static final Color COLD = new Color(190, 190, 255);
+
+    public static final BoilerHeatExchanger[] BOILER_HES = new BoilerHeatExchanger[] {
+        new BoilerHeatExchanger(null, HOT, HOT, null, HOT),
+        new BoilerHeatExchanger(HOT, null, COLD, COLD, HOT),
+        new BoilerHeatExchanger(HOT, null, COLD, null, HOT),
+        new BoilerHeatExchanger(HOT, null, null, HOT, HOT)
+    };
+
+    public static final Image BOILER_SYMBOL = new BoilerSymbol2(FILL_COLOR, FILL_COLOR, BOILER_HES);
+    public static final Image BOILER_SHADOW = new Shadow(BOILER_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image COMPRESSOR_SYMBOL = new CompressorSymbol(FILL_COLOR, BORDER_COLOR);
+    public static final Image COMPRESSOR_SHADOW = new Shadow(COMPRESSOR_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image NO_SPIN_SYMBOL = new NoSpinSymbol(FILL_COLOR, BORDER_COLOR);
+    public static final Image NO_SPIN_SHADOW = new Shadow(NO_SPIN_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image CONTROLVALVE_SYMBOL = new ControlValveSymbol(BORDER_COLOR, FILL_COLOR);
+    public static final Image CONTROLVALVE_SHADOW = new Shadow(CONTROLVALVE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image THREEWAYVALVE_SYMBOL = new ThreeWayValveSymbol(BORDER_COLOR, FILL_COLOR);
+    public static final Image THREEWAYVALVE_SHADOW = new Shadow(THREEWAYVALVE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image HEATEXCHANGER_SYMBOL = new HeatExchangerSymbol(BORDER_COLOR, FILL_COLOR);
+    public static final Image HEATEXCHANGER_SHADOW = new Shadow(HEATEXCHANGER_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image PUMP_SYMBOL = new PumpSymbol(BORDER_COLOR, FILL_COLOR);
+    public static final Image PUMP_SHADOW = new Shadow(PUMP_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image SHUTOFFVALVE_SYMBOL = new ShutoffValveSymbol(BORDER_COLOR, FILL_COLOR);
+    public static final Image SHUTOFFVALVE_SHADOW = new Shadow(SHUTOFFVALVE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image SWITCH_SYMBOL = new SwitchSymbol(BORDER_COLOR);
+    public static final Image SWITCH_SHADOW = new Shadow(SWITCH_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image TURBINE_SYMBOL = new TurbineSymbol(BORDER_COLOR, FILL_COLOR);
+    public static final Image TURBINE_SHADOW = new Shadow(TURBINE_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image VOLTAGETRANSFORMER_SYMBOL = new VoltageTransformerSymbol(SECONDARY_COLOR, BORDER_COLOR);
+    public static final Image VOLTAGETRANSFORMER_SHADOW = new Shadow(VOLTAGETRANSFORMER_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image CHIMNEY_SYMBOL = new ChimneySymbol(SECONDARY_COLOR, BORDER_COLOR);
+    public static final Image CHIMNEY_SHADOW = new Shadow(CHIMNEY_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image GENERATOR_SYMBOL = new GeneratorSymbol(SECONDARY_COLOR, BORDER_COLOR);
+    public static final Image GENERATOR_SHADOW = new Shadow(GENERATOR_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image TANK_SYMBOL = new TankSymbol(new Rectangle2D.Double(0,0, 20.0, 8.0), 2.0, SECONDARY_COLOR, BORDER_COLOR);
+    public static final Image TANK_SHADOW = new Shadow(TANK_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static final Image TANK2_SYMBOL = new Tank2Symbol(new Rectangle2D.Double(0,0, 20.0, 8.0), 2.0, SECONDARY_COLOR, BORDER_COLOR, HOT);
+    public static final Image TANK2_SHADOW = new Shadow(TANK2_SYMBOL, SHADOW, SHADOW_SIZE, SHADOW_SIZE);
+
+    public static class BoilerSymbol extends PS implements Image {
+        public static final int DIM = 10;
+        public static final Polygon SHAPE =
+            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);
+        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
+
+        public BoilerSymbol(Color bc, Color fc) {
+            super(SHAPE.getBounds2D(), bc, fc, null, null);
+        }
+        @Override
+        public void paint(Graphics2D g) {
+//                     if (fc!=null) {
+//                             g.setColor(fc);
+//                             g.fill(SHAPE);
+//                     }
+//                     if (bc!=null) {
+//                             g.setColor(bc);
+//                             g.draw(SHAPE);
+//                     }
+        }
+    }
+
+    public static class BoilerHeatExchanger {
+        public final Color color;
+        public final Color topLeft, topRight, bottomLeft, bottomRight;
+        public BoilerHeatExchanger(Color topLeft, Color topRight,
+                Color bottomLeft, Color bottomRight,
+                Color color) {
+            this.bottomLeft = bottomLeft;
+            this.bottomRight = bottomRight;
+            this.color = color;
+            this.topLeft = topLeft;
+            this.topRight = topRight;
+        }
+    }
+
+    public static class BoilerSymbol2 extends PS implements Image {
+
+        public static Path2D HE = PathUtils.path(10,0, 0,0, 0,5, 5,10, -5,10, 0,15, 0,20);
+
+        public static Rectangle2D getBoilerRect(BoilerHeatExchanger ... hes)
+        {
+            return new Rectangle2D.Double(-10, 0, 20, hes.length*25+25);
+        }
+
+        public static Shape getBoilerShape(BoilerHeatExchanger ... hes)
+        {
+            Path2D p = new Path2D.Double();
+            p.moveTo(-10, 10);
+            p.lineTo(  0,  0);
+            p.lineTo( 10, 10);
+            double h = hes.length * 25;
+            p.lineTo( 10, h+15);
+            p.lineTo(  0, h+25);
+            p.lineTo(-10, h+15);
+            p.closePath();
+            return p;
+        }
+
+        private final Shape shape;
+        private final BoilerHeatExchanger [] hes;
+
+        public BoilerSymbol2(Color fc, Color bc, BoilerHeatExchanger ... hes) {
+            super( getBoilerRect(hes), bc, fc, null, null);
+            shape = getBoilerShape(hes);
+            this.hes = hes;
+        }
+
+        @Override
+        public void paint(Graphics2D g) {
+            if (fc!=null) {
+                g.setColor(fc);
+                g.fill(shape);
+            }
+            if (bc!=null) {
+                g.setColor(bc);
+                g.draw(shape);
+            }
+            // paint heat exchangers
+            g.translate(0, 15);
+            for (BoilerHeatExchanger he : hes)
+            {
+                g.setColor(he.color);
+                g.draw(HE);
+                if (he.topLeft!=null) {
+                    g.setColor(he.topLeft);
+                    g.drawLine(-10, 0, 0, 0);
+                }
+                if (he.topRight!=null) {
+                    g.setColor(he.topRight);
+                    g.drawLine(0, 0, 10, 0);
+                }
+                if (he.bottomLeft!=null) {
+                    g.setColor(he.bottomLeft);
+                    g.drawLine(-10, 20, 0, 20);
+                }
+                if (he.bottomRight!=null) {
+                    g.setColor(he.bottomRight);
+                    g.drawLine(0, 20, 10, 20);
+                }
+                g.translate(0, 25);
+            }
+        }
+    }
+
+    public static class ChimneySymbol extends PS implements Image {
+
+        public static final int DIM = 10;
+        public static final int D2 = 8;
+        public static final Shape C1 = new Ellipse2D.Double(-DIM, -DIM, DIM*2, DIM*2);
+        public static final Shape C2 = new Ellipse2D.Double(-D2, -D2, D2*2, D2*2);
+
+        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-10, -10, 20, 40);
+
+        public ChimneySymbol(Color fc, Color bc) {
+            super( BOUNDS, bc, fc, null, null);
+            assert(bc!=null);
+        }
+
+        @Override
+        public void paint(Graphics2D g) {
+            g.setColor(fc);
+            g.fill(C2);
+            g.fillRect(-5, 14, 10, 8);
+            g.setColor(bc);
+            g.draw(C1);
+            g.draw(C2);
+
+            g.drawLine(0, DIM, 0, 15);
+            g.drawRect(-5, 14, 10, 8);
+            g.drawLine(-5, 14, 5, 22);
+        }
+    }
+
+
+    public static class GeneratorSymbol extends PS implements Image {
+
+        public static final int DIM = 10;
+        public static final Shape C1 = new Ellipse2D.Double(-DIM, -DIM, DIM*2, DIM*2);
+
+        public static final Rectangle2D BOUNDS = C1.getBounds2D();
+        private final static Font FONT = Font.decode("Serif-12");
+
+        public GeneratorSymbol(Color fc, Color bc) {
+            super( BOUNDS, bc, fc, null, null);
+            assert(bc!=null && fc!=null);
+        }
+
+        @Override
+        public void paint(Graphics2D g) {
+            g.setColor(fc);
+            g.fill(C1);
+            g.setColor(bc);
+            g.draw(C1);
+            g.setFont(FONT);
+            g.drawString("G", -4, 4);
+        }
+    }
+
+    public static class NoSpinSymbol extends PS {
+        public NoSpinSymbol(Color fc, Color bc) {
+            super(BOUNDS, bc, fc, null, null);
+        }
+        public static final Stroke STROKE = new BasicStroke(1.5f);
+        public static final int DIM = 10;
+        public static final int D2 = 8;
+        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-DIM, -DIM, 2*DIM, 2*DIM);
+        public static final Shape CIRCLE = new Ellipse2D.Double(-D2, -D2, D2*2, D2*2);
+
+        @Override
+        public void paint(Graphics2D g) {
+            g.setStroke(STROKE);
+            g.setColor(fc);
+            g.fillRect(-DIM, -DIM, DIM*2, DIM*2);
+            g.setColor(bc);
+            g.drawRect(-DIM, -DIM, DIM*2, DIM*2);
+            g.draw(CIRCLE);
+            g.drawLine(-DIM/3, -DIM/3, DIM/3, DIM/3);
+            g.drawLine(DIM/3, -DIM/3, -DIM/3, DIM/3);
+        }
+    }
+
+    public static class ControlValveSymbol extends PS implements Image {
+
+        public static final Stroke STROKE = new BasicStroke(1.5f);
+        public static final int D = 10;
+        public static final Path2D SHAPE =
+            PathUtils.closedPath(-D,-D, -D,D, D,-D, D,D );
+        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
+
+        public ControlValveSymbol(Color bc, Color fc) {
+            super(BOUNDS, bc, fc, null, null);
+        }
+        @Override
+        public void paint(Graphics2D g) {
+            if (fc!=null) {
+                g.setColor(fc);
+                g.fill(SHAPE);
+            }
+            if (bc!=null) {
+                g.setColor(bc);
+                g.draw(SHAPE);
+            }
+        }
+    }
+
+    public static class ThreeWayValveSymbol extends PS implements Image {
+
+        public static final Stroke STROKE = new BasicStroke(1.5f);
+        public static final int D = 10;
+        public static final Path2D SHAPE =
+            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 );
+        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
+
+        public ThreeWayValveSymbol(Color bc, Color fc) {
+            super(BOUNDS, bc, fc, null, null);
+        }
+        @Override
+        public void paint(Graphics2D g) {
+            if (fc!=null) {
+                g.setColor(fc);
+                g.fill(SHAPE);
+            }
+            if (bc!=null) {
+                g.setColor(bc);
+                g.draw(SHAPE);
+            }
+        }
+    }
+
+
+    public static class HeatExchangerSymbol extends PS {
+
+        public HeatExchangerSymbol(Color bc, Color fc) {
+            super(BOUNDS, bc, fc, null, null);
+        }
+        public static final Stroke STROKE = new BasicStroke(1.5f);
+        public static final int D = 10;
+        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-D, -D, 2*D, 2*D);
+        public static final int xPoints[] = new int [] {-D, 0, 0, -D/2, D/2, 0, 0, D};
+        public static final int yPoints[] = new int [] {D/2, D/2, D/8, 0, 0, -D/8, -D/2, -D/2};
+
+        @Override
+        public void paint(Graphics2D g) {
+            g.setColor(fc);
+            g.fill(BOUNDS);
+            g.setColor(bc);
+            g.draw(BOUNDS);
+            g.setStroke(STROKE);
+            g.drawPolyline(xPoints, yPoints, xPoints.length);
+        }
+    }
+
+    public static class PumpSymbol extends PS {
+
+        public PumpSymbol(Color bc, Color fc) {
+            super(BOUNDS, bc, fc, null, null);
+        }
+        public static final Stroke STROKE = new BasicStroke(1.5f);
+        public static final int DIM = 10;
+        public static final int D2 = 12;
+        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-D2, -D2, 2*D2, 2*D2);
+        public static final Shape CIRCLE = new Ellipse2D.Double(-D2, -D2, D2*2, D2*2);
+        public static final Polygon SHAPE =
+            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);
+
+        @Override
+        public void paint(Graphics2D g) {
+            g.setColor(fc);
+            g.fill(CIRCLE);
+            g.setColor(bc);
+            g.setStroke( STROKE );
+            g.draw(CIRCLE);
+            g.draw(SHAPE);
+        }
+    }
+
+
+    public static class ShutoffValveSymbol extends PS implements Image {
+
+        public static final Stroke STROKE = new BasicStroke(1.5f);
+        public static final int DIM = 10;
+        public static final Path2D SHAPE =
+            PathUtils.closedPath(-DIM,-DIM, -DIM,DIM, DIM,-DIM, DIM,DIM );
+        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
+
+        public ShutoffValveSymbol(Color bc, Color fc) {
+            super(BOUNDS, bc, fc, null, null);
+        }
+        @Override
+        public void paint(Graphics2D g) {
+            if (fc!=null) {
+                g.setColor(fc);
+                g.fill(SHAPE);
+            }
+            if (bc!=null) {
+                g.setColor(bc);
+                g.draw(SHAPE);
+                g.drawLine(0, -DIM, 0, DIM);
+            }
+        }
+    }
+
+
+    public static class SwitchSymbol extends PS {
+
+        public SwitchSymbol(Color bc) {
+            super(BOUNDS, bc, null, null, null);
+        }
+        public static final Stroke STROKE = new BasicStroke(1.5f);
+        public static final int D = 10;
+        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-D, -D, 2*D, 2*D);
+
+        @Override
+        public void paint(Graphics2D g) {
+            g.setColor(bc);
+            g.setStroke(STROKE);
+
+            g.drawLine(0, -D, 0, D);
+            g.drawLine(-D/4, -D/2, D/4, -D/2);
+            g.drawLine(-D, 0, D, 0);
+            g.drawLine(-D/4, D/2, D/4, D/2);
+        }
+    }
+
+
+    public static class TurbineSymbol extends PS implements Image {
+
+        public static final int DIM = 10;
+        public static final Polygon SHAPE =
+            new Polygon(new int[] {-DIM, -DIM, DIM, DIM}, new int[] {-DIM, DIM, DIM*2, -DIM*2}, 4);
+        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
+
+        public TurbineSymbol(Color bc, Color fc) {
+            super(BOUNDS, bc, fc, null, null);
+        }
+        @Override
+        public void paint(Graphics2D g) {
+            if (fc!=null) {
+                g.setColor(fc);
+                g.fill(SHAPE);
+            }
+            if (bc!=null) {
+                g.setColor(bc);
+                g.draw(SHAPE);
+            }
+        }
+    }
+
+    public static class CompressorSymbol extends PS implements Image {
+
+        public static final int DIM = 10;
+        public static final Polygon SHAPE =
+            new Polygon(new int[] {DIM, DIM, -DIM, -DIM}, new int[] {-DIM, DIM, DIM*2, -DIM*2}, 4);
+        public static final Rectangle2D BOUNDS = SHAPE.getBounds2D();
+
+        public CompressorSymbol(Color bc, Color fc) {
+            super(BOUNDS, bc, fc, null, null);
+        }
+        @Override
+        public void paint(Graphics2D g) {
+            if (fc!=null) {
+                g.setColor(fc);
+                g.fill(SHAPE);
+            }
+            if (bc!=null) {
+                g.setColor(bc);
+                g.draw(SHAPE);
+            }
+        }
+    }
+
+    public static class VoltageTransformerSymbol extends PS implements Image {
+
+        public static final Stroke STROKE = new BasicStroke(1.5f);
+        public static final int DIM = 10;
+        public static final Rectangle2D BOUNDS = new Rectangle2D.Double(-DIM, -DIM*1.7, 2*DIM, 2*DIM*1.7);
+        public static final Shape CIRCLE = new Ellipse2D.Double(-DIM, -DIM, DIM*2, DIM*2);
+
+        public VoltageTransformerSymbol(Color c1, Color c2) {
+            super(BOUNDS, null, null, c1, c2);
+        }
+        @Override
+        public void paint(Graphics2D g) {
+            g.setStroke(STROKE);
+            Graphics2D sg = (Graphics2D) g.create();
+
+            sg.clipRect(-DIM*2, -DIM*2, DIM*4, DIM*2);
+            sg.setColor(c1);
+            sg.translate(0, -0.7*DIM);
+            sg.draw(CIRCLE);
+            sg.setColor(c2);
+            sg.translate(0, 1.4*DIM);
+            sg.draw(CIRCLE);
+            sg.dispose();
+
+            g.clipRect(-DIM*2, 0, DIM*4, DIM*2);
+            g.setColor(c2);
+            g.translate(0, 0.7*DIM);
+            g.draw(CIRCLE);
+            g.setColor(c1);
+            g.translate(0, -1.4*DIM);
+            g.draw(CIRCLE);
+        }
+    }
+
+    public static class TankSymbol extends PS implements Image {
+
+        /**
+         * Create tank shape.
+         * @param r rectangle
+         * @param cap cap size
+         * @return tank shape
+         */
+        public static Path2D createTankShape(Rectangle2D r, double cap)
+        {
+            double x1 = r.getMinX();
+            double y1 = r.getMinY();
+            double x2 = r.getMaxX();
+            double y2 = r.getMaxY();
+            Path2D p = new Path2D.Double();
+            p.moveTo(x1+cap, y1);
+            p.lineTo(x2-cap, y1);
+            p.quadTo(x2,y1, x2,y1+cap);
+            p.lineTo(x2, y2-cap);
+            p.quadTo(x2, y2, x2-cap, y2);
+            p.lineTo(x1+cap, y2);
+            p.quadTo(x1, y2, x1, y2-cap);
+            p.lineTo(x1, y1+cap);
+            p.quadTo(x1, y1, x1+cap, y1);
+            return p;
+        }
+
+        Path2D shape;
+
+        public TankSymbol(Rectangle2D rect, double cap, Color bc, Color fc) {
+            super(rect, bc, fc, null, null);
+            shape = createTankShape(rect, cap);
+        }
+
+        @Override
+        public void paint(Graphics2D g) {
+            g.setColor(fc);
+            g.setStroke(GeometryUtils.BASIC_STROKE);
+            g.fill(shape);
+            if (bc!=null) {
+                g.setColor(bc);
+                g.draw(shape);
+            }
+        }
+
+    }
+
+    public static class Tank2Symbol extends PS implements Image {
+
+        public static Path2D createWShape()
+        {
+            Path2D p = new Path2D.Double();
+            double k = Math.sqrt(2);
+            p.moveTo(-1, -1);
+            p.quadTo(0, -k, 1, -1);
+            p.quadTo(k, 0, 1, 1);
+            p.quadTo(0, k, -1, 1);
+            p.quadTo(-k, 0, -1, -1);
+            p.lineTo(-1, 1);
+            p.lineTo(0,0);
+            p.lineTo(1, 1);
+            p.lineTo(1, -1);
+            return p;
+        }
+
+        Path2D shape;
+        Path2D shape2;
+
+        public Tank2Symbol(Rectangle2D rect, double cap, Color bc, Color fc, Color a1) {
+            super(rect, bc, fc, a1, null);
+            shape = TankSymbol.createTankShape(rect, cap);
+            shape2 = createWShape();
+        }
+
+        @Override
+        public void paint(Graphics2D g) {
+            g.setColor(fc);
+            g.setStroke(GeometryUtils.BASIC_STROKE);
+            g.setStroke(new BasicStroke(0.3f));
+            g.fill(shape);
+            if (bc!=null) {
+                g.setColor(bc);
+                g.draw(shape);
+            }
+            g.setColor(c1);
+            double d = Math.min(bounds.getHeight(), bounds.getWidth());
+            g.translate(bounds.getMinX()+d/2, bounds.getMinY()+d/2);
+            g.scale(d/3, d/3);
+            g.draw(shape2);
+        }
+
+    }
+
+    private abstract static class PS implements Image {
+
+
+        public final Rectangle2D bounds;
+        public final Color c1;
+        public final Color c2;
+        public final Color bc;
+        public final Color fc;
+        private final int hash;
+        public PS(Rectangle2D bounds, Color bc, Color fc, Color c1, Color c2) {
+            this.bounds = bounds;
+            this.bc = bc;
+            this.fc = fc;
+            this.c1 = c1;
+            this.c2 = c2;
+            int hash = this.getClass().hashCode();
+            if (bc!=null) hash += 3 * bc.hashCode();
+            if (fc!=null) hash += 5 * fc.hashCode();
+            if (c1!=null) hash += 7 * c1.hashCode();
+            if (c2!=null) hash += 11 * c2.hashCode();
+            this.hash = hash;
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!obj.getClass().equals(getClass()))return false;
+            PS other = (PS) obj;
+            return
+            ObjectUtils.objectEquals(other.c1, c1) &&
+            ObjectUtils.objectEquals(other.c2, c2) &&
+            ObjectUtils.objectEquals(other.fc, fc) &&
+            ObjectUtils.objectEquals(other.bc, bc);
+        }
+        @Override
+        public Rectangle2D getBounds() {
+            return bounds;
+        }
+
+        @Override
+        public Shape getOutline() {
+            return bounds;
+        }
+
+        @Override
+        public Node init(G2DParentNode g) {
+//                     return init(g);
+            return null;
+        }
+
+        public void paint(Graphics2D g2d) { // FIXME: get rid of this
+
+        }
+
+        @Override
+        public void addImageListener(ImageListener listener) {
+        }
+
+        static EnumSet<Feature> caps = EnumSet.of(Feature.Vector);
+        @Override
+        public EnumSet<Feature> getFeatures() {
+            return caps;
+        }
+
+        @Override
+        public void removeImageListener(ImageListener listener) {
+        }
+
+    }
+
+}