JavaCAD
BezierPath.java
Go to the documentation of this file.
1 package com.piro.bezier;
2 
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.LinkedList;
6 import java.util.regex.Matcher;
7 import java.util.regex.Pattern;
8 
9 import eu.mihosoft.vrl.v3d.Vector3d;
10 
11 public class BezierPath {
12 
13  static final Matcher matchPoint = Pattern.compile("\\s*(\\d+)[^\\d]+(\\d+)\\s*").matcher("");
14 
15  BezierListProducer path;
16 
17  private ArrayList<Vector3d> pointList = new ArrayList<Vector3d>();
18  double resolution = 0.075;
19 
21  public BezierPath() {
22  }
23 
25  public BezierPath(String path) {
26  parsePathString(path);
27  }
28 
29  public void parsePathString(String d) {
30 
31  this.path = new BezierListProducer();
32 
33  parsePathList(d);
34  }
35 
36  protected void parsePathList(String list) {
37  // Oh come on... well i have no idea what this regx is going to parse for, good
38  // luck
39  final Matcher matchPathCmd = Pattern
40  .compile("([MmLlHhVvAaQqTtCcSsZz])|([-+]?((\\d*\\.\\d+)|(\\d+))([eE][-+]?\\d+)?)").matcher(list);
41 
42  // Tokenize
43  LinkedList<String> tokens = new LinkedList<String>();
44  while (matchPathCmd.find()) {
45  tokens.addLast(matchPathCmd.group());
46  }
47 
48  char curCmd = 'Z';
49  while (tokens.size() != 0) {
50  String curToken = tokens.removeFirst();
51  char initChar = curToken.charAt(0);
52  if ((initChar >= 'A' && initChar <= 'Z') || (initChar >= 'a' && initChar <= 'z')) {
53  curCmd = initChar;
54  } else {
55  tokens.addFirst(curToken);
56  }
57  float x, y;
58  switch (curCmd) {
59  case 'M':
60  x = nextFloat(tokens);
61  y = nextFloat(tokens);
62  path.movetoAbs(x, y);
63  pointList.add(new Vector3d(x, y, 0));
64  curCmd = 'L';
65  break;
66  case 'm':
67  x = nextFloat(tokens);
68  y = nextFloat(tokens);
69  path.movetoRel(x, y);
70  pointList.add(new Vector3d(x, y, 0));
71  curCmd = 'l';
72  break;
73  case 'L':
74  path.linetoAbs(nextFloat(tokens), nextFloat(tokens));
75  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(1));
76  break;
77  case 'l':
78  path.linetoRel(nextFloat(tokens), nextFloat(tokens));
79  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(1));
80  break;
81  case 'H':
82  path.linetoHorizontalAbs(nextFloat(tokens));
83 
84  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(1));
85 
86  break;
87  case 'h':
88  path.linetoHorizontalRel(nextFloat(tokens));
89 
90  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(1));
91 
92  break;
93  case 'V':
94  path.linetoVerticalAbs(nextFloat(tokens));
95 
96  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(1));
97 
98  break;
99  case 'v':
100  path.linetoVerticalAbs(nextFloat(tokens));
101  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(1));
102  break;
103  case 'A':
104  case 'a':
105  break;
106  case 'Q':
107  path.curvetoQuadraticAbs(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens));
108  for (double i = resolution; i < 1; i += resolution) {
109  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(i));
110  }
111  break;
112  case 'q':
113  path.curvetoQuadraticAbs(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens));
114  for (double i = resolution; i < 1; i += resolution) {
115  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(i));
116  }
117  break;
118  case 'T':
119  path.curvetoQuadraticSmoothAbs(nextFloat(tokens), nextFloat(tokens));
120  for (double i = resolution; i < 1; i += resolution) {
121  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(i));
122  }
123  break;
124  case 't':
125  path.curvetoQuadraticSmoothRel(nextFloat(tokens), nextFloat(tokens));
126  for (double i = resolution; i < 1; i += resolution) {
127  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(i));
128  }
129  break;
130  case 'C':
131  path.curvetoCubicAbs(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens),
132  nextFloat(tokens), nextFloat(tokens));
133  for (double i = resolution; i < 1; i += resolution) {
134  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(i));
135  }
136  break;
137  case 'c':
138  path.curvetoCubicRel(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens),
139  nextFloat(tokens), nextFloat(tokens));
140  for (double i = resolution; i < 1; i += resolution) {
141  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(i));
142  }
143  break;
144  case 'S':
145  path.curvetoCubicSmoothAbs(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens));
146  for (double i = resolution; i < 1; i += resolution) {
147  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(i));
148  }
149  break;
150  case 's':
151  path.curvetoCubicSmoothRel(nextFloat(tokens), nextFloat(tokens), nextFloat(tokens), nextFloat(tokens));
152  for (double i = resolution; i < 1; i += resolution) {
153  pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(i));
154  }
155  break;
156  case 'Z':
157  case 'z':
158  path.closePath();
159  // pointList.add(path.bezierSegs.get(path.bezierSegs.size() - 1).eval(1));
160  break;
161  case '/':
162  // comment line
163  break;
164  default:
165  throw new RuntimeException("Invalid path element");
166  }
167  }
168  }
169 
170  static protected float nextFloat(LinkedList<String> l) {
171  String s = l.removeFirst();
172  return Float.parseFloat(s);
173  }
174 
179  public Vector3d eval(float interp) {
180  Vector3d point = new Vector3d(0, 0);// = new Vector3d();
181  if (interp < 0.001)
182  interp = (float) 0.001;
183  if (interp > 0.9999)
184  interp = (float) 0.9999;
185 
186  double curLength = path.curveLength * interp;
187  for (Iterator<Bezier> it = path.bezierSegs.iterator(); it.hasNext();) {
188  Bezier bez = it.next();
189 
190  double bezLength = bez.getLength();
191  if (curLength < bezLength) {
192  double param = curLength / bezLength;
193  point = bez.eval(param);
194  break;
195  }
196 
197  curLength -= bezLength;
198  }
199 
200  return point;
201  }
202 
207  public ArrayList<Vector3d> evaluate() {
208 
209  return pointList;
210  }
211 
212 }
void curvetoQuadraticAbs(float x1, float y1, float x, float y)
void curvetoCubicSmoothRel(float x2, float y2, float x, float y)
void curvetoCubicRel(float x1, float y1, float x2, float y2, float x, float y)
void curvetoCubicSmoothAbs(float x2, float y2, float x, float y)
void curvetoCubicAbs(float x1, float y1, float x2, float y2, float x, float y)
void curvetoQuadraticSmoothRel(float x, float y)
void curvetoQuadraticSmoothAbs(float x, float y)
ArrayList< Vector3d > pointList
Definition: BezierPath.java:17
void parsePathList(String list)
Definition: BezierPath.java:36
void parsePathString(String d)
Definition: BezierPath.java:29
static float nextFloat(LinkedList< String > l)
ArrayList< Vector3d > evaluate()
Vector3d eval(float interp)