geo 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/common.c +5 -4
- data/ext/common.h +9 -9
- data/ext/extconf.rb +3 -2
- data/ext/geo.c +10 -4
- data/ext/geo_set.c +66 -35
- data/ext/geo_set.h +9 -7
- data/ext/intersection.c +6 -2
- data/ext/intersection.h +1 -1
- data/ext/line.c +164 -14
- data/ext/line.h +21 -6
- data/ext/line_set.c +83 -165
- data/ext/line_set.h +15 -6
- data/ext/point.c +28 -4
- data/ext/point.h +10 -3
- data/ext/point_set.c +9 -5
- data/ext/point_set.h +3 -3
- data/ext/triangle.c +49 -27
- data/ext/triangle.h +4 -2
- data/ext/triangle_set.c +52 -26
- data/ext/triangle_set.h +9 -3
- data/ext/types.h +2 -0
- metadata +40 -33
data/ext/common.c
CHANGED
@@ -16,12 +16,10 @@
|
|
16
16
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
17
|
|
18
18
|
|
19
|
-
#include
|
19
|
+
#include <common.h>
|
20
20
|
|
21
|
-
|
22
|
-
// The indentation of DBEUG messages.
|
21
|
+
// The indentation of DEBUG messages.
|
23
22
|
gint DEBUG_indentation = 0;
|
24
|
-
#endif
|
25
23
|
|
26
24
|
gboolean
|
27
25
|
rb_is_a(VALUE obj, VALUE c) {
|
@@ -50,3 +48,6 @@ gpointer_compare_as_uint(gconstpointer p1, gconstpointer p2) {
|
|
50
48
|
return GPOINTER_TO_UINT(p1) - GPOINTER_TO_UINT(p2);
|
51
49
|
}
|
52
50
|
|
51
|
+
void
|
52
|
+
init_common_o() {
|
53
|
+
}
|
data/ext/common.h
CHANGED
@@ -23,15 +23,15 @@
|
|
23
23
|
#include <stdlib.h>
|
24
24
|
#include <math.h>
|
25
25
|
#include <glib.h>
|
26
|
-
#include
|
27
|
-
#include
|
28
|
-
#include
|
29
|
-
#include
|
30
|
-
#include
|
31
|
-
#include
|
32
|
-
#include
|
33
|
-
#include
|
34
|
-
#include
|
26
|
+
#include <types.h>
|
27
|
+
#include <point.h>
|
28
|
+
#include <line.h>
|
29
|
+
#include <intersection.h>
|
30
|
+
#include <triangle.h>
|
31
|
+
#include <geo_set.h>
|
32
|
+
#include <line_set.h>
|
33
|
+
#include <point_set.h>
|
34
|
+
#include <triangle_set.h>
|
35
35
|
|
36
36
|
#ifndef M_PI
|
37
37
|
#define M_PI 3.14159265358979323846 /* pi */
|
data/ext/extconf.rb
CHANGED
@@ -28,12 +28,13 @@ unless find_executable("pkg-config")
|
|
28
28
|
crash("pkg-config needed")
|
29
29
|
end
|
30
30
|
|
31
|
+
$CFLAGS += " -std=c99 -Wall -I. " + `pkg-config --cflags glib-2.0`.strip
|
32
|
+
$LIBS += " " + `pkg-config --libs glib-2.0`
|
33
|
+
|
31
34
|
unless have_library('glib-2.0')
|
32
35
|
crash "libglib-2.0 needed"
|
33
36
|
end
|
34
37
|
|
35
|
-
$CFLAGS += " -std=c99 -Wall " + `pkg-config --cflags glib-2.0`.strip
|
36
|
-
|
37
38
|
if ARGV.include?("-d")
|
38
39
|
$CFLAGS += " -D GEO_DEBUG"
|
39
40
|
end
|
data/ext/geo.c
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
17
|
|
18
18
|
|
19
|
-
#include
|
19
|
+
#include <common.h>
|
20
20
|
|
21
21
|
VALUE
|
22
22
|
rb_float_intlike(VALUE self) {
|
@@ -30,12 +30,10 @@ rb_float_intlike(VALUE self) {
|
|
30
30
|
extern "C" {
|
31
31
|
#endif
|
32
32
|
void Init_geo() {
|
33
|
-
rb_funcall(rb_cObject, rb_intern("require"), 1, rb_str_new2("set"));
|
34
|
-
|
35
33
|
rb_define_method(rb_cFloat, "intlike?", rb_float_intlike, 0);
|
36
34
|
|
37
35
|
VALUE rb_geo = rb_define_module("Geo");
|
38
|
-
rb_define_const(rb_geo, "VERSION", rb_str_new2("0.1.
|
36
|
+
rb_define_const(rb_geo, "VERSION", rb_str_new2("0.1.5"));
|
39
37
|
|
40
38
|
rb_triangle_set = rb_define_class_under(rb_geo,
|
41
39
|
"TriangleSet",
|
@@ -78,6 +76,8 @@ extern "C" {
|
|
78
76
|
rb_define_method(rb_triangle_set, "_segments_for", rb_triangle_set_segment_ids_for_triangle, 1);
|
79
77
|
rb_define_method(rb_triangle_set, "_with_common_segment", rb_triangle_set_triangles_with_common_segment_id, 1);
|
80
78
|
rb_define_method(rb_triangle_set, "_in_segment", rb_triangle_set_structures_in_segment, 2);
|
79
|
+
rb_define_method(rb_triangle_set, "indexed", rb_geo_set_get_indexed, 0);
|
80
|
+
rb_define_method(rb_triangle_set, "indexed=", rb_geo_set_set_indexed, 1);
|
81
81
|
|
82
82
|
rb_define_alloc_func(rb_point_set, rb_point_set_alloc);
|
83
83
|
rb_define_method(rb_point_set, "<<", rb_point_set_insert, 1);
|
@@ -112,6 +112,8 @@ extern "C" {
|
|
112
112
|
rb_define_method(rb_line_set, "_width", rb_geo_set_width, 0);
|
113
113
|
rb_define_method(rb_line_set, "_height", rb_geo_set_height, 0);
|
114
114
|
rb_define_method(rb_line_set, "_with_common_segment", rb_line_set_lines_with_common_segment_id, 1);
|
115
|
+
rb_define_method(rb_line_set, "indexed", rb_geo_set_get_indexed, 0);
|
116
|
+
rb_define_method(rb_line_set, "indexed=", rb_geo_set_set_indexed, 1);
|
115
117
|
|
116
118
|
rb_define_alloc_func(rb_triangle, rb_triangle_alloc);
|
117
119
|
rb_define_method(rb_triangle, "initialize", rb_triangle_initialize, -1);
|
@@ -178,3 +180,7 @@ extern "C" {
|
|
178
180
|
}
|
179
181
|
#endif
|
180
182
|
|
183
|
+
void
|
184
|
+
init_geo_o() {
|
185
|
+
}
|
186
|
+
|
data/ext/geo_set.c
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
17
|
|
18
18
|
|
19
|
-
#include
|
19
|
+
#include <common.h>
|
20
20
|
|
21
21
|
VALUE
|
22
22
|
rb_geo_set_inspect(VALUE self) {
|
@@ -39,19 +39,6 @@ g_hash_table_destroy_notify(gpointer p) {
|
|
39
39
|
g_hash_table_destroy((GHashTable *) p);
|
40
40
|
}
|
41
41
|
|
42
|
-
static GeoSet*
|
43
|
-
new_geo_set_without_table() {
|
44
|
-
GeoSet *rval = ALLOC(GeoSet);
|
45
|
-
rval->iterating = FALSE;
|
46
|
-
rval->bottom_left = new_point(0,0);
|
47
|
-
rval->top_right = new_point(0,0);
|
48
|
-
rval->segment_side = 0;
|
49
|
-
rval->segments = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_hash_table_destroy_notify);
|
50
|
-
rval->segment_lines = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, line_destroy_notify);
|
51
|
-
rval->index_dirty = TRUE;
|
52
|
-
return rval;
|
53
|
-
}
|
54
|
-
|
55
42
|
void
|
56
43
|
geo_set_free(GeoSet *t) {
|
57
44
|
free(t->bottom_left);
|
@@ -62,17 +49,19 @@ geo_set_free(GeoSet *t) {
|
|
62
49
|
free(t);
|
63
50
|
}
|
64
51
|
|
65
|
-
GeoSet*
|
66
|
-
new_geo_set_with_destroy_notifier(GDestroyNotify destroy_notify) {
|
67
|
-
GeoSet *rval = new_geo_set_without_table();
|
68
|
-
rval->table = g_hash_table_new_full(g_direct_hash, g_direct_equal, destroy_notify, NULL);
|
69
|
-
return rval;
|
70
|
-
}
|
71
|
-
|
72
52
|
GeoSet*
|
73
53
|
new_geo_set() {
|
74
|
-
GeoSet *rval =
|
54
|
+
GeoSet *rval = ALLOC(GeoSet);
|
55
|
+
rval->iterating = FALSE;
|
56
|
+
rval->bottom_left = new_point(0,0);
|
57
|
+
rval->top_right = new_point(0,0);
|
58
|
+
rval->segment_side = 0;
|
59
|
+
rval->segments = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_hash_table_destroy_notify);
|
60
|
+
rval->segment_lines = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, line_destroy_notify);
|
61
|
+
rval->index_dirty = TRUE;
|
62
|
+
rval->indexed = TRUE;
|
75
63
|
rval->table = g_hash_table_new(g_direct_hash, g_direct_equal);
|
64
|
+
rval->rbGeoSet = 0;
|
76
65
|
return rval;
|
77
66
|
}
|
78
67
|
|
@@ -141,11 +130,11 @@ geo_set_find_bounds(GeoSet *set, geo_set_bound_finder bound_finder) {
|
|
141
130
|
set->bottom_left = NULL;
|
142
131
|
set->top_right = NULL;
|
143
132
|
bound_finder(set);
|
144
|
-
set->segment_side = sqrt(GEO_SET_WIDTH(set) * GEO_SET_HEIGHT(set) / g_hash_table_size(set->table));
|
133
|
+
set->segment_side = sqrt(MAX(1, GEO_SET_WIDTH(set)) * MAX(1, GEO_SET_HEIGHT(set)) / g_hash_table_size(set->table));
|
145
134
|
if (GEO_SET_HORIZONTAL_SEGMENTS(set) > MAX_GEO_SET_SEGMENTS)
|
146
|
-
set->segment_side = GEO_SET_WIDTH(set) / MAX_GEO_SET_SEGMENTS;
|
135
|
+
set->segment_side = MAX(1, GEO_SET_WIDTH(set)) / MAX_GEO_SET_SEGMENTS;
|
147
136
|
if (GEO_SET_VERTICAL_SEGMENTS(set) > MAX_GEO_SET_SEGMENTS)
|
148
|
-
set->segment_side = GEO_SET_HEIGHT(set) / MAX_GEO_SET_SEGMENTS;
|
137
|
+
set->segment_side = MAX(1, GEO_SET_HEIGHT(set)) / MAX_GEO_SET_SEGMENTS;
|
149
138
|
}
|
150
139
|
|
151
140
|
static void
|
@@ -199,7 +188,7 @@ rb_geo_set_structures_in_segment(VALUE self, VALUE xV, VALUE yV, geo_structure_t
|
|
199
188
|
}
|
200
189
|
|
201
190
|
static gboolean
|
202
|
-
|
191
|
+
g_hash_table_call_handler_for_unique_structure_until(gpointer key, gpointer value, gpointer user_data) {
|
203
192
|
gpointer *args = (gpointer *) user_data;
|
204
193
|
GeoSet *set = (GeoSet *) args[0];
|
205
194
|
geo_set_structure_handler handler = (geo_set_structure_handler) args[1];
|
@@ -232,7 +221,7 @@ geo_set_each_structure_in_segment_id_until(GeoSet *set, guint32 segment_id, gpoi
|
|
232
221
|
if (structures_in_id != NULL) {
|
233
222
|
gpointer rval = NULL;
|
234
223
|
gpointer args[5] = { set, handler, seen_structures, &rval, handler_args };
|
235
|
-
g_hash_table_find(structures_in_id,
|
224
|
+
g_hash_table_find(structures_in_id, g_hash_table_call_handler_for_unique_structure_until, args);
|
236
225
|
return rval;
|
237
226
|
} else {
|
238
227
|
return NULL;
|
@@ -427,7 +416,7 @@ geo_set_find_segments(GeoSet *set, geo_set_segment_finder segment_finder) {
|
|
427
416
|
|
428
417
|
gboolean
|
429
418
|
geo_set_reindex(GeoSet *set, geo_set_bound_finder bound_finder, geo_set_segment_finder segment_finder) {
|
430
|
-
if (set->index_dirty && g_hash_table_size(set->table) > 0) {
|
419
|
+
if (set->indexed && set->index_dirty && g_hash_table_size(set->table) > 0) {
|
431
420
|
set->index_dirty = FALSE;
|
432
421
|
geo_set_find_bounds(set, bound_finder);
|
433
422
|
if (set->segment_side > 0) {
|
@@ -442,13 +431,46 @@ geo_set_reindex(GeoSet *set, geo_set_bound_finder bound_finder, geo_set_segment_
|
|
442
431
|
}
|
443
432
|
}
|
444
433
|
|
445
|
-
|
446
|
-
|
447
|
-
set
|
448
|
-
|
449
|
-
|
434
|
+
VALUE
|
435
|
+
rb_geo_set_set_indexed(VALUE self, VALUE new_indexed) {
|
436
|
+
GeoSet *set;
|
437
|
+
GEO_SET(self, set);
|
438
|
+
if (new_indexed == Qtrue)
|
439
|
+
set->indexed = TRUE;
|
440
|
+
else
|
441
|
+
set->indexed = FALSE;
|
442
|
+
return GBOOL2RB(set->indexed);
|
443
|
+
}
|
444
|
+
|
445
|
+
VALUE
|
446
|
+
rb_geo_set_get_indexed(VALUE self) {
|
447
|
+
GeoSet *set;
|
448
|
+
GEO_SET(self, set);
|
449
|
+
return GBOOL2RB(set->indexed);
|
450
|
+
}
|
451
|
+
|
452
|
+
static gboolean
|
453
|
+
g_hash_table_call_handler_for_structure_until(gpointer key, gpointer value, gpointer user_data) {
|
454
|
+
gpointer *args = (gpointer *) user_data;
|
455
|
+
GeoSet *set = (GeoSet *) args[0];
|
456
|
+
geo_set_structure_handler handler = (geo_set_structure_handler) args[1];
|
457
|
+
gpointer *rval = (gpointer *) args[2];
|
458
|
+
if ((*rval = handler(set, key, args[3])) != NULL) {
|
459
|
+
return TRUE;
|
460
|
+
} else {
|
461
|
+
return FALSE;
|
462
|
+
}
|
463
|
+
return FALSE;
|
450
464
|
}
|
451
465
|
|
466
|
+
gpointer
|
467
|
+
geo_set_each_structure_until(GeoSet *set, geo_set_structure_handler handler, gpointer handler_args) {
|
468
|
+
gpointer rval;
|
469
|
+
gpointer args[5] = { set, handler, &rval, handler_args };
|
470
|
+
g_hash_table_find(set->table, g_hash_table_call_handler_for_structure_until, args);
|
471
|
+
return rval;
|
472
|
+
}
|
473
|
+
|
452
474
|
VALUE
|
453
475
|
geo_set_delete(GeoSet *set, gpointer p, VALUE rval) {
|
454
476
|
CHECK_ITERATING(set);
|
@@ -479,15 +501,19 @@ rb_geo_set_segment_lines(VALUE self) {
|
|
479
501
|
VALUE
|
480
502
|
rb_geo_set_bottom_left(VALUE self) {
|
481
503
|
GeoSet *set;
|
504
|
+
Point *point;
|
482
505
|
GEO_SET(self, set);
|
483
|
-
|
506
|
+
point = new_point(set->bottom_left->x, set->bottom_left->y);
|
507
|
+
return RB_POINT(point, rb_point);
|
484
508
|
}
|
485
509
|
|
486
510
|
VALUE
|
487
511
|
rb_geo_set_top_right(VALUE self) {
|
488
512
|
GeoSet *set;
|
513
|
+
Point *point;
|
489
514
|
GEO_SET(self, set);
|
490
|
-
|
515
|
+
point = new_point(set->top_right->x, set->top_right->y);
|
516
|
+
return RB_POINT(point, rb_point);
|
491
517
|
}
|
492
518
|
|
493
519
|
VALUE
|
@@ -503,3 +529,8 @@ rb_geo_set_height(VALUE self) {
|
|
503
529
|
GEO_SET(self, set);
|
504
530
|
return rb_float_new(GEO_SET_HEIGHT(set));
|
505
531
|
}
|
532
|
+
|
533
|
+
void
|
534
|
+
init_geo_set_o() {
|
535
|
+
}
|
536
|
+
|
data/ext/geo_set.h
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
#ifndef GEO_SET_H
|
20
20
|
#define GEO_SET_H
|
21
21
|
|
22
|
-
#include
|
22
|
+
#include <common.h>
|
23
23
|
|
24
24
|
struct IntersectionStruct;
|
25
25
|
enum IntersectionTypeEnum;
|
@@ -75,9 +75,6 @@ rb_geo_set_inspect(VALUE self);
|
|
75
75
|
VALUE
|
76
76
|
rb_geo_set_size(VALUE self);
|
77
77
|
|
78
|
-
GeoSet*
|
79
|
-
new_geo_set_with_destroy_notifier(GDestroyNotify destroy_notify);
|
80
|
-
|
81
78
|
GeoSet*
|
82
79
|
new_geo_set();
|
83
80
|
|
@@ -90,9 +87,6 @@ geo_set_clone(GeoSet *set);
|
|
90
87
|
gboolean
|
91
88
|
geo_set_reindex(GeoSet *set, geo_set_bound_finder bound_finder, geo_set_segment_finder segment_finder);
|
92
89
|
|
93
|
-
void
|
94
|
-
geo_set_foreach(GeoSet *set, GHFunc func);
|
95
|
-
|
96
90
|
VALUE
|
97
91
|
geo_set_delete(GeoSet *set, gpointer p, VALUE rval);
|
98
92
|
|
@@ -169,5 +163,13 @@ geo_set_each_structure_in_segment_id_until(GeoSet *set, guint32 segment_id, gpoi
|
|
169
163
|
gpointer
|
170
164
|
geo_set_insert_structure_into_rb_ary(GeoSet *set, gpointer structure, gpointer user_data);
|
171
165
|
|
166
|
+
VALUE
|
167
|
+
rb_geo_set_set_indexed(VALUE self, VALUE new_indexed);
|
168
|
+
|
169
|
+
VALUE
|
170
|
+
rb_geo_set_get_indexed(VALUE self);
|
171
|
+
|
172
|
+
gpointer
|
173
|
+
geo_set_each_structure_until(GeoSet *set, geo_set_structure_handler handler, gpointer handler_args);
|
172
174
|
|
173
175
|
#endif
|
data/ext/intersection.c
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
17
|
|
18
18
|
|
19
|
-
#include
|
19
|
+
#include <common.h>
|
20
20
|
|
21
21
|
|
22
22
|
void
|
@@ -24,7 +24,7 @@ free_intersection(Intersection *intersection) {
|
|
24
24
|
if (intersection->type == itPOINT)
|
25
25
|
free(intersection->point);
|
26
26
|
else if (intersection->type == itLINE)
|
27
|
-
|
27
|
+
line_free(intersection->line);
|
28
28
|
free(intersection);
|
29
29
|
}
|
30
30
|
|
@@ -73,3 +73,7 @@ rb_intersection(Intersection *intersection, Point *from) {
|
|
73
73
|
}
|
74
74
|
}
|
75
75
|
|
76
|
+
void
|
77
|
+
init_intersection_o() {
|
78
|
+
}
|
79
|
+
|
data/ext/intersection.h
CHANGED
data/ext/line.c
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
17
|
|
18
18
|
|
19
|
-
#include
|
19
|
+
#include <common.h>
|
20
20
|
|
21
21
|
VALUE rb_line;
|
22
22
|
|
@@ -25,7 +25,7 @@ VALUE rb_line;
|
|
25
25
|
* since they will be freed by ruby. Make sure that they have
|
26
26
|
* rubified points (RB_POINT) as well though!
|
27
27
|
*/
|
28
|
-
|
28
|
+
void
|
29
29
|
line_free(Line *l) {
|
30
30
|
free(l->p1);
|
31
31
|
free(l->p2);
|
@@ -103,16 +103,30 @@ rb_line_initialize(int argc, VALUE *argv, VALUE self) {
|
|
103
103
|
return self;
|
104
104
|
}
|
105
105
|
|
106
|
+
gchar *
|
107
|
+
line_inspect(Line *l) {
|
108
|
+
gchar *rval = calloc(1024, sizeof(gchar));
|
109
|
+
gchar *p1 = point_inspect(l->p1);
|
110
|
+
gchar *p2 = point_inspect(l->p2);
|
111
|
+
snprintf(rval, 1024, "<%s:%p p1=%s p2=%s>",
|
112
|
+
rb_obj_classname(l->rbLine), l,
|
113
|
+
p1,
|
114
|
+
p2);
|
115
|
+
free(p1);
|
116
|
+
free(p2);
|
117
|
+
return rval;
|
118
|
+
}
|
119
|
+
|
106
120
|
VALUE
|
107
121
|
rb_line_inspect(VALUE self) {
|
108
|
-
gchar
|
122
|
+
gchar *str;
|
109
123
|
Line *l;
|
124
|
+
VALUE rval;
|
110
125
|
LINE(self, l);
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
return rb_str_new2(rval);
|
126
|
+
str = line_inspect(l);
|
127
|
+
rval = rb_str_new2(str);
|
128
|
+
free(str);
|
129
|
+
return rval;
|
116
130
|
}
|
117
131
|
|
118
132
|
VALUE
|
@@ -319,6 +333,11 @@ rb_line_abs(VALUE self) {
|
|
319
333
|
return rb_float_new(DISTANCE(me->p1, me->p2));
|
320
334
|
}
|
321
335
|
|
336
|
+
gboolean
|
337
|
+
line_equals(gconstpointer l1, gconstpointer l2) {
|
338
|
+
return LINE_EQUALS(l1, l2);
|
339
|
+
}
|
340
|
+
|
322
341
|
VALUE
|
323
342
|
rb_line_equals(VALUE self, VALUE o) {
|
324
343
|
if (!LINE_P(o)) {
|
@@ -336,14 +355,14 @@ rb_line_equals(VALUE self, VALUE o) {
|
|
336
355
|
}
|
337
356
|
}
|
338
357
|
|
339
|
-
gint
|
358
|
+
static gint
|
340
359
|
line_cmp(Line *me, Line *other) {
|
341
360
|
gint tmp;
|
342
361
|
gdouble my_length;
|
343
362
|
gdouble other_length;
|
344
363
|
my_length = DISTANCE(me->p1, me->p2);
|
345
364
|
other_length = DISTANCE(other->p1, other->p2);
|
346
|
-
if (my_length
|
365
|
+
if (!DBL_EQL(my_length, other_length))
|
347
366
|
return CMP(my_length, other_length);
|
348
367
|
else if ((tmp = point_cmp(me->p1, other->p1)) != 0)
|
349
368
|
return tmp;
|
@@ -395,16 +414,20 @@ rb_line_angle(VALUE self) {
|
|
395
414
|
return rb_float_new(LINE_ANGLE(me));
|
396
415
|
}
|
397
416
|
|
417
|
+
void
|
418
|
+
line_set_abs(Line *me, double new_abs) {
|
419
|
+
double ratio = new_abs / DISTANCE(me->p1, me->p2);
|
420
|
+
me->p2->x = me->p2->x * ratio;
|
421
|
+
me->p2->y = me->p2->y * ratio;
|
422
|
+
}
|
423
|
+
|
398
424
|
VALUE
|
399
425
|
rb_line_set_abs(VALUE self, VALUE new_abs) {
|
400
426
|
Line *me;
|
401
|
-
gdouble ratio;
|
402
427
|
CHECK_NUMERICALITY(new_abs);
|
403
428
|
LINE(self, me);
|
404
429
|
ZERO_DISTANCE_CHECK(me->p1, me->p2);
|
405
|
-
|
406
|
-
me->p2->x = me->p2->x * ratio;
|
407
|
-
me->p2->y = me->p2->y * ratio;
|
430
|
+
line_set_abs(me, NUM2DBL(new_abs));
|
408
431
|
return new_abs;
|
409
432
|
}
|
410
433
|
|
@@ -450,4 +473,131 @@ rb_line_from_gpointer(gpointer l) {
|
|
450
473
|
return ( (Line *) l)->rbLine;
|
451
474
|
}
|
452
475
|
|
476
|
+
gboolean
|
477
|
+
line_slide_point(Intersection *intersection, Line *line, gint ttl) {
|
478
|
+
Point touchPoint;
|
479
|
+
Point destOne;
|
480
|
+
Point destTwo;
|
481
|
+
gdouble distanceLeft;
|
482
|
+
gdouble errorOne;
|
483
|
+
gdouble errorTwo;
|
484
|
+
/*
|
485
|
+
* The line we want to adjust against. If the intersection is with a line of zero
|
486
|
+
* length, then it is against ourselves. Otherwise with the intersecting line.
|
487
|
+
*/
|
488
|
+
gboolean zero_intersection = intersection->type == itLINE && ZERO_DISTANCE_P(intersection->with->p1, intersection->with->p2);
|
489
|
+
gdouble adjustment_length = zero_intersection ? DISTANCE(line->p1, line->p2) : DISTANCE(intersection->with->p1, intersection->with->p2);
|
490
|
+
gdouble adjustment_xunit = zero_intersection ? \
|
491
|
+
(line->p2->x - line->p1->x) / adjustment_length : \
|
492
|
+
(intersection->with->p2->x - intersection->with->p1->x) / adjustment_length;
|
493
|
+
gdouble adjustment_yunit = zero_intersection ? \
|
494
|
+
(line->p2->y - line->p1->y) / adjustment_length : \
|
495
|
+
(intersection->with->p2->y - intersection->with->p1->y) / adjustment_length;
|
496
|
+
/*
|
497
|
+
* Calculate where we actually touch the other line.
|
498
|
+
*/
|
499
|
+
if (intersection->type == itLINE) {
|
500
|
+
if (DISTANCE(intersection->line->p1, line->p1) <
|
501
|
+
DISTANCE(intersection->line->p2, line->p1)) {
|
502
|
+
touchPoint = *(intersection->line->p1);
|
503
|
+
} else {
|
504
|
+
touchPoint = *(intersection->line->p2);
|
505
|
+
}
|
506
|
+
} else {
|
507
|
+
touchPoint = *(intersection->point);
|
508
|
+
}
|
509
|
+
if (intersection->type == itPOINT) {
|
510
|
+
/*
|
511
|
+
* If we intersected with a point, move the touch point back towards the start point to not actually touch the other line.
|
512
|
+
*/
|
513
|
+
if (line->p1->x > touchPoint.x)
|
514
|
+
touchPoint.x += MIN(1, line->p1->x - touchPoint.x);
|
515
|
+
if (line->p1->x < touchPoint.x)
|
516
|
+
touchPoint.x -= MIN(1, touchPoint.x - line->p1->x);
|
517
|
+
if (line->p1->y > touchPoint.y)
|
518
|
+
touchPoint.y += MIN(1, line->p1->y - touchPoint.y);
|
519
|
+
if (line->p1->y < touchPoint.y)
|
520
|
+
touchPoint.y -= MIN(1, touchPoint.y - line->p1->y);
|
521
|
+
} else {
|
522
|
+
/*
|
523
|
+
* If we intersected with a line, move perpendicular to our adjustment-line.
|
524
|
+
*/
|
525
|
+
if (rand() < RAND_MAX / 2) {
|
526
|
+
touchPoint.x += adjustment_yunit;
|
527
|
+
touchPoint.y -= adjustment_xunit;
|
528
|
+
} else {
|
529
|
+
touchPoint.x -= adjustment_yunit;
|
530
|
+
touchPoint.y += adjustment_xunit;
|
531
|
+
}
|
532
|
+
}
|
533
|
+
/*
|
534
|
+
* If the ttl is reached then we just set the line's p2 to the touchPoint.
|
535
|
+
*/
|
536
|
+
if (ttl < 1) {
|
537
|
+
line->p2->x = touchPoint.x;
|
538
|
+
line->p2->y = touchPoint.y;
|
539
|
+
/*
|
540
|
+
* We are done here, no more sliding.
|
541
|
+
*/
|
542
|
+
return TRUE;
|
543
|
+
} else {
|
544
|
+
/*
|
545
|
+
* Otherwise we calculate two alternate destinations.
|
546
|
+
*
|
547
|
+
* If we intersected with a zero length line, then we just go ahead in our
|
548
|
+
* original direction, otherwise we follow the intersecting line.
|
549
|
+
*
|
550
|
+
*/
|
551
|
+
destOne = touchPoint;
|
552
|
+
destTwo = touchPoint;
|
553
|
+
distanceLeft = DISTANCE(line->p1, line->p2) - DISTANCE(&touchPoint, line->p1);
|
554
|
+
if (zero_intersection) {
|
555
|
+
destOne.x += adjustment_xunit * distanceLeft;
|
556
|
+
destOne.y += adjustment_yunit * distanceLeft;
|
557
|
+
destTwo.x += adjustment_xunit * distanceLeft;
|
558
|
+
destTwo.y += adjustment_yunit * distanceLeft;
|
559
|
+
} else {
|
560
|
+
destOne.x += adjustment_xunit * distanceLeft;
|
561
|
+
destOne.y += adjustment_yunit * distanceLeft;
|
562
|
+
destTwo.x -= adjustment_xunit * distanceLeft;
|
563
|
+
destTwo.y -= adjustment_yunit * distanceLeft;
|
564
|
+
}
|
565
|
+
/*
|
566
|
+
* And select the one with the least error.
|
567
|
+
*/
|
568
|
+
errorOne = DISTANCE(line->p2, &destOne);
|
569
|
+
errorTwo = DISTANCE(line->p2, &destTwo);
|
570
|
+
if (DBL_EQL(errorOne, errorTwo)) {
|
571
|
+
line->p2->x = touchPoint.x;
|
572
|
+
line->p2->y = touchPoint.y;
|
573
|
+
/*
|
574
|
+
* We are done here, no more sliding.
|
575
|
+
*/
|
576
|
+
return TRUE;
|
577
|
+
} else {
|
578
|
+
if (errorOne < errorTwo) {
|
579
|
+
line->p2->x = destOne.x;
|
580
|
+
line->p2->y = destOne.y;
|
581
|
+
} else if (errorOne > errorTwo) {
|
582
|
+
line->p2->x = destTwo.x;
|
583
|
+
line->p2->y = destTwo.y;
|
584
|
+
}
|
585
|
+
line->p1->x = touchPoint.x;
|
586
|
+
line->p1->y = touchPoint.y;
|
587
|
+
/*
|
588
|
+
* We are possibly not done, return FALSE.
|
589
|
+
*/
|
590
|
+
return FALSE;
|
591
|
+
}
|
592
|
+
}
|
593
|
+
}
|
453
594
|
|
595
|
+
guint
|
596
|
+
line_hash(gconstpointer l) {
|
597
|
+
Line *line = (Line *) l;
|
598
|
+
return (guint) (line->p1->x + line->p1->y + line->p2->x + line->p2->y);
|
599
|
+
}
|
600
|
+
|
601
|
+
void
|
602
|
+
init_line_o() {
|
603
|
+
}
|
data/ext/line.h
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
#ifndef LINE_H
|
20
20
|
#define LINE_H
|
21
21
|
|
22
|
-
#include
|
22
|
+
#include <common.h>
|
23
23
|
|
24
24
|
extern VALUE rb_line;
|
25
25
|
|
@@ -30,7 +30,7 @@ extern VALUE rb_line;
|
|
30
30
|
#define LINE_Y(line,v) (LINE_VERTICAL((line)) ? \
|
31
31
|
(line)->p1->y : \
|
32
32
|
(line)->p1->y + ((line)->p2->y - (line)->p1->y) * ((v - (line)->p1->x) / ((line)->p2->x - (line)->p1->x)))
|
33
|
-
#define LINE_EQUALS(l1,l2) (POINT_EQUALS((l1)->p1, (l2)->p1) && POINT_EQUALS((l1)->p2, (l2)->p2))
|
33
|
+
#define LINE_EQUALS(l1,l2) (POINT_EQUALS(((Line *) (l1))->p1, ((Line *) (l2))->p1) && POINT_EQUALS(((Line *) (l1))->p2, ((Line *) (l2))->p2))
|
34
34
|
/*
|
35
35
|
* Is the point outside the rectangle described by the endpoints of the line?
|
36
36
|
*/
|
@@ -74,7 +74,7 @@ extern VALUE rb_line;
|
|
74
74
|
#define POINT_BETWEEN_PARALLEL_LINES(l1,l2,p) ((line_side((l1),(p)) >= 0 && line_side((l2),(p)) <= 0) || \
|
75
75
|
(line_side((l1),(p)) <= 0 && line_side((l2),(p)) >= 0))
|
76
76
|
#define LINE_P(l) (!NIL_P((l)) && rb_is_a((l), rb_line))
|
77
|
-
#define CHECK_LINE(l) if (!LINE_P((l))) rb_raise(rb_eTypeError, "Expected
|
77
|
+
#define CHECK_LINE(l) if (!LINE_P((l))) rb_raise(rb_eTypeError, "Expected Geo::Line!")
|
78
78
|
#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))
|
79
79
|
#define LINE_BOUNDS(line,bottom_left,top_right) (bottom_left)->x = MIN(line->p1->x, line->p2->x); \
|
80
80
|
(bottom_left)->y = MIN(line->p1->y, line->p2->y); \
|
@@ -178,10 +178,25 @@ rb_line_side(VALUE self, VALUE p);
|
|
178
178
|
VALUE
|
179
179
|
rb_line_contains(VALUE self, VALUE p);
|
180
180
|
|
181
|
-
gint
|
182
|
-
line_cmp(Line *me, Line *other);
|
183
|
-
|
184
181
|
VALUE
|
185
182
|
rb_line_from_gpointer(gpointer l);
|
186
183
|
|
184
|
+
void
|
185
|
+
line_set_abs(Line *me, double new_abs);
|
186
|
+
|
187
|
+
gboolean
|
188
|
+
line_slide_point(Intersection *intersection, Line *line, gint ttl);
|
189
|
+
|
190
|
+
gchar *
|
191
|
+
line_inspect(Line *l);
|
192
|
+
|
193
|
+
guint
|
194
|
+
line_hash(gconstpointer l);
|
195
|
+
|
196
|
+
gboolean
|
197
|
+
line_equals(gconstpointer a, gconstpointer b);
|
198
|
+
|
199
|
+
void
|
200
|
+
line_free(Line *l);
|
201
|
+
|
187
202
|
#endif
|