package com.google.maps.android.kml; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.maps.model.PolygonOptions; import com.google.android.gms.maps.model.PolylineOptions; import android.graphics.Color; import java.util.HashMap; import java.util.HashSet; import java.util.Random; /** * Represents the defined styles in the KML document */ /* package */ class KmlStyle { private final static int HSV_VALUES = 3; private final static int HUE_VALUE = 0; private final static int INITIAL_SCALE = 1; private final MarkerOptions mMarkerOptions; private final PolylineOptions mPolylineOptions; private final PolygonOptions mPolygonOptions; private final HashMap<String, String> mBalloonOptions; private final HashSet<String> mStylesSet; private boolean mFill = true; private boolean mOutline = true; private String mIconUrl; private double mScale; private String mStyleId; private boolean mIconRandomColorMode; private boolean mLineRandomColorMode; private boolean mPolyRandomColorMode; private float mMarkerColor; /** * Creates a new Style object */ /* package */ KmlStyle() { mStyleId = null; mMarkerOptions = new MarkerOptions(); mPolylineOptions = new PolylineOptions(); mPolygonOptions = new PolygonOptions(); mBalloonOptions = new HashMap<String, String>(); mStylesSet = new HashSet<String>(); mScale = INITIAL_SCALE; mMarkerColor = 0; mIconRandomColorMode = false; mLineRandomColorMode = false; mPolyRandomColorMode = false; } /** * Sets text found for an info window * * @param text Text for an info window */ /* package */ void setInfoWindowText(String text) { mBalloonOptions.put("text", text); } /** * Gets the id for the style * * @return Style Id, null otherwise */ /* package */ String getStyleId() { return mStyleId; } /** * Sets id for a style * * @param styleId Id for the style */ /* package */ void setStyleId(String styleId) { mStyleId = styleId; } /** * Checks if a given style (for a marker, linestring or polygon) has been set * * @param style style to check if set * @return True if style was set, false otherwise */ /* package */ boolean isStyleSet(String style) { return mStylesSet.contains(style); } /** * Gets whether the Polygon fill is set * * @return True if there is a fill for the polygon, false otherwise */ /* package */ boolean hasFill() { return mFill; } /** * Sets whether the Polygon has a fill * * @param fill True if the polygon fill is set, false otherwise */ /* package */ void setFill(boolean fill) { mFill = fill; } /** * Gets the scale for a marker icon * * @return scale value */ /* package */ double getIconScale() { return mScale; } /** * Sets the scale for a marker icon * * @param scale scale value */ /* package */ void setIconScale(double scale) { mScale = scale; mStylesSet.add("iconScale"); } /** * Gets whether the Polygon outline is set * * @return True if the polygon outline is set, false otherwise */ /* package */ boolean hasOutline() { return mOutline; } /** * Gets whether a BalloonStyle has been set * * @return True if a BalloonStyle has been set, false otherwise */ /* package */ boolean hasBalloonStyle() { return mBalloonOptions.size() > 0; } /** * Sets whether the Polygon has an outline * * @param outline True if the polygon outline is set, false otherwise */ /* package */ void setOutline(boolean outline) { mOutline = outline; mStylesSet.add("outline"); } /** * Gets the url for the marker icon * * @return Url for the marker icon, null otherwise */ /* package */ String getIconUrl() { return mIconUrl; } /** * Sets the url for the marker icon * * @param iconUrl Url for the marker icon */ /* package */ void setIconUrl(String iconUrl) { mIconUrl = iconUrl; if (!mIconUrl.startsWith("http://")) { // Icon stored locally mMarkerOptions.icon(BitmapDescriptorFactory.fromPath(iconUrl)); } mStylesSet.add("iconUrl"); } /** * Sets the fill color for a Polygon * * @param color Fill color for a Polygon */ /* package */ void setFillColor(String color) { // Add # to allow for mOutline color to be parsed correctly mPolygonOptions.fillColor(Color.parseColor("#" + convertColor(color))); mStylesSet.add("fillColor"); } /** * Sets the color for a marker * * @param color Color for a marker */ /* package */ void setMarkerColor(String color) { int integerColor = Color.parseColor("#" + convertColor(color)); mMarkerColor = getHueValue(integerColor); mMarkerOptions.icon(BitmapDescriptorFactory.defaultMarker(mMarkerColor)); mStylesSet.add("markerColor"); } /** * Gets the hue value from a color * * @param integerColor Integer representation of a color * @return Hue value from a color */ private static float getHueValue (int integerColor) { float[] hsvValues = new float[HSV_VALUES]; Color.colorToHSV(integerColor, hsvValues); return hsvValues[HUE_VALUE]; } /** * Converts a color format of the form AABBGGRR to AARRGGBB * * @param color Color of the form AABBGGRR * @return Color of the form AARRGGBB */ private static String convertColor(String color) { String newColor; if (color.length() > 6) { newColor = color.substring(0, 2) + color.substring(6, 8) + color.substring(4,6)+ color.substring(2, 4); } else { newColor = color.substring(4,6) + color.substring(2,4) + color.substring(0,2); } return newColor; } /** * Sets the rotation / heading for a marker * * @param heading Decimal representation of a rotation value */ /* package */ void setHeading(float heading) { mMarkerOptions.rotation(heading); mStylesSet.add("heading"); } /** * Sets the hotspot / anchor point of a marker * * @param x x point of a marker position * @param y y point of a marker position * @param xUnits units in which the x value is specified * @param yUnits units in which the y value is specified */ /* package */ void setHotSpot(float x, float y, String xUnits, String yUnits) { float xAnchor = 0.5f; float yAnchor = 1.0f; // Set x coordinate if (xUnits.equals("fraction")) { xAnchor = x; } if (yUnits.equals("fraction")) { yAnchor = y; } mMarkerOptions.anchor(xAnchor, yAnchor); mStylesSet.add("hotSpot"); } /** * Sets the color mode for a marker. A "random" color mode sets the color mode to true, * a "normal" colormode sets the color mode to false. * * @param colorMode A "random" or "normal" color mode */ /* package */ void setIconColorMode(String colorMode) { mIconRandomColorMode = colorMode.equals("random"); mStylesSet.add("iconColorMode"); } /** * Checks whether the color mode for a marker is true / random * * @return True if the color mode is true, false otherwise */ /* package */ boolean isIconRandomColorMode() { return mIconRandomColorMode; } /** * Sets the color mode for a polyline. A "random" color mode sets the color mode to true, * a "normal" colormode sets the color mode to false. * * @param colorMode A "random" or "normal" color mode */ /* package */ void setLineColorMode(String colorMode) { mLineRandomColorMode = colorMode.equals("random"); mStylesSet.add("lineColorMode"); } /** * Checks whether the color mode for a polyline is true / random * * @return True if the color mode is true, false otherwise */ /* package */ boolean isLineRandomColorMode() { return mLineRandomColorMode; } /** * Sets the color mode for a polygon. A "random" color mode sets the color mode to true, * a "normal" colormode sets the color mode to false. * * @param colorMode A "random" or "normal" color mode */ /* package */ void setPolyColorMode(String colorMode) { mPolyRandomColorMode = colorMode.equals("random"); mStylesSet.add("polyColorMode"); } /** * Checks whether the color mode for a polygon is true / random * * @return True if the color mode is true, false otherwise */ /* package */ boolean isPolyRandomColorMode() { return mPolyRandomColorMode; } /** * Sets the outline color for a Polyline and a Polygon * * @param color Outline color for a Polyline and a Polygon */ /* package */ void setOutlineColor(String color) { // Add # to allow for mOutline color to be parsed correctly mPolylineOptions.color(Color.parseColor("#" + convertColor(color))); mPolygonOptions.strokeColor(Color.parseColor("#" + color)); mStylesSet.add("outlineColor"); } /** * Sets the line width for a Polyline and a Polygon * * @param width Line width for a Polyline and a Polygon */ /* package */ void setWidth(Float width) { mPolylineOptions.width(width); mPolygonOptions.strokeWidth(width); mStylesSet.add("width"); } /** * Gets the balloon options * * @return Balloon Options */ /* package */ HashMap<String, String> getBalloonOptions() { return mBalloonOptions; } /** * Creates a new marker option from given properties of an existing marker option * * @param originalMarkerOption An existing MarkerOption instance * @param iconRandomColorMode True if marker color mode is random, false otherwise * @param markerColor Color of the marker * @return A new MarkerOption */ private static MarkerOptions createMarkerOptions(MarkerOptions originalMarkerOption, boolean iconRandomColorMode, float markerColor) { MarkerOptions newMarkerOption = new MarkerOptions(); newMarkerOption.rotation(originalMarkerOption.getRotation()); newMarkerOption.anchor(originalMarkerOption.getAnchorU(), originalMarkerOption.getAnchorV()); if (iconRandomColorMode) { float hue = getHueValue(computeRandomColor((int) markerColor)); originalMarkerOption.icon(BitmapDescriptorFactory.defaultMarker(hue)); } newMarkerOption.icon(originalMarkerOption.getIcon()); return newMarkerOption; } /** * Creates a new PolylineOption from given properties of an existing PolylineOption * @param originalPolylineOption An existing PolylineOption instance * @return A new PolylineOption */ private static PolylineOptions createPolylineOptions (PolylineOptions originalPolylineOption) { PolylineOptions polylineOptions = new PolylineOptions(); polylineOptions.color(originalPolylineOption.getColor()); polylineOptions.width(originalPolylineOption.getWidth()); return polylineOptions; } /** *Creates a new PolygonOption from given properties of an existing PolygonOption * @param originalPolygonOption An existing PolygonOption instance * @param isFill Whether the fill for a polygon is set * @param isOutline Whether the outline for a polygon is set * @return A new PolygonOption */ private static PolygonOptions createPolygonOptions (PolygonOptions originalPolygonOption, boolean isFill, boolean isOutline) { PolygonOptions polygonOptions = new PolygonOptions(); if (isFill) { polygonOptions.fillColor(originalPolygonOption.getFillColor()); } if (isOutline) { polygonOptions.strokeColor(originalPolygonOption.getStrokeColor()); polygonOptions.strokeWidth(originalPolygonOption.getStrokeWidth()); } return polygonOptions; } /** * Gets a MarkerOption * * @return A new MarkerOption */ /* package */ MarkerOptions getMarkerOptions() { return createMarkerOptions(mMarkerOptions, isIconRandomColorMode(), mMarkerColor); } /** * Gets a PolylineOption * * @return new PolylineOptions */ /* package */ PolylineOptions getPolylineOptions() { return createPolylineOptions(mPolylineOptions); } /** * Gets a PolygonOption * * @return new PolygonOptions */ /* package */ PolygonOptions getPolygonOptions() { return createPolygonOptions(mPolygonOptions, mFill, mOutline); } /** * Computes a random color given an integer. Algorithm to compute the random color can be * found in https://developers.google.com/kml/documentation/kmlreference#colormode * * @param color Color represented as an integer * @return Integer representing a random color */ /* package */ static int computeRandomColor(int color) { Random random = new Random(); int red = Color.red(color); int green = Color.green(color); int blue = Color.blue(color); //Random number can only be computed in range [0, n) if (red != 0) { red = random.nextInt(red); } if (blue != 0) { blue = random.nextInt(blue); } if (green != 0) { green = random.nextInt(green); } return Color.rgb(red, green, blue); } @Override public String toString() { StringBuilder sb = new StringBuilder("Style").append("{"); sb.append("\n balloon options=").append(mBalloonOptions); sb.append(",\n fill=").append(mFill); sb.append(",\n outline=").append(mOutline); sb.append(",\n icon url=").append(mIconUrl); sb.append(",\n scale=").append(mScale); sb.append(",\n style id=").append(mStyleId); sb.append("\n}\n"); return sb.toString(); } }