6829673: ThinLineTest: A line < 1 pixel disappears
Reviewed-by: igor, prr
This commit is contained in:
parent
430c84f1ea
commit
63e666407c
@ -171,9 +171,9 @@ public class PiscesRenderingEngine extends RenderingEngine {
|
||||
float lw;
|
||||
if (thin) {
|
||||
if (antialias) {
|
||||
lw = 0.5f;
|
||||
lw = userSpaceLineWidth(at, 0.5f);
|
||||
} else {
|
||||
lw = 1.0f;
|
||||
lw = userSpaceLineWidth(at, 1.0f);
|
||||
}
|
||||
} else {
|
||||
lw = bs.getLineWidth();
|
||||
@ -189,6 +189,72 @@ public class PiscesRenderingEngine extends RenderingEngine {
|
||||
lsink);
|
||||
}
|
||||
|
||||
private float userSpaceLineWidth(AffineTransform at, float lw) {
|
||||
|
||||
double widthScale;
|
||||
|
||||
if ((at.getType() & (AffineTransform.TYPE_GENERAL_TRANSFORM |
|
||||
AffineTransform.TYPE_GENERAL_SCALE)) != 0) {
|
||||
widthScale = Math.sqrt(at.getDeterminant());
|
||||
} else {
|
||||
/* First calculate the "maximum scale" of this transform. */
|
||||
double A = at.getScaleX(); // m00
|
||||
double C = at.getShearX(); // m01
|
||||
double B = at.getShearY(); // m10
|
||||
double D = at.getScaleY(); // m11
|
||||
|
||||
/*
|
||||
* Given a 2 x 2 affine matrix [ A B ] such that
|
||||
* [ C D ]
|
||||
* v' = [x' y'] = [Ax + Cy, Bx + Dy], we want to
|
||||
* find the maximum magnitude (norm) of the vector v'
|
||||
* with the constraint (x^2 + y^2 = 1).
|
||||
* The equation to maximize is
|
||||
* |v'| = sqrt((Ax+Cy)^2+(Bx+Dy)^2)
|
||||
* or |v'| = sqrt((AA+BB)x^2 + 2(AC+BD)xy + (CC+DD)y^2).
|
||||
* Since sqrt is monotonic we can maximize |v'|^2
|
||||
* instead and plug in the substitution y = sqrt(1 - x^2).
|
||||
* Trigonometric equalities can then be used to get
|
||||
* rid of most of the sqrt terms.
|
||||
*/
|
||||
|
||||
double EA = A*A + B*B; // x^2 coefficient
|
||||
double EB = 2*(A*C + B*D); // xy coefficient
|
||||
double EC = C*C + D*D; // y^2 coefficient
|
||||
|
||||
/*
|
||||
* There is a lot of calculus omitted here.
|
||||
*
|
||||
* Conceptually, in the interests of understanding the
|
||||
* terms that the calculus produced we can consider
|
||||
* that EA and EC end up providing the lengths along
|
||||
* the major axes and the hypot term ends up being an
|
||||
* adjustment for the additional length along the off-axis
|
||||
* angle of rotated or sheared ellipses as well as an
|
||||
* adjustment for the fact that the equation below
|
||||
* averages the two major axis lengths. (Notice that
|
||||
* the hypot term contains a part which resolves to the
|
||||
* difference of these two axis lengths in the absence
|
||||
* of rotation.)
|
||||
*
|
||||
* In the calculus, the ratio of the EB and (EA-EC) terms
|
||||
* ends up being the tangent of 2*theta where theta is
|
||||
* the angle that the long axis of the ellipse makes
|
||||
* with the horizontal axis. Thus, this equation is
|
||||
* calculating the length of the hypotenuse of a triangle
|
||||
* along that axis.
|
||||
*/
|
||||
|
||||
double hypot = Math.sqrt(EB*EB + (EA-EC)*(EA-EC));
|
||||
/* sqrt omitted, compare to squared limits below. */
|
||||
double widthsquared = ((EA + EC + hypot)/2.0);
|
||||
|
||||
widthScale = Math.sqrt(widthsquared);
|
||||
}
|
||||
|
||||
return (float) (lw / widthScale);
|
||||
}
|
||||
|
||||
void strokeTo(Shape src,
|
||||
AffineTransform at,
|
||||
float width,
|
||||
|
63
jdk/test/sun/pisces/ThinLineTest.java
Normal file
63
jdk/test/sun/pisces/ThinLineTest.java
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
/**
|
||||
* @author chrisn@google.com (Chris Nokleberg)
|
||||
* @author yamauchi@google.com (Hiroshi Yamauchi)
|
||||
*/
|
||||
public class ThinLineTest {
|
||||
private static final int PIXEL = 381;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setPaint(Color.WHITE);
|
||||
g.fill(new Rectangle(image.getWidth(), image.getHeight()));
|
||||
|
||||
g.scale(0.5 / PIXEL, 0.5 / PIXEL);
|
||||
g.setPaint(Color.BLACK);
|
||||
g.setStroke(new BasicStroke(PIXEL));
|
||||
g.draw(new Ellipse2D.Double(PIXEL * 50, PIXEL * 50, PIXEL * 300, PIXEL * 300));
|
||||
|
||||
// To visually check it
|
||||
//ImageIO.write(image, "PNG", new File(args[0]));
|
||||
|
||||
boolean nonWhitePixelFound = false;
|
||||
for (int x = 0; x < 200; ++x) {
|
||||
if (image.getRGB(x, 100) != Color.WHITE.getRGB()) {
|
||||
nonWhitePixelFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!nonWhitePixelFound) {
|
||||
throw new RuntimeException("The thin line disappeared.");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user