All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.worldwind.render.Size Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */

package gov.nasa.worldwind.render;

import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.util.*;

import java.awt.*;

/**
 * Defines the dimensions of an image, label or other screen-space item relative to a container (for example, the
 * viewport). A size contains a width, a height, a width size mode, a height size mode, and for each of these a "units"
 * string indicating the coordinate units.
 * 

* The possible size modes are:

  • {@link #NATIVE_DIMENSION} - Maintain the native dimensions.
  • {@link * #MAINTAIN_ASPECT_RATIO} - Maintain the aspect ratio of the image when one dimension is specified and the other is * not.
  • {@link #EXPLICIT_DIMENSION} - Use an explicit dimension. This dimension may be either an absolute * pixel value, or a fraction of the container.
  • *

    * Recognized units are {@link AVKey#PIXELS}, which indicates pixel units relative to the lower left corner of the * image, or {@link AVKey#FRACTION}, which indicates the units are fractions of the image width and height. *

    * Examples: *

     * Width mode      Height mode      Width (Units)      Height (Units)        Result
     * --------------------------------------------------------------------------------------------------------------------
     * Native          Native           N/A                N/A                   Keep native dimensions
     * Aspect ratio    Explicit         N/A                100 (pix)             Scale image so that height is 100 pixels,
     *                                                                           but maintain aspect ratio
     * Explicit        Aspect ratio     0.5 (fraction)     N/A                   Make the width half of the container, and
     *                                                                           scale height to maintain aspect ratio
     * Explicit        Native           1.0 (fraction)     N/A                   Stretch the image to fill the width of the
     *                                                                           container, but do not scale the height.
     *
     * This class implements the functionality of a KML size.
     *
     * @author pabercrombie
     * @version $Id: Size.java 1171 2013-02-11 21:45:02Z dcollins $
     */
    public class Size
    {
        /** Size mode to indicate that the content's native dimension must be used. */
        public static final String NATIVE_DIMENSION = "gov.nasa.worldwind.render.Size.NativeDimension";
    
        /** Size mode to indicate that the content's aspect ratio must be maintained. */
        public static final String MAINTAIN_ASPECT_RATIO = "gov.nasa.worldwind.render.Size.MaintainAspectRatio";
    
        /**
         * Size mode to indicate that the size parameter indicates an explicit dimension measured either in pixels, or as a
         * fraction of the container.
         */
        public static final String EXPLICIT_DIMENSION = "gov.nasa.worldwind.render.Size.ExplicitDimension";
    
        /**
         * Size mode for width. May be one of {@link #NATIVE_DIMENSION}, {@link #MAINTAIN_ASPECT_RATIO}, or {@link
         * #EXPLICIT_DIMENSION}.
         */
        protected String widthMode = NATIVE_DIMENSION;
        /** Units of width. */
        protected String widthUnits = AVKey.PIXELS;
        /** Width size parameter. */
        protected double widthParam;
    
        /**
         * Size mode for height. May be one of {@link #NATIVE_DIMENSION}, {@link #MAINTAIN_ASPECT_RATIO}, or {@link
         * #EXPLICIT_DIMENSION}.
         */
        protected String heightMode = NATIVE_DIMENSION;
        /** Units of height. */
        protected String heightUnits = AVKey.PIXELS;
        /** Height size parameter. */
        protected double heightParam;
    
        /** Create a Size object that will preserve native dimensions. */
        public Size()
        {
        }
    
        /**
         * Create a Size with specified dimensions.
         *
         * @param widthMode   Width mode, one of {@link #NATIVE_DIMENSION}, {@link #MAINTAIN_ASPECT_RATIO}, or {@link
         *                    #EXPLICIT_DIMENSION}.
         * @param widthParam  The width (applies only to {@link #EXPLICIT_DIMENSION} mode).
         * @param widthUnits  Units of {@code width}. Either {@link AVKey#PIXELS} or {@link AVKey#PIXELS}.
         * @param heightMode  height mode, one of {@link #NATIVE_DIMENSION}, {@link #MAINTAIN_ASPECT_RATIO}, or {@link
         *                    #EXPLICIT_DIMENSION}.
         * @param heightParam The height (applies only to {@link #EXPLICIT_DIMENSION} mode).
         * @param heightUnits Units of {@code height}. Either {@link AVKey#PIXELS} or {@link AVKey#PIXELS}.
         *
         * @see #setWidth(String, double, String)
         * @see #setHeight(String, double, String)
         */
        public Size(String widthMode, double widthParam, String widthUnits, String heightMode, double heightParam,
            String heightUnits)
        {
            this.setWidth(widthMode, widthParam, widthUnits);
            this.setHeight(heightMode, heightParam, heightUnits);
        }
    
        /**
         * Create a size from explicit pixel dimensions.
         *
         * @param widthInPixels  Width of rectangle in pixels.
         * @param heightInPixels Height of rectangle in pixels.
         *
         * @return New size object.
         */
        public static Size fromPixels(int widthInPixels, int heightInPixels)
        {
            return new Size(EXPLICIT_DIMENSION, widthInPixels, AVKey.PIXELS,
                EXPLICIT_DIMENSION, heightInPixels, AVKey.PIXELS);
        }
    
        /**
         * Creates a new size from explicit fraction dimensions.
         *
         * @param widthFraction  the size's width as a fraction of the containing rectangle.
         * @param heightFraction the size's height as a fraction of the containing rectangle.
         *
         * @return a new size with the specified width and height.
         */
        public static Size fromFraction(double widthFraction, double heightFraction)
        {
            return new Size(EXPLICIT_DIMENSION, widthFraction, AVKey.FRACTION,
                EXPLICIT_DIMENSION, heightFraction, AVKey.FRACTION);
        }
    
        /**
         * Set the width.
         *
         * @param mode  Width mode, one of {@link #NATIVE_DIMENSION}, {@link #MAINTAIN_ASPECT_RATIO}, or {@link
         *              #EXPLICIT_DIMENSION}.
         * @param width The width (applies only to {@link #EXPLICIT_DIMENSION} mode).
         * @param units Units of {@code width}. Either {@link AVKey#PIXELS} or {@link AVKey#PIXELS}.
         *
         * @throws IllegalArgumentException if {@code mode} is null.
         */
        public void setWidth(String mode, double width, String units)
        {
            if (mode == null)
            {
                String message = Logging.getMessage("nullValue.SizeModeIsNull");
                Logging.logger().severe(message);
                throw new IllegalArgumentException(message);
            }
    
            this.widthMode = mode;
            this.widthParam = width;
            this.widthUnits = units;
        }
    
        /**
         * Set the height.
         *
         * @param mode   Width mode, one of {@link #NATIVE_DIMENSION}, {@link #MAINTAIN_ASPECT_RATIO}, or {@link
         *               #EXPLICIT_DIMENSION}.
         * @param height The width (applies only to {@link #EXPLICIT_DIMENSION} mode).
         * @param units  Units of {@code width}. Either {@link AVKey#PIXELS} or {@link AVKey#FRACTION}.
         *
         * @throws IllegalArgumentException if {@code mode} is null.
         */
        public void setHeight(String mode, double height, String units)
        {
            if (mode == null)
            {
                String message = Logging.getMessage("nullValue.SizeModeIsNull");
                Logging.logger().severe(message);
                throw new IllegalArgumentException(message);
            }
    
            this.heightMode = mode;
            this.heightParam = height;
            this.heightUnits = units;
        }
    
        /**
         * Returns the units of the offset X value. See {@link #setWidth(String, double, String)} for a description of the
         * recognized values.
         *
         * @return the units of the offset X value, or null.
         */
        public String getWidthUnits()
        {
            return widthUnits;
        }
    
        /**
         * Returns the units of the offset Y value. See {@link #setHeight(String, double, String)} for a description of the
         * recognized values.
         *
         * @return the units of the offset Y value, or null.
         */
        public String getHeightUnits()
        {
            return heightUnits;
        }
    
        /**
         * Get the mode of the width dimension.
         *
         * @return Width mode, one of {@link #NATIVE_DIMENSION}, {@link #MAINTAIN_ASPECT_RATIO}, or {@link
         *         #EXPLICIT_DIMENSION}.
         */
        public String getWidthMode()
        {
            return this.widthMode;
        }
    
        /**
         * Get the mode of the height dimension.
         *
         * @return Height mode, one of {@link #NATIVE_DIMENSION}, {@link #MAINTAIN_ASPECT_RATIO}, or {@link
         *         #EXPLICIT_DIMENSION}.
         */
        public String getHeightMode()
        {
            return this.heightMode;
        }
    
        /**
         * Get the unscaled width.
         *
         * @return Unscaled width. The units of this value depend on the current height units.
         *
         * @see #getWidthMode()
         * @see #getWidthUnits()
         */
        public double getWidth()
        {
            return widthParam;
        }
    
        /**
         * Get the unscaled height.
         *
         * @return Unscaled height. The units of this value depend on the current height units.
         *
         * @see #getHeightMode()
         * @see #getHeightUnits()
         */
        public double getHeight()
        {
            return heightParam;
        }
    
        /**
         * Computes the width and height of a rectangle within a container rectangle.
         *
         * @param rectWidth       The width of the rectangle to size.
         * @param rectHeight      The height of the rectangle to size.
         * @param containerWidth  The width of the container.
         * @param containerHeight The height of the container.
         *
         * @return The desired image dimensions.
         */
        public Dimension compute(int rectWidth, int rectHeight, int containerWidth, int containerHeight)
        {
            if (rectWidth < 0)
            {
                String message = Logging.getMessage("generic.InvalidWidth", rectWidth);
                Logging.logger().severe(message);
                throw new IllegalArgumentException(message);
            }
    
            if (rectHeight < 0)
            {
                String message = Logging.getMessage("generic.InvalidHeight", rectHeight);
                Logging.logger().severe(message);
                throw new IllegalArgumentException(message);
            }
    
            if (containerWidth < 0)
            {
                String message = Logging.getMessage("generic.InvalidWidth", containerWidth);
                Logging.logger().severe(message);
                throw new IllegalArgumentException(message);
            }
    
            if (containerHeight < 0)
            {
                String message = Logging.getMessage("generic.InvalidHeight", containerHeight);
                Logging.logger().severe(message);
                throw new IllegalArgumentException(message);
            }
    
            double aspectRatio;
            if (rectHeight != 0)
                aspectRatio = (double) rectWidth / rectHeight;
            else
                aspectRatio = 0;
    
            String xMode = this.getWidthMode();
            String yMode = this.getHeightMode();
    
            double width, height;
    
            if (NATIVE_DIMENSION.equals(xMode) && NATIVE_DIMENSION.equals(yMode)
                || NATIVE_DIMENSION.equals(xMode) && MAINTAIN_ASPECT_RATIO.equals(yMode)
                || MAINTAIN_ASPECT_RATIO.equals(xMode) && NATIVE_DIMENSION.equals(yMode)
                || MAINTAIN_ASPECT_RATIO.equals(xMode) && MAINTAIN_ASPECT_RATIO.equals(yMode))
            {
                // Keep original dimensions
                width = rectWidth;
                height = rectHeight;
            }
            else if (MAINTAIN_ASPECT_RATIO.equals(xMode))
            {
                // y dimension is specified, scale x to maintain aspect ratio
                height = computeSize(this.heightParam, this.heightUnits, containerHeight);
                width = height * aspectRatio;
            }
            else if (MAINTAIN_ASPECT_RATIO.equals(yMode))
            {
                // x dimension is specified, scale y to maintain aspect ratio
                width = computeSize(this.widthParam, this.widthUnits, containerWidth);
                if (aspectRatio != 0)
                    height = width / aspectRatio;
                else
                    height = 0;
            }
            else
            {
                if (NATIVE_DIMENSION.equals(xMode))
                    width = rectWidth;
                else
                    width = computeSize(this.widthParam, this.widthUnits, containerWidth);
    
                if (NATIVE_DIMENSION.equals(yMode))
                    height = rectHeight;
                else
                    height = computeSize(this.heightParam, this.heightUnits, containerHeight);
            }
    
            return new Dimension((int) width, (int) height);
        }
    
        /**
         * Compute a dimension taking into account the units of the dimension.
         *
         * @param size               The size parameter.
         * @param units              One of {@link AVKey#PIXELS} or {@link AVKey#FRACTION}. If the {@code units} value is
         *                           not one of the expected options, {@link AVKey#PIXELS} is used as the default.
         * @param containerDimension The viewport dimension.
         *
         * @return Size in pixels
         */
        protected double computeSize(double size, String units, double containerDimension)
        {
            if (AVKey.FRACTION.equals(units))
                return size * containerDimension;
            else  // Default to pixel
                return size;
        }
    
        /**
         * Saves the size's current state in the specified restorableSupport. If context is not
         * null, the state is appended to it.  Otherwise the state is added to the
         * RestorableSupport root. This state can be restored later by calling {@link
         * #restoreState(gov.nasa.worldwind.util.RestorableSupport, gov.nasa.worldwind.util.RestorableSupport.StateObject)}.
         *
         * @param restorableSupport the RestorableSupport that receives the size's state.
         * @param context           the StateObject the state is appended to, if not null.
         *
         * @throws IllegalArgumentException if restorableSupport is null.
         */
        public void getRestorableState(RestorableSupport restorableSupport, RestorableSupport.StateObject context)
        {
            if (restorableSupport == null)
            {
                String message = Logging.getMessage("nullValue.RestorableSupportIsNull");
                Logging.logger().severe(message);
                throw new IllegalArgumentException(message);
            }
    
            RestorableSupport.StateObject so = restorableSupport.addStateObject(context, "width");
            if (so != null)
            {
                restorableSupport.addStateValueAsString(so, "mode", this.getWidthMode());
                restorableSupport.addStateValueAsDouble(so, "param", this.getWidth());
    
                if (this.getWidthUnits() != null)
                    restorableSupport.addStateValueAsString(so, "units", this.getWidthUnits());
            }
    
            so = restorableSupport.addStateObject(context, "height");
            if (so != null)
            {
                restorableSupport.addStateValueAsString(so, "mode", this.getHeightMode());
                restorableSupport.addStateValueAsDouble(so, "param", this.getHeight());
    
                if (this.getHeightUnits() != null)
                    restorableSupport.addStateValueAsString(so, "units", this.getHeightUnits());
            }
        }
    
        /**
         * Restores the state of any size parameters contained in the specified RestorableSupport. If the
         * StateObject is not null it's searched for state values, otherwise the
         * RestorableSupport root is searched.
         *
         * @param restorableSupport the RestorableSupport that contains the size's state.
         * @param context           the StateObject to search for state values, if not null.
         *
         * @throws IllegalArgumentException if restorableSupport is null.
         */
        public void restoreState(RestorableSupport restorableSupport, RestorableSupport.StateObject context)
        {
            if (restorableSupport == null)
            {
                String message = Logging.getMessage("nullValue.RestorableSupportIsNull");
                Logging.logger().severe(message);
                throw new IllegalArgumentException(message);
            }
    
            RestorableSupport.StateObject so = restorableSupport.getStateObject(context, "width");
            if (so != null)
            {
                String mode = restorableSupport.getStateValueAsString(so, "mode");
                mode = convertLegacyModeString(mode);
    
                Double param = restorableSupport.getStateValueAsDouble(so, "param");
                String units = restorableSupport.getStateValueAsString(so, "units");
    
                // Restore the width only when the mode and param are specified. null is an acceptable value for units.
                if (mode != null && param != null)
                    this.setWidth(mode, param, units);
            }
    
            so = restorableSupport.getStateObject(context, "height");
            if (so != null)
            {
                String mode = restorableSupport.getStateValueAsString(so, "mode");
                mode = convertLegacyModeString(mode);
    
                Double param = restorableSupport.getStateValueAsDouble(so, "param");
                String units = restorableSupport.getStateValueAsString(so, "units");
    
                // Restore the height only when the mode and param are specified. null is an acceptable value for units.
                if (mode != null && param != null)
                    this.setHeight(mode, param, units);
            }
        }
    
        /**
         * Converts a legacy size mode string ("NativeDimension", "MaintainAspectRatio", "ExplicitDimension"),
         * into one of the mode constants (NATIVE_DIMENSION, MAINTAIN_ASPECT_RATIO, or
         * EXPLICIT_DIMENSION). Returns the input string unmodified if the input does not match a legacy size
         * mode.
         *
         * @param string the legacy size mode String to convert to a size mode.
         *
         * @return a size mode constant, or the input string if string is not a legacy size mode.
         */
        protected String convertLegacyModeString(String string)
        {
            if ("NativeDimension".equals(string))
                return NATIVE_DIMENSION;
            else if ("MaintainAspectRatio".equals(string))
                return MAINTAIN_ASPECT_RATIO;
            else if ("ExplicitDimension".equals(string))
                return EXPLICIT_DIMENSION;
            else
                return string;
        }
    
        @Override
        public boolean equals(Object o)
        {
            if (this == o)
                return true;
            if (o == null || this.getClass() != o.getClass())
                return false;
    
            Size that = (Size) o;
    
            if (Double.compare(this.widthParam, that.widthParam) != 0)
                return false;
            if (Double.compare(this.heightParam, that.heightParam) != 0)
                return false;
            if (this.widthUnits != null ? !this.widthUnits.equals(that.widthUnits) : that.widthUnits != null)
                return false;
            if (this.heightUnits != null ? !this.heightUnits.equals(that.heightUnits) : that.heightUnits != null)
                return false;
            if (this.widthMode != null ? !this.widthMode.equals(that.widthMode) : that.widthMode != null)
                return false;
            //noinspection RedundantIfStatement
            if (this.heightMode != null ? !this.heightMode.equals(that.heightMode) : that.heightMode != null)
                return false;
    
            return true;
        }
    
        @Override
        public int hashCode()
        {
            int result;
            long temp;
            temp = this.widthParam != +0.0d ? Double.doubleToLongBits(this.widthParam) : 0L;
            result = (int) (temp ^ (temp >>> 32));
            temp = this.heightParam != +0.0d ? Double.doubleToLongBits(this.heightParam) : 0L;
            result = 31 * result + (int) (temp ^ (temp >>> 32));
            result = 31 * result + (this.widthUnits != null ? this.widthUnits.hashCode() : 0);
            result = 31 * result + (this.heightUnits != null ? this.heightUnits.hashCode() : 0);
            result = 31 * result + (this.widthMode != null ? this.widthMode.hashCode() : 0);
            result = 31 * result + (this.heightMode != null ? this.heightMode.hashCode() : 0);
            return result;
        }
    }
    




© 2015 - 2024 Weber Informatics LLC | Privacy Policy