Skip to content

Commit

Permalink
Fixed clip rect according to affine transform (neg scale or complex tx)
Browse files Browse the repository at this point in the history
  • Loading branch information
bourgesl committed Aug 30, 2018
1 parent 4f98dbe commit 92ca53e
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 82 deletions.
10 changes: 5 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<groupId>org.marlin</groupId>
<artifactId>marlin</artifactId>
<packaging>jar</packaging>
<version>0.9.2-Unsafe</version>
<version>0.9.3-Unsafe</version>
<name>Marlin software rasterizer</name>

<url>https://github.com/bourgesl/marlin-renderer</url>
Expand Down Expand Up @@ -40,7 +40,7 @@
<encoding>UTF-8</encoding>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
Expand All @@ -52,7 +52,7 @@
<encoding>UTF-8</encoding>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
Expand Down Expand Up @@ -99,7 +99,7 @@
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
Expand Down Expand Up @@ -133,7 +133,7 @@
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
Expand Down
11 changes: 8 additions & 3 deletions src/main/java/org/marlin/pisces/DMarlinRenderingEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.security.AccessController;
import java.util.Arrays;
import org.marlin.geom.Path2D;
import static org.marlin.pisces.MarlinUtils.logInfo;
import org.marlin.ReentrantContextProvider;
Expand Down Expand Up @@ -334,7 +335,6 @@ void strokeTo(final DRendererContext rdrCtx,

int dashLen = -1;
boolean recycleDashes = false;
double scale = 1.0d;
double[] dashesD = null;

// Ensure converting dashes to double precision:
Expand Down Expand Up @@ -375,7 +375,7 @@ void strokeTo(final DRendererContext rdrCtx,
// a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
// leave a bit of room for error.
if (nearZero(a*b + c*d) && nearZero(a*a + c*c - (b*b + d*d))) {
scale = Math.sqrt(a*a + c*c);
final double scale = Math.sqrt(a*a + c*c);

if (dashesD != null) {
for (int i = 0; i < dashLen; i++) {
Expand Down Expand Up @@ -427,7 +427,7 @@ void strokeTo(final DRendererContext rdrCtx,
pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat);

// stroker will adjust the clip rectangle (width / miter limit):
pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit, scale,
pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit,
(dashesD == null));

// Curve Monotizer:
Expand Down Expand Up @@ -839,6 +839,11 @@ public AATileGenerator getAATileGenerator(Shape s,
clipRect[2] = clip.getLoX();
clipRect[3] = clip.getLoX() + clip.getWidth();

if (MarlinConst.DO_LOG_CLIP) {
MarlinUtils.logInfo("clipRect (clip): "
+ Arrays.toString(rdrCtx.clipRect));
}

// Enable clipping:
rdrCtx.doClip = true;
}
Expand Down
23 changes: 9 additions & 14 deletions src/main/java/org/marlin/pisces/DStroker.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ final class DStroker implements DPathConsumer2D, MarlinConst {
* <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
* <code>JOIN_BEVEL</code>.
* @param miterLimit the desired miter limit
* @param scale scaling factor applied to clip boundaries
* @param subdivideCurves true to indicate to subdivide curves, false if dasher does
* @return this instance
*/
Expand All @@ -148,7 +147,6 @@ DStroker init(final DPathConsumer2D pc2d,
final int capStyle,
final int joinStyle,
final double miterLimit,
final double scale,
final boolean subdivideCurves)
{
this.out = pc2d;
Expand All @@ -169,7 +167,6 @@ DStroker init(final DPathConsumer2D pc2d,

if (rdrCtx.doClip) {
// Adjust the clipping rectangle with the stroker margin (miter limit, width)
double rdrOffX = 0.0d, rdrOffY = 0.0d;
double margin = lineWidth2;

if (capStyle == CAP_SQUARE) {
Expand All @@ -178,23 +175,21 @@ DStroker init(final DPathConsumer2D pc2d,
if ((joinStyle == JOIN_MITER) && (margin < limit)) {
margin = limit;
}
if (scale != 1.0d) {
margin *= scale;
rdrOffX = scale * DRenderer.RDR_OFFSET_X;
rdrOffY = scale * DRenderer.RDR_OFFSET_Y;
}
// add a small rounding error:
margin += 1e-3d;

// bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
// adjust clip rectangle (ymin, ymax, xmin, xmax):
final double[] _clipRect = rdrCtx.clipRect;
_clipRect[0] -= margin - rdrOffY;
_clipRect[1] += margin + rdrOffY;
_clipRect[2] -= margin - rdrOffX;
_clipRect[3] += margin + rdrOffX;
_clipRect[0] -= margin;
_clipRect[1] += margin;
_clipRect[2] -= margin;
_clipRect[3] += margin;
this.clipRect = _clipRect;

if (MarlinConst.DO_LOG_CLIP) {
MarlinUtils.logInfo("clipRect (stroker): "
+ Arrays.toString(rdrCtx.clipRect));
}

// initialize curve splitter here for stroker & dasher:
if (DO_CLIP_SUBDIVIDER) {
subdivide = subdivideCurves;
Expand Down
68 changes: 47 additions & 21 deletions src/main/java/org/marlin/pisces/DTransformingPathConsumer2D.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ DPathConsumer2D pathClipper(DPathConsumer2D out) {
DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
AffineTransform at)
{
if (rdrCtx.doClip) {
adjustClipOffset(rdrCtx.clipRect);
}

if (at == null) {
return out;
}
Expand Down Expand Up @@ -133,30 +137,51 @@ DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
}

private static void adjustClipOffset(final double[] clipRect) {
clipRect[0] += Renderer.RDR_OFFSET_Y;
clipRect[1] += Renderer.RDR_OFFSET_Y;
clipRect[2] += Renderer.RDR_OFFSET_X;
clipRect[3] += Renderer.RDR_OFFSET_X;
// Adjust the clipping rectangle with the renderer offsets
final double rdrOffX = DRenderer.RDR_OFFSET_X;
final double rdrOffY = DRenderer.RDR_OFFSET_Y;

// add a small rounding error:
final double margin = 1e-3d;

clipRect[0] -= margin - rdrOffY;
clipRect[1] += margin + rdrOffY;
clipRect[2] -= margin - rdrOffX;
clipRect[3] += margin + rdrOffX;
}

private static void adjustClipScale(final double[] clipRect,
final double mxx, final double myy)
{
adjustClipOffset(clipRect);

// Adjust the clipping rectangle (iv_DeltaScaleFilter):
clipRect[0] /= myy;
clipRect[1] /= myy;

if (clipRect[1] < clipRect[0]) {
double tmp = clipRect[0];
clipRect[0] = clipRect[1];
clipRect[1] = tmp;
}

clipRect[2] /= mxx;
clipRect[3] /= mxx;

if (clipRect[3] < clipRect[2]) {
double tmp = clipRect[2];
clipRect[2] = clipRect[3];
clipRect[3] = tmp;
}

if (MarlinConst.DO_LOG_CLIP) {
MarlinUtils.logInfo("clipRect (ClipScale): "
+ Arrays.toString(clipRect));
}
}

private static void adjustClipInverseDelta(final double[] clipRect,
final double mxx, final double mxy,
final double myx, final double myy)
{
adjustClipOffset(clipRect);

// Adjust the clipping rectangle (iv_DeltaTransformFilter):
final double det = mxx * myy - mxy * myx;
final double imxx = myy / det;
Expand Down Expand Up @@ -198,6 +223,11 @@ private static void adjustClipInverseDelta(final double[] clipRect,
clipRect[1] = ymax;
clipRect[2] = xmin;
clipRect[3] = xmax;

if (MarlinConst.DO_LOG_CLIP) {
MarlinUtils.logInfo("clipRect (ClipInverseDelta): "
+ Arrays.toString(clipRect));
}
}

DPathConsumer2D inverseDeltaTransformConsumer(DPathConsumer2D out,
Expand Down Expand Up @@ -532,18 +562,12 @@ static final class PathClipFilter implements DPathConsumer2D {
PathClipFilter init(final DPathConsumer2D out) {
this.out = out;

// Adjust the clipping rectangle with the renderer offsets
final double rdrOffX = DRenderer.RDR_OFFSET_X;
final double rdrOffY = DRenderer.RDR_OFFSET_Y;

// add a small rounding error:
final double margin = 1e-3d;
adjustClipOffset(this.clipRect);

final double[] _clipRect = this.clipRect;
_clipRect[0] -= margin - rdrOffY;
_clipRect[1] += margin + rdrOffY;
_clipRect[2] -= margin - rdrOffX;
_clipRect[3] += margin + rdrOffX;
if (MarlinConst.DO_LOG_CLIP) {
MarlinUtils.logInfo("clipRect (PathClipFilter): "
+ Arrays.toString(clipRect));
}

if (MarlinConst.DO_CLIP_SUBDIVIDER) {
// adjust padded clip rectangle:
Expand Down Expand Up @@ -890,6 +914,8 @@ static final class CurveClipSplitter {

void init() {
this.init_clipRectPad = true;

// TODO: adjust LEN_TH by rough scale ?
}

private void initPaddedClip() {
Expand All @@ -906,7 +932,7 @@ private void initPaddedClip() {

if (TRACE) {
MarlinUtils.logInfo("clip: X [" + _clipRectPad[2] + " .. " + _clipRectPad[3] +"] "
+ "Y ["+ _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
+ "Y [" + _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
}
}

Expand Down Expand Up @@ -991,7 +1017,7 @@ private boolean subdivideAtIntersections(final int type, final int outCodeOR,
outCodeOR, clipRectPad);

if (TRACE) {
MarlinUtils.logInfo("nSplits: "+ nSplits);
MarlinUtils.logInfo("nSplits: " + nSplits);
MarlinUtils.logInfo("subTs: " + Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
}
if (nSplits == 0) {
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/marlin/pisces/MarlinConst.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ interface MarlinConst {

static final boolean DO_CLIP_SUBDIVIDER = MarlinProperties.isDoClipSubdivider();

// flag to enable logs related bounds checks
// flag to enable logs related to bounds checks
static final boolean DO_LOG_BOUNDS = ENABLE_LOGS && false;

// flag to enable logs related to clip rect
static final boolean DO_LOG_CLIP = ENABLE_LOGS && false;

// Initial Array sizing (initial context capacity) ~ 450K

// 4096 pixels (width) for initial capacity
Expand Down
11 changes: 8 additions & 3 deletions src/main/java/org/marlin/pisces/MarlinRenderingEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.security.AccessController;
import java.util.Arrays;
import org.marlin.geom.Path2D;
import static org.marlin.pisces.MarlinUtils.logInfo;
import sun.awt.geom.PathConsumer2D;
Expand Down Expand Up @@ -333,7 +334,6 @@ void strokeTo(final RendererContext rdrCtx,

int dashLen = -1;
boolean recycleDashes = false;
float scale = 1.0f;

if (at != null && !at.isIdentity()) {
final double a = at.getScaleX();
Expand Down Expand Up @@ -366,7 +366,7 @@ void strokeTo(final RendererContext rdrCtx,
// a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
// leave a bit of room for error.
if (nearZero(a*b + c*d) && nearZero(a*a + c*c - (b*b + d*d))) {
scale = (float) Math.sqrt(a*a + c*c);
final float scale = (float) Math.sqrt(a*a + c*c);

if (dashes != null) {
recycleDashes = true;
Expand Down Expand Up @@ -421,7 +421,7 @@ void strokeTo(final RendererContext rdrCtx,
pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat);

// stroker will adjust the clip rectangle (width / miter limit):
pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit, scale,
pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit,
(dashes == null));

// Curve Monotizer:
Expand Down Expand Up @@ -836,6 +836,11 @@ public AATileGenerator getAATileGenerator(Shape s,
clipRect[2] = clip.getLoX();
clipRect[3] = clip.getLoX() + clip.getWidth();

if (MarlinConst.DO_LOG_CLIP) {
MarlinUtils.logInfo("clipRect (clip): "
+ Arrays.toString(rdrCtx.clipRect));
}

// Enable clipping:
rdrCtx.doClip = true;
}
Expand Down
23 changes: 9 additions & 14 deletions src/main/java/org/marlin/pisces/Stroker.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ final class Stroker implements PathConsumer2D, MarlinConst {
* <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
* <code>JOIN_BEVEL</code>.
* @param miterLimit the desired miter limit
* @param scale scaling factor applied to clip boundaries
* @param subdivideCurves true to indicate to subdivide curves, false if dasher does
* @return this instance
*/
Expand All @@ -150,7 +149,6 @@ Stroker init(final PathConsumer2D pc2d,
final int capStyle,
final int joinStyle,
final float miterLimit,
final float scale,
final boolean subdivideCurves)
{
this.out = pc2d;
Expand All @@ -171,7 +169,6 @@ Stroker init(final PathConsumer2D pc2d,

if (rdrCtx.doClip) {
// Adjust the clipping rectangle with the stroker margin (miter limit, width)
float rdrOffX = 0.0f, rdrOffY = 0.0f;
float margin = lineWidth2;

if (capStyle == CAP_SQUARE) {
Expand All @@ -180,23 +177,21 @@ Stroker init(final PathConsumer2D pc2d,
if ((joinStyle == JOIN_MITER) && (margin < limit)) {
margin = limit;
}
if (scale != 1.0f) {
margin *= scale;
rdrOffX = scale * Renderer.RDR_OFFSET_X;
rdrOffY = scale * Renderer.RDR_OFFSET_Y;
}
// add a small rounding error:
margin += 1e-3f;

// bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
// adjust clip rectangle (ymin, ymax, xmin, xmax):
final float[] _clipRect = rdrCtx.clipRect;
_clipRect[0] -= margin - rdrOffY;
_clipRect[1] += margin + rdrOffY;
_clipRect[2] -= margin - rdrOffX;
_clipRect[3] += margin + rdrOffX;
_clipRect[0] -= margin;
_clipRect[1] += margin;
_clipRect[2] -= margin;
_clipRect[3] += margin;
this.clipRect = _clipRect;

if (MarlinConst.DO_LOG_CLIP) {
MarlinUtils.logInfo("clipRect (stroker): "
+ Arrays.toString(rdrCtx.clipRect));
}

// initialize curve splitter here for stroker & dasher:
if (DO_CLIP_SUBDIVIDER) {
subdivide = subdivideCurves;
Expand Down
Loading

0 comments on commit 92ca53e

Please sign in to comment.