views:

386

answers:

4

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"?

A: 

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();
}
Tom Hawtin - tackline
Sorry but I'm not actually working with a graphics context.
Epaga
It's kind of what java.awt.geom is designed for.
Tom Hawtin - tackline
Otherwise, well you have the raw data to do the math by yourself.
Tom Hawtin - tackline
A: 

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.

Pesto
+1  A: 

The source code for Rectangle2D.intersectLine() [anchor link not working] 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.

Michael Myers
A: 

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.

Epaga