001package com.hfg.graphics.units;
002
003
004import java.util.regex.Matcher;
005import java.util.regex.Pattern;
006
007import com.hfg.units.UnitException;
008import com.hfg.util.StringUtil;
009
010//------------------------------------------------------------------------------
011/**
012 * Interface for a unit-independent graphic length measurement.
013 *
014 * @author J. Alex Taylor, hairyfatguy.com
015 */
016//------------------------------------------------------------------------------
017// com.hfg XML/HTML Coding Library
018//
019// This library is free software; you can redistribute it and/or
020// modify it under the terms of the GNU Lesser General Public
021// License as published by the Free Software Foundation; either
022// version 2.1 of the License, or (at your option) any later version.
023//
024// This library is distributed in the hope that it will be useful,
025// but WITHOUT ANY WARRANTY; without even the implied warranty of
026// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
027// Lesser General Public License for more details.
028//
029// You should have received a copy of the GNU Lesser General Public
030// License along with this library; if not, write to the Free Software
031// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
032//
033// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
034// jataylor@hairyfatguy.com
035//------------------------------------------------------------------------------
036
037public interface GfxSize
038{
039
040   public float to(GfxUnits inUnits);
041
042   public int toInt(GfxUnits inUnits);
043
044   public float value();
045
046   public GfxUnits getUnits();
047
048   public GfxSize add(GfxSize inValue);
049   public GfxSize subtract(GfxSize inValue);
050
051   public void scale(float inScalingFactor);
052
053   static final Pattern MEASUREMENT_PATTERN = Pattern.compile("(\\-?[\\d\\.]+)\\s*(\\w+)?");
054
055   static final Pattern INT_WITH_UNITS_PATTERN = Pattern.compile("(-?\\d+)\\s?+([^\\d]+)");
056   static final Pattern DOUBLE_WITH_UNITS_PATTERN = Pattern.compile("(-?\\d+\\.\\d+)\\s?+([^\\d]+)");
057   static final Pattern SCIENTIFIC_NOTATION_WITH_UNITS_PATTERN = Pattern.compile("(-?\\d+(?:\\.\\d+)?E\\-?\\d+)\\s?+(\\S+)");
058
059   //---------------------------------------------------------------------------
060   /**
061    Convenience allocator that accepts a string with a value followed by units.
062    * @param inStringValue the string value
063    */
064   public static GfxSize allocate(String inStringValue)
065   {
066      float floatVal;
067      GfxUnits units;
068
069      Matcher m = INT_WITH_UNITS_PATTERN.matcher(inStringValue.trim());
070      if (m.matches())
071      {
072         floatVal = Float.parseFloat(m.group(1));
073         units = GfxUnits.valueOf(m.group(2));
074      }
075      else
076      {
077         m = DOUBLE_WITH_UNITS_PATTERN.matcher(inStringValue.trim());
078         if (m.matches())
079         {
080            floatVal = Float.parseFloat(m.group(1));
081            units = GfxUnits.valueOf(m.group(2));
082         }
083         else
084         {
085            m = SCIENTIFIC_NOTATION_WITH_UNITS_PATTERN.matcher(inStringValue.trim());
086            if (m.matches())
087            {
088               floatVal = Float.parseFloat(m.group(1));
089               units = GfxUnits.valueOf(m.group(2));
090            }
091            else
092            {
093               throw new UnitException("Couldn't parse " + StringUtil.singleQuote(inStringValue) + " into a GfxSize!");
094            }
095         }
096      }
097
098
099      if (null == units)
100      {
101         throw new UnitException("Couldn't parse " + StringUtil.singleQuote(inStringValue) + " into a GfxSize! Unrecognized units value.");
102      }
103
104      GfxSize size = null;
105
106      if (units.equals(GfxUnits.pixels))
107      {
108         size = new Pixels((int)floatVal);
109      }
110      else if (units.equals(GfxUnits.points))
111      {
112         size = new Points(floatVal);
113      }
114      else if (units.equals(GfxUnits.dxa))
115      {
116         size = new Points(floatVal / 20);
117      }
118      else if (units.equals(GfxUnits.inches))
119      {
120         size = new Points(floatVal * 72f); // There are 72 points per inch
121      }
122
123      return size;
124   }
125
126   //--------------------------------------------------------------------------
127   /**
128    Function for converting a string representation of a graphics measurement into its appropriate object.
129    @param inStringValue  the string representation (ex: "10px", "12pt", or "17.5")
130    @param inDefaultUnits  the units to use if the string representation is unit-less.
131    @return a GfxSize-extending object
132    */
133   public static GfxSize allocate(String inStringValue, GfxUnits inDefaultUnits)
134   {
135      if (! StringUtil.isSet(inStringValue))
136      {
137         throw new RuntimeException("No String value sent to GfxSize.allocate()!");
138      }
139
140      inStringValue = inStringValue.trim();
141
142      Matcher m = MEASUREMENT_PATTERN.matcher(inStringValue);
143      if (! m.matches())
144      {
145         throw new RuntimeException(StringUtil.singleQuote(inStringValue) + " could not be interpreted by GfxSize.allocate()!");
146      }
147
148      float floatVal = Float.parseFloat(m.group(1));
149      GfxSize size = null;
150      GfxUnits units = GfxUnits.valueOf(m.group(2));
151      if (null == units)
152      {
153         units = inDefaultUnits;
154      }
155
156      if (units.equals(GfxUnits.pixels))
157      {
158         size = new Pixels((int)floatVal);
159      }
160      else if (units.equals(GfxUnits.points))
161      {
162         size = new Points(floatVal);
163      }
164      else if (units.equals(GfxUnits.dxa))
165      {
166         size = new Points(floatVal / 20);
167      }
168      else if (units.equals(GfxUnits.inches))
169      {
170         size = new Points(floatVal * 72f); // There are 72 points per inch
171      }
172
173      return size;
174   }
175
176   //--------------------------------------------------------------------------
177   /**
178    Function for constructing a GfxSize object.
179    @param inValue  the integer value
180    @param inUnits  the units to use
181    @return a GfxSize-extending object
182    */
183   public static GfxSize allocate(int inValue, GfxUnits inUnits)
184   {
185      return new GfxSizeImpl(inValue, inUnits);
186   }
187
188   //--------------------------------------------------------------------------
189   /**
190    Function for constructing a GfxSize object.
191    @param inValue  the float value
192    @param inUnits  the units to use
193    @return a GfxSize-extending object
194    */
195   public static GfxSize allocate(float inValue, GfxUnits inUnits)
196   {
197      return new GfxSizeImpl(inValue, inUnits);
198   }
199
200   //---------------------------------------------------------------------------
201   public default boolean greaterThan(GfxSize inValue)
202   {
203      boolean result = false;
204      if (inValue != null)
205      {
206         result = to(getUnits()) > inValue.to(getUnits());
207      }
208
209      return result;
210   }
211
212   //---------------------------------------------------------------------------
213   public default boolean lessThan(GfxSize inValue)
214   {
215      boolean result = false;
216      if (inValue != null)
217      {
218         result = to(getUnits()) < inValue.to(getUnits());
219      }
220
221      return result;
222   }
223
224}