Source code: com/arranger/jarl/util/WidgetUtil.java
1 package com.arranger.jarl.util;
2
3 import com.arranger.jarl.base.ITimedJarlObject;
4 import com.arranger.jarl.base.Time;
5 import com.arranger.jarl.base.IJarlObject;
6 import org.w3c.dom.Element;
7 import org.w3c.dom.NodeList;
8
9 import java.awt.*;
10 import java.awt.geom.*;
11 import java.util.ArrayList;
12 import java.util.Iterator;
13 import java.util.Arrays;
14 import java.util.Comparator;
15
16 /**
17 * MotionPathUtil created on Feb 22, 2003
18 */
19 public class WidgetUtil {
20
21 public static final double DEFAULT_FLATTENING_LEVEL = 0.0001;
22 protected static final double DEFAULT_PRECISION = .1;
23
24 /**
25 * returns a Point2D from an string that looks like: '40%, 25%'
26 * @param string
27 * @return an initialized Point2D
28 * @see #normalize
29 */
30 public static Point2D getPointFromString(String string) {
31 java.util.List list = StringTools.getDelimitedList(string, ",");
32 return new Point2D.Double(
33 normalize(1.0, (String) list.get(0)),
34 normalize(1.0, (String) list.get(1))
35 );
36 }
37
38 /**
39 * returns two Point2D from an string that looks like: '40%, 25%, 50%, 25%' (x1, y1, x2, y2)
40 * @param string
41 * @return an initialized Point2D
42 * @see #normalize
43 */
44 public static Point2D[] getCoordsFromString(String string) {
45 java.util.List list = StringTools.getDelimitedList(string, ",");
46 return new Point2D[]{
47 new Point2D.Double(
48 normalize(1.0, (String) list.get(0)),
49 normalize(1.0, (String) list.get(1))),
50 new Point2D.Double(
51 normalize(1.0, (String) list.get(2)),
52 normalize(1.0, (String) list.get(3)))
53 };
54 }
55
56 /**
57 * If value ends with a % then make it a percentage of the real value
58 * @param baseValue the 100% version of value if it is a pct
59 * @param value either a pct or a real value
60 * @return the normalized value
61 */
62 public static double normalize(double baseValue, String value) {
63 boolean isPct = value.endsWith("%");
64 if (isPct) {
65 value = value.replace('%', ' ').trim();
66 double pct = Double.parseDouble(value) / 100;
67 return pct * baseValue;
68 } else {
69 return Double.parseDouble(value);
70 }
71 }
72
73 /**
74 * Given a shape, return an array of points describing its shape
75 * @param shape
76 * @return an array of points describing its shape
77 */
78 public static Point2D[] getPoints(Shape shape) {
79 return getPoints(shape, DEFAULT_FLATTENING_LEVEL);
80 }
81
82 /**
83 * Given a shape, return an array of points describing its shape
84 * @param shape
85 * @param flatteningLevel see {@link Shape#getPathIterator}
86 * @return an array of points describing its shape
87 */
88 public static Point2D[] getPoints(Shape shape, double flatteningLevel) {
89 java.util.List tempPoints = new ArrayList();
90 PathIterator pi = shape.getPathIterator(null, flatteningLevel);
91 while (!pi.isDone()) {
92 float[] pt = new float[6];
93 switch (pi.currentSegment(pt)) {
94 case FlatteningPathIterator.SEG_MOVETO:
95 case FlatteningPathIterator.SEG_LINETO:
96 tempPoints.add(new Point2D.Float(pt[0], pt[1]));
97 }
98 pi.next();
99 }
100
101 Point2D[] points = new Point2D[tempPoints.size()];
102 return (Point2D[]) tempPoints.toArray(points);
103 }
104
105 /**
106 * Returns a list of motions segments, or null if none are found
107 * @param elem
108 * @return a list of {@link com.arranger.jarl.util.WidgetConfigSegment} or null if none are found
109 */
110 public static java.util.List initWidgetConfigSegments(Element elem, IWidgetConfigSegmentFactory widgetConfigSegmentFactory) {
111 NodeList nodeList = XMLUtil.selectNodeList(elem, "segment");
112 if (nodeList == null || nodeList.getLength() < 1) {
113 return null;
114 }
115
116 java.util.List configSegments = new ArrayList();
117 int length = nodeList.getLength();
118 for (int index = 0; index < length; index++) {
119 Element segmentElement = (Element) nodeList.item(index);
120 configSegments.add(widgetConfigSegmentFactory.createSegment(segmentElement));
121 }
122 return configSegments;
123 }
124
125 /**
126 * Obtain the proper MotionPath
127 *
128 * @param widgetConfigSegments returned from {@link #initWidgetConfigSegments}
129 * @return the proper MotionPath
130 */
131 public static WidgetConfigSegment getWidgetConfigSegment(java.util.List widgetConfigSegments,
132 double currentTimePct) {
133 if (widgetConfigSegments == null || widgetConfigSegments.isEmpty()) {
134 throw new IllegalStateException("There are no config segments. " + "" +
135 "This normally happens when a jarl object doesn't have all of its required attributes");
136 }
137
138 Iterator it = widgetConfigSegments.iterator();
139 WidgetConfigSegment prev = null;
140 WidgetConfigSegment curr = null;
141 while (it.hasNext()) {
142 curr = (WidgetConfigSegment) it.next();
143 int result = curr.checkRange(currentTimePct);
144 if (result == -1) {
145 return (prev == null) ? curr : prev;
146 } else if (result == 0) {
147 return curr;
148 }
149
150 prev = curr;
151 }
152 return prev;
153 }
154
155 public static Time getRelativeTime(ITimedJarlObject timedJarlObject, Time currentTime) {
156 return new Time(currentTime.getFrame() - timedJarlObject.getStartTime().getFrame());
157 }
158
159 /**
160 * This will turn a series of points into a shape
161 * @param points
162 */
163 public static GeneralPath pointsToShape(Point2D[] points, boolean addClose) {
164 if (points.length == 0) {
165 System.out.println("points are of length 0");
166 return new GeneralPath();
167 }
168
169 GeneralPath generalPath = new GeneralPath();
170 generalPath.moveTo((float) points[0].getX(), (float) points[0].getY());
171 for (int index = 1; index < points.length; index++) {
172 generalPath.lineTo((float) points[index].getX(), (float) points[index].getY());
173 }
174 if (addClose) {
175 generalPath.closePath();
176 }
177
178 return generalPath;
179 }
180
181 /**
182 * Transforms the shape by the widgetTransform function
183 * @param sourceShape
184 * @param widgetTransform
185 * @return an array of transformed points, call {@link #pointsToShape} to convert to a shape
186 */
187 public static Point2D[] transform(Shape sourceShape, IWidgetTransform widgetTransform) {
188 //get the base array of points
189 Point2D[] shapePoints = WidgetUtil.getPoints(sourceShape);
190 double offset = widgetTransform.initializeTransform(shapePoints);
191 boolean reverse = widgetTransform.isReverse();
192
193 java.util.List points = new ArrayList();
194 double totalX = 0;
195 for (int sourceIndex = 0; sourceIndex < shapePoints.length - 1; sourceIndex++) {
196 int adjustedIndex = (int) (sourceIndex + offset);
197 adjustedIndex %= (shapePoints.length - 1);
198
199 double x1, y1, x2, y2;
200 if (reverse) {
201 adjustedIndex = (shapePoints.length - 1) - adjustedIndex;
202 int index2 = (adjustedIndex == 0) ? shapePoints.length - 1 : adjustedIndex - 1;
203 x1 = shapePoints[adjustedIndex].getX();
204 y1 = shapePoints[adjustedIndex].getY();
205 x2 = shapePoints[index2].getX();
206 y2 = shapePoints[index2].getY();
207 } else {
208 x1 = shapePoints[adjustedIndex].getX();
209 y1 = shapePoints[adjustedIndex].getY();
210 x2 = shapePoints[adjustedIndex + 1].getX();
211 y2 = shapePoints[adjustedIndex + 1].getY();
212 }
213
214 //calculate the distance, and get the simple coordinates from the widgetTransform
215 double distance = Point2D.distance(x1, y1, x2, y2);
216 double[] preTransPoints = widgetTransform.getPoints(distance, totalX, DEFAULT_PRECISION);
217
218 //got the simple points, now rotate and translate
219 double rads = MathUtil.findRadians(x1, y1, x2, y2);
220 double degrees = Math.toDegrees(rads) % 360;
221 //System.out.println(degrees);
222 if (x2 < x1 && y2 < y1) {
223 } else if (x2 < x1 && degrees < 180) {
224 degrees = 180 - degrees;
225 rads = Math.toRadians(degrees);
226 } else if (y2 < y1 && degrees > 180) {
227 degrees = 180 - degrees;
228 rads = Math.toRadians(degrees);
229 }
230
231 //translate and rotate
232 AffineTransform affineTransform = AffineTransform.getTranslateInstance(x1, y1);
233 affineTransform.concatenate(AffineTransform.getRotateInstance(rads));
234
235 //apply the transformation to the points
236 double[] dstPoints = new double[preTransPoints.length];
237 affineTransform.transform(preTransPoints, 0, dstPoints, 0, preTransPoints.length / 2);
238 for (int index = 0; index < dstPoints.length; index += 2) {
239 points.add(new Point2D.Double(dstPoints[index], dstPoints[index + 1]));
240 }
241
242 //get rid of redundant points
243 while (points.size() > 1 && points.get(0).equals(points.get(points.size() - 1))) {
244 points.remove(points.size() - 1);
245 }
246
247 //accumulate the total distance
248 totalX += distance;
249 }
250
251 //all done
252 Point2D[] resultPoints = new Point2D[points.size()];
253 resultPoints = (Point2D[]) points.toArray(resultPoints);
254
255 return resultPoints;
256 }
257
258
259 /**
260 * Prints points to system out
261 * @param points
262 */
263 public static void dumpPoints(Point2D[] points) {
264 for (int index = 0; index < points.length; index++) {
265 System.out.println(points[index].toString());
266 }
267 }
268
269 /**
270 * sort a list of objects by their zorder
271 * @param baseJarlObjectList
272 */
273 public static void sortBaseJarlObjectZOrder(java.util.List baseJarlObjectList) {
274
275 IJarlObject[] baseJarlObjects = new IJarlObject[baseJarlObjectList.size()];
276 baseJarlObjects = (IJarlObject[]) baseJarlObjectList.toArray(baseJarlObjects);
277 Arrays.sort(baseJarlObjects, new BaseJarlObjectZOrderComparator());
278 baseJarlObjectList.clear();
279 for (int index = 0; index < baseJarlObjects.length; index++) {
280 baseJarlObjectList.add(baseJarlObjects[index]);
281 }
282 }
283
284 protected static class BaseJarlObjectZOrderComparator implements Comparator {
285
286 public int compare(Object o1, Object o2) {
287 IJarlObject jo1 = (IJarlObject) o1;
288 IJarlObject jo2 = (IJarlObject) o2;
289 int zOrder1 = jo1.getZOrder();
290 int zOrder2 = jo2.getZOrder();
291
292 if (zOrder1 == zOrder2) {
293 return 0;
294 } else if (zOrder1 < zOrder2) {
295 return -1;
296 } else {
297 return 1;
298 }
299 }
300 }
301 }