Something is wrong with your logic that computes the angles. The reason you are not seeing it with rectangles and circles is because they have 180 degree rotational symmetry.
Apply the attached patch to your code to see what the real angle is you are rotating by, which bounces around during part of the rotation. Don't know what the exact problem is but you can probably figure it out from here... -Archie On Jan 23, 2008 3:29 PM, Bishop, Michael W. CONTR J9C880 < [EMAIL PROTECTED]> wrote: > I got snapshots from the original, rotated (flipped) and rotated > (correct) DOMs. Since the transform is in matrix form, it's hard to > discern anything save the fact that all three are different. I loaded > each snapshot in Squiggle; they looked the same as they do in my > application. > > I was able to create a test class that can showcase this behavior. It's > not a specific SVG; it's an application that rotates a rect element, > degree-by-degree a full 360 degrees on a JSVGCanvas successfully. Then > it does the same with a text element and the errors occur between 90 and > 270. > > I'll attach the class for those curious; it's a single file that just > needs Batik on the classpath: > mil.jfcom.cie.whiteboard.TestElementTransform > > I guess I should also file a bug unless someone finds something wrong > with the attached code. > > Michael Bishop > > > -----Original Message----- > > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] > > On Behalf Of Archie Cobbs > > Sent: Wednesday, January 23, 2008 2:52 PM > > To: batik-users@xmlgraphics.apache.org > > Subject: Re: Rendering bug with transforms? > > > > I would be interesting to "snapshot" your DOM after the > > unexpected flip occurs then: > > > > - Save it to a file. > > - Verify relaunching squiggle on the file still shows item flipped. > > - Do analysis to determine whether matrix is incorrect (your > > bug) or batik is mis-reading it (batik bug). > > - If Batik is mis-reading matrix, create Bugzilla issue > > containing simplified counterexample SVG file. > > > > One possibility is your computation is broken around the > > "corner cases" of 90 and 270 degress. Continuous reading and > > updating of the matrix makes these corner cases more likely > > to be hit. > > > > > > On Jan 23, 2008 1:36 PM, Bishop, Michael W. CONTR J9C880 > > <[EMAIL PROTECTED]> wrote: > > > > > > OK, the slider basically reports a degree from 0 to > > 359. I have a > > ChangeListener attached that updates the "transform" > > attribute of the > > selected element. > > > > So what essentially happens: > > > > - Retrieve the "transform" (I use the matrix only) > > attribute as an > > AffineTransform. > > - Revert the current rotation angle on the AffineTransform. > > - Apply the new rotation angle to the AffineTransform. > > - Convert the AffineTransform to a "transform" attribute. > > - Apply the new "transform" attribute to the element on the > > UpdateManager. > > > > I don't think static rotation covers it. My old > > rotation technique was > > a plain JSlider that would only update the element > > after the change > > occurs. This never fails. It only seems to happen > > when the document is > > continuously updated as the slider is moving. Another > > interesting fact > > is that sometimes an element STAYS flipped; when I get back to 0 > > degrees, I see that a text element might be upside-down. > > > > If this behavior was consistant across all elements, > > I'd be more apt to > > dig through my code. It only seems to happen with > > certain elements. > > Maybe I can write a test case that will draw an element > > to a canvas, > > then rotate it through 360 degrees with a for loop. > > > > Michael Bishop > > > > > > > -----Original Message----- > > > From: [EMAIL PROTECTED] [mailto: > > [EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]> ] > > > On Behalf Of Archie Cobbs > > > Sent: Wednesday, January 23, 2008 1:41 PM > > > To: batik-users@xmlgraphics.apache.org > > > Subject: Re: Rendering bug with transforms? > > > > > > What is your slider actually doing? > > > > > > If it's just updating the "transform" attribute of a DOM > > > element, in theory you should be able to produce a static > > > document containing a polygon rotated e.g. 120 degrees that > > > squiggle renders upside down. > > > > > > I.e., what's the simplest document or program that reproduces > > > incorrect rendering? I'm sure something obvious like an > > > upside down rotation would be fixed pretty quickly. > > > > > > On the other hand, it could be your logic. How exactly does a > > > circular slider position turn into SVG attributes? > > > > > > > > > On Jan 23, 2008 12:31 PM, Bishop, Michael W. CONTR J9C880 > > > <[EMAIL PROTECTED]> wrote: > > > > > > > > > Hello, > > > I've come across a pretty odd problem with Batik. > > > I'm using the > > > 1.7 release version. For my application, I've > > > developed a "circle > > > slider" which is pretty much a Jslider that goes in a > > > circle. I use it > > > to rotate elements from 0 degrees to 360 degrees. As I > > > move the slider, > > > the shape on the JSVGCanvas changes. This works > > > perfectly for circle, > > > ellipse, line, and rect elements. On other elements > > > (polygon, polyline, > > > path, text), the element is rapidly flipped 180 degrees > > > ONLY when the > > > circle slider is between 90 and 270 degrees. > > > So I get a smooth rotation from 0 to 90. > > From 90 to 270 the > > > element gets flipped upside-down over and over again, > > > oscillating back > > > and forth. From 270 to 360 (0), I get smooth rotation > > > again. The > > > reason I think it's Batik is because it doesn't occur > > > with every element > > > and my application is reporting the correct number of > > > degrees. I think > > > it's odd that it only happens witin that certain range. > > > Has anyone > > > experienced this? > > > > > > Michael Bishop > > > > > > > > > > > --------------------------------------------------------------------- > > > To unsubscribe, e-mail: > > > [EMAIL PROTECTED] > > <mailto:[EMAIL PROTECTED]> > > > For additional commands, e-mail: > > > [EMAIL PROTECTED] > > > > > > > > > > > > > > > > > > > > > -- > > > Archie L. Cobbs > > > > > > > > > > > > --------------------------------------------------------------------- > > To unsubscribe, e-mail: > > [EMAIL PROTECTED] > > <mailto:[EMAIL PROTECTED]> > > For additional commands, e-mail: > > [EMAIL PROTECTED] > > > > > > > > > > > > > > -- > > Archie L. Cobbs > > > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > -- Archie L. Cobbs
--- TestElementTransform.java.ORIG 2008-01-23 15:58:00.134486774 -0600 +++ TestElementTransform.java 2008-01-23 16:10:48.789471476 -0600 @@ -5,9 +5,11 @@ import java.awt.BorderLayout; import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; import java.text.MessageFormat; import javax.swing.JFrame; import javax.swing.JLabel; +import javax.swing.SwingUtilities; import org.apache.batik.dom.svg.SVGDOMImplementation; import org.apache.batik.parser.AWTTransformProducer; import org.apache.batik.swing.JSVGCanvas; @@ -93,17 +95,19 @@ final double centerX = boundingBox.getX() + boundingBox.getWidth() * 0.5d; final double centerY = boundingBox.getY() + boundingBox.getHeight() * 0.5d; for (int count = 0; count < 360; count++) { - final AffineTransform transform = - AWTTransformProducer.createAffineTransform( - rotateElement.getAttribute( - SVGConstants.SVG_TRANSFORM_ATTRIBUTE)); - final AffineTransform rotated = TestElementTransform.rotate( - transform, Math.toRadians(count), centerX, centerY); + final int count2 = count; jsvgCanvas.getUpdateManager().getUpdateRunnableQueue().invokeLater( new Runnable() { public void run () { + final AffineTransform transform = + AWTTransformProducer.createAffineTransform( + rotateElement.getAttribute(SVGConstants.SVG_TRANSFORM_ATTRIBUTE)); + final AffineTransform rotated = TestElementTransform.rotate( + transform, Math.toRadians(count2), centerX, centerY); final double[] matrixValues = new double[6]; rotated.getMatrix(matrixValues); + int matrixAngle0 = (int)(getRotationAngle2(rotated) * 180.0 / Math.PI); + final int matrixAngle = matrixAngle0 < 0 ? 360 + matrixAngle0 : matrixAngle0; final Object[] args = { @@ -116,9 +120,13 @@ rotateElement.setAttribute( SVGConstants.SVG_TRANSFORM_ATTRIBUTE, MessageFormat.format(MATRIX_STRING, args)); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + degreeLabel.setText(count2 + " ... " + matrixAngle); + } + }); } }); - degreeLabel.setText(String.valueOf(count)); Thread.sleep(20); } } @@ -227,4 +235,38 @@ // Return the value in radians. return radians; } + + + /** + * Compute the rotation angle of an affine transformation. + * Counter-clockwise rotation is considered positive. + * + * @return rotation angle in radians (beween -pi and pi), + * or NaN if the transformation is bogus. + */ + public static double getRotationAngle2(AffineTransform transform) { + + // Eliminate any post-translation + transform = (AffineTransform)transform.clone(); + transform.preConcatenate(AffineTransform.getTranslateInstance( + -transform.getTranslateX(), -transform.getTranslateY())); + + // Apply transformation to a vector + Point2D v1 = new Point2D.Double(1, 0); + Point2D v2 = transform.transform(v1, null); + + // Compute dot product + double dotProduct = v1.getX() * v2.getX() + v1.getY() * v2.getY(); + + // Compute positive angle + double angle = Math.acos(dotProduct + / (v1.distance(0, 0) * v2.distance(0, 0))); + + // Negate angle if rotation direction is clockwise + if (v2.getY() < 0) + angle = -angle; + + // Done + return angle; + } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]