geo 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+
2
+ #ifndef INTERSECTION_H
3
+ #define INTERSECTION_H
4
+
5
+ #include "common.h"
6
+
7
+
8
+ #define INTERSECTION_CLOSEST_POINT(intersection_pointer,point_pointer) ((intersection_pointer)->type == itPOINT ? \
9
+ (intersection_pointer)->point : \
10
+ (DISTANCE((intersection_pointer)->line->p1, \
11
+ (point_pointer)) < DISTANCE((intersection_pointer)->line->p2, \
12
+ (point_pointer)) ? \
13
+ (intersection_pointer)->line->p1 : \
14
+ (intersection_pointer)->line->p2))
15
+ #define INTERSECTION_DISTANCE(intersection_pointer,point_pointer) ((intersection_pointer)->type == itPOINT ? \
16
+ DISTANCE((intersection_pointer)->point, (point_pointer)) : \
17
+ MIN(DISTANCE((intersection_pointer)->line->p1, (point_pointer)), \
18
+ DISTANCE((intersection_pointer)->line->p2, (point_pointer))))
19
+
20
+
21
+ void
22
+ free_intersection(Intersection *intersection);
23
+
24
+ Intersection*
25
+ new_intersection_with_line(Line *l, Line *with);
26
+
27
+ Intersection *
28
+ new_intersection_with_point(Point *p, Line *with);
29
+
30
+ VALUE
31
+ rb_intersection(Intersection *intersection, Point *from);
32
+
33
+
34
+
35
+
36
+
37
+
38
+ #endif
data/ext/line.c ADDED
@@ -0,0 +1,436 @@
1
+
2
+ #include "common.h"
3
+
4
+ VALUE rb_line;
5
+
6
+ /*
7
+ * Dont use this on lines that have been rubified (RB_LINE),
8
+ * since they will be freed by ruby. Make sure that they have
9
+ * rubified points (RB_POINT) as well though!
10
+ */
11
+ static void
12
+ line_free(Line *l) {
13
+ free(l->p1);
14
+ free(l->p2);
15
+ free(l);
16
+ }
17
+
18
+ void
19
+ line_mark(Line *line) {
20
+ if (line->p1 != NULL)
21
+ rb_gc_mark(line->p1->rbPoint);
22
+ if (line->p2 != NULL)
23
+ rb_gc_mark(line->p2->rbPoint);
24
+ }
25
+
26
+ Line*
27
+ new_line_with_points(Point *p1, Point *p2) {
28
+ Line *rval = ALLOC(Line);
29
+ rval->p1 = p1;
30
+ rval->p2 = p2;
31
+ rval->rbLine = 0;
32
+ return rval;
33
+ }
34
+
35
+ Line*
36
+ new_line_with_coordinates(gdouble x1, gdouble y1, gdouble x2, gdouble y2) {
37
+ Line *rval = ALLOC(Line);
38
+ rval->p1 = new_point(x1, y1);
39
+ rval->p2 = new_point(x2, y2);
40
+ rval->rbLine = 0;
41
+ return rval;
42
+ }
43
+
44
+ void
45
+ line_destroy_notify(gpointer l) {
46
+ line_free((Line *) l);
47
+ }
48
+
49
+ VALUE
50
+ rb_line_alloc(VALUE class) {
51
+ Line *l = ALLOC(Line);
52
+ l->p1 = NULL;
53
+ l->p2 = NULL;
54
+ return RB_LINE(l, class);
55
+ }
56
+
57
+ VALUE
58
+ rb_line_initialize(int argc, VALUE *argv, VALUE self) {
59
+ Line *l;
60
+ Point *p1;
61
+ Point *p2;
62
+ if (argc == 2) {
63
+ CHECK_POINT(argv[0]);
64
+ CHECK_POINT(argv[1]);
65
+ POINT(argv[0], p1);
66
+ POINT(argv[1], p2);
67
+ } else if (argc == 4) {
68
+ CHECK_NUMERICALITY(argv[0]);
69
+ CHECK_NUMERICALITY(argv[1]);
70
+ CHECK_NUMERICALITY(argv[2]);
71
+ CHECK_NUMERICALITY(argv[3]);
72
+ p1 = ALLOC(Point);
73
+ p1->x = NUM2DBL(argv[0]);
74
+ p1->y = NUM2DBL(argv[1]);
75
+ p2 = ALLOC(Point);
76
+ p2->x = NUM2DBL(argv[2]);
77
+ p2->y = NUM2DBL(argv[3]);
78
+ RB_POINT(p1, rb_point);
79
+ RB_POINT(p2, rb_point);
80
+ } else {
81
+ rb_raise(rb_eTypeError, "Arguments to %s#new have to be 2 Grueserve::Map::Points or 4 numbers.", rb_obj_classname(self));
82
+ }
83
+ LINE(self, l);
84
+ l->p1 = p1;
85
+ l->p2 = p2;
86
+ return self;
87
+ }
88
+
89
+ VALUE
90
+ rb_line_inspect(VALUE self) {
91
+ gchar rval[1024];
92
+ Line *l;
93
+ LINE(self, l);
94
+ snprintf(rval, 1024, "<%s:%p p1=<%s:%p x=%f y=%f> p2=<%s:%p x=%f y=%f>>",
95
+ rb_obj_classname(self), l,
96
+ rb_obj_classname(l->p1->rbPoint), l->p1, l->p1->x, l->p1->y,
97
+ rb_obj_classname(l->p2->rbPoint), l->p2, l->p2->x, l->p2->y);
98
+ return rb_str_new2(rval);
99
+ }
100
+
101
+ VALUE
102
+ rb_line_set_p1(VALUE self, VALUE new_point) {
103
+ Line *l;
104
+ Point *p;
105
+ CHECK_POINT(new_point);
106
+ LINE(self, l);
107
+ POINT(new_point, p);
108
+ l->p1 = p;
109
+ return new_point;
110
+ }
111
+
112
+ VALUE
113
+ rb_line_set_p2(VALUE self, VALUE new_point) {
114
+ Line *l;
115
+ Point *p;
116
+ CHECK_POINT(new_point);
117
+ LINE(self, l);
118
+ POINT(new_point, p);
119
+ l->p2 = p;
120
+ return new_point;
121
+ }
122
+
123
+ VALUE
124
+ rb_line_p1(VALUE self) {
125
+ Line *l;
126
+ LINE(self, l);
127
+ return l->p1->rbPoint;
128
+ }
129
+
130
+ VALUE
131
+ rb_line_p2(VALUE self) {
132
+ Line *l;
133
+ LINE(self, l);
134
+ return l->p2->rbPoint;
135
+ }
136
+
137
+ /*
138
+ * If argument is a point:
139
+ * Is the point between the endpoints of the line?
140
+ * If argument is a line:
141
+ * Is any of the endpoints of the subject within the endpoints of the object?
142
+ */
143
+ VALUE
144
+ rb_line_within(VALUE self, VALUE arg) {
145
+ Line *l;
146
+ Point *p;
147
+ Line *other;
148
+ if (CLASS(arg) == rb_point) {
149
+ LINE(self, l);
150
+ POINT(arg, p);
151
+ if (POINT_WITHIN_LINE(l, p)) {
152
+ return Qtrue;
153
+ } else {
154
+ return Qfalse;
155
+ }
156
+ } else if (CLASS(arg) == rb_line) {
157
+ LINE(self, l);
158
+ LINE(arg, other);
159
+ if (LINE_WITHIN_LINE(l, other)) {
160
+ return Qtrue;
161
+ } else {
162
+ return Qfalse;
163
+ }
164
+ } else {
165
+ rb_raise(rb_eTypeError, "Argument to %s#within? has to be either Grueserve::Map::Line or Grueserve::Map::Point.", rb_obj_classname(self));
166
+ }
167
+ }
168
+
169
+ /*
170
+ * If argument is a point:
171
+ * Is the point outside the rectangle described by the endpoints of the line?
172
+ * If argument is a line:
173
+ * Is both of the subjects endpoints outside the rectangle described by the endpoints of the object?
174
+ */
175
+ VALUE
176
+ rb_line_outside(VALUE self, VALUE arg) {
177
+ Line *l;
178
+ Point *p;
179
+ Line *other;
180
+ if (CLASS(arg) == rb_point) {
181
+ LINE(self, l);
182
+ POINT(arg, p);
183
+ if (POINT_OUTSIDE_LINE(l, p)) {
184
+ return Qtrue;
185
+ } else {
186
+ return Qfalse;
187
+ }
188
+ } else if (CLASS(arg) == rb_line) {
189
+ LINE(self, l);
190
+ LINE(arg, other);
191
+ if (LINE_OUTSIDE_LINE(l, other)) {
192
+ return Qtrue;
193
+ } else {
194
+ return Qfalse;
195
+ }
196
+ } else {
197
+ rb_raise(rb_eTypeError, "Argument to %s#outside? has to be either Grueserve::Map::Line or Grueserve::Map::Point.", rb_obj_classname(self));
198
+ }
199
+ }
200
+
201
+ VALUE
202
+ rb_line_parallel(VALUE self, VALUE p) {
203
+ Line *me;
204
+ Line *rval;
205
+ Point *point;
206
+ CHECK_POINT(p);
207
+ LINE(self, me);
208
+ POINT(p, point);
209
+ rval = LINE_PARALLEL(me, point);
210
+ RB_POINT(rval->p1, CLASS(me->p1->rbPoint));
211
+ RB_POINT(rval->p2, CLASS(me->p2->rbPoint));
212
+ return RB_LINE(rval, CLASS(self));
213
+ }
214
+
215
+ gint
216
+ line_side(Line *me, Point *point) {
217
+ if (LINE_VERTICAL(me)) {
218
+ if (DBL_EQL(me->p1->x, point->x)) {
219
+ return 0;
220
+ } else if (DBL_EOG(me->p1->x, point->x)) {
221
+ return 1;
222
+ } else if (DBL_EOL(me->p1->x, point->x)) {
223
+ return -1;
224
+ } else {
225
+ rb_raise(rb_eRuntimeError, "Weird! A point should be either on, left or right of a line!");
226
+ }
227
+ } else {
228
+ gdouble y = LINE_Y(me, point->x);
229
+ if (DBL_EQL(y, point->y)) {
230
+ return 0;
231
+ } else if (DBL_EOG(y, point->y)) {
232
+ return -1;
233
+ } else if (DBL_EOL(y, point->y)) {
234
+ return 1;
235
+ } else {
236
+ rb_raise(rb_eRuntimeError, "Weird! A point should be either on, above or below a line!");
237
+ }
238
+ }
239
+ }
240
+
241
+ /*
242
+ * See http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
243
+ */
244
+ Intersection*
245
+ line_intersection(Line *l1, Line *l2) {
246
+ if (LINE_OUTSIDE_LINE(l1, l2)) {
247
+ return NULL;
248
+ } else {
249
+ gdouble x4_x3 = l2->p2->x - l2->p1->x;
250
+ gdouble y1_y3 = l1->p1->y - l2->p1->y;
251
+ gdouble y4_y3 = l2->p2->y - l2->p1->y;
252
+ gdouble x1_x3 = l1->p1->x - l2->p1->x;
253
+ gdouble x2_x1 = l1->p2->x - l1->p1->x;
254
+ gdouble y2_y1 = l1->p2->y - l1->p1->y;
255
+ gdouble denominator = y4_y3 * x2_x1 - x4_x3 * y2_y1;
256
+ if (denominator == 0) {
257
+ gdouble numerator1 = x4_x3 * y1_y3 - y4_y3 * x1_x3;
258
+ if (numerator1 == 0) {
259
+ gdouble new_x1 = MAX(MIN(l1->p1->x, l1->p2->x), MIN(l2->p1->x, l2->p2->x));
260
+ gdouble new_y1 = MAX(MIN(l1->p1->y, l1->p2->y), MIN(l2->p1->y, l2->p2->y));
261
+ gdouble new_x2 = MIN(MAX(l1->p1->x, l1->p2->x), MAX(l2->p1->x, l2->p2->x));
262
+ gdouble new_y2 = MIN(MAX(l1->p1->y, l1->p2->y), MAX(l2->p1->y, l2->p2->y));
263
+ return new_intersection_with_line(new_line_with_coordinates(new_x1, new_y1, new_x2, new_y2), l1);
264
+ } else {
265
+ return NULL;
266
+ }
267
+ } else {
268
+ gdouble t1 = (x4_x3 * y1_y3 - y4_y3 * x1_x3) / denominator;
269
+ gdouble t2 = (x2_x1 * y1_y3 - y2_y1 * x1_x3) / denominator;
270
+ if (t1 < 0 || t1 > 1 || t2 < 0 || t2 > 1)
271
+ return NULL;
272
+ return new_intersection_with_point(new_point(l1->p1->x + t1 * (l1->p2->x - l1->p1->x),
273
+ l1->p1->y + t1 * (l1->p2->y - l1->p1->y)), l1);
274
+ }
275
+ }
276
+ }
277
+
278
+ VALUE
279
+ rb_line_intersection(VALUE self, VALUE other_line) {
280
+ Line *me;
281
+ Line *other;
282
+ CHECK_LINE(other_line);
283
+ LINE(self, me);
284
+ LINE(other_line, other);
285
+ return rb_intersection(line_intersection(me, other), other->p1);
286
+ }
287
+
288
+ VALUE
289
+ rb_line_dot(VALUE self, VALUE o) {
290
+ Line *me;
291
+ Line *line;
292
+ CHECK_LINE(o);
293
+ LINE(self, me);
294
+ LINE(o, line);
295
+ return rb_float_new(LINE_DOT(line, me));
296
+ }
297
+
298
+ VALUE
299
+ rb_line_abs(VALUE self) {
300
+ Line *me;
301
+ LINE(self, me);
302
+ return rb_float_new(DISTANCE(me->p1, me->p2));
303
+ }
304
+
305
+ VALUE
306
+ rb_line_equals(VALUE self, VALUE o) {
307
+ if (!LINE_P(o)) {
308
+ return Qfalse;
309
+ } else {
310
+ Line *me;
311
+ Line *other;
312
+ LINE(self, me);
313
+ LINE(o, other);
314
+ if (LINE_EQUALS(me, other)) {
315
+ return Qtrue;
316
+ } else {
317
+ return Qfalse;
318
+ }
319
+ }
320
+ }
321
+
322
+ gint
323
+ line_cmp(Line *me, Line *other) {
324
+ gint tmp;
325
+ gdouble my_length;
326
+ gdouble other_length;
327
+ my_length = DISTANCE(me->p1, me->p2);
328
+ other_length = DISTANCE(other->p1, other->p2);
329
+ if (my_length != other_length)
330
+ return CMP(my_length, other_length);
331
+ else if ((tmp = point_cmp(me->p1, other->p1)) != 0)
332
+ return tmp;
333
+ else
334
+ return point_cmp(me->p2, other->p2);
335
+ }
336
+
337
+ VALUE
338
+ rb_line_cmp(VALUE self, VALUE o) {
339
+ if (!LINE_P(o)) {
340
+ return INT2NUM(CMP(CLASS(self), CLASS(o)));
341
+ } else {
342
+ Line *me;
343
+ Line *other;
344
+ LINE(self, me);
345
+ LINE(o, other);
346
+ return INT2NUM(line_cmp(me, other));
347
+ }
348
+ }
349
+
350
+ VALUE
351
+ rb_line_reverse(VALUE self) {
352
+ Line *me;
353
+ LINE(self, me);
354
+ return RB_LINE(new_line_with_points(me->p2, me->p1), rb_line);
355
+ }
356
+
357
+ VALUE
358
+ rb_line_set_angle(VALUE self, VALUE new_angle) {
359
+ Line *me;
360
+ gdouble length;
361
+ gdouble angle;
362
+ CHECK_NUMERICALITY(new_angle);
363
+ LINE(self, me);
364
+ angle = NUM2DBL(new_angle);
365
+ length = DISTANCE(me->p1, me->p2);
366
+ while (angle > M_PI * 2)
367
+ angle -= M_PI * 2;
368
+ me->p2->x = me->p1->x + length * cos(angle);
369
+ me->p2->y = me->p1->y + length * sin(angle);
370
+ return rb_float_new(angle);
371
+ }
372
+
373
+ VALUE
374
+ rb_line_angle(VALUE self) {
375
+ Line *me;
376
+ LINE(self, me);
377
+ ZERO_DISTANCE_CHECK(me->p1, me->p2);
378
+ return rb_float_new(LINE_ANGLE(me));
379
+ }
380
+
381
+ VALUE
382
+ rb_line_set_abs(VALUE self, VALUE new_abs) {
383
+ Line *me;
384
+ gdouble ratio;
385
+ CHECK_NUMERICALITY(new_abs);
386
+ LINE(self, me);
387
+ ZERO_DISTANCE_CHECK(me->p1, me->p2);
388
+ ratio = NUM2DBL(new_abs) / DISTANCE(me->p1, me->p2);
389
+ me->p2->x = me->p2->x * ratio;
390
+ me->p2->y = me->p2->y * ratio;
391
+ return new_abs;
392
+ }
393
+
394
+ VALUE
395
+ rb_line_clone(VALUE self) {
396
+ Line *me;
397
+ Line *rval;
398
+ LINE(self, me);
399
+ rval = new_line_with_coordinates(me->p1->x, me->p1->y, me->p2->x, me->p2->y);
400
+ RB_POINT(rval->p1, CLASS(me->p1->rbPoint));
401
+ RB_POINT(rval->p2, CLASS(me->p2->rbPoint));
402
+ return RB_LINE(rval, CLASS(self));
403
+ }
404
+
405
+ VALUE
406
+ rb_line_side(VALUE self, VALUE p) {
407
+ Line *me;
408
+ Point *point;
409
+ CHECK_POINT(p);
410
+ LINE(self, me);
411
+ POINT(p, point);
412
+ return INT2NUM(line_side(me, point));
413
+ }
414
+
415
+ VALUE
416
+ rb_line_contains(VALUE self, VALUE p) {
417
+ Line *me;
418
+ Point *point;
419
+ gint side;
420
+ CHECK_POINT(p);
421
+ LINE(self,me);
422
+ POINT(p, point);
423
+ side = line_side(me, point);
424
+ if (side == 0) {
425
+ return Qtrue;
426
+ } else {
427
+ return Qfalse;
428
+ }
429
+ }
430
+
431
+ VALUE
432
+ rb_line_from_gpointer(gpointer l) {
433
+ return ( (Line *) l)->rbLine;
434
+ }
435
+
436
+
data/ext/line.h ADDED
@@ -0,0 +1,170 @@
1
+
2
+ #ifndef LINE_H
3
+ #define LINE_H
4
+
5
+ #include "common.h"
6
+
7
+ extern VALUE rb_line;
8
+
9
+ #define RB_LINE(line_pointer,klass) ((line_pointer)->rbLine = Data_Wrap_Struct(klass, line_mark, free, (line_pointer)))
10
+ #define LINE(rb_line,line_pointer) Data_Get_Struct((rb_line), Line, (line_pointer))
11
+ #define LINE_ANGLE(me) (ANGLE((me)->p2->x - (me)->p1->x,(me)->p2->y - (me)->p1->y))
12
+ #define LINE_VERTICAL(line) ((line)->p1->x == (line)->p2->x)
13
+ #define LINE_Y(line,v) (LINE_VERTICAL((line)) ? \
14
+ (line)->p1->y : \
15
+ (line)->p1->y + ((line)->p2->y - (line)->p1->y) * ((v - (line)->p1->x) / ((line)->p2->x - (line)->p1->x)))
16
+ #define LINE_EQUALS(l1,l2) (POINT_EQUALS((l1)->p1, (l2)->p1) && POINT_EQUALS((l1)->p2, (l2)->p2))
17
+ /*
18
+ * Is the point outside the rectangle described by the endpoints of the line?
19
+ */
20
+ #define POINT_OUTSIDE_LINE(l,p) (((DBL_GT((p)->x, (l)->p1->x) && DBL_GT((p)->x, (l)->p2->x)) || \
21
+ (DBL_LT((p)->x, (l)->p1->x) && DBL_LT((p)->x, (l)->p2->x))) && \
22
+ ((DBL_GT((p)->y, (l)->p1->y) && DBL_GT((p)->y, (l)->p2->y)) || \
23
+ (DBL_LT((p)->y, (l)->p1->y) && DBL_LT((p)->y, (l)->p2->y))))
24
+
25
+ #define POINT_RIGHT_OF_LINE(l,p) (DBL_GT((p)->x, (l)->p1->x) && DBL_GT((p)->x, (l)->p2->x))
26
+ #define POINT_LEFT_OF_LINE(l,p) (DBL_LT((p)->x, (l)->p1->x) && DBL_LT((p)->x, (l)->p2->x))
27
+ #define POINT_ABOVE_LINE(l,p) (DBL_LT((p)->y, (l)->p1->y) && DBL_LT((p)->y, (l)->p2->y))
28
+ #define POINT_BELOW_LINE(l,p) (DBL_GT((p)->y, (l)->p1->y) && DBL_GT((p)->y, (l)->p2->y))
29
+ #define LINE_RIGHT_OF_LINE(subject,object) (POINT_RIGHT_OF_LINE((object), (subject)->p1) && POINT_RIGHT_OF_LINE((object), (subject)->p2))
30
+ #define LINE_LEFT_OF_LINE(subject,object) (POINT_LEFT_OF_LINE((object), (subject)->p1) && POINT_LEFT_OF_LINE((object), (subject)->p2))
31
+ #define LINE_ABOVE_LINE(subject,object) (POINT_ABOVE_LINE((object), (subject)->p1) && POINT_ABOVE_LINE((object), (subject)->p2))
32
+ #define LINE_BELOW_LINE(subject,object) (POINT_BELOW_LINE((object), (subject)->p1) && POINT_BELOW_LINE((object), (subject)->p2))
33
+ /*
34
+ * Is both of the subjects endpoints outside the rectangle described by the endpoints of the object?
35
+ */
36
+ #define LINE_OUTSIDE_LINE(subject,object) (LINE_RIGHT_OF_LINE((subject), (object)) || \
37
+ LINE_LEFT_OF_LINE((subject), (object)) || \
38
+ LINE_ABOVE_LINE((subject), (object)) || \
39
+ LINE_BELOW_LINE((subject), (object)))
40
+
41
+ /*
42
+ * Is the point between the endpoints of the line?
43
+ */
44
+ #define POINT_WITHIN_LINE(line_pointer,point_pointer) (DBL_EOG((point_pointer)->x, MIN((line_pointer)->p1->x, (line_pointer)->p2->x)) && \
45
+ DBL_EOL((point_pointer)->x, MAX((line_pointer)->p1->x, (line_pointer)->p2->x)) && \
46
+ DBL_EOG((point_pointer)->y, MIN((line_pointer)->p1->y, (line_pointer)->p2->y)) && \
47
+ DBL_EOL((point_pointer)->y, MAX((line_pointer)->p1->y, (line_pointer)->p2->y)))
48
+
49
+ #define POINT_ON_LINE(line_pointer,point_pointer) (DBL_EQL((point_pointer)->y, LINE_Y((line_pointer), (point_pointer)->x)) && \
50
+ POINT_WITHIN_LINE((line_pointer), (point_pointer))
51
+ /*
52
+ * Is any of the endpoints of the subject within the endpoints of the object?
53
+ */
54
+ #define LINE_WITHIN_LINE(subject,object) (POINT_WITHIN_LINE((subject), (object)->p1) || \
55
+ POINT_WITHIN_LINE((subject), (object)->p2))
56
+ #define LINE_DOT(l1,l2) ((((l1)->p2->x - (l1)->p1->x) * ((l2)->p2->x - (l2)->p1->x)) + (((l1)->p2->y - (l1)->p1->y) * ((l2)->p2->y - (l2)->p1->y)))
57
+ #define POINT_BETWEEN_PARALLEL_LINES(l1,l2,p) ((line_side((l1),(p)) >= 0 && line_side((l2),(p)) <= 0) || \
58
+ (line_side((l1),(p)) <= 0 && line_side((l2),(p)) >= 0))
59
+ #define LINE_P(l) (!NIL_P((l)) && rb_is_a((l), rb_line))
60
+ #define CHECK_LINE(l) if (!LINE_P((l))) rb_raise(rb_eTypeError, "Expected Grueserve::Map::Line!")
61
+ #define LINE_PARALLEL(l,p) (new_line_with_coordinates((p)->x, (p)->y, (p)->x + (l)->p2->x - (l)->p1->x, (p)->y + (l)->p2->y - (l)->p1->y))
62
+ #define LINE_BOUNDS(line,bottom_left,top_right) (bottom_left)->x = MIN(line->p1->x, line->p2->x); \
63
+ (bottom_left)->y = MIN(line->p1->y, line->p2->y); \
64
+ (top_right)->x = MAX(line->p1->x, line->p2->x); \
65
+ (top_right)->y = MAX(line->p1->y, line->p2->y)
66
+
67
+ void
68
+ line_mark(Line *line);
69
+
70
+ Line*
71
+ new_line_with_points(Point *p1, Point *p2);
72
+
73
+ Line*
74
+ new_line_with_coordinates(gdouble x1, gdouble y1, gdouble x2, gdouble y2);
75
+
76
+ void
77
+ line_destroy_notify(gpointer l);
78
+
79
+ VALUE
80
+ rb_line_alloc(VALUE class);
81
+
82
+ VALUE
83
+ rb_line_initialize(int argc, VALUE *argv, VALUE self);
84
+
85
+ VALUE
86
+ rb_line_inspect(VALUE self);
87
+
88
+ VALUE
89
+ rb_line_set_p1(VALUE self, VALUE new_point);
90
+
91
+ VALUE
92
+ rb_line_set_p2(VALUE self, VALUE new_point);
93
+
94
+ VALUE
95
+ rb_line_p1(VALUE self);
96
+
97
+ VALUE
98
+ rb_line_p2(VALUE self);
99
+
100
+ /*
101
+ * If argument is a point:
102
+ * Is the point between the endpoints of the line?
103
+ * If argument is a line:
104
+ * Is any of the endpoints of the subject within the endpoints of the object?
105
+ */
106
+ VALUE
107
+ rb_line_within(VALUE self, VALUE arg);
108
+
109
+ /*
110
+ * If argument is a point:
111
+ * Is the point outside the rectangle described by the endpoints of the line?
112
+ * If argument is a line:
113
+ * Is both of the subjects endpoints outside the rectangle described by the endpoints of the object?
114
+ */
115
+ VALUE
116
+ rb_line_outside(VALUE self, VALUE arg);
117
+
118
+
119
+ VALUE
120
+ rb_line_parallel(VALUE self, VALUE p);
121
+
122
+ gint
123
+ line_side(Line *me, Point *point);
124
+
125
+ Intersection*
126
+ line_intersection(Line *l1, Line *l2);
127
+
128
+ VALUE
129
+ rb_line_intersection(VALUE self, VALUE other_line);
130
+
131
+ VALUE
132
+ rb_line_dot(VALUE self, VALUE o);
133
+
134
+ VALUE
135
+ rb_line_abs(VALUE self);
136
+
137
+ VALUE
138
+ rb_line_equals(VALUE self, VALUE o);
139
+
140
+ VALUE
141
+ rb_line_cmp(VALUE self, VALUE o);
142
+
143
+ VALUE
144
+ rb_line_reverse(VALUE self);
145
+
146
+ VALUE
147
+ rb_line_set_angle(VALUE self, VALUE new_angle);
148
+
149
+ VALUE
150
+ rb_line_angle(VALUE self);
151
+
152
+ VALUE
153
+ rb_line_set_abs(VALUE self, VALUE new_abs);
154
+
155
+ VALUE
156
+ rb_line_clone(VALUE self);
157
+
158
+ VALUE
159
+ rb_line_side(VALUE self, VALUE p);
160
+
161
+ VALUE
162
+ rb_line_contains(VALUE self, VALUE p);
163
+
164
+ gint
165
+ line_cmp(Line *me, Line *other);
166
+
167
+ VALUE
168
+ rb_line_from_gpointer(gpointer l);
169
+
170
+ #endif