Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/arranger/jarl/stroke/base/Trace.java


1   package com.arranger.jarl.stroke.base;
2   
3   import com.arranger.jarl.base.IContext;
4   import com.arranger.jarl.base.IJarlObjectInfo;
5   import com.arranger.jarl.stroke.BaseSegmentStroke;
6   import com.arranger.jarl.util.*;
7   import com.arranger.jarl.widget.IWidget;
8   import org.w3c.dom.Element;
9   
10  import java.awt.*;
11  import java.awt.geom.Point2D;
12  
13  /**
14   * Trace traces just a portion of the overall shape
15   *
16   *
17   * @strokeAttribute traceLength ## xs:string ## the percentage of the overall shape to trace (eg 5%)
18   * @strokeAttribute offset ## xs:string ## the percentage throgh the shape to start at (eg 0%)
19   * @strokeAttribute clockwise ## xs:boolean ## the direction to go (true|false)
20   *
21   * @strokeAttribute startTraceLength ## xs:string ## the starting percentage of the overall shape to trace (eg 5%)
22   * @strokeAttribute startOffset ## xs:string ## the starting percentage throgh the shape to start at (eg 0%)
23   * @strokeAttribute startClockwise ## xs:boolean ## the starting direction to go (true|false)
24   * @strokeAttribute endTraceLength ## xs:string ## the ending percentage of the overall shape to trace (eg 5%)
25   * @strokeAttribute endOffset ## xs:string ## the ending percentage throgh the shape to end at (eg 0%)
26   * @strokeAttribute endClockwise ## xs:boolean ## the ending direction to go (true|false)
27   */
28  public class Trace extends BaseSegmentStroke {
29  
30      protected double m_traceLength = Double.NEGATIVE_INFINITY;
31      protected double m_offset = Double.NEGATIVE_INFINITY;
32      protected boolean m_clockwise = true;
33  
34      protected double m_startTraceLength = Double.NEGATIVE_INFINITY;
35      protected double m_startOffset = Double.NEGATIVE_INFINITY;
36      protected boolean m_startClockwise = true;
37      protected double m_endTraceLength = Double.NEGATIVE_INFINITY;
38      protected double m_endOffset = Double.NEGATIVE_INFINITY;
39      protected boolean m_endClockwise = true;
40  
41  
42      /**
43       * This will perform custom drawing of the shape
44       * onto the graphics on behalf of the widget
45       *
46       * NB: this will need to interpolate points in between points
47       *
48       * @param widget
49       * @param context
50       * @param graphics2D
51       * @param shape
52       */
53      public Shape processShape(IWidget widget,
54                                IContext context,
55                                Graphics2D graphics2D,
56                                Shape shape) {
57  
58          double currentWidgetPct = InterpolateUtil.interpolate(widget, context.getTime());
59          double currentTraceLength;
60          double currentOffset;
61          boolean currentClockwise;
62  
63          if (m_traceLength != Double.NEGATIVE_INFINITY) {
64              currentTraceLength = m_traceLength;
65          } else if (m_startTraceLength != Double.NEGATIVE_INFINITY && m_endTraceLength != Double.NEGATIVE_INFINITY) {
66              currentTraceLength = InterpolateUtil.interpolate(0,
67                      1,
68                      m_startTraceLength,
69                      m_endTraceLength,
70                      currentWidgetPct);
71          } else {
72              TraceConfigSegment traceConfigSegment = (TraceConfigSegment) getCurrentSegment(widget, context);
73              double currentSegmentWidgetPct = getCurrentSegmentTimePct(widget, context, traceConfigSegment);
74              currentTraceLength = InterpolateUtil.interpolate(0,
75                      1,
76                      traceConfigSegment.getStartTraceLength(),
77                      traceConfigSegment.getEndTraceLength(),
78                      currentSegmentWidgetPct);
79          }
80  
81          //base the clockwise off of offset
82          if (m_offset != Double.NEGATIVE_INFINITY) {
83              currentOffset = m_offset;
84              currentClockwise = m_clockwise;
85          } else if (m_startOffset != Double.NEGATIVE_INFINITY && m_endOffset != Double.NEGATIVE_INFINITY) {
86              currentOffset = InterpolateUtil.interpolate(0,
87                      360,
88                      m_startOffset,
89                      m_endOffset,
90                      currentWidgetPct);
91              currentClockwise = m_startClockwise;
92          } else {
93              TraceConfigSegment traceConfigSegment = (TraceConfigSegment) getCurrentSegment(widget, context);
94              double currentSegmentWidgetPct = getCurrentSegmentTimePct(widget, context, traceConfigSegment);
95              currentOffset = InterpolateUtil.interpolate(0,
96                      1,
97                      traceConfigSegment.getStartOffset(),
98                      traceConfigSegment.getEndOffset(),
99                      currentSegmentWidgetPct);
100             currentClockwise = traceConfigSegment.isStartClockwise();
101         }
102         currentOffset %= 1.0;    //normalize
103         Point2D[] points = WidgetUtil.transform(shape,
104                 new TraceWidgetTransform(currentTraceLength,
105                         currentOffset,
106                         currentClockwise,
107                         context));
108         return WidgetUtil.pointsToShape(points, false);
109     }
110 
111     /**
112      * Always remember some attrs might not be there
113      * @param context
114      */
115     protected void initAttributes(IContext context) {
116         super.initAttributes(context);
117 
118         ObjectUtil.initializeField("traceLength", m_configElement, this, ObjectUtil.NORMALIZING_CONVERSION);
119         ObjectUtil.initializeField("clockwise", m_configElement, this, ObjectUtil.PRIMITIVE_CONVERSION);
120         ObjectUtil.initializeField("offset", m_configElement, this, ObjectUtil.NORMALIZING_CONVERSION);
121 
122         ObjectUtil.initializeField("startTraceLength", m_configElement, this, ObjectUtil.NORMALIZING_CONVERSION);
123         ObjectUtil.initializeField("startClockwise", m_configElement, this, ObjectUtil.PRIMITIVE_CONVERSION);
124         ObjectUtil.initializeField("startOffset", m_configElement, this, ObjectUtil.NORMALIZING_CONVERSION);
125         ObjectUtil.initializeField("endTraceLength", m_configElement, this, ObjectUtil.NORMALIZING_CONVERSION);
126         ObjectUtil.initializeField("endClockwise", m_configElement, this, ObjectUtil.PRIMITIVE_CONVERSION);
127         ObjectUtil.initializeField("endOffset", m_configElement, this, ObjectUtil.NORMALIZING_CONVERSION);
128     }
129 
130     /**
131      * Override this, and for every field that you're using, call {@link #populateInfo}
132      * for example:
133      * <code>
134      *   populateInfo(jarlObjectInfo, "zOrder", "Z-Order", JarlInfoUtil.PRIMITIVE_DISPLAY);
135      * </code>
136      *
137      * @param jarlObjectInfo
138      *
139      * @see JarlInfoUtil#PRIMITIVE_DISPLAY
140      * @see #populateInfo
141      * @see ObjectUtil#initializeField
142      */
143     protected void addJarlObjectInfo(IJarlObjectInfo jarlObjectInfo) {
144         super.addJarlObjectInfo(jarlObjectInfo);
145         populateInfo(jarlObjectInfo, "traceLength", "Trace Length", JarlInfoUtil.PCT_DISPLAY);
146         populateInfo(jarlObjectInfo, "clockwise", "Clockwise", JarlInfoUtil.PRIMITIVE_DISPLAY);
147         populateInfo(jarlObjectInfo, "offset", "Offset", JarlInfoUtil.PCT_DISPLAY);
148 
149         populateInfo(jarlObjectInfo, "startTraceLength", "Start Trace Length", JarlInfoUtil.PCT_DISPLAY);
150         populateInfo(jarlObjectInfo, "endTraceLength", "End Trace Length", JarlInfoUtil.PCT_DISPLAY);
151         populateInfo(jarlObjectInfo, "startClockwise", "Start Clockwise", JarlInfoUtil.PRIMITIVE_DISPLAY);
152         populateInfo(jarlObjectInfo, "endClockwise", "End Clockwise", JarlInfoUtil.PRIMITIVE_DISPLAY);
153         populateInfo(jarlObjectInfo, "startOffset", "Start Offset", JarlInfoUtil.PCT_DISPLAY);
154         populateInfo(jarlObjectInfo, "endOffset", "End Offset", JarlInfoUtil.PCT_DISPLAY);
155     }
156 
157     /**
158      * Create a concrete {@link WidgetConfigSegment} based on this element
159      * @param element
160      * @return a specific {@link WidgetConfigSegment}
161      */
162     public WidgetConfigSegment createSegment(Element element) {
163         return new TraceConfigSegment(element);
164     }
165 
166     protected static class TraceConfigSegment extends WidgetConfigSegment {
167 
168         protected double m_startTraceLength = Double.NEGATIVE_INFINITY;
169         protected double m_startOffset = Double.NEGATIVE_INFINITY;
170         protected boolean m_startClockwise = true;
171         protected double m_endTraceLength = Double.NEGATIVE_INFINITY;
172         protected double m_endOffset = Double.NEGATIVE_INFINITY;
173         protected boolean m_endClockwise = true;
174 
175         public TraceConfigSegment(Element element) {
176             super(element);
177 
178             ObjectUtil.initializeFieldStrict("startTraceLength", element, this, ObjectUtil.NORMALIZING_CONVERSION);
179             ObjectUtil.initializeFieldStrict("startClockwise", element, this, ObjectUtil.PRIMITIVE_CONVERSION);
180             ObjectUtil.initializeFieldStrict("startOffset", element, this, ObjectUtil.NORMALIZING_CONVERSION);
181             ObjectUtil.initializeFieldStrict("endTraceLength", element, this, ObjectUtil.NORMALIZING_CONVERSION);
182             ObjectUtil.initializeFieldStrict("endClockwise", element, this, ObjectUtil.PRIMITIVE_CONVERSION);
183             ObjectUtil.initializeFieldStrict("endOffset", element, this, ObjectUtil.NORMALIZING_CONVERSION);
184         }
185 
186 
187         protected void addJarlObjectInfo(IJarlObjectInfo jarlObjectInfo) {
188             super.addJarlObjectInfo(jarlObjectInfo);
189             populateInfo(jarlObjectInfo, "startTraceLength", "Start Trace Length", JarlInfoUtil.PCT_DISPLAY);
190             populateInfo(jarlObjectInfo, "endTraceLength", "End Trace Length", JarlInfoUtil.PCT_DISPLAY);
191             populateInfo(jarlObjectInfo, "startClockwise", "Start Clockwise", JarlInfoUtil.PRIMITIVE_DISPLAY);
192             populateInfo(jarlObjectInfo, "endClockwise", "End Clockwise", JarlInfoUtil.PRIMITIVE_DISPLAY);
193             populateInfo(jarlObjectInfo, "startOffset", "Start Offset", JarlInfoUtil.PCT_DISPLAY);
194             populateInfo(jarlObjectInfo, "endOffset", "End Offset", JarlInfoUtil.PCT_DISPLAY);
195         }
196 
197         public double getStartTraceLength() {
198             return m_startTraceLength;
199         }
200 
201         public double getStartOffset() {
202             return m_startOffset;
203         }
204 
205         public boolean isStartClockwise() {
206             return m_startClockwise;
207         }
208 
209         public double getEndTraceLength() {
210             return m_endTraceLength;
211         }
212 
213         public double getEndOffset() {
214             return m_endOffset;
215         }
216 
217         public boolean isEndClockwise() {
218             return m_endClockwise;
219         }
220     }
221 
222     public static class TraceWidgetTransform implements IWidgetTransform {
223         protected double m_currentTraceLength;
224         protected double m_currentOffset;
225         protected boolean m_currentClockwise;
226         protected double m_currentHigh;
227         protected IContext m_currentContext;
228 
229         public TraceWidgetTransform(double currentTraceLength,
230                                     double currentOffset,
231                                     boolean currentClockwise,
232                                     IContext currentContext) {
233             m_currentTraceLength = currentTraceLength;
234             m_currentOffset = currentOffset;
235             m_currentClockwise = currentClockwise;
236             m_currentContext = currentContext;
237         }
238 
239         /**
240          * Initialize the transform, returning the offset if needed
241          *
242          * @param shapePoints the original shape points
243          * @return the offset into the array of points.  return 0 for no offset
244          */
245         public double initializeTransform(Point2D[] shapePoints) {
246             //need to figure out the offset and the length boundaries
247             double currentTotalDistance = 0;
248             for (int sourceIndex = 0; sourceIndex < shapePoints.length - 1; sourceIndex++) {
249                 double x1 = shapePoints[sourceIndex].getX();
250                 double y1 = shapePoints[sourceIndex].getY();
251                 double x2 = shapePoints[sourceIndex + 1].getX();
252                 double y2 = shapePoints[sourceIndex + 1].getY();
253 
254                 currentTotalDistance += Point2D.distance(x1, y1, x2, y2);
255             }
256 
257             m_currentHigh = currentTotalDistance * m_currentTraceLength;
258 
259             /*m_currentContext.onStatus("totalDistance: " + m_currentTotalDistance);
260             m_currentContext.onStatus("currentHigh: " + m_currentHigh);*/
261 
262             return m_currentOffset * shapePoints.length;
263         }
264 
265 
266         /**
267          * Generate a series of points that will be used to transform
268          * other lines
269          *
270          * @param distance the total x requested (pt[N].x - pt[0].x == x)
271          * @param offset an offset into the internal algortihm
272          * @param precision how frequent to get points
273          * @return an arry of points of the form: x1, y1, x2, y2, .... xN, yN
274          */
275         public double[] getPoints(double distance, double offset, double precision) {
276             //only return points when the request (distance + offset) is within the currentStart and currentEnd
277             double testPoint = distance + offset;
278 
279             if (testPoint >= m_currentHigh) {
280                 if (offset >= m_currentHigh) {
281                     return new double[0];
282                 } else {
283                     distance = m_currentHigh - offset;
284                 }
285             }
286 
287             double[] points = new double[(int) ((distance / precision) + 1) * 2];
288             int writeIndex = 0;
289             for (double x = 0; x <= distance; x += precision) {
290                 points[writeIndex++] = x;
291                 points[writeIndex++] = 0;
292             }
293 
294             if (writeIndex != points.length) {
295                 double[] filteredPoints = new double[writeIndex];
296                 System.arraycopy(points, 0, filteredPoints, 0, writeIndex);
297                 points = filteredPoints;
298             }
299 
300             return points;
301         }
302 
303         /**
304          * Whether or not to reverse through the points
305          * @return true for reversing, false for normal
306          */
307         public boolean isReverse() {
308             return !m_currentClockwise;
309         }
310     }
311 }