001package com.hfg.svg.path; 002 003import com.hfg.exception.ProgrammingException; 004import com.hfg.util.StringBuilderPlus; 005import com.hfg.util.collection.CollectionUtil; 006 007import java.awt.geom.Path2D; 008import java.awt.geom.Point2D; 009import java.lang.reflect.Constructor; 010import java.util.ArrayList; 011import java.util.HashMap; 012import java.util.List; 013import java.util.Map; 014 015//------------------------------------------------------------------------------ 016/** 017 * Base representation of an SVG (Scalable Vector Graphics) path command. 018 * 019 * @author J. Alex Taylor, hairyfatguy.com 020 */ 021//------------------------------------------------------------------------------ 022// com.hfg XML/HTML Coding Library 023// 024// This library is free software; you can redistribute it and/or 025// modify it under the terms of the GNU Lesser General Public 026// License as published by the Free Software Foundation; either 027// version 2.1 of the License, or (at your option) any later version. 028// 029// This library is distributed in the hope that it will be useful, 030// but WITHOUT ANY WARRANTY; without even the implied warranty of 031// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 032// Lesser General Public License for more details. 033// 034// You should have received a copy of the GNU Lesser General Public 035// License along with this library; if not, write to the Free Software 036// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 037// 038// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 039// jataylor@hairyfatguy.com 040//------------------------------------------------------------------------------ 041 042public abstract class SvgPathCmd 043{ 044 private char mCmdChar; 045 private List<Float> mRawNumbers; 046 private boolean mIsRelative; 047 private Point2D.Float mStartingPoint; 048 private int mNumSteps; 049 050 private static Map<Character, Constructor> sCmdMap = new HashMap<>(25); 051 052 static 053 { 054 try 055 { 056 sCmdMap.put('A', SvgPathEllipticalArcCmd.class.getConstructor()); 057 sCmdMap.put('C', SvgPathCurveToCmd.class.getConstructor()); 058 sCmdMap.put('H', SvgPathHorizLineToCmd.class.getConstructor()); 059 sCmdMap.put('L', SvgPathLineToCmd.class.getConstructor()); 060 sCmdMap.put('M', SvgPathMoveToCmd.class.getConstructor()); 061 sCmdMap.put('Q', SvgPathQuadCurveToCmd.class.getConstructor()); 062 sCmdMap.put('S', SvgPathSmoothCurveToCmd.class.getConstructor()); 063 sCmdMap.put('T', SvgPathSmoothQuadCurveToCmd.class.getConstructor()); 064 sCmdMap.put('V', SvgPathVertLineToCmd.class.getConstructor()); 065 sCmdMap.put('Z', SvgPathClosePathCmd.class.getConstructor()); 066 } 067 catch (NoSuchMethodException e) 068 { 069 throw new ProgrammingException(e); 070 } 071 } 072 073 //--------------------------------------------------------------------------- 074 protected SvgPathCmd(char inCmdChar) 075 { 076 mCmdChar = inCmdChar; 077 } 078 079 //--------------------------------------------------------------------------- 080 public static SvgPathCmd allocate(char inCmdChar) 081 { 082 SvgPathCmd pathCmd = null; 083 084 Constructor cmdClassConstructor = sCmdMap.get(Character.toUpperCase(inCmdChar)); 085 if (cmdClassConstructor != null) 086 { 087 try 088 { 089 pathCmd = (SvgPathCmd) cmdClassConstructor.newInstance(); 090 } 091 catch (Exception e) 092 { 093 throw new ProgrammingException(e); 094 } 095 096 if (Character.isLowerCase(inCmdChar)) 097 { 098 pathCmd.mIsRelative = true; 099 } 100 } 101 102 return pathCmd; 103 } 104 105 //--------------------------------------------------------------------------- 106 public char getCmdChar() 107 { 108 return (mIsRelative ? Character.toLowerCase(mCmdChar) : mCmdChar); 109 } 110 111 //--------------------------------------------------------------------------- 112 public SvgPathCmd setIsRelative(boolean inValue) 113 { 114 mIsRelative = inValue; 115 return this; 116 } 117 118 //--------------------------------------------------------------------------- 119 public boolean isRelative() 120 { 121 return mIsRelative; 122 } 123 124 //--------------------------------------------------------------------------- 125 public SvgPathCmd setRawNumbers(List<Float> inValue) 126 { 127 mRawNumbers = (inValue != null ? new ArrayList<>(inValue) : null); 128 return this; 129 } 130 131 //--------------------------------------------------------------------------- 132 public List<Float> getRawNumbers() 133 { 134 return mRawNumbers; 135 } 136 137 //--------------------------------------------------------------------------- 138 public SvgPathCmd setStartingPoint(Point2D.Float inValue) 139 { 140 mStartingPoint = inValue; 141 return this; 142 } 143 144 //--------------------------------------------------------------------------- 145 public Point2D.Float getStartingPoint() 146 { 147 return mStartingPoint; 148 } 149 150 //--------------------------------------------------------------------------- 151 protected SvgPathCmd setNumSteps(int inValue) 152 { 153 mNumSteps = inValue; 154 return this; 155 } 156 157 //--------------------------------------------------------------------------- 158 public int getNumSteps() 159 { 160 return mNumSteps; 161 } 162 163 //--------------------------------------------------------------------------- 164 public abstract Point2D.Float draw(Path2D.Float inPolyline); 165 166 //--------------------------------------------------------------------------- 167 @Override 168 public String toString() 169 { 170 StringBuilderPlus buffer = new StringBuilderPlus().setDelimiter(" "); 171 if (CollectionUtil.hasValues(mRawNumbers)) 172 { 173 for (Float num : mRawNumbers) 174 { 175 buffer.delimitedAppend(num.floatValue() == num.intValue() ? num.intValue() + "" : num + ""); 176 } 177 } 178 179 buffer.insert(0, getCmdChar()); 180 181 return buffer.toString(); 182 } 183}