John Goering
John Goering

Reputation: 39030

Most elegant way to clip a line?

I have a Rectangle2D and a Line2D. I want to "clip" the line so that only the part of the line which is within the rectangle remains. If none of the line is within the rectangle I want the line to be set to (0,0,0,0). Basically something along the lines of a

Rectangle2D.intersect(Line2D src, Line2D dest)

or something similar.

Is there a way to do this with the java.awt.geom API? Or an elegant way to code it "by hand"?

Upvotes: 3

Views: 2726

Answers (4)

Michael Myers
Michael Myers

Reputation: 191875

The source code for Rectangle2D.intersectLine() might be helpful:

public boolean intersectsLine(double x1, double y1, double x2, double y2) {
    int out1, out2;
    if ((out2 = outcode(x2, y2)) == 0) {
        return true;
    }
    while ((out1 = outcode(x1, y1)) != 0) {
        if ((out1 & out2) != 0) {
            return false;
        }
        if ((out1 & (OUT_LEFT | OUT_RIGHT)) != 0) {
            double x = getX();
            if ((out1 & OUT_RIGHT) != 0) {
                x += getWidth();
            }
            y1 = y1 + (x - x1) * (y2 - y1) / (x2 - x1);
            x1 = x;
        } else {
            double y = getY();
            if ((out1 & OUT_BOTTOM) != 0) {
                y += getHeight();
            }
            x1 = x1 + (y - y1) * (x2 - x1) / (y2 - y1);
            y1 = y;
        }
    }
    return true;
}

where outcode() is defined as:

public int outcode(double x, double y) {
    int out = 0;
    if (this.width <= 0) {
        out |= OUT_LEFT | OUT_RIGHT;
    } else if (x < this.x) {
        out |= OUT_LEFT;
    } else if (x > this.x + this.width) {
        out |= OUT_RIGHT;
    }
    if (this.height <= 0) {
        out |= OUT_TOP | OUT_BOTTOM;
    } else if (y < this.y) {
        out |= OUT_TOP;
    } else if (y > this.y + this.height) {
        out |= OUT_BOTTOM;
    }
    return out;
}

(from OpenJDK)

It shouldn't be extremely difficult to change this to clip instead of returning true or false.

Upvotes: 4

John Goering
John Goering

Reputation: 39030

Well, I ended up doing it myself.

For those intereseted, I ended up solving it by turning the line into a rectangle (with getBounds), then using Rectangle.intersect(clipRect,lineRect,intersectLineRect) to create the intersection, then turning the intersection back into a line.

Upvotes: 0

Pesto
Pesto

Reputation: 23880

There's no pretty way to do it with AWT. Your best bet is something like the Cohen-Sutherland algorithm. Here's a link with example Java code (lern2indent, amirite?) to show you how it's done.

Upvotes: 1

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147154

The usual thing to do is restrict the clipping region in the graphics context with Graphics2D.clip. You might want to call Graphics.create so that you do not interfere with the original context.

Graphics2D g = (Graphics2D)gOrig.create();
try {
    g.clip(clip);
    ...
} finally {
    g.dispose();
}

Upvotes: 0

Related Questions