/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.styling; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.geotools.factory.CommonFactoryFinder; import org.geotools.factory.GeoTools; import org.geotools.filter.ConstantExpression; import org.geotools.util.Utilities; import org.opengis.filter.FilterFactory; import org.opengis.filter.expression.Expression; import org.opengis.style.AnchorPoint; import org.opengis.style.GraphicalSymbol; import org.opengis.style.StyleVisitor; import org.opengis.util.Cloneable; /** * Direct implementation of Graphic. * * @author Ian Turton, CCG * @author Johann Sorel (Geomatys) * * @source $URL$ * @version $Id$ */ public class GraphicImpl implements Graphic, Cloneable { /** The logger for the default core module. */ //private static final java.util.logging.Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.core"); private final List<GraphicalSymbol> graphics = new ArrayList<GraphicalSymbol>(); private AnchorPointImpl anchor; private Expression gap; private Expression initialGap; private FilterFactory filterFactory; private Expression rotation = null; private Expression size = null; private DisplacementImpl displacement = null; private Expression opacity = null; /** * Creates a new instance of DefaultGraphic */ protected GraphicImpl() { this( CommonFactoryFinder.getFilterFactory(GeoTools.getDefaultHints())); } public GraphicImpl(FilterFactory factory) { this(factory,null,null,null); } public GraphicImpl(FilterFactory factory, AnchorPoint anchor,Expression gap, Expression initialGap) { filterFactory = factory; this.anchor = AnchorPointImpl.cast(anchor); if(gap == null) this.gap = ConstantExpression.constant(0); else this.gap = gap; if(initialGap == null) this.initialGap = ConstantExpression.constant(0); else this.initialGap = initialGap; } @Deprecated public void setFilterFactory(FilterFactory factory) { filterFactory = factory; } public List<GraphicalSymbol> graphicalSymbols() { return graphics; } /** * Provides a list of external graphics which can be used to represent this * graphic. Each one should be an equivalent representation but in a * different format. If none are provided, or if none of the formats are * supported, then the list of Marks should be used instead. * * @return An array of ExternalGraphics objects which should be equivalents * but in different formats. If null is returned use getMarks * instead. */ @Deprecated public ExternalGraphic[] getExternalGraphics() { Collection<ExternalGraphic> exts = new ArrayList<ExternalGraphic>(); for(GraphicalSymbol s : graphics){ if(s instanceof ExternalGraphic){ exts.add((ExternalGraphic) s); } } return exts.toArray(new ExternalGraphic[0]); } @Deprecated public void setExternalGraphics(ExternalGraphic[] externalGraphics) { Collection<GraphicalSymbol> currExternalGraphics = new ArrayList<GraphicalSymbol>(); for(GraphicalSymbol s : graphics){ if (s instanceof ExternalGraphic){ currExternalGraphics.add(s); } } graphics.removeAll(currExternalGraphics); for(ExternalGraphic g : externalGraphics){ graphics.add(g); } } @Deprecated public void addExternalGraphic(ExternalGraphic externalGraphic) { graphics.add(externalGraphic); } /** * Provides a list of suitable marks which can be used to represent this * graphic. These should only be used if no ExternalGraphic is provided, * or if none of the external graphics formats are supported. * * @return An array of marks to use when displaying this Graphic. By * default, a "square" with 50% gray fill and black outline with a * size of 6 pixels (unless a size is specified) is provided. */ @Deprecated public Mark[] getMarks() { Collection<Mark> exts = new ArrayList<Mark>(); for(GraphicalSymbol s : graphics){ if(s instanceof Mark){ exts.add((Mark) s); } } return exts.toArray(new Mark[0]); } @Deprecated public void setMarks(Mark[] marks) { Collection<GraphicalSymbol> currMarks = new ArrayList<GraphicalSymbol>(); for(GraphicalSymbol s : graphics){ if (s instanceof Mark){ currMarks.add(s); } } graphics.removeAll(currMarks); for(Mark g : marks){ graphics.add(g); } } @Deprecated public void addMark(Mark mark) { graphics.add(mark); } /** * Provides a list of all the symbols which can be used to represent this * graphic * <p> * A symbol is an ExternalGraphic, Mark or any other object which * implements the Symbol interface. These are returned in the order they * were set. * <p> * This class operates as a "view" on getMarks() and getExternalGraphics() * with the added magic that if nothing has been set ever a single default * MarkImpl will be provided. This default will not effect the internal * state it is only there as a sensible default for rendering. * * @return An array of symbols to use when displaying this Graphic. By * default, a "square" with 50% gray fill and black outline with a * size of 6 pixels (unless a size is specified) is provided. */ @Deprecated public Symbol[] getSymbols() { ArrayList<Symbol> symbols = new ArrayList<Symbol>(); for( GraphicalSymbol graphic : graphics ){ if( graphic instanceof Symbol ){ symbols.add( (Symbol) graphic ); } } return symbols.toArray(new Symbol[0]); } // public List<Symbol> graphicalSymbols() { // return symbols; // } @Deprecated public void setSymbols(Symbol[] symbols) { graphics.clear(); for(Symbol g : symbols){ graphics.add(g); } } @Deprecated public void addSymbol(Symbol symbol) { graphics.add(symbol); } public AnchorPointImpl getAnchorPoint() { return anchor; } public void setAnchorPoint(org.geotools.styling.AnchorPoint anchor) { this.anchor = AnchorPointImpl.cast( anchor ); } public void setAnchorPoint(org.opengis.style.AnchorPoint anchorPoint) { this.anchor = AnchorPointImpl.cast( anchorPoint ); } /** * This specifies the level of translucency to use when rendering the graphic.<br> * The value is encoded as a floating-point value between 0.0 and 1.0 with * 0.0 representing totally transparent and 1.0 representing totally * opaque, with a linear scale of translucency for intermediate values.<br> * For example, "0.65" would represent 65% opacity. The default value is * 1.0 (opaque). * * @return The opacity of the Graphic, where 0.0 is completely transparent * and 1.0 is completely opaque. */ public Expression getOpacity() { return opacity; } /** * This parameter defines the rotation of a graphic in the clockwise * direction about its centre point in decimal degrees. The value encoded * as a floating point number. * * @return The angle of rotation in decimal degrees. Negative values * represent counter-clockwise rotation. The default is 0.0 (no * rotation). */ public Expression getRotation() { return rotation; } /** * This paramteter gives the absolute size of the graphic in pixels encoded * as a floating point number. * * <p> * The default size of an image format (such as GIFD) is the inherent size * of the image. The default size of a format without an inherent size * (such as SVG) is defined to be 16 pixels in height and the * corresponding aspect in width. If a size is specified, the height of * the graphic will be scaled to that size and the corresponding aspect * will be used for the width. * </p> * * @return The size of the graphic, the default is context specific. * Negative values are not possible. */ public Expression getSize() { return size; } public DisplacementImpl getDisplacement() { return displacement; } public Expression getInitialGap() { return initialGap; } public void setInitialGap( Expression initialGap ){ this.initialGap = initialGap; } public Expression getGap() { return gap; } public void setGap(Expression gap) { this.gap = gap; } public void setDisplacement(org.opengis.style.Displacement offset) { this.displacement = DisplacementImpl.cast( offset ); } /** * Graphic opacity. * * @param opacity New value of property opacity. */ public void setOpacity(Expression opacity) { this.opacity = opacity; } @Deprecated public void setOpacity(double opacity) { setOpacity(filterFactory.literal(opacity)); } /** * Setter for property rotation. * * @param rotation New value of property rotation. */ public void setRotation(Expression rotation) { this.rotation = rotation; } @Deprecated public void setRotation(double rotation) { setRotation(filterFactory.literal(rotation)); } /** * Setter for property size. * * @param size New value of property size. */ public void setSize(Expression size) { this.size = size; } @Deprecated public void setSize(int size) { setSize(filterFactory.literal(size)); } public Object accept(StyleVisitor visitor, Object data) { return visitor.visit((org.opengis.style.GraphicStroke)this, data); } public void accept(org.geotools.styling.StyleVisitor visitor) { visitor.visit(this); } /** * Creates a deep copy clone. * * @return The deep copy clone. * * @throws RuntimeException DOCUMENT ME! */ public Object clone() { GraphicImpl clone; try { clone = (GraphicImpl) super.clone(); clone.graphics.clear(); clone.graphics.addAll(graphics); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); // this should never happen. } return clone; } /** * Override of hashcode * * @return The hashcode. */ public int hashCode() { final int PRIME = 1000003; int result = 0; if (graphics != null) { result = (PRIME * result) + graphics.hashCode(); } if (rotation != null) { result = (PRIME * result) + rotation.hashCode(); } if (size != null) { result = (PRIME * result) + size.hashCode(); } if (opacity != null) { result = (PRIME * result) + opacity.hashCode(); } // if (gap != null) { // result = (PRIME * result) + gap.hashCode(); // } // // if (initialGap != null) { // result = (PRIME * result) + initialGap.hashCode(); // } return result; } /** * Compares this GraphicImpl with another for equality. * * <p> * Two graphics are equal if and only if they both have the same geometry * property name and the same list of symbols and the same rotation, size * and opacity. * </p> * * @param oth The other GraphicsImpl to compare with. * * @return True if this is equal to oth according to the above conditions. */ public boolean equals(Object oth) { if (this == oth) { return true; } if (oth instanceof GraphicImpl) { GraphicImpl other = (GraphicImpl) oth; return Utilities.equals(this.size, other.size) && Utilities.equals(this.rotation, other.rotation) && Utilities.equals(this.opacity, other.opacity) && Arrays.equals(this.getMarks(), other.getMarks() ) && Arrays.equals( this.getExternalGraphics(), other.getExternalGraphics() ) && Arrays.equals( this.getSymbols(), other.getSymbols() ); // return // Utilities.equals(this.geometryPropertyName,other.geometryPropertyName) // && Utilities.equals(this.size, other.size) // && Utilities.equals(this.rotation, other.rotation) // && Utilities.equals(this.opacity, other.opacity) // && Utilities.equals(this.graphics, other.graphics ) // && Utilities.equals(this.anchor, other.anchor) // && Utilities.equals(this.gap, other.gap) // && Utilities.equals(this.initialGap, other.initialGap); } return false; } static GraphicImpl cast(org.opengis.style.Graphic graphic) { if( graphic == null){ return null; } else if ( graphic instanceof GraphicImpl){ return (GraphicImpl) graphic; } else { GraphicImpl copy = new GraphicImpl(); copy.setAnchorPoint( graphic.getAnchorPoint() ); copy.setDisplacement( graphic.getDisplacement() ); if( graphic.graphicalSymbols() != null ){ for ( GraphicalSymbol item : graphic.graphicalSymbols()) { if( item instanceof org.opengis.style.ExternalGraphic){ copy.graphicalSymbols().add( ExternalGraphicImpl.cast( item )); } else if( item instanceof org.opengis.style.Mark){ copy.graphicalSymbols().add( MarkImpl.cast( item )); } } } return copy; } } }