18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.animation;
27
28 import javafx.beans.property.ObjectProperty;
29 import javafx.beans.property.ObjectPropertyBase;
30 import javafx.beans.property.SimpleObjectProperty;
31 import javafx.scene.Node;
32 import javafx.scene.shape.Shape;
33 import javafx.util.Duration;
34
35 import com.sun.javafx.geom.Path2D;
36 import com.sun.javafx.geom.PathIterator;
37 import com.sun.javafx.geom.transform.BaseTransform;
38 import com.sun.javafx.scene.shape.ShapeHelper;
39 import java.util.ArrayList;
40
41 /**
42 * This {@code Transition} creates a path animation that spans its
43 * {@link #duration}. The translation along the path is done by updating the
44 * {@code translateX} and {@code translateY} variables of the {@code node}, and
45 * the {@code rotate} variable will get updated if {@code orientation} is set to
46 * {@code OrientationType.ORTHOGONAL_TO_TANGENT}, at regular interval.
47 * <p>
48 * The animated path is defined by the outline of a shape.
49 *
50 * <p>
51 * Code Segment Example:
52 * </p>
53 *
54 * <pre>
55 * <code>
56 * import javafx.scene.shape.*;
57 * import javafx.animation.*;
324
325 // provide smooth rotation on segment bounds
326 double z = Math.min(SMOOTH_ZONE, seg.length / 2);
327 if (partLength < z && !prevSeg.isMoveTo) {
328 //interpolate rotation to previous segment
329 rotateAngle = interpolate(
330 prevSeg.rotateAngle, seg.rotateAngle,
331 partLength / z / 2 + 0.5F);
332 } else {
333 double dist = seg.length - partLength;
334 Segment nextSeg = seg.nextSeg;
335 if (dist < z && nextSeg != null) {
336 //interpolate rotation to next segment
337 if (!nextSeg.isMoveTo) {
338 rotateAngle = interpolate(
339 seg.rotateAngle, nextSeg.rotateAngle,
340 (z - dist) / z / 2);
341 }
342 }
343 }
344 cachedNode.setTranslateX(x - cachedNode.impl_getPivotX());
345 cachedNode.setTranslateY(y - cachedNode.impl_getPivotY());
346 // Need to handle orientation if it is requested
347 if (cachedIsNormalRequired) {
348 cachedNode.setRotate(rotateAngle);
349 }
350 }
351
352 private Node getTargetNode() {
353 final Node node = getNode();
354 return (node != null) ? node : getParentTargetNode();
355 }
356
357 @Override
358 boolean startable(boolean forceSync) {
359 return super.startable(forceSync)
360 && (((getTargetNode() != null) && (getPath() != null) && !getPath().getLayoutBounds().isEmpty()) || (!forceSync
361 && (cachedNode != null)));
362 }
363
364 @Override
365 void sync(boolean forceSync) {
366 super.sync(forceSync);
367 if (forceSync || (cachedNode == null)) {
368 cachedNode = getTargetNode();
369 recomputeSegments();
370 cachedIsNormalRequired = getOrientation() == OrientationType.ORTHOGONAL_TO_TANGENT;
371 }
372 }
373
374 private void recomputeSegments() {
375 segments.clear();
376 final Shape p = getPath();
377 Segment moveToSeg = Segment.getZeroSegment();
378 Segment lastSeg = Segment.getZeroSegment();
379
380 float[] coords = new float[6];
381 for (PathIterator i = ShapeHelper.configShape(p).getPathIterator(p.impl_getLeafTransform(), 1.0f); !i.isDone(); i.next()) {
382 Segment newSeg = null;
383 int segType = i.currentSegment(coords);
384 double x = coords[0];
385 double y = coords[1];
386
387 switch (segType) {
388 case PathIterator.SEG_MOVETO:
389 moveToSeg = Segment.newMoveTo(x, y, lastSeg.accumLength);
390 newSeg = moveToSeg;
391 break;
392 case PathIterator.SEG_CLOSE:
393 newSeg = Segment.newClosePath(lastSeg, moveToSeg);
394 if (newSeg == null) {
395 // make the last segment to close the path
396 lastSeg.convertToClosePath(moveToSeg);
397 }
398 break;
399 case PathIterator.SEG_LINETO:
400 newSeg = Segment.newLineTo(lastSeg, x, y);
401 break;
|
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.animation;
27
28 import javafx.beans.property.ObjectProperty;
29 import javafx.beans.property.ObjectPropertyBase;
30 import javafx.beans.property.SimpleObjectProperty;
31 import javafx.scene.Node;
32 import javafx.scene.shape.Shape;
33 import javafx.util.Duration;
34
35 import com.sun.javafx.geom.Path2D;
36 import com.sun.javafx.geom.PathIterator;
37 import com.sun.javafx.geom.transform.BaseTransform;
38 import com.sun.javafx.scene.NodeHelper;
39 import com.sun.javafx.scene.shape.ShapeHelper;
40 import java.util.ArrayList;
41
42 /**
43 * This {@code Transition} creates a path animation that spans its
44 * {@link #duration}. The translation along the path is done by updating the
45 * {@code translateX} and {@code translateY} variables of the {@code node}, and
46 * the {@code rotate} variable will get updated if {@code orientation} is set to
47 * {@code OrientationType.ORTHOGONAL_TO_TANGENT}, at regular interval.
48 * <p>
49 * The animated path is defined by the outline of a shape.
50 *
51 * <p>
52 * Code Segment Example:
53 * </p>
54 *
55 * <pre>
56 * <code>
57 * import javafx.scene.shape.*;
58 * import javafx.animation.*;
325
326 // provide smooth rotation on segment bounds
327 double z = Math.min(SMOOTH_ZONE, seg.length / 2);
328 if (partLength < z && !prevSeg.isMoveTo) {
329 //interpolate rotation to previous segment
330 rotateAngle = interpolate(
331 prevSeg.rotateAngle, seg.rotateAngle,
332 partLength / z / 2 + 0.5F);
333 } else {
334 double dist = seg.length - partLength;
335 Segment nextSeg = seg.nextSeg;
336 if (dist < z && nextSeg != null) {
337 //interpolate rotation to next segment
338 if (!nextSeg.isMoveTo) {
339 rotateAngle = interpolate(
340 seg.rotateAngle, nextSeg.rotateAngle,
341 (z - dist) / z / 2);
342 }
343 }
344 }
345 cachedNode.setTranslateX(x - NodeHelper.getPivotX(cachedNode));
346 cachedNode.setTranslateY(y - NodeHelper.getPivotY(cachedNode));
347 // Need to handle orientation if it is requested
348 if (cachedIsNormalRequired) {
349 cachedNode.setRotate(rotateAngle);
350 }
351 }
352
353 private Node getTargetNode() {
354 final Node node = getNode();
355 return (node != null) ? node : getParentTargetNode();
356 }
357
358 @Override
359 boolean startable(boolean forceSync) {
360 return super.startable(forceSync)
361 && (((getTargetNode() != null) && (getPath() != null) && !getPath().getLayoutBounds().isEmpty()) || (!forceSync
362 && (cachedNode != null)));
363 }
364
365 @Override
366 void sync(boolean forceSync) {
367 super.sync(forceSync);
368 if (forceSync || (cachedNode == null)) {
369 cachedNode = getTargetNode();
370 recomputeSegments();
371 cachedIsNormalRequired = getOrientation() == OrientationType.ORTHOGONAL_TO_TANGENT;
372 }
373 }
374
375 private void recomputeSegments() {
376 segments.clear();
377 final Shape p = getPath();
378 Segment moveToSeg = Segment.getZeroSegment();
379 Segment lastSeg = Segment.getZeroSegment();
380
381 float[] coords = new float[6];
382 for (PathIterator i = ShapeHelper.configShape(p).getPathIterator(NodeHelper.getLeafTransform(p), 1.0f); !i.isDone(); i.next()) {
383 Segment newSeg = null;
384 int segType = i.currentSegment(coords);
385 double x = coords[0];
386 double y = coords[1];
387
388 switch (segType) {
389 case PathIterator.SEG_MOVETO:
390 moveToSeg = Segment.newMoveTo(x, y, lastSeg.accumLength);
391 newSeg = moveToSeg;
392 break;
393 case PathIterator.SEG_CLOSE:
394 newSeg = Segment.newClosePath(lastSeg, moveToSeg);
395 if (newSeg == null) {
396 // make the last segment to close the path
397 lastSeg.convertToClosePath(moveToSeg);
398 }
399 break;
400 case PathIterator.SEG_LINETO:
401 newSeg = Segment.newLineTo(lastSeg, x, y);
402 break;
|