You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cf...@apache.org on 2012/10/25 21:01:49 UTC
svn commit: r1402274 [5/31] - in
/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext:
./ awt/ awt/color/ awt/font/ awt/g2d/ awt/geom/ awt/image/ awt/image/codec/
awt/image/codec/jpeg/ awt/image/codec/pn...
Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/GraphicContext.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/GraphicContext.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/GraphicContext.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/GraphicContext.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,897 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.g2d;
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.NoninvertibleTransformException;
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Handles the attributes in a graphic context:<br>
+ * + Composite <br>
+ * + Font <br>
+ * + Paint <br>
+ * + Stroke <br>
+ * + Clip <br>
+ * + RenderingHints <br>
+ * + AffineTransform <br>
+ *
+ * @author <a href="mailto:cjolif@ilog.fr">Christophe Jolif</a>
+ * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
+ * @version $Id: GraphicContext.java 479564 2006-11-27 09:56:57Z dvholten $
+ */
+public class GraphicContext implements Cloneable{
+ /**
+ * Default Transform to be used for creating FontRenderContext.
+ */
+ protected AffineTransform defaultTransform = new AffineTransform();
+
+ /**
+ * Current AffineTransform. This is the concatenation
+ * of the original AffineTransform (i.e., last setTransform
+ * invocation) and the following transform invocations,
+ * as captured by originalTransform and the transformStack.
+ */
+ protected AffineTransform transform = new AffineTransform();
+
+ /**
+ * Transform stack
+ */
+ protected List transformStack = new ArrayList();
+
+ /**
+ * Defines whether the transform stack is valide or not.
+ * This is for use by the class clients. The client should
+ * validate the stack every time it starts using it. The
+ * stack becomes invalid when a new transform is set.
+ * @see #invalidateTransformStack()
+ * @see #isTransformStackValid
+ * @see #setTransform
+ */
+ protected boolean transformStackValid = true;
+
+ /**
+ * Current Paint
+ */
+ protected Paint paint = Color.black;
+
+ /**
+ * Current Stroke
+ */
+ protected Stroke stroke = new BasicStroke();
+
+ /**
+ * Current Composite
+ */
+ protected Composite composite = AlphaComposite.SrcOver;
+
+ /**
+ * Current clip
+ */
+ protected Shape clip = null;
+
+ /**
+ * Current set of RenderingHints
+ */
+ protected RenderingHints hints = new RenderingHints(null);
+
+ /**
+ * Current Font
+ */
+ protected Font font = new Font("sanserif", Font.PLAIN, 12);
+
+ /**
+ * Current background color.
+ */
+ protected Color background = new Color(0, 0, 0, 0);
+
+ /**
+ * Current foreground color
+ */
+ protected Color foreground = Color.black;
+
+ /**
+ * Default constructor
+ */
+ public GraphicContext() {
+ // to workaround a JDK bug
+ hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_DEFAULT);
+ }
+
+ /**
+ * @param defaultDeviceTransform Default affine transform applied to map the user space to the
+ * user space.
+ */
+ public GraphicContext(AffineTransform defaultDeviceTransform) {
+ this();
+ defaultTransform = new AffineTransform(defaultDeviceTransform);
+ transform = new AffineTransform(defaultTransform);
+ if (!defaultTransform.isIdentity())
+ transformStack.add(TransformStackElement.createGeneralTransformElement(defaultTransform));
+ }
+
+ /**
+ * @return a deep copy of this context
+ */
+ public Object clone(){
+ GraphicContext copyGc = new GraphicContext(defaultTransform);
+
+ //
+ // Now, copy each GC element in turn
+ //
+
+ // Default transform
+ /* Set in constructor */
+
+ // Transform
+ copyGc.transform = new AffineTransform(this.transform);
+
+ // Transform stack
+ copyGc.transformStack = new ArrayList( transformStack.size() );
+ for(int i=0; i<this.transformStack.size(); i++){
+ TransformStackElement stackElement =
+ (TransformStackElement)this.transformStack.get(i);
+ copyGc.transformStack.add(stackElement.clone());
+ }
+
+ // Transform stack validity
+ copyGc.transformStackValid = this.transformStackValid;
+
+ // Paint (immutable by requirement)
+ copyGc.paint = this.paint;
+
+ // Stroke (immutable by requirement)
+ copyGc.stroke = this.stroke;
+
+ // Composite (immutable by requirement)
+ copyGc.composite = this.composite;
+
+ // Clip
+ if(clip != null)
+ copyGc.clip = new GeneralPath(clip);
+ else
+ copyGc.clip = null;
+
+ // RenderingHints
+ copyGc.hints = (RenderingHints)this.hints.clone();
+
+ // Font (immutable)
+ copyGc.font = this.font;
+
+ // Background, Foreground (immutable)
+ copyGc.background = this.background;
+ copyGc.foreground = this.foreground;
+
+ return copyGc;
+ }
+
+ /**
+ * Gets this graphics context's current color.
+ * @return this graphics context's current color.
+ * @see java.awt.Color
+ * @see java.awt.Graphics#setColor
+ */
+ public Color getColor(){
+ return foreground;
+ }
+
+ /**
+ * Sets this graphics context's current color to the specified
+ * color. All subsequent graphics operations using this graphics
+ * context use this specified color.
+ * @param c the new rendering color.
+ * @see java.awt.Color
+ * @see java.awt.Graphics#getColor
+ */
+ public void setColor(Color c){
+ if(c == null)
+ return;
+
+ if(paint != c)
+ setPaint(c);
+ }
+
+ /**
+ * Gets the current font.
+ * @return this graphics context's current font.
+ * @see java.awt.Font
+ * @see java.awt.Graphics#setFont
+ */
+ public Font getFont(){
+ return font;
+ }
+
+ /**
+ * Sets this graphics context's font to the specified font.
+ * All subsequent text operations using this graphics context
+ * use this font.
+ * @param font the font.
+ * @see java.awt.Graphics#getFont
+ */
+ public void setFont(Font font){
+ if(font != null)
+ this.font = font;
+ }
+
+ /**
+ * Returns the bounding rectangle of the current clipping area.
+ * This method refers to the user clip, which is independent of the
+ * clipping associated with device bounds and window visibility.
+ * If no clip has previously been set, or if the clip has been
+ * cleared using <code>setClip(null)</code>, this method returns
+ * <code>null</code>.
+ * The coordinates in the rectangle are relative to the coordinate
+ * system origin of this graphics context.
+ * @return the bounding rectangle of the current clipping area,
+ * or <code>null</code> if no clip is set.
+ * @see java.awt.Graphics#getClip
+ * @see java.awt.Graphics#clipRect
+ * @see java.awt.Graphics#setClip(int, int, int, int)
+ * @see java.awt.Graphics#setClip(Shape)
+ * @since JDK1.1
+ */
+ public Rectangle getClipBounds(){
+ Shape c = getClip();
+ if(c==null)
+ return null;
+ else
+ return c.getBounds();
+ }
+
+
+ /**
+ * Intersects the current clip with the specified rectangle.
+ * The resulting clipping area is the intersection of the current
+ * clipping area and the specified rectangle. If there is no
+ * current clipping area, either because the clip has never been
+ * set, or the clip has been cleared using <code>setClip(null)</code>,
+ * the specified rectangle becomes the new clip.
+ * This method sets the user clip, which is independent of the
+ * clipping associated with device bounds and window visibility.
+ * This method can only be used to make the current clip smaller.
+ * To set the current clip larger, use any of the setClip methods.
+ * Rendering operations have no effect outside of the clipping area.
+ * @param x the x coordinate of the rectangle to intersect the clip with
+ * @param y the y coordinate of the rectangle to intersect the clip with
+ * @param width the width of the rectangle to intersect the clip with
+ * @param height the height of the rectangle to intersect the clip with
+ * @see #setClip(int, int, int, int)
+ * @see #setClip(Shape)
+ */
+ public void clipRect(int x, int y, int width, int height){
+ clip(new Rectangle(x, y, width, height));
+ }
+
+
+ /**
+ * Sets the current clip to the rectangle specified by the given
+ * coordinates. This method sets the user clip, which is
+ * independent of the clipping associated with device bounds
+ * and window visibility.
+ * Rendering operations have no effect outside of the clipping area.
+ * @param x the <i>x</i> coordinate of the new clip rectangle.
+ * @param y the <i>y</i> coordinate of the new clip rectangle.
+ * @param width the width of the new clip rectangle.
+ * @param height the height of the new clip rectangle.
+ * @see java.awt.Graphics#clipRect
+ * @see java.awt.Graphics#setClip(Shape)
+ * @since JDK1.1
+ */
+ public void setClip(int x, int y, int width, int height){
+ setClip(new Rectangle(x, y, width, height));
+ }
+
+
+ /**
+ * Gets the current clipping area.
+ * This method returns the user clip, which is independent of the
+ * clipping associated with device bounds and window visibility.
+ * If no clip has previously been set, or if the clip has been
+ * cleared using <code>setClip(null)</code>, this method returns
+ * <code>null</code>.
+ * @return a <code>Shape</code> object representing the
+ * current clipping area, or <code>null</code> if
+ * no clip is set.
+ * @see java.awt.Graphics#getClipBounds()
+ * @see java.awt.Graphics#clipRect
+ * @see java.awt.Graphics#setClip(int, int, int, int)
+ * @see java.awt.Graphics#setClip(Shape)
+ * @since JDK1.1
+ */
+ public Shape getClip(){
+ try{
+ return transform.createInverse().createTransformedShape(clip);
+ }catch(NoninvertibleTransformException e){
+ return null;
+ }
+ }
+
+
+ /**
+ * Sets the current clipping area to an arbitrary clip shape.
+ * Not all objects that implement the <code>Shape</code>
+ * interface can be used to set the clip. The only
+ * <code>Shape</code> objects that are guaranteed to be
+ * supported are <code>Shape</code> objects that are
+ * obtained via the <code>getClip</code> method and via
+ * <code>Rectangle</code> objects. This method sets the
+ * user clip, which is independent of the clipping associated
+ * with device bounds and window visibility.
+ * @param clip the <code>Shape</code> to use to set the clip
+ * @see java.awt.Graphics#getClip()
+ * @see java.awt.Graphics#clipRect
+ * @see java.awt.Graphics#setClip(int, int, int, int)
+ * @since JDK1.1
+ */
+ public void setClip(Shape clip) {
+ if (clip != null)
+ this.clip = transform.createTransformedShape(clip);
+ else
+ this.clip = null;
+ }
+
+ /**
+ * Sets the <code>Composite</code> for the <code>Graphics2D</code> context.
+ * The <code>Composite</code> is used in all drawing methods such as
+ * <code>drawImage</code>, <code>drawString</code>, <code>draw</code>,
+ * and <code>fill</code>. It specifies how new pixels are to be combined
+ * with the existing pixels on the graphics device during the rendering
+ * process.
+ * <p>If this <code>Graphics2D</code> context is drawing to a
+ * <code>Component</code> on the display screen and the
+ * <code>Composite</code> is a custom object rather than an
+ * instance of the <code>AlphaComposite</code> class, and if
+ * there is a security manager, its <code>checkPermission</code>
+ * method is called with an <code>AWTPermission("readDisplayPixels")</code>
+ * permission.
+ *
+ * @param comp the <code>Composite</code> object to be used for rendering
+ * @throws SecurityException
+ * if a custom <code>Composite</code> object is being
+ * used to render to the screen and a security manager
+ * is set and its <code>checkPermission</code> method
+ * does not allow the operation.
+ * @see java.awt.Graphics#setXORMode
+ * @see java.awt.Graphics#setPaintMode
+ * @see java.awt.AlphaComposite
+ */
+ public void setComposite(Composite comp){
+ this.composite = comp;
+ }
+
+
+ /**
+ * Sets the <code>Paint</code> attribute for the
+ * <code>Graphics2D</code> context. Calling this method
+ * with a <code>null</code> <code>Paint</code> object does
+ * not have any effect on the current <code>Paint</code> attribute
+ * of this <code>Graphics2D</code>.
+ * @param paint the <code>Paint</code> object to be used to generate
+ * color during the rendering process, or <code>null</code>
+ * @see java.awt.Graphics#setColor
+ * @see java.awt.GradientPaint
+ * @see java.awt.TexturePaint
+ */
+ public void setPaint( Paint paint ){
+ if(paint == null)
+ return;
+
+ this.paint = paint;
+ if(paint instanceof Color)
+ foreground = (Color)paint;
+ }
+
+
+ /**
+ * Sets the <code>Stroke</code> for the <code>Graphics2D</code> context.
+ * @param s the <code>Stroke</code> object to be used to stroke a
+ * <code>Shape</code> during the rendering process
+ * @see BasicStroke
+ */
+ public void setStroke(Stroke s){
+ stroke = s;
+ }
+
+ /**
+ * Sets the value of a single preference for the rendering algorithms.
+ * Hint categories include controls for rendering quality and overall
+ * time/quality trade-off in the rendering process. Refer to the
+ * <code>RenderingHints</code> class for definitions of some common
+ * keys and values.
+ * @param hintKey the key of the hint to be set.
+ * @param hintValue the value indicating preferences for the specified
+ * hint category.
+ * @see RenderingHints
+ */
+ public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue){
+ hints.put(hintKey, hintValue);
+ }
+
+
+ /**
+ * Returns the value of a single preference for the rendering algorithms.
+ * Hint categories include controls for rendering quality and overall
+ * time/quality trade-off in the rendering process. Refer to the
+ * <code>RenderingHints</code> class for definitions of some common
+ * keys and values.
+ * @param hintKey the key corresponding to the hint to get.
+ * @return an object representing the value for the specified hint key.
+ * Some of the keys and their associated values are defined in the
+ * <code>RenderingHints</code> class.
+ * @see RenderingHints
+ */
+ public Object getRenderingHint(RenderingHints.Key hintKey){
+ return hints.get(hintKey);
+ }
+
+
+ /**
+ * Replaces the values of all preferences for the rendering
+ * algorithms with the specified <code>hints</code>.
+ * The existing values for all rendering hints are discarded and
+ * the new set of known hints and values are initialized from the
+ * specified {@link Map} object.
+ * Hint categories include controls for rendering quality and
+ * overall time/quality trade-off in the rendering process.
+ * Refer to the <code>RenderingHints</code> class for definitions of
+ * some common keys and values.
+ * @param hints the rendering hints to be set
+ * @see RenderingHints
+ */
+ public void setRenderingHints(Map hints){
+ this.hints = new RenderingHints(hints);
+ }
+
+
+ /**
+ * Sets the values of an arbitrary number of preferences for the
+ * rendering algorithms.
+ * Only values for the rendering hints that are present in the
+ * specified <code>Map</code> object are modified.
+ * All other preferences not present in the specified
+ * object are left unmodified.
+ * Hint categories include controls for rendering quality and
+ * overall time/quality trade-off in the rendering process.
+ * Refer to the <code>RenderingHints</code> class for definitions of
+ * some common keys and values.
+ * @param hints the rendering hints to be set
+ * @see RenderingHints
+ */
+ public void addRenderingHints(Map hints){
+ this.hints.putAll(hints);
+ }
+
+
+ /**
+ * Gets the preferences for the rendering algorithms. Hint categories
+ * include controls for rendering quality and overall time/quality
+ * trade-off in the rendering process.
+ * Returns all of the hint key/value pairs that were ever specified in
+ * one operation. Refer to the
+ * <code>RenderingHints</code> class for definitions of some common
+ * keys and values.
+ * @return a reference to an instance of <code>RenderingHints</code>
+ * that contains the current preferences.
+ * @see RenderingHints
+ */
+ public RenderingHints getRenderingHints(){
+ return hints;
+ }
+
+ /**
+ * Translates the origin of the graphics context to the point
+ * (<i>x</i>, <i>y</i>) in the current coordinate system.
+ * Modifies this graphics context so that its new origin corresponds
+ * to the point (<i>x</i>, <i>y</i>) in this graphics context's
+ * original coordinate system. All coordinates used in subsequent
+ * rendering operations on this graphics context will be relative
+ * to this new origin.
+ * @param x the <i>x</i> coordinate.
+ * @param y the <i>y</i> coordinate.
+ */
+ public void translate(int x, int y){
+ if(x!=0 || y!=0){
+ transform.translate(x, y);
+ transformStack.add(TransformStackElement.createTranslateElement(x, y));
+ }
+ }
+
+
+ /**
+ * Concatenates the current
+ * <code>Graphics2D</code> <code>Transform</code>
+ * with a translation transform.
+ * Subsequent rendering is translated by the specified
+ * distance relative to the previous position.
+ * This is equivalent to calling transform(T), where T is an
+ * <code>AffineTransform</code> represented by the following matrix:
+ * <pre>
+ * [ 1 0 tx ]
+ * [ 0 1 ty ]
+ * [ 0 0 1 ]
+ * </pre>
+ * @param tx the distance to translate along the x-axis
+ * @param ty the distance to translate along the y-axis
+ */
+ public void translate(double tx, double ty){
+ transform.translate(tx, ty);
+ transformStack.add(TransformStackElement.createTranslateElement(tx, ty));
+ }
+
+ /**
+ * Concatenates the current <code>Graphics2D</code>
+ * <code>Transform</code> with a rotation transform.
+ * Subsequent rendering is rotated by the specified radians relative
+ * to the previous origin.
+ * This is equivalent to calling <code>transform(R)</code>, where R is an
+ * <code>AffineTransform</code> represented by the following matrix:
+ * <pre>
+ * [ cos(theta) -sin(theta) 0 ]
+ * [ sin(theta) cos(theta) 0 ]
+ * [ 0 0 1 ]
+ * </pre>
+ * Rotating with a positive angle theta rotates points on the positive
+ * x axis toward the positive y axis.
+ * @param theta the angle of rotation in radians
+ */
+ public void rotate(double theta){
+ transform.rotate(theta);
+ transformStack.add(TransformStackElement.createRotateElement(theta));
+ }
+
+ /**
+ * Concatenates the current <code>Graphics2D</code>
+ * <code>Transform</code> with a translated rotation
+ * transform. Subsequent rendering is transformed by a transform
+ * which is constructed by translating to the specified location,
+ * rotating by the specified radians, and translating back by the same
+ * amount as the original translation. This is equivalent to the
+ * following sequence of calls:
+ * <pre>
+ * translate(x, y);
+ * rotate(theta);
+ * translate(-x, -y);
+ * </pre>
+ * Rotating with a positive angle theta rotates points on the positive
+ * x axis toward the positive y axis.
+ * @param theta the angle of rotation in radians
+ * @param x x coordinate of the origin of the rotation
+ * @param y y coordinate of the origin of the rotation
+ */
+ public void rotate(double theta, double x, double y){
+ transform.rotate(theta, x, y);
+ transformStack.add(TransformStackElement.createTranslateElement(x, y));
+ transformStack.add(TransformStackElement.createRotateElement(theta));
+ transformStack.add(TransformStackElement.createTranslateElement(-x, -y));
+ }
+
+ /**
+ * Concatenates the current <code>Graphics2D</code>
+ * <code>Transform</code> with a scaling transformation
+ * Subsequent rendering is resized according to the specified scaling
+ * factors relative to the previous scaling.
+ * This is equivalent to calling <code>transform(S)</code>, where S is an
+ * <code>AffineTransform</code> represented by the following matrix:
+ * <pre>
+ * [ sx 0 0 ]
+ * [ 0 sy 0 ]
+ * [ 0 0 1 ]
+ * </pre>
+ * @param sx the amount by which X coordinates in subsequent
+ * rendering operations are multiplied relative to previous
+ * rendering operations.
+ * @param sy the amount by which Y coordinates in subsequent
+ * rendering operations are multiplied relative to previous
+ * rendering operations.
+ */
+ public void scale(double sx, double sy){
+ transform.scale(sx, sy);
+ transformStack.add(TransformStackElement.createScaleElement(sx, sy));
+ }
+
+ /**
+ * Concatenates the current <code>Graphics2D</code>
+ * <code>Transform</code> with a shearing transform.
+ * Subsequent renderings are sheared by the specified
+ * multiplier relative to the previous position.
+ * This is equivalent to calling <code>transform(SH)</code>, where SH
+ * is an <code>AffineTransform</code> represented by the following
+ * matrix:
+ * <pre>
+ * [ 1 shx 0 ]
+ * [ shy 1 0 ]
+ * [ 0 0 1 ]
+ * </pre>
+ * @param shx the multiplier by which coordinates are shifted in
+ * the positive X axis direction as a function of their Y coordinate
+ * @param shy the multiplier by which coordinates are shifted in
+ * the positive Y axis direction as a function of their X coordinate
+ */
+ public void shear(double shx, double shy){
+ transform.shear(shx, shy);
+ transformStack.add(TransformStackElement.createShearElement(shx, shy));
+ }
+
+ /**
+ * Composes an <code>AffineTransform</code> object with the
+ * <code>Transform</code> in this <code>Graphics2D</code> according
+ * to the rule last-specified-first-applied. If the current
+ * <code>Transform</code> is Cx, the result of composition
+ * with Tx is a new <code>Transform</code> Cx'. Cx' becomes the
+ * current <code>Transform</code> for this <code>Graphics2D</code>.
+ * Transforming a point p by the updated <code>Transform</code> Cx' is
+ * equivalent to first transforming p by Tx and then transforming
+ * the result by the original <code>Transform</code> Cx. In other
+ * words, Cx'(p) = Cx(Tx(p)). A copy of the Tx is made, if necessary,
+ * so further modifications to Tx do not affect rendering.
+ * @param Tx the <code>AffineTransform</code> object to be composed with
+ * the current <code>Transform</code>
+ * @see #setTransform
+ * @see AffineTransform
+ */
+ public void transform(AffineTransform Tx){
+ transform.concatenate(Tx);
+ transformStack.add(TransformStackElement.createGeneralTransformElement(Tx));
+ }
+
+ /**
+ * Sets the <code>Transform</code> in the <code>Graphics2D</code>
+ * context.
+ * @param Tx the <code>AffineTransform</code> object to be used in the
+ * rendering process
+ * @see #transform
+ * @see AffineTransform
+ */
+ public void setTransform(AffineTransform Tx){
+ transform = new AffineTransform(Tx);
+ invalidateTransformStack();
+ if(!Tx.isIdentity())
+ transformStack.add(TransformStackElement.createGeneralTransformElement(Tx));
+ }
+
+ /**
+ * Marks the GraphicContext's isNewTransformStack to false
+ * as a memento that the current transform stack was read and
+ * has not been reset. Only the setTransform method can
+ * override this memento.
+ */
+ public void validateTransformStack(){
+ transformStackValid = true;
+ }
+
+ /**
+ * Checks the status of the transform stack
+ */
+ public boolean isTransformStackValid(){
+ return transformStackValid;
+ }
+
+ /**
+ * @return array containing the successive transforms that
+ * were concatenated with the original one.
+ */
+ public TransformStackElement[] getTransformStack(){
+ TransformStackElement[] stack = new TransformStackElement[transformStack.size()];
+ transformStack.toArray( stack );
+ return stack;
+ }
+
+ /**
+ * Marks the GraphicContext's isNewTransformStack to true
+ * as a memento that the current transform stack was reset
+ * since it was last read. Only validateTransformStack
+ * can override this memento
+ */
+ protected void invalidateTransformStack(){
+ transformStack.clear();
+ transformStackValid = false;
+ }
+
+ /**
+ * Returns a copy of the current <code>Transform</code> in the
+ * <code>Graphics2D</code> context.
+ * @return the current <code>AffineTransform</code> in the
+ * <code>Graphics2D</code> context.
+ * @see #transform
+ * @see #setTransform
+ */
+ public AffineTransform getTransform(){
+ return new AffineTransform(transform);
+ }
+
+ /**
+ * Returns the current <code>Paint</code> of the
+ * <code>Graphics2D</code> context.
+ * @return the current <code>Graphics2D</code> <code>Paint</code>,
+ * which defines a color or pattern.
+ * @see #setPaint
+ * @see java.awt.Graphics#setColor
+ */
+ public Paint getPaint(){
+ return paint;
+ }
+
+
+ /**
+ * Returns the current <code>Composite</code> in the
+ * <code>Graphics2D</code> context.
+ * @return the current <code>Graphics2D</code> <code>Composite</code>,
+ * which defines a compositing style.
+ * @see #setComposite
+ */
+ public Composite getComposite(){
+ return composite;
+ }
+
+ /**
+ * Sets the background color for the <code>Graphics2D</code> context.
+ * The background color is used for clearing a region.
+ * When a <code>Graphics2D</code> is constructed for a
+ * <code>Component</code>, the background color is
+ * inherited from the <code>Component</code>. Setting the background color
+ * in the <code>Graphics2D</code> context only affects the subsequent
+ * <code>clearRect</code> calls and not the background color of the
+ * <code>Component</code>. To change the background
+ * of the <code>Component</code>, use appropriate methods of
+ * the <code>Component</code>.
+ * @param color the background color that isused in
+ * subsequent calls to <code>clearRect</code>
+ * @see #getBackground
+ * @see java.awt.Graphics#clearRect
+ */
+ public void setBackground(Color color){
+ if(color == null)
+ return;
+
+ background = color;
+ }
+
+
+ /**
+ * Returns the background color used for clearing a region.
+ * @return the current <code>Graphics2D</code> <code>Color</code>,
+ * which defines the background color.
+ * @see #setBackground
+ */
+ public Color getBackground(){
+ return background;
+ }
+
+ /**
+ * Returns the current <code>Stroke</code> in the
+ * <code>Graphics2D</code> context.
+ * @return the current <code>Graphics2D</code> <code>Stroke</code>,
+ * which defines the line style.
+ * @see #setStroke
+ */
+ public Stroke getStroke(){
+ return stroke;
+ }
+
+
+ /**
+ * Intersects the current <code>Clip</code> with the interior of the
+ * specified <code>Shape</code> and sets the <code>Clip</code> to the
+ * resulting intersection. The specified <code>Shape</code> is
+ * transformed with the current <code>Graphics2D</code>
+ * <code>Transform</code> before being intersected with the current
+ * <code>Clip</code>. This method is used to make the current
+ * <code>Clip</code> smaller.
+ * To make the <code>Clip</code> larger, use <code>setClip</code>.
+ * The <i>user clip</i> modified by this method is independent of the
+ * clipping associated with device bounds and visibility. If no clip has
+ * previously been set, or if the clip has been cleared using
+ * {@link java.awt.Graphics#setClip(Shape) setClip} with a
+ * <code>null</code> argument, the specified <code>Shape</code> becomes
+ * the new user clip.
+ * @param s the <code>Shape</code> to be intersected with the current
+ * <code>Clip</code>. If <code>s</code> is <code>null</code>,
+ * this method clears the current <code>Clip</code>.
+ */
+ public void clip(Shape s){
+ if (s != null)
+ s = transform.createTransformedShape(s);
+
+ if (clip != null) {
+ Area newClip = new Area(clip);
+ newClip.intersect(new Area(s));
+ clip = new GeneralPath(newClip);
+ } else {
+ clip = s;
+ }
+ }
+
+ /**
+ * Get the rendering context of the <code>Font</code> within this
+ * <code>Graphics2D</code> context.
+ * The {@link FontRenderContext}
+ * encapsulates application hints such as anti-aliasing and
+ * fractional metrics, as well as target device specific information
+ * such as dots-per-inch. This information should be provided by the
+ * application when using objects that perform typographical
+ * formatting, such as <code>Font</code> and
+ * <code>TextLayout</code>. This information should also be provided
+ * by applications that perform their own layout and need accurate
+ * measurements of various characteristics of glyphs such as advance
+ * and line height when various rendering hints have been applied to
+ * the text rendering.
+ *
+ * @return a reference to an instance of FontRenderContext.
+ * @see java.awt.font.FontRenderContext
+ * @see java.awt.Font#createGlyphVector(FontRenderContext,char[])
+ * @see java.awt.font.TextLayout
+ * @since JDK1.2
+ */
+ public FontRenderContext getFontRenderContext(){
+ //
+ // Find if antialiasing should be used.
+ //
+ Object antialiasingHint = hints.get(RenderingHints.KEY_TEXT_ANTIALIASING);
+ boolean isAntialiased = true;
+ if(antialiasingHint != RenderingHints.VALUE_TEXT_ANTIALIAS_ON &&
+ antialiasingHint != RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT){
+
+ // If antialias was not turned off, then use the general rendering
+ // hint.
+ if(antialiasingHint != RenderingHints.VALUE_TEXT_ANTIALIAS_OFF){
+ antialiasingHint = hints.get(RenderingHints.KEY_ANTIALIASING);
+
+ // Test general hint
+ if(antialiasingHint != RenderingHints.VALUE_ANTIALIAS_ON &&
+ antialiasingHint != RenderingHints.VALUE_ANTIALIAS_DEFAULT){
+ // Antialiasing was not requested. However, if it was not turned
+ // off explicitly, use it.
+ if(antialiasingHint == RenderingHints.VALUE_ANTIALIAS_OFF)
+ isAntialiased = false;
+ }
+ }
+ else
+ isAntialiased = false;
+
+ }
+
+ //
+ // Find out whether fractional metrics should be used.
+ //
+ boolean useFractionalMetrics = true;
+ if(hints.get(RenderingHints.KEY_FRACTIONALMETRICS)
+ == RenderingHints.VALUE_FRACTIONALMETRICS_OFF)
+ useFractionalMetrics = false;
+
+ FontRenderContext frc = new FontRenderContext(defaultTransform,
+ isAntialiased,
+ useFractionalMetrics);
+ return frc;
+ }
+}
Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/GraphicContext.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/TransformStackElement.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/TransformStackElement.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/TransformStackElement.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/TransformStackElement.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,206 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.g2d;
+
+import java.awt.geom.AffineTransform;
+
+/**
+ * Contains a description of an elementary transform stack element,
+ * such as a rotate or translate. A transform stack element has a
+ * type and a value, which is an array of double values.<br>
+ *
+ * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
+ * @author <a href="mailto:paul_evenblij@compuware.com">Paul Evenblij</a>
+ * @version $Id: TransformStackElement.java 478249 2006-11-22 17:29:37Z dvholten $
+ */
+public abstract class TransformStackElement implements Cloneable{
+
+ /**
+ * Transform type
+ */
+ private TransformType type;
+
+ /**
+ * Value
+ */
+ private double[] transformParameters;
+
+ /**
+ * @param type transform type
+ * @param transformParameters parameters for transform
+ */
+ protected TransformStackElement(TransformType type,
+ double[] transformParameters){
+ this.type = type;
+ this.transformParameters = transformParameters;
+ }
+
+ /**
+ * @return an object which is a deep copy of this one
+ */
+ public Object clone() {
+ TransformStackElement newElement = null;
+
+ // start with a shallow copy to get our implementations right
+ try {
+ newElement = (TransformStackElement) super.clone();
+ } catch(java.lang.CloneNotSupportedException ex) {}
+
+ // now deep copy the parameter array
+ double[] transformParameters = new double[this.transformParameters.length];
+ System.arraycopy(this.transformParameters, 0, transformParameters, 0, transformParameters.length);
+ newElement.transformParameters = transformParameters;
+ return newElement;
+ }
+
+ /*
+ * Factory methods
+ */
+
+ public static TransformStackElement createTranslateElement(double tx,
+ double ty){
+ return new TransformStackElement(TransformType.TRANSLATE,
+ new double[]{ tx, ty }) {
+ boolean isIdentity(double[] parameters) {
+ return parameters[0] == 0 && parameters[1] == 0;
+ }
+ };
+ }
+
+ public static TransformStackElement createRotateElement(double theta){
+ return new TransformStackElement(TransformType.ROTATE,
+ new double[]{ theta }) {
+ boolean isIdentity(double[] parameters) {
+ return Math.cos(parameters[0]) == 1;
+ }
+ };
+ }
+
+ public static TransformStackElement createScaleElement(double scaleX,
+ double scaleY){
+ return new TransformStackElement(TransformType.SCALE,
+ new double[]{ scaleX, scaleY }) {
+ boolean isIdentity(double[] parameters) {
+ return parameters[0] == 1 && parameters[1] == 1;
+ }
+ };
+ }
+
+ public static TransformStackElement createShearElement(double shearX,
+ double shearY){
+ return new TransformStackElement(TransformType.SHEAR,
+ new double[]{ shearX, shearY }) {
+ boolean isIdentity(double[] parameters) {
+ return parameters[0] == 0 && parameters[1] == 0;
+ }
+ };
+ }
+
+ public static TransformStackElement createGeneralTransformElement
+ (AffineTransform txf){
+ double[] matrix = new double[6];
+ txf.getMatrix(matrix);
+ return new TransformStackElement(TransformType.GENERAL, matrix) {
+ boolean isIdentity(double[] m) {
+ return (m[0] == 1 && m[2] == 0 && m[4] == 0 &&
+ m[1] == 0 && m[3] == 1 && m[5] == 0);
+ }
+ };
+ }
+
+ /**
+ * Implementation should determine if the parameter list represents
+ * an identity transform, for the instance transform type.
+ */
+ abstract boolean isIdentity(double[] parameters);
+
+ /**
+ * @return true iff this transform is the identity transform
+ */
+ public boolean isIdentity() {
+ return isIdentity(transformParameters);
+ }
+
+ /**
+ * @return array of values containing this transform element's parameters
+ */
+ public double[] getTransformParameters(){
+ return transformParameters;
+ }
+
+ /**
+ * @return this transform type
+ */
+ public TransformType getType(){
+ return type;
+ }
+
+ /*
+ * Concatenation utility. Requests this transform stack element
+ * to concatenate with the input stack element. Only elements
+ * of the same types are concatenated. For example, if this
+ * element represents a translation, it will concatenate with
+ * another translation, but not with any other kind of
+ * stack element.
+ * @param stackElement element to be concatenated with this one.
+ * @return true if the input stackElement was concatenated with
+ * this one. False otherwise.
+ */
+ public boolean concatenate(TransformStackElement stackElement){
+ boolean canConcatenate = false;
+
+ if(type.toInt() == stackElement.type.toInt()){
+ canConcatenate = true;
+ switch(type.toInt()){
+ case TransformType.TRANSFORM_TRANSLATE:
+ transformParameters[0] += stackElement.transformParameters[0];
+ transformParameters[1] += stackElement.transformParameters[1];
+ break;
+ case TransformType.TRANSFORM_ROTATE:
+ transformParameters[0] += stackElement.transformParameters[0];
+ break;
+ case TransformType.TRANSFORM_SCALE:
+ transformParameters[0] *= stackElement.transformParameters[0];
+ transformParameters[1] *= stackElement.transformParameters[1];
+ break;
+ case TransformType.TRANSFORM_GENERAL:
+ transformParameters
+ = matrixMultiply(transformParameters,
+ stackElement.transformParameters);
+ break;
+ default:
+ canConcatenate = false;
+ }
+ }
+
+ return canConcatenate;
+ }
+
+ /**
+ * Multiplies two 2x3 matrices of double precision values
+ */
+ private double[] matrixMultiply(double[] matrix1, double[] matrix2) {
+ double[] product = new double[6];
+ AffineTransform transform1 = new AffineTransform(matrix1);
+ transform1.concatenate(new AffineTransform(matrix2));
+ transform1.getMatrix(product);
+ return product;
+ }
+
+}
Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/TransformStackElement.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/TransformType.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/TransformType.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/TransformType.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/TransformType.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,111 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+package org.apache.flex.forks.batik.ext.awt.g2d;
+
+/**
+ * Enumeration for transformation types.
+ *
+ * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
+ * @version $Id: TransformType.java 504084 2007-02-06 11:24:46Z dvholten $
+ */
+public class TransformType{
+ /*
+ * Transform type constants
+ */
+ public static final int TRANSFORM_TRANSLATE = 0;
+ public static final int TRANSFORM_ROTATE = 1;
+ public static final int TRANSFORM_SCALE = 2;
+ public static final int TRANSFORM_SHEAR = 3;
+ public static final int TRANSFORM_GENERAL = 4;
+
+ /**
+ * Strings describing the elementary transforms
+ */
+ public static final String TRANSLATE_STRING = "translate";
+ public static final String ROTATE_STRING = "rotate";
+ public static final String SCALE_STRING = "scale";
+ public static final String SHEAR_STRING = "shear";
+ public static final String GENERAL_STRING = "general";
+
+ /**
+ * TransformType values
+ */
+ public static final TransformType TRANSLATE = new TransformType(TRANSFORM_TRANSLATE, TRANSLATE_STRING);
+ public static final TransformType ROTATE = new TransformType(TRANSFORM_ROTATE, ROTATE_STRING);
+ public static final TransformType SCALE = new TransformType(TRANSFORM_SCALE, SCALE_STRING);
+ public static final TransformType SHEAR = new TransformType(TRANSFORM_SHEAR, SHEAR_STRING);
+ public static final TransformType GENERAL = new TransformType(TRANSFORM_GENERAL, GENERAL_STRING);
+
+ private String desc;
+ private int val;
+
+ /**
+ * Constructor is private so that no instances other than
+ * the ones in the enumeration can be created.
+ * @see #readResolve
+ */
+ private TransformType(int val, String desc){
+ this.desc = desc;
+ this.val = val;
+ }
+
+ /**
+ * @return description
+ */
+ public String toString(){
+ return desc;
+ }
+
+ /**
+ * Convenience for enumeration switching.
+ * That is,
+ * <pre>
+ * switch(transformType.toInt()){
+ * case TransformType.TRANSFORM_TRANSLATE:
+ * ....
+ * case TransformType.TRANSFORM_ROTATE:
+ * </pre>
+ */
+ public int toInt(){
+ return val;
+ }
+
+ /**
+ * This is called by the serialization code before it returns an unserialized
+ * object. To provide for unicity of instances, the instance that was read
+ * is replaced by its static equivalent
+ */
+ public Object readResolve() {
+ switch(val){
+ case TRANSFORM_TRANSLATE:
+ return TransformType.TRANSLATE;
+ case TRANSFORM_ROTATE:
+ return TransformType.ROTATE;
+ case TRANSFORM_SCALE:
+ return TransformType.SCALE;
+ case TRANSFORM_SHEAR:
+ return TransformType.SHEAR;
+ case TRANSFORM_GENERAL:
+ return TransformType.GENERAL;
+ default:
+ throw new Error("Unknown TransformType value:" + val );
+ }
+ }
+}
Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/TransformType.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/package.html
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/package.html?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/package.html (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/package.html Thu Oct 25 19:01:43 2012
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
+"http://www.w3.org/TR/REC-html40/loose.dtd">
+<html>
+ <head>
+ <title>Abstract Graphics2D Package</title>
+ </head>
+ <body>
+ Provides an API for subclassing the <code>java.awt.Graphics2D</code>
+ class in order to translate Java 2D primitives into another graphic
+ format.
+ </body>
+</html>
Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/g2d/package.html
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/geom/AbstractSegment.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/geom/AbstractSegment.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/geom/AbstractSegment.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/geom/AbstractSegment.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,327 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.geom;
+
+import java.awt.geom.Point2D;
+import java.util.Arrays;
+
+/**
+ * An abstract class for path segments.
+ *
+ * @version $Id: AbstractSegment.java 478249 2006-11-22 17:29:37Z dvholten $
+ */
+public abstract class AbstractSegment implements Segment {
+
+ protected abstract int findRoots(double y, double [] roots);
+
+ public Segment.SplitResults split(double y) {
+ double [] roots = { 0, 0, 0 };
+ int numSol = findRoots(y, roots);
+ if (numSol == 0) return null; // No split
+
+ Arrays.sort(roots, 0, numSol);
+ double [] segs = new double[numSol+2];
+ int numSegments=0;
+ segs[numSegments++] = 0;
+ for (int i=0; i<numSol; i++) {
+ double r = roots[i];
+ if (r <= 0.0) continue;
+ if (r >= 1.0) break;
+ if (segs[numSegments-1] != r)
+ segs[numSegments++] = r;
+ }
+ segs[numSegments++] = 1.0;
+
+ if (numSegments == 2) return null;
+ // System.err.println("Y: " + y + "#Seg: " + numSegments +
+ // " Seg: " + this);
+
+ Segment [] parts = new Segment[numSegments];
+ double pT = 0.0;
+ int pIdx = 0;
+ boolean firstAbove=false, prevAbove=false;
+ for (int i=1; i<numSegments; i++) {
+ // System.err.println("Segs: " + segs[i-1]+", "+segs[i]);
+ parts[pIdx] = getSegment(segs[i-1], segs[i]);
+ Point2D.Double pt = parts[pIdx].eval(0.5);
+ // System.err.println("Pt: " + pt);
+ if (pIdx == 0) {
+ pIdx++;
+ firstAbove = prevAbove = (pt.y < y);
+ continue;
+ }
+ boolean above = (pt.y < y);
+ if (prevAbove == above) {
+ // Merge segments
+ parts[pIdx-1] = getSegment(pT, segs[i]);
+ } else {
+ pIdx++;
+ pT=segs[i-1];
+ prevAbove = above;
+ }
+ }
+ if (pIdx == 1) return null;
+ Segment [] below, above;
+ if (firstAbove) {
+ above = new Segment[(pIdx+1)/2];
+ below = new Segment[pIdx/2];
+ } else {
+ above = new Segment[pIdx/2];
+ below = new Segment[(pIdx+1)/2];
+ }
+ int ai=0, bi=0;
+ for (int i=0; i<pIdx; i++) {
+ if (firstAbove) above[ai++] = parts[i];
+ else below[bi++] = parts[i];
+ firstAbove = !firstAbove;
+ }
+ return new SplitResults(below, above);
+ }
+
+ public Segment splitBefore(double t) {
+ return getSegment(0.0, t);
+ }
+
+ public Segment splitAfter(double t) {
+ return getSegment(t, 1.0);
+ }
+
+ // Doubles have 48bit precision
+ static final double eps = 1/(double)(1L<<48);
+ static final double tol = 4.0*eps;
+
+ public static int solveLine(double a, double b,
+ double [] roots) {
+ if (a == 0) {
+ if (b != 0)
+ // No intersection.
+ return 0;
+ // All pts intersect just return 0.
+ roots[0] = 0;
+ return 1;
+ }
+
+ roots[0] = -b/a;
+ return 1;
+ }
+
+ public static int solveQuad(double a, double b, double c,
+ double [] roots) {
+ // System.err.println("Quad: " + a +"t^2 + " + b +"t + " + c);
+ if (a == 0) {
+ // no square term.
+ return solveLine(b, c, roots);
+ }
+
+ double det = b*b-4*a*c;
+ // System.err.println("Det: " + det);
+
+ if (Math.abs(det) <= tol*b*b) {
+ // one real root (det doesn't contain any useful info)
+ roots[0] = -b/(2*a);
+ return 1;
+ }
+
+ if (det < 0)
+ return 0; // No real roots
+
+ // Two real roots
+ det = Math.sqrt(det);
+ double w = -(b + matchSign(det, b));
+ roots[0] = (2*c)/w;
+ roots[1] = w/(2*a);
+ return 2;
+ }
+
+ public static double matchSign(double a, double b) {
+ if (b < 0) return (a < 0)?a:-a;
+ return (a > 0)?a:-a;
+ }
+
+ public static int solveCubic(double a3, double a2,
+ double a1, double a0,
+ double [] roots) {
+
+ // System.err.println("Cubic: " + a3 + "t^3 + " +
+ // a2 +"t^2 + " +
+ // a1 +"t + " + a0);
+
+ double [] dRoots = { 0, 0};
+ int dCnt = solveQuad(3*a3, 2*a2, a1, dRoots);
+ double [] yVals = {0, 0, 0, 0};
+ double [] tVals = {0, 0, 0, 0};
+ int yCnt=0;
+ yVals[yCnt] = a0;
+ tVals[yCnt++] = 0;
+ double r;
+ switch (dCnt) {
+ case 1:
+ r = dRoots[0];
+ if ((r > 0) && (r < 1)) {
+ yVals[yCnt] = ((a3*r+a2)*r+a1)*r+a0;
+ tVals[yCnt++] = r;
+ }
+ break;
+ case 2:
+ if (dRoots[0] > dRoots[1]) {
+ double t = dRoots[0];
+ dRoots[0] = dRoots[1];
+ dRoots[1] = t;
+ }
+ r = dRoots[0];
+ if ((r > 0) && (r < 1)) {
+ yVals[yCnt] = ((a3*r+a2)*r+a1)*r+a0;
+ tVals[yCnt++] = r;
+ }
+ r = dRoots[1];
+ if ((r > 0) && (r < 1)) {
+ yVals[yCnt] = ((a3*r+a2)*r+a1)*r+a0;
+ tVals[yCnt++] = r;
+ }
+ break;
+ default: break;
+ }
+ yVals[yCnt] = a3+a2+a1+a0;
+ tVals[yCnt++] = 1.0;
+
+ int ret=0;
+ for (int i=0; i<yCnt-1; i++) {
+ double y0 = yVals[i], t0 = tVals[i];
+ double y1 = yVals[i+1], t1 = tVals[i+1];
+ if ((y0 < 0) && (y1 < 0)) continue;
+ if ((y0 > 0) && (y1 > 0)) continue;
+
+ if (y0 > y1) { // swap so y0 < 0 and y1 > 0
+ double t;
+ t = y0; y0=y1; y1=t;
+ t = t0; t0=t1; t1=t;
+ }
+
+ if (-y0 < tol*y1) { roots[ret++] = t0; continue; }
+ if (y1 < -tol*y0) { roots[ret++] = t1; i++; continue; }
+
+ double epsZero = tol*(y1-y0);
+ int cnt;
+ for (cnt=0; cnt<20; cnt++) {
+ double dt = t1-t0;
+ double dy = y1-y0;
+ // double t = (t0+t1)/2;
+ // double t= t0+Math.abs(y0/dy)*dt;
+ // This tends to make sure that we come up
+ // a little short each time this generaly allows
+ // you to eliminate as much of the range as possible
+ // without overshooting (in which case you may eliminate
+ // almost nothing).
+ double t= t0+(Math.abs(y0/dy)*99+.5)*dt/100;
+ double v = ((a3*t+a2)*t+a1)*t+a0;
+ if (Math.abs(v) < epsZero) {
+ roots[ret++] = t; break;
+ }
+ if (v < 0) { t0 = t; y0=v;}
+ else { t1 = t; y1=v;}
+ }
+ if (cnt == 20)
+ roots[ret++] = (t0+t1)/2;
+ }
+ return ret;
+ }
+
+ /*
+ public static void check(Segment seg, float y, PrintStream ps) {
+ ps.println("<path fill=\"none\" stroke=\"black\" " +
+ " stroke-width=\"3\" d=\"" + seg + "\"/>");
+
+ ps.println("<line x1=\"-1000\" y1=\""+y+
+ "\" x2=\"1000\" y2=\""+y+"\" fill=\"none\" stroke=\"orange\"/>\n");
+
+ SplitResults sr = seg.split(y);
+ if (sr == null) return;
+ Segment [] above = sr.getAbove();
+ Segment [] below = sr.getBelow();
+ for (int i=0; i<above.length; i++) {
+ ps.println("<path fill=\"none\" stroke=\"blue\" " +
+ " stroke-width=\"2.5\" " +
+ " d=\"" + above[i] + "\"/>");
+ }
+ for (int i=0; i<below.length; i++) {
+ ps.println("<path fill=\"none\" stroke=\"red\" " +
+ " stroke-width=\"2\" " +
+ "d=\"" + below[i] + "\"/>");
+ }
+ }
+ public static void main(String [] args) {
+ PrintStream ps;
+ double [] roots = { 0, 0, 0 };
+ int n = solveCubic (-0.10000991821289062, 9.600013732910156,
+ -35.70000457763672, 58.0, roots);
+ for (int i=0; i<n; i++)
+ System.err.println("Root: " + roots[i]);
+ Cubic c;
+ c = new Cubic(new Point2D.Double(153.6999969482422,5.099999904632568),
+ new Point2D.Double(156.6999969482422,4.099999904632568),
+ new Point2D.Double(160.39999389648438,2.3999998569488525),
+ new Point2D.Double(164.6999969482422,0.0));
+ c.split(0);
+
+ c = new Cubic(new Point2D.Double(24.899999618530273,23.10000228881836),
+ new Point2D.Double(41.5,8.399999618530273),
+ new Point2D.Double(64.69999694824219,1.0),
+ new Point2D.Double(94.5999984741211,1.0));
+ c.split(0);
+
+ try {
+ ps = new PrintStream(new FileOutputStream(args[0]));
+ } catch(java.io.IOException ioe) {
+ ioe.printStackTrace();
+ return;
+ }
+
+ ps.println("<?xml version=\"1.0\" standalone=\"no\"?>\n" +
+ "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n" +
+ "\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n" +
+ "<svg width=\"450\" height=\"500\"\n" +
+ " viewBox=\"-100 -100 450 500\"\n" +
+ " xmlns=\"http://www.w3.org/2000/svg\"\n" +
+ " xmlns:xlink=\"http://www.w3.org/1999/xlink\">");
+
+ check(new Cubic(new Point2D.Double(0, 0),
+ new Point2D.Double(100, 100),
+ new Point2D.Double(-50, 100),
+ new Point2D.Double(50, 0)), 40, ps);
+
+ check(new Cubic(new Point2D.Double(100, 0),
+ new Point2D.Double(200, 100),
+ new Point2D.Double(50, -50),
+ new Point2D.Double(150, 30)), 20, ps);
+
+ check(new Cubic(new Point2D.Double(200, 0),
+ new Point2D.Double(300, 100),
+ new Point2D.Double(150, 100),
+ new Point2D.Double(250, 0)), 75, ps);
+
+ check(new Quadradic(new Point2D.Double(0, 100),
+ new Point2D.Double(50,150),
+ new Point2D.Double(10,100)), 115, ps);
+
+ check(new Linear(new Point2D.Double(100, 100),
+ new Point2D.Double(150,150)), 115, ps);
+ ps.println("</svg>");
+ }
+ */
+}
Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/geom/AbstractSegment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/geom/Cubic.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/geom/Cubic.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/geom/Cubic.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/geom/Cubic.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,422 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.geom;
+
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * A class representing a cubic path segment.
+ *
+ * @version $Id: Cubic.java 478249 2006-11-22 17:29:37Z dvholten $
+ */
+public class Cubic extends AbstractSegment {
+
+ public Point2D.Double p1, p2, p3, p4;
+ public Cubic() {
+ p1 = new Point2D.Double();
+ p2 = new Point2D.Double();
+ p3 = new Point2D.Double();
+ p4 = new Point2D.Double();
+ }
+ public Cubic(double x1, double y1, double x2, double y2,
+ double x3, double y3, double x4, double y4) {
+ p1 = new Point2D.Double(x1, y1);
+ p2 = new Point2D.Double(x2, y2);
+ p3 = new Point2D.Double(x3, y3);
+ p4 = new Point2D.Double(x4, y4);
+ }
+
+ public Cubic(Point2D.Double p1, Point2D.Double p2,
+ Point2D.Double p3, Point2D.Double p4) {
+ this.p1 = p1;
+ this.p2 = p2;
+ this.p3 = p3;
+ this.p4 = p4;
+ }
+
+ public Object clone() {
+ return new Cubic(new Point2D.Double(p1.x, p1.y),
+ new Point2D.Double(p2.x, p2.y),
+ new Point2D.Double(p3.x, p3.y),
+ new Point2D.Double(p4.x, p4.y));
+ }
+
+ public Segment reverse() {
+ return new Cubic(new Point2D.Double(p4.x, p4.y),
+ new Point2D.Double(p3.x, p3.y),
+ new Point2D.Double(p2.x, p2.y),
+ new Point2D.Double(p1.x, p1.y));
+ }
+
+ private void getMinMax(double p1, double p2,
+ double p3, double p4,
+ double [] minMax) {
+ if (p4 > p1){
+ minMax[0] = p1; minMax[1] = p4;
+ } else {
+ minMax[0] = p4; minMax[1] = p1;
+ }
+
+ double c0 = 3*(p2-p1);
+ double c1 = 6*(p3-p2);
+ double c2 = 3*(p4-p3);
+ double [] eqn = { c0, c1-2*c0, c2-c1+c0 };
+ int roots = QuadCurve2D.solveQuadratic(eqn);
+ for (int r=0; r<roots; r++) {
+ double tv = eqn[r];
+ if ((tv <= 0) || (tv >= 1)) continue;
+ tv = ((1-tv)*(1-tv)*(1-tv)*p1 +
+ 3*tv*(1-tv)*(1-tv)*p2 +
+ 3*tv*tv*(1-tv)*p3 +
+ tv*tv*tv*p4);
+ if (tv < minMax[0]) minMax[0] = tv;
+ else if (tv > minMax[1]) minMax[1] = tv;
+ }
+ }
+ public double minX() {
+ double [] minMax = {0, 0};
+ getMinMax(p1.x, p2.x, p3.x, p4.x, minMax);
+ return minMax[0];
+ }
+ public double maxX() {
+ double [] minMax = {0, 0};
+ getMinMax(p1.x, p2.x, p3.x, p4.x, minMax);
+ return minMax[1];
+ }
+ public double minY() {
+ double [] minMax = {0, 0};
+ getMinMax(p1.y, p2.y, p3.y, p4.y, minMax);
+ return minMax[0];
+ }
+ public double maxY() {
+ double [] minMax = {0, 0};
+ getMinMax(p1.y, p2.y, p3.y, p4.y, minMax);
+ return minMax[1];
+ }
+
+ public Rectangle2D getBounds2D() {
+ double [] minMaxX = {0, 0};
+ getMinMax(p1.x, p2.x, p3.x, p4.x, minMaxX);
+ double [] minMaxY = {0, 0};
+ getMinMax(p1.y, p2.y, p3.y, p4.y, minMaxY);
+
+ return new Rectangle2D.Double
+ (minMaxX[0], minMaxY[0],
+ minMaxX[1]-minMaxX[0], minMaxY[1]-minMaxY[0]);
+ }
+
+ protected int findRoots(double y, double [] roots) {
+ double [] eqn = { p1.y-y, 3*(p2.y-p1.y), 3*(p1.y-2*p2.y+p3.y),
+ 3*p2.y-p1.y+p4.y-3*p3.y };
+ return CubicCurve2D.solveCubic(eqn, roots);
+ // return solveCubic(eqn[3], eqn[2], eqn[1], eqn[0], roots);
+ }
+
+ public Point2D.Double evalDt(double t) {
+ double x = 3*( (p2.x-p1.x)*(1-t)*(1-t) +
+ 2*(p3.x-p2.x)*(1-t)*t +
+ (p4.x-p3.x)*t*t);
+ double y = 3*( (p2.y-p1.y)*(1-t)*(1-t) +
+ 2*(p3.y-p2.y)*(1-t)*t +
+ (p4.y-p3.y)*t*t);
+ return new Point2D.Double(x, y);
+ }
+
+
+ public Point2D.Double eval(double t) {
+ double x = ((1-t)*(1-t)*(1-t)*p1.x +
+ 3*(t* (1-t)*(1-t)*p2.x +
+ t* t* (1-t)*p3.x) +
+ t*t*t *p4.x);
+ double y = ((1-t)*(1-t)*(1-t)*p1.y +
+ 3*(t* (1-t)*(1-t)*p2.y +
+ t* t* (1-t)*p3.y) +
+ t*t*t *p4.y);
+ return new Point2D.Double(x, y);
+ }
+
+ /**
+ * Subdivides this Cubic curve into two curves at t = 0.5.
+ * can be done with getSegment but this is more efficent.
+ * @param s0 if non-null contains portion of curve from 0->.5
+ * @param s1 if non-null contains portion of curve from .5->1
+ */
+ public void subdivide(Segment s0, Segment s1) {
+ Cubic c0=null, c1=null;
+ if (s0 instanceof Cubic) c0 = (Cubic)s0;
+ if (s1 instanceof Cubic) c1 = (Cubic)s1;
+ subdivide(c0, c1);
+ }
+
+ /**
+ * Subdivides this Cubic curve into two curves at given t.
+ * @param s0 if non-null contains portion of curve from 0->t.
+ * @param s1 if non-null contains portion of curve from t->1.
+ */
+ public void subdivide(double t, Segment s0, Segment s1) {
+ Cubic c0=null, c1=null;
+ if (s0 instanceof Cubic) c0 = (Cubic)s0;
+ if (s1 instanceof Cubic) c1 = (Cubic)s1;
+ subdivide(t, c0, c1);
+ }
+
+ /**
+ * Subdivides this Cubic curve into two curves at t = 0.5.
+ * can be done with getSegment but this is more efficent.
+ * @param c0 if non-null contains portion of curve from 0->.5
+ * @param c1 if non-null contains portion of curve from .5->1
+ */
+ public void subdivide(Cubic c0, Cubic c1) {
+ if ((c0 == null) && (c1 == null)) return;
+
+ double npX = (p1.x+3*(p2.x+p3.x)+p4.x)*0.125;
+ double npY = (p1.y+3*(p2.y+p3.y)+p4.y)*0.125;
+
+ double npdx = ((p2.x-p1.x)+2*(p3.x-p2.x)+(p4.x-p3.x))*0.125;
+ double npdy = ((p2.y-p1.y)+2*(p3.y-p2.y)+(p4.y-p3.y))*0.125;
+
+ if (c0 != null) {
+ c0.p1.x = p1.x;
+ c0.p1.y = p1.y;
+ c0.p2.x = (p2.x+p1.x)*0.5;
+ c0.p2.y = (p2.y+p1.y)*0.5;
+
+ c0.p3.x = npX-npdx;
+ c0.p3.y = npY-npdy;
+ c0.p4.x = npX;
+ c0.p4.y = npY;
+ }
+
+ if (c1 != null) {
+ c1.p1.x = npX;
+ c1.p1.y = npY;
+ c1.p2.x = npX+npdx;
+ c1.p2.y = npY+npdy;
+
+ c1.p3.x = (p4.x+p3.x)*0.5;
+ c1.p3.y = (p4.y+p3.y)*0.5;
+ c1.p4.x = p4.x;
+ c1.p4.y = p4.y;
+ }
+ }
+
+ /**
+ * Subdivides this Cubic curve into two curves at given t.
+ * @param c0 if non-null contains portion of curve from 0->t.
+ * @param c1 if non-null contains portion of curve from t->1.
+ */
+ public void subdivide(double t, Cubic c0, Cubic c1) {
+ if ((c0 == null) && (c1 == null)) return;
+
+ Point2D.Double np = eval(t);
+ Point2D.Double npd = evalDt(t);
+
+ if (c0 != null) {
+ c0.p1.x = p1.x;
+ c0.p1.y = p1.y;
+ c0.p2.x = (p2.x+p1.x)*t;
+ c0.p2.y = (p2.y+p1.y)*t;
+
+ c0.p3.x = np.x-(npd.x*t/3);
+ c0.p3.y = np.y-(npd.y*t/3);
+ c0.p4.x = np.x;
+ c0.p4.y = np.y;
+ }
+
+ if (c1 != null) {
+ c1.p1.x = np.x;
+ c1.p1.y = np.y;
+ c1.p2.x = np.x+(npd.x*(1-t)/3);
+ c1.p2.y = np.y+(npd.y*(1-t)/3);
+
+ c1.p3.x = (p4.x+p3.x)*(1-t);
+ c1.p3.y = (p4.y+p3.y)*(1-t);
+ c1.p4.x = p4.x;
+ c1.p4.y = p4.y;
+ }
+ }
+
+ public Segment getSegment(double t0, double t1) {
+ double dt = t1-t0;
+ Point2D.Double np1 = eval(t0);
+ Point2D.Double dp1 = evalDt(t0);
+ Point2D.Double np2 = new Point2D.Double(np1.x+dt*dp1.x/3,
+ np1.y+dt*dp1.y/3);
+
+ Point2D.Double np4 = eval(t1);
+ Point2D.Double dp4 = evalDt(t1);
+
+ Point2D.Double np3 = new Point2D.Double(np4.x-dt*dp4.x/3,
+ np4.y-dt*dp4.y/3);
+ return new Cubic(np1, np2, np3, np4);
+ }
+
+ private static int count = 0;
+
+ protected double subLength(double leftLegLen, double rightLegLen,
+ double maxErr) {
+ count++;
+ double cldx, cldy, cdx, cdy;
+ cldx = p3.x-p2.x;
+ cldy = p3.y-p2.y;
+ double crossLegLen = Math.sqrt(cldx*cldx+cldy*cldy);
+
+ cdx = p4.x-p1.x;
+ cdy = p4.y-p1.y;
+ double cordLen = Math.sqrt(cdx*cdx+cdy*cdy);
+
+ double hullLen = leftLegLen+rightLegLen+crossLegLen;
+ if (hullLen < maxErr) return (hullLen+cordLen)/2;
+
+ double err = (hullLen-cordLen);
+ if (err < maxErr)
+ return (hullLen+cordLen)/2;
+
+ Cubic c = new Cubic();
+ double npX = (p1.x+3*(p2.x+p3.x)+p4.x)*0.125;
+ double npY = (p1.y+3*(p2.y+p3.y)+p4.y)*0.125;
+
+ double npdx = (cldx + cdx)*.125;
+ double npdy = (cldy + cdy)*.125;
+
+ c.p1.x = p1.x;
+ c.p1.y = p1.y;
+ c.p2.x = (p2.x+p1.x)*.5;
+ c.p2.y = (p2.y+p1.y)*.5;
+
+ c.p3.x = npX-npdx;
+ c.p3.y = npY-npdy;
+ c.p4.x = npX;
+ c.p4.y = npY;
+
+ double midLen = Math.sqrt(npdx*npdx+npdy*npdy);
+ double len = c.subLength(leftLegLen/2, midLen, maxErr/2);
+
+ c.p1.x = npX;
+ c.p1.y = npY;
+ c.p2.x = npX+npdx;
+ c.p2.y = npY+npdy;
+
+ c.p3.x = (p4.x+p3.x)*.5;
+ c.p3.y = (p4.y+p3.y)*.5;
+ c.p4.x = p4.x;
+ c.p4.y = p4.y;
+
+ len += c.subLength(midLen, rightLegLen/2, maxErr/2);
+ return len;
+ }
+
+ public double getLength() {
+ return getLength(0.000001);
+ }
+
+ public double getLength(double maxErr) {
+ double dx, dy;
+ dx = p2.x-p1.x;
+ dy = p2.y-p1.y;
+ double leftLegLen = Math.sqrt(dx*dx+dy*dy);
+ dx = p4.x-p3.x;
+ dy = p4.y-p3.y;
+ double rightLegLen = Math.sqrt(dx*dx+dy*dy);
+ dx = p3.x-p2.x;
+ dy = p3.y-p2.y;
+ double crossLegLen = Math.sqrt(dx*dx+dy*dy);
+
+ double eps = maxErr*(leftLegLen+rightLegLen+crossLegLen);
+
+ return subLength(leftLegLen, rightLegLen, eps);
+ }
+
+ public String toString() {
+ return "M" + p1.x + ',' + p1.y +
+ 'C' + p2.x + ',' + p2.y + ' ' +
+ p3.x + ',' + p3.y + ' ' +
+ p4.x + ',' + p4.y;
+ }
+ /*
+ public static boolean epsEq(double a, double b) {
+ final double eps = 0.000001;
+ return (((a + eps) > b) && ((a-eps) < b));
+ }
+
+ public static void sub(Cubic orig, Cubic curr,
+ double t, double inc, int lev) {
+ Cubic left=new Cubic();
+ Cubic right=new Cubic();
+ curr.subdivide(left, right);
+ Point2D.Double ptl = left.eval(.5);
+ Point2D.Double ptr = right.eval(.5);
+ Point2D.Double pt1 = orig.eval(t-inc);
+ Point2D.Double pt2 = orig.eval(t+inc);
+ int steps = 100;
+ Point2D.Double l, r, o;
+ for (int i=0; i<=steps; i++) {
+ l = left.eval(i/(double)steps);
+ o = orig.eval(t-(2*inc)*(1-i/(double)steps));
+ if (!epsEq(l.x, o.x) || !epsEq(l.y, o.y))
+ System.err.println("Lf Pt: [" + l.x + "," + l.y +
+ "] Orig: [" + o.x + "," + o.y +"]");
+ r = right.eval(i/(double)steps);
+ o = orig.eval(t+(2*inc*i/(double)steps));
+ if (!epsEq(r.x, o.x) || !epsEq(r.y, o.y))
+ System.err.println("Rt Pt: [" + r.x + "," + r.y +
+ "] Orig: [" + o.x + "," + o.y +"]");
+ }
+ if (lev != 0) {
+ sub(orig, left, t-inc, inc/2, lev-1);
+ sub(orig, right, t+inc, inc/2, lev-1);
+ }
+ }
+
+ public static void evalCubic(Cubic c) {
+
+ int steps = 1000000;
+ Point2D.Double oldP = c.eval(0);
+ Point2D.Double newP;
+ double len = 0;
+ for (int i=1; i<=steps; i++) {
+ newP = c.eval(i/(double)steps);
+ double dx = newP.x-oldP.x;
+ double dy = newP.y-oldP.y;
+ len += Math.sqrt(dx*dx + dy*dy);
+ oldP = newP;
+ }
+ System.err.println("Length(.1): " + c.getLength(.001) +
+ " x " + count); count = 0;
+ System.err.println("Length : " + c.getLength() +
+ " x " + count); count = 0;
+ System.err.println("D Len : " + len);
+ }
+
+ public static void main(String args[]) {
+ Cubic c;
+
+ c = new Cubic(0,0, 10,10, 20,-10, 30,0);
+ sub(c, c, .5, .25, 3);
+ evalCubic(c);
+
+ c = new Cubic(0,0, 1,0, 2,-1, 3,0);
+ sub(c, c, .5, .25, 3);
+ evalCubic(c);
+ }
+ */
+}
Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/geom/Cubic.java
------------------------------------------------------------------------------
svn:eol-style = native