001package com.hfg.svg.path; 002 003import java.awt.geom.GeneralPath; 004import java.awt.geom.Path2D; 005import java.awt.geom.Point2D; 006import java.util.List; 007 008//------------------------------------------------------------------------------ 009/** 010 * Object representation of an SVG (Scalable Vector Graphics) path smooth curveTo ('S' or 's') command. 011 * 012 * @author J. Alex Taylor, hairyfatguy.com 013 */ 014//------------------------------------------------------------------------------ 015// com.hfg XML/HTML Coding Library 016// 017// This library is free software; you can redistribute it and/or 018// modify it under the terms of the GNU Lesser General Public 019// License as published by the Free Software Foundation; either 020// version 2.1 of the License, or (at your option) any later version. 021// 022// This library is distributed in the hope that it will be useful, 023// but WITHOUT ANY WARRANTY; without even the implied warranty of 024// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 025// Lesser General Public License for more details. 026// 027// You should have received a copy of the GNU Lesser General Public 028// License along with this library; if not, write to the Free Software 029// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 030// 031// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 032// jataylor@hairyfatguy.com 033//------------------------------------------------------------------------------ 034 035public class SvgPathSmoothCurveToCmd extends SvgPathCurveToCmd 036{ 037 private Point2D.Float mPrevCmdSecondControlPoint; 038 039 //--------------------------------------------------------------------------- 040 public SvgPathSmoothCurveToCmd() 041 { 042 super('S'); 043 } 044 045 046 //--------------------------------------------------------------------------- 047 @Override 048 public SvgPathSmoothCurveToCmd setRawNumbers(List<Float> inValue) 049 { 050 if (inValue.size()%4 != 0) 051 { 052 throw new SvgPathDataException("A pair of points per command must be given to a smooth curveTo path command!"); 053 } 054 055 setNumSteps(inValue.size()/4); 056 057 super.setRawNumbers(inValue); 058 return this; 059 } 060 061 //--------------------------------------------------------------------------- 062 public void setPrevCmdSecondControlPoint(Point2D.Float inValue) 063 { 064 mPrevCmdSecondControlPoint = inValue; 065 } 066 067 068 //-------------------------------------------------------------------------- 069 // From http://www.w3.org/TR/SVG/paths.html 070 // 071 // Draws a cubic Bézier curve from the current point to (x,y). 072 // The first control point is assumed to be the reflection of the second control point on the previous command relative 073 // to the current point. (If there is no previous command or if the previous command was not an C, c, S or s, assume 074 // the first control point is coincident with the current point.) (x2,y2) is the second control point (i.e., the 075 // control point at the end of the curve). S (uppercase) indicates that absolute coordinates will follow; 076 // s (lowercase) indicates that relative coordinates will follow. Multiple sets of coordinates may be specified to draw a polybézier. 077 // At the end of the command, the new current point becomes the final (x,y) coordinate pair used in the polybézier. 078 public Point2D.Float draw(Path2D.Float inPolyline) 079 { 080 List<Float> rawNumbers = getRawNumbers(); 081 int numIndex = 0; 082 083 Point2D.Float currentPoint = getStartingPoint(); 084 085 while (numIndex < rawNumbers.size() - 1) 086 { 087 Point2D.Float point1 = new Point2D.Float(rawNumbers.get(numIndex++), rawNumbers.get(numIndex++)); 088 Point2D.Float point2 = new Point2D.Float(rawNumbers.get(numIndex++), rawNumbers.get(numIndex++)); 089 090 if (isRelative()) 091 { 092 point1.setLocation(point1.getX() + currentPoint.getX(), point1.getY() + currentPoint.getY()); 093 point2.setLocation(point2.getX() + currentPoint.getX(), point2.getY() + currentPoint.getY()); 094 } 095 096 Point2D.Float firstCtrlPoint = currentPoint; 097 if (mPrevCmdSecondControlPoint != null) 098 { 099 // Calculate reflection of the prev second control point 100 firstCtrlPoint = new Point2D.Float((float) (currentPoint.getX() + (2 * (currentPoint.getX() - mPrevCmdSecondControlPoint.getX()))), 101 (float) (currentPoint.getY() + (2 * (currentPoint.getY() - mPrevCmdSecondControlPoint.getY())))); 102 } 103 104 inPolyline.curveTo(firstCtrlPoint.getX(), firstCtrlPoint.getY(), point1.getX(), point1.getY(), point2.getX(), point2.getY()); 105 106 setSecondControlPoint(point2); 107 108 currentPoint = point2; 109 } 110 111 // Return the last point. 112 return currentPoint; 113 } 114}