geo 0.1.4 → 0.1.5
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.
- 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
|