/
LineClipping.c
110 lines (93 loc) · 2.63 KB
/
LineClipping.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "LineClipping.h"
/*Outcode set elements*/
#define LEFT 0
#define RIGHT 1
#define BOTTOM 2
#define TOP 3
static int In(int x, int A) /*returns non-zero iff x is a member of set A (bit x in A is set)*/
{
return ((1 << x) & A) != 0;
}
static void Include(int x, int *A) /*includes element x in set *A*/
{
*A |= (1 << x);
}
static int Outcode(double x, double y, const struct LineClipping_Rectangle *r) /*returns the outcode for point (x, y) in relation to rectangle r*/
{
int result;
result = 0; /*empty set*/
if (x < r->xMin) {
Include(LEFT, &result);
} else if (x > r->xMax) {
Include(RIGHT, &result);
}
if (y < r->yMin) {
Include(BOTTOM, &result);
} else if (y > r->yMax) {
Include(TOP, &result);
}
return result;
}
static int SameSide(int outcode0, int outcode1) /*returns non-zero iff both outcodes lie on the same side outside of the clip rectangle*/
{
return (outcode0 & outcode1) != 0;
}
static int Inside(int outcode0, int outcode1) /*returns non-zero iff both outcodes lie inside of the clip rectangle*/
{
return (outcode0 == 0) && (outcode1 == 0);
}
static void GetIntersection(const struct LineClipping_Rectangle *r,
const struct LineClipping_Segment *s,
int outcode,
double *x,
double *y) /*sets (x, y) to the intersection point of s and an edge of r contained in `outcode'*/
{
if (In(TOP, outcode)) {
assert(s->y0 != s->y1);
*x = s->x0 + (s->x1 - s->x0) * (r->yMax - s->y0) / (s->y1 - s->y0);
*y = r->yMax;
} else if (In(BOTTOM, outcode)) {
assert(s->y0 != s->y1);
*x = s->x0 + (s->x1 - s->x0) * (r->yMin - s->y0) / (s->y1 - s->y0);
*y = r->yMin;
} else if (In(RIGHT, outcode)) {
assert(s->x0 != s->x1);
*y = s->y0 + (s->y1 - s->y0) * (r->xMax - s->x0) / (s->x1 - s->x0);
*x = r->xMax;
} else if (In(LEFT, outcode)) {
assert(s->x0 != s->x1);
*y = s->y0 + (s->y1 - s->y0) * (r->xMin - s->x0) / (s->x1 - s->x0);
*x = r->xMin;
}
}
void LineClipping_Clip(const struct LineClipping_Rectangle *r,
struct LineClipping_Segment *s,
int *done)
{
const int maxIter = 4;
int outcode0, outcode1, i;
double x, y;
/*Cohen-Sutherland line clipping algorithm*/
outcode0 = Outcode(s->x0, s->y0, r);
outcode1 = Outcode(s->x1, s->y1, r);
i = 0;
while (! Inside(outcode0, outcode1) && ! SameSide(outcode0, outcode1) && (i < maxIter)) {
if (outcode0 != 0) {
GetIntersection(r, s, outcode0, &x, &y);
s->x0 = x;
s->y0 = y;
outcode0 = Outcode(x, y, r);
} else {
GetIntersection(r, s, outcode1, &x, &y);
s->x1 = x;
s->y1 = y;
outcode1 = Outcode(x, y, r);
}
i++;
}
assert(i < maxIter);
*done = Inside(outcode0, outcode1);
}