1

I have a chart and a regression line (the blue one). Now the ends of the line can exit from the black rectangle that has dimensions (x0, x1, y0, y1).

I would like the blue line to be shown only inside the black rectangle. How can I do?

I know the coordinates of: x0, x1, y0, y1, A and B. I want to know the coordinates of C and D. I need help..

A figure of a rectangle with a line crossing it diagonally

Markus Dresch
  • 5,290
  • 3
  • 20
  • 40
  • What have you tried so far, if there is no code, maybe you should go to https://math.stackexchange.com/ – Sebastian Speitel Jun 27 '19 at 13:52
  • @SebastianSpeitel Thanks Sebastian, I have no code because I don't know how to start.. –  Jun 27 '19 at 13:53
  • This should help: [calculating the point of intersection of two lines](https://stackoverflow.com/questions/13937782/calculating-the-point-of-intersection-of-two-lines) – Mark Jun 27 '19 at 13:53
  • 2
    The [**Cohen-Sutherland algorithm**](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm) is exactly what you need. It performs efficient line clipping in the special case where the stencil is an axis-aligned rectangle. – meowgoesthedog Jun 27 '19 at 14:15
  • 2
    One more effecitve method - [Liang-Barski](https://en.wikipedia.org/wiki/Liang–Barsky_algorithm) – MBo Jun 27 '19 at 15:29

1 Answers1

0

Here is a javascript implementation of Liang–Barsky. It also runs an example calculation with your variable names:

var x0 = 0;
var y0 = 0;
var x1 = 640;
var y1 = 480;
var xa = 20;
var ya = -40;
var xb = 680;
var yb = 460;

// JS port of https://github.com/w8r/liang-barsky/blob/master/src/liang-barsky.ts

const EPSILON = 1e-6;
const INSIDE = 1;
const OUTSIDE = 0;

/**
 * @param {Number} num
 * @param {Number} denom
 * @param {Number[]} c result [x,y]-array
 */
function clipT(num, denom, c) {
    const [tE, tL] = c;
    if (Math.abs(denom) < EPSILON) return num < 0;
    const t = num / denom;

    if (denom > 0) {
        if (t > tL) return 0;
        if (t > tE) c[0] = t;
    } else {
        if (t < tE) return 0;
        if (t < tL) c[1] = t;
    }
    return 1;
}

/**
 * @param {Number[]} a [x,y]-array
 * @param {Number[]} b [x,y]-array
 * @param {Number[]} box [xmin, ymin, xmax, ymax]-array
 * @param {Number[]} da result [x,y]-array
 * @param {Number[]} db result [x,y]-array
 * @return {Number} Returns OUTSIDE or INSIDE
 */
function clip(a, b, box, da = null, db = null) {
    const [x1, y1] = a;
    const [x2, y2] = b;
    const dx = x2 - x1;
    const dy = y2 - y1;

    if (da === undefined || db === undefined) {
        da = a;
        db = b;
    } else {
        da[0] = a[0];
        da[1] = a[1];
        db[0] = b[0];
        db[1] = b[1];
    }

    if (Math.abs(dx) < EPSILON && Math.abs(dy) < EPSILON && x1 >= box[0] && x1 <= box[2] && y1 >= box[1] && y1 <= box[3]) {
        return INSIDE;
    }

    const c = [0, 1]; // Point
    if (clipT(box[0] - x1, dx, c) && clipT(x1 - box[2], -dx, c) && clipT(box[1] - y1, dy, c) && clipT(y1 - box[3], -dy, c)) {
        const [tE, tL] = c;
        if (tL < 1) {
            db[0] = x1 + tL * dx;
            db[1] = y1 + tL * dy;
        }
        if (tE > 0) {
            da[0] += tE * dx;
            da[1] += tE * dy;
        }
        return INSIDE;
    }
    return OUTSIDE;
}

var da = [null, null];
var db = [null, null];
var res = clip([xa, ya], [xb, yb], [x0, y0, x1, y1], da, db);

var [xc, yc] = da;
var [xd, yd] = db;
console.log(res, xc, yc, xd, yd);
tornord
  • 336
  • 4
  • 8