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/line_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 rb_line_set;
|
22
22
|
|
@@ -70,16 +70,17 @@ rb_line_set_delete(VALUE self, VALUE line) {
|
|
70
70
|
return geo_set_delete(me, (gpointer) t, line);
|
71
71
|
}
|
72
72
|
|
73
|
-
static
|
74
|
-
g_hash_table_yield_line(
|
75
|
-
rb_yield(( (Line *)
|
73
|
+
static gpointer
|
74
|
+
g_hash_table_yield_line(GeoSet *set, gpointer structure, gpointer user_data) {
|
75
|
+
rb_yield(( (Line *) structure )->rbLine);
|
76
|
+
return NULL;
|
76
77
|
}
|
77
78
|
|
78
79
|
VALUE
|
79
80
|
rb_line_set_each(VALUE self) {
|
80
81
|
GeoSet *set;
|
81
82
|
GEO_SET(self, set);
|
82
|
-
|
83
|
+
geo_set_each_structure_until(set, g_hash_table_yield_line, NULL);
|
83
84
|
return self;
|
84
85
|
}
|
85
86
|
|
@@ -95,9 +96,13 @@ line_set_intersection(GeoSet *set, gpointer set_line_gp, gpointer line_gp) {
|
|
95
96
|
|
96
97
|
gboolean
|
97
98
|
line_set_intersects(GeoSet *set, Line *line) {
|
98
|
-
Intersection *intersection;
|
99
|
-
|
100
|
-
|
99
|
+
Intersection *intersection = NULL;
|
100
|
+
if (set->indexed) {
|
101
|
+
LINE_SET_REINDEX(set);
|
102
|
+
intersection = geo_set_each_structure_having_common_segment_id_with_line_until(set, line, line_set_intersection, line);
|
103
|
+
} else {
|
104
|
+
intersection = geo_set_each_structure_until(set, line_set_intersection, line);
|
105
|
+
}
|
101
106
|
if (intersection != NULL)
|
102
107
|
free_intersection(intersection);
|
103
108
|
return GBOOL2RB(intersection != NULL);
|
@@ -147,127 +152,24 @@ line_set_closest_intersection(GeoSet *set, Line *line) {
|
|
147
152
|
Intersection *closest = NULL;
|
148
153
|
double closest_distance = -1;
|
149
154
|
gpointer args[3] = { &closest_distance, &closest, line };
|
150
|
-
|
151
|
-
|
155
|
+
if (set->indexed) {
|
156
|
+
LINE_SET_REINDEX(set);
|
157
|
+
geo_set_each_structure_having_common_segment_id_with_line_until(set, line, line_set_closest_intersection_in_segments, args);
|
158
|
+
} else {
|
159
|
+
geo_set_each_structure_until(set, line_set_closest_intersection_in_segments, args);
|
160
|
+
}
|
152
161
|
return closest;
|
153
162
|
}
|
154
163
|
|
155
|
-
|
156
|
-
|
164
|
+
void
|
165
|
+
line_set_slide_point(GeoSet *set, Line *line, gint ttl) {
|
166
|
+
gboolean done = FALSE;
|
167
|
+
Intersection *intersection;
|
157
168
|
ZERO_DISTANCE_CHECK(line->p1, line->p2);
|
158
|
-
|
159
|
-
|
160
|
-
Point touchPoint;
|
161
|
-
Point destOne;
|
162
|
-
Point destTwo;
|
163
|
-
gdouble distanceLeft;
|
164
|
-
gdouble errorOne;
|
165
|
-
gdouble errorTwo;
|
166
|
-
/*
|
167
|
-
* The line we want to adjust against. If the intersection is with a line of zero
|
168
|
-
* length, then it is against ourselves. Otherwise with the intersecting line.
|
169
|
-
*/
|
170
|
-
gboolean zero_intersection = intersection->type == itLINE && ZERO_DISTANCE_P(intersection->with->p1, intersection->with->p2);
|
171
|
-
gdouble adjustment_length = zero_intersection ? DISTANCE(line->p1, line->p2) : DISTANCE(intersection->with->p1, intersection->with->p2);
|
172
|
-
gdouble adjustment_xunit = zero_intersection ? \
|
173
|
-
(line->p2->x - line->p1->x) / adjustment_length : \
|
174
|
-
(intersection->with->p2->x - intersection->with->p1->x) / adjustment_length;
|
175
|
-
gdouble adjustment_yunit = zero_intersection ? \
|
176
|
-
(line->p2->y - line->p1->y) / adjustment_length : \
|
177
|
-
(intersection->with->p2->y - intersection->with->p1->y) / adjustment_length;
|
178
|
-
/*
|
179
|
-
* Calculate where we actually touch the other line.
|
180
|
-
*/
|
181
|
-
if (intersection->type == itLINE) {
|
182
|
-
if (DISTANCE(intersection->line->p1, line->p1) <
|
183
|
-
DISTANCE(intersection->line->p2, line->p1)) {
|
184
|
-
touchPoint = *(intersection->line->p1);
|
185
|
-
} else {
|
186
|
-
touchPoint = *(intersection->line->p2);
|
187
|
-
}
|
188
|
-
} else {
|
189
|
-
touchPoint = *(intersection->point);
|
190
|
-
}
|
191
|
-
if (intersection->type == itPOINT) {
|
192
|
-
/*
|
193
|
-
* If we intersected with a point, move the touch point back towards the start point to not actually touch the other line.
|
194
|
-
*/
|
195
|
-
if (line->p1->x > touchPoint.x)
|
196
|
-
touchPoint.x += MIN(1, line->p1->x - touchPoint.x);
|
197
|
-
if (line->p1->x < touchPoint.x)
|
198
|
-
touchPoint.x -= MIN(1, touchPoint.x - line->p1->x);
|
199
|
-
if (line->p1->y > touchPoint.y)
|
200
|
-
touchPoint.y += MIN(1, line->p1->y - touchPoint.y);
|
201
|
-
if (line->p1->y < touchPoint.y)
|
202
|
-
touchPoint.y -= MIN(1, touchPoint.y - line->p1->y);
|
203
|
-
} else {
|
204
|
-
/*
|
205
|
-
* If we intersected with a line, move perpendicular to our adjustment-line.
|
206
|
-
*/
|
207
|
-
if (rand() < RAND_MAX / 2) {
|
208
|
-
touchPoint.x += adjustment_yunit;
|
209
|
-
touchPoint.y -= adjustment_xunit;
|
210
|
-
} else {
|
211
|
-
touchPoint.x -= adjustment_yunit;
|
212
|
-
touchPoint.y += adjustment_xunit;
|
213
|
-
}
|
214
|
-
}
|
215
|
-
/*
|
216
|
-
* Now that we wont use the intersection anymore, lets free it.
|
217
|
-
*/
|
169
|
+
while ((intersection = line_set_closest_intersection(set, line)) != NULL && ttl > 0 && !done) {
|
170
|
+
done = line_slide_point(intersection, line, ttl);
|
218
171
|
free_intersection(intersection);
|
219
|
-
|
220
|
-
* If the ttl is reached then we just set the line's p2 to the touchPoint.
|
221
|
-
*/
|
222
|
-
if (ttl < 1) {
|
223
|
-
line->p2->x = touchPoint.x;
|
224
|
-
line->p2->y = touchPoint.y;
|
225
|
-
} else {
|
226
|
-
/*
|
227
|
-
* Otherwise we calculate two alternate destinations.
|
228
|
-
*
|
229
|
-
* If we intersected with a zero length line, then we just go ahead in our
|
230
|
-
* original direction, otherwise we follow the intersecting line.
|
231
|
-
*
|
232
|
-
*/
|
233
|
-
destOne = touchPoint;
|
234
|
-
destTwo = touchPoint;
|
235
|
-
distanceLeft = DISTANCE(line->p1, line->p2) - DISTANCE(&touchPoint, line->p1);
|
236
|
-
if (zero_intersection) {
|
237
|
-
destOne.x += adjustment_xunit * distanceLeft;
|
238
|
-
destOne.y += adjustment_yunit * distanceLeft;
|
239
|
-
destTwo.x += adjustment_xunit * distanceLeft;
|
240
|
-
destTwo.y += adjustment_yunit * distanceLeft;
|
241
|
-
} else {
|
242
|
-
destOne.x += adjustment_xunit * distanceLeft;
|
243
|
-
destOne.y += adjustment_yunit * distanceLeft;
|
244
|
-
destTwo.x -= adjustment_xunit * distanceLeft;
|
245
|
-
destTwo.y -= adjustment_yunit * distanceLeft;
|
246
|
-
}
|
247
|
-
/*
|
248
|
-
* And select the one with the least error.
|
249
|
-
*/
|
250
|
-
errorOne = DISTANCE(line->p2, &destOne);
|
251
|
-
errorTwo = DISTANCE(line->p2, &destTwo);
|
252
|
-
if (DBL_EQL(errorOne, errorTwo)) {
|
253
|
-
line->p2->x = touchPoint.x;
|
254
|
-
line->p2->y = touchPoint.y;
|
255
|
-
} else {
|
256
|
-
if (errorOne < errorTwo) {
|
257
|
-
line->p2->x = destOne.x;
|
258
|
-
line->p2->y = destOne.y;
|
259
|
-
} else if (errorOne > errorTwo) {
|
260
|
-
line->p2->x = destTwo.x;
|
261
|
-
line->p2->y = destTwo.y;
|
262
|
-
}
|
263
|
-
line->p1->x = touchPoint.x;
|
264
|
-
line->p1->y = touchPoint.y;
|
265
|
-
/*
|
266
|
-
* And slide along, in case something else gets in the way.
|
267
|
-
*/
|
268
|
-
line_set_slide(set, line, ttl - 1);
|
269
|
-
}
|
270
|
-
}
|
172
|
+
ttl--;
|
271
173
|
}
|
272
174
|
}
|
273
175
|
|
@@ -278,48 +180,64 @@ rb_line_set_slide(VALUE self, VALUE l) {
|
|
278
180
|
CHECK_LINE(l);
|
279
181
|
GEO_SET(self, set);
|
280
182
|
LINE(l, line);
|
281
|
-
|
183
|
+
line_set_slide_point(set, line, 3);
|
282
184
|
return line->p2->rbPoint;
|
283
185
|
}
|
284
186
|
|
285
187
|
static void
|
286
|
-
|
188
|
+
g_hash_table_each_intersection_free_endpoint(gpointer key, gpointer data, gpointer user_data) {
|
287
189
|
gpointer *arg_wrapper = (gpointer *) user_data;
|
288
190
|
|
289
191
|
gpointer *original_args = (gpointer *) arg_wrapper[0];
|
290
192
|
gdouble *max_distance = (gdouble *) original_args[1];
|
291
|
-
Line *tmpLine = (Line *) original_args[
|
292
|
-
|
193
|
+
Line *tmpLine = (Line *) original_args[2];
|
194
|
+
GeoSet *line_set = (GeoSet *) original_args[3];
|
195
|
+
geo_set_structure_handler handler = (geo_set_structure_handler) original_args[4];
|
196
|
+
gpointer handler_args = original_args[5];
|
197
|
+
GHashTable *seen_points = (GHashTable *) original_args[6];
|
198
|
+
|
293
199
|
*(tmpLine->p1) = *( (Point *) arg_wrapper[1] );
|
294
200
|
*(tmpLine->p2) = *( (Point *) key);
|
295
201
|
|
296
202
|
if (*max_distance < 0 || DISTANCE(tmpLine->p1, tmpLine->p2) < *max_distance) {
|
297
|
-
if (!line_set_intersects(
|
298
|
-
|
203
|
+
if (!line_set_intersects(line_set, tmpLine)) {
|
204
|
+
if (g_hash_table_lookup(seen_points, key) == NULL) {
|
205
|
+
handler(line_set, key, handler_args);
|
206
|
+
g_hash_table_insert(seen_points, key, GINT_TO_POINTER(1));
|
207
|
+
}
|
299
208
|
}
|
300
209
|
}
|
301
210
|
}
|
302
211
|
|
212
|
+
static gpointer
|
213
|
+
line_set_insert_point_into_rb_ary(GeoSet *line_set, gpointer point, gpointer rval) {
|
214
|
+
rb_ary_push(*( (VALUE *) rval ), ((Point *) point)->rbPoint);
|
215
|
+
return NULL;
|
216
|
+
}
|
217
|
+
|
303
218
|
static void
|
304
|
-
|
219
|
+
g_hash_table_each_intersection_free_endpoint_for_point(gpointer key, gpointer data, gpointer user_data) {
|
305
220
|
gpointer my_args[2];
|
306
221
|
gpointer *given_args = (gpointer *) user_data;
|
307
|
-
GeoSet *
|
222
|
+
GeoSet *endpoints = (GeoSet *) given_args[0];
|
308
223
|
my_args[0] = user_data;
|
309
224
|
my_args[1] = key;
|
310
|
-
g_hash_table_foreach(
|
225
|
+
g_hash_table_foreach(endpoints->table, g_hash_table_each_intersection_free_endpoint, (gpointer) my_args);
|
311
226
|
}
|
312
227
|
|
313
|
-
|
314
|
-
|
315
|
-
|
228
|
+
void
|
229
|
+
line_set_each_intersection_free_endpoint(GeoSet *set,
|
230
|
+
GeoSet *origins,
|
231
|
+
GeoSet *endpoints,
|
232
|
+
gdouble max_distance,
|
233
|
+
geo_set_structure_handler handler,
|
234
|
+
gpointer user_data) {
|
316
235
|
Line *line = new_line_with_coordinates(0,0,0,0);
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
return rval;
|
236
|
+
GHashTable *seen_points = g_hash_table_new(g_direct_hash, g_direct_equal);
|
237
|
+
gpointer args[7] = { endpoints, &max_distance, line, set, handler, user_data, seen_points };
|
238
|
+
g_hash_table_foreach(origins->table, g_hash_table_each_intersection_free_endpoint_for_point, args);
|
239
|
+
line_free(line);
|
240
|
+
g_hash_table_destroy(seen_points);
|
323
241
|
}
|
324
242
|
|
325
243
|
static gpointer
|
@@ -340,8 +258,12 @@ static gint
|
|
340
258
|
line_set_n_intersections_with_line(GeoSet *set, Line *line) {
|
341
259
|
gint rval = 0;
|
342
260
|
gpointer args[2] = { &rval, line };
|
343
|
-
|
344
|
-
|
261
|
+
if (set->indexed) {
|
262
|
+
LINE_SET_REINDEX(set);
|
263
|
+
geo_set_each_structure_having_common_segment_id_with_line_until(set, line, line_set_count_intersections, args);
|
264
|
+
} else {
|
265
|
+
geo_set_each_structure_until(set, line_set_count_intersections, args);
|
266
|
+
}
|
345
267
|
return rval;
|
346
268
|
}
|
347
269
|
|
@@ -355,22 +277,6 @@ rb_line_set_n_intersections(VALUE self, VALUE line) {
|
|
355
277
|
return INT2NUM(line_set_n_intersections_with_line(me, l));
|
356
278
|
}
|
357
279
|
|
358
|
-
static void
|
359
|
-
g_hash_table_each_intersection(gpointer key, gpointer value, gpointer user_data) {
|
360
|
-
gpointer *args = (gpointer *) user_data;
|
361
|
-
Intersection *intersection = line_intersection((Line *) key, (Line *) args[0]);
|
362
|
-
if (intersection != NULL) {
|
363
|
-
((GFunc) args[1])(intersection, args[2]);
|
364
|
-
free_intersection(intersection);
|
365
|
-
}
|
366
|
-
}
|
367
|
-
|
368
|
-
void
|
369
|
-
line_set_each_intersection(GeoSet *set, Line *line, GFunc func, gpointer user_data) {
|
370
|
-
gpointer args[3] = { line, func, user_data };
|
371
|
-
g_hash_table_foreach(set->table, g_hash_table_each_intersection, args);
|
372
|
-
}
|
373
|
-
|
374
280
|
static gpointer
|
375
281
|
line_set_collect_intersections_in_rb_ary(GeoSet *set, gpointer segment_line_gp, gpointer user_data) {
|
376
282
|
gpointer *args = (gpointer *) user_data;
|
@@ -388,8 +294,12 @@ static VALUE
|
|
388
294
|
line_set_intersections(GeoSet *set, Line *line) {
|
389
295
|
VALUE rval = rb_ary_new();
|
390
296
|
gpointer args[2] = { line, &rval };
|
391
|
-
|
392
|
-
|
297
|
+
if (set->indexed) {
|
298
|
+
LINE_SET_REINDEX(set);
|
299
|
+
geo_set_each_structure_having_common_segment_id_with_line_until(set, line, line_set_collect_intersections_in_rb_ary, args);
|
300
|
+
} else {
|
301
|
+
geo_set_each_structure_until(set, line_set_collect_intersections_in_rb_ary, args);
|
302
|
+
}
|
393
303
|
return rval;
|
394
304
|
}
|
395
305
|
|
@@ -422,7 +332,7 @@ rb_line_set_intersection_free_endpoints(int argc, VALUE *argv, VALUE self) {
|
|
422
332
|
endpoints = argv[1];
|
423
333
|
max_distance = NUM2DBL(argv[2]);
|
424
334
|
} else {
|
425
|
-
rb_raise(rb_eTypeError, "Arguments to %s#intersection_free_endpoints have to be (Geo::Point | Geo::PointSet, Geo::PointSet [, Number])");
|
335
|
+
rb_raise(rb_eTypeError, "Arguments to %s#intersection_free_endpoints have to be (Geo::Point | Geo::PointSet, Geo::PointSet [, Number])", rb_obj_classname(self));
|
426
336
|
}
|
427
337
|
if (POINT_P(origins)) {
|
428
338
|
ops = new_geo_set();
|
@@ -433,12 +343,13 @@ rb_line_set_intersection_free_endpoints(int argc, VALUE *argv, VALUE self) {
|
|
433
343
|
} else if (POINT_SET_P(origins)) {
|
434
344
|
GEO_SET(origins, ops);
|
435
345
|
} else {
|
436
|
-
rb_raise(rb_eTypeError, "Arguments to %s#intersection_free_endpoints have to be (Geo::Point | Geo::PointSet, Geo::PointSet [, Number])");
|
346
|
+
rb_raise(rb_eTypeError, "Arguments to %s#intersection_free_endpoints have to be (Geo::Point | Geo::PointSet, Geo::PointSet [, Number])", rb_obj_classname(self));
|
437
347
|
}
|
438
348
|
CHECK_POINT_SET(endpoints);
|
439
349
|
GEO_SET(self, me);
|
440
350
|
GEO_SET(endpoints, eps);
|
441
|
-
rval =
|
351
|
+
rval = rb_ary_new();
|
352
|
+
line_set_each_intersection_free_endpoint(me, ops, eps, max_distance, line_set_insert_point_into_rb_ary, &rval);
|
442
353
|
if (created_ops)
|
443
354
|
geo_set_free(ops);
|
444
355
|
return rval;
|
@@ -514,6 +425,9 @@ geo_set_each_segment_id_of_intersection_until(GeoSet *set, Line *segment_line, g
|
|
514
425
|
if ((intersection = line_intersection(line, segment_line)) != NULL) {
|
515
426
|
if (intersection->type == itPOINT) {
|
516
427
|
rval = geo_set_each_segment_id_for_point_until(set, intersection->point, seen_segment_ids, handler, handler_args);
|
428
|
+
} else {
|
429
|
+
rval = geo_set_each_segment_id_for_point_until(set, intersection->line->p1, seen_segment_ids, handler, handler_args);
|
430
|
+
rval = geo_set_each_segment_id_for_point_until(set, intersection->line->p2, seen_segment_ids, handler, handler_args);
|
517
431
|
}
|
518
432
|
free_intersection(intersection);
|
519
433
|
}
|
@@ -611,3 +525,7 @@ rb_line_set_reindex(VALUE self) {
|
|
611
525
|
return GBOOL2RB(line_set_reindex(me));
|
612
526
|
}
|
613
527
|
|
528
|
+
void
|
529
|
+
init_line_set_o() {
|
530
|
+
}
|
531
|
+
|
data/ext/line_set.h
CHANGED
@@ -19,12 +19,13 @@
|
|
19
19
|
#ifndef LINE_SET_H
|
20
20
|
#define LINE_SET_H
|
21
21
|
|
22
|
-
#include
|
22
|
+
#include <common.h>
|
23
23
|
|
24
24
|
extern VALUE rb_line_set;
|
25
25
|
|
26
|
-
#define RB_LINE_SET(line_set_pointer,klass) Data_Wrap_Struct(klass, line_set_mark, geo_set_free, (line_set_pointer))
|
27
|
-
#define LINE_SET_REINDEX(set) if (set->index_dirty) line_set_reindex(set)
|
26
|
+
#define RB_LINE_SET(line_set_pointer,klass) ((line_set_pointer)->rbGeoSet = Data_Wrap_Struct(klass, line_set_mark, geo_set_free, (line_set_pointer)))
|
27
|
+
#define LINE_SET_REINDEX(set) if (set->index_dirty && set->indexed) line_set_reindex(set)
|
28
|
+
#define LINE_SET_P(l) (!NIL_P((l)) && rb_is_a((l), rb_line_set))
|
28
29
|
|
29
30
|
typedef gboolean
|
30
31
|
(*line_set_line_handler)(GeoSet *set, Line *line, gpointer user_data);
|
@@ -77,9 +78,6 @@ g_hash_table_clone_line_value_into_rb_value(gpointer key, gpointer value, gpoint
|
|
77
78
|
VALUE
|
78
79
|
rb_line_set_segment_lines(VALUE self, VALUE line);
|
79
80
|
|
80
|
-
void
|
81
|
-
line_set_each_intersection(GeoSet *set, Line *line, GFunc func, gpointer user_data);
|
82
|
-
|
83
81
|
VALUE
|
84
82
|
rb_line_set_structures_in_segment(VALUE self, VALUE x, VALUE y);
|
85
83
|
|
@@ -101,4 +99,15 @@ geo_set_each_structure_having_common_segment_id_with_line_until(GeoSet *set,
|
|
101
99
|
geo_set_structure_handler handler,
|
102
100
|
gpointer user_data);
|
103
101
|
|
102
|
+
void
|
103
|
+
line_set_slide_point(GeoSet *set, Line *line, gint ttl);
|
104
|
+
|
105
|
+
void
|
106
|
+
line_set_each_intersection_free_endpoint(GeoSet *set,
|
107
|
+
GeoSet *origins,
|
108
|
+
GeoSet *endpoints,
|
109
|
+
gdouble max_distance,
|
110
|
+
geo_set_structure_handler handler,
|
111
|
+
gpointer user_data);
|
112
|
+
|
104
113
|
#endif
|
data/ext/point.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_point;
|
22
22
|
|
@@ -81,13 +81,23 @@ rb_point_y(VALUE self) {
|
|
81
81
|
return rb_float_new(p->y);
|
82
82
|
}
|
83
83
|
|
84
|
+
gchar*
|
85
|
+
point_inspect(Point *p) {
|
86
|
+
gchar *rval = calloc(1024, sizeof(gchar));
|
87
|
+
snprintf(rval, 1024, "<%s:%p x=%f y=%f>", rb_obj_classname(p->rbPoint), p, p->x, p->y);
|
88
|
+
return rval;
|
89
|
+
}
|
90
|
+
|
84
91
|
VALUE
|
85
92
|
rb_point_inspect(VALUE self) {
|
86
|
-
gchar
|
93
|
+
gchar *str;
|
87
94
|
Point *p;
|
95
|
+
VALUE rval;
|
88
96
|
POINT(self, p);
|
89
|
-
|
90
|
-
|
97
|
+
str = point_inspect(p);
|
98
|
+
rval = rb_str_new2(str);
|
99
|
+
free(str);
|
100
|
+
return rval;
|
91
101
|
}
|
92
102
|
|
93
103
|
|
@@ -108,6 +118,11 @@ rb_point_abs(VALUE self) {
|
|
108
118
|
return rb_float_new(DISTANCE(&ORIGO, me));
|
109
119
|
}
|
110
120
|
|
121
|
+
gboolean
|
122
|
+
point_equals(gconstpointer p1, gconstpointer p2) {
|
123
|
+
return POINT_EQUALS(p1, p2);
|
124
|
+
}
|
125
|
+
|
111
126
|
VALUE
|
112
127
|
rb_point_equals(VALUE self, VALUE o) {
|
113
128
|
if (!POINT_P(o)) {
|
@@ -280,3 +295,12 @@ rb_point_minus(VALUE self, VALUE p) {
|
|
280
295
|
return RB_POINT(rval, CLASS(self));
|
281
296
|
}
|
282
297
|
|
298
|
+
guint
|
299
|
+
point_hash(gconstpointer p) {
|
300
|
+
Point *point = (Point *) p;
|
301
|
+
return (guint) (point->x + point->y);
|
302
|
+
}
|
303
|
+
|
304
|
+
void
|
305
|
+
init_point_o() {
|
306
|
+
}
|
data/ext/point.h
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
#ifndef POINT_H
|
20
20
|
#define POINT_H
|
21
21
|
|
22
|
-
#include
|
22
|
+
#include <common.h>
|
23
23
|
|
24
24
|
extern VALUE rb_point;
|
25
25
|
|
@@ -51,10 +51,10 @@ extern VALUE rb_point;
|
|
51
51
|
: \
|
52
52
|
M_PI)))
|
53
53
|
|
54
|
-
#define POINT_EQUALS(p1,p2) (DBL_EQL((p1)->x, (p2)->x) && DBL_EQL((p1)->y, (p2)->y))
|
54
|
+
#define POINT_EQUALS(p1,p2) (DBL_EQL(((Point *) (p1))->x, ((Point *) (p2))->x) && DBL_EQL(((Point *) (p1))->y, ((Point *) (p2))->y))
|
55
55
|
#define POINT_DOT(p1,p2) ((p1)->x * (p2)->x + (p1)->y * (p2)->y)
|
56
56
|
#define POINT_P(p) (!NIL_P((p)) && rb_is_a((p), rb_point))
|
57
|
-
#define CHECK_POINT(p) if (!POINT_P((p))) rb_raise(rb_eTypeError, "Expected
|
57
|
+
#define CHECK_POINT(p) if (!POINT_P((p))) rb_raise(rb_eTypeError, "Expected Geo::Point!")
|
58
58
|
#define ZERO_LENGTH_P(p) ((p)->x == 0 && (p)->y == 0)
|
59
59
|
#define ZERO_LENGTH_CHECK(p) if (ZERO_LENGTH_P((p))) rb_raise(rb_eTypeError, "Expected something with length > 0!")
|
60
60
|
#define ZERO_DISTANCE_P(p1,p2) ((p1)->x == (p2)->x && ((p1)->y == (p2)->y))
|
@@ -129,7 +129,14 @@ rb_point_minus(VALUE self, VALUE p);
|
|
129
129
|
gint
|
130
130
|
point_cmp(Point *me, Point *other);
|
131
131
|
|
132
|
+
gchar*
|
133
|
+
point_inspect(Point *p);
|
132
134
|
|
135
|
+
guint
|
136
|
+
point_hash(gconstpointer p);
|
137
|
+
|
138
|
+
gboolean
|
139
|
+
point_equals(gconstpointer a, gconstpointer b);
|
133
140
|
|
134
141
|
|
135
142
|
|
data/ext/point_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 rb_point_set;
|
22
22
|
|
@@ -69,16 +69,17 @@ rb_point_set_delete(VALUE self, VALUE point) {
|
|
69
69
|
return geo_set_delete(me, (gpointer) t, point);
|
70
70
|
}
|
71
71
|
|
72
|
-
static
|
73
|
-
g_hash_table_yield_point(
|
74
|
-
rb_yield(( (Point *)
|
72
|
+
static gpointer
|
73
|
+
g_hash_table_yield_point(GeoSet *set, gpointer structure, gpointer user_data) {
|
74
|
+
rb_yield(( (Point *) structure )->rbPoint);
|
75
|
+
return NULL;
|
75
76
|
}
|
76
77
|
|
77
78
|
VALUE
|
78
79
|
rb_point_set_each(VALUE self) {
|
79
80
|
GeoSet *set;
|
80
81
|
GEO_SET(self, set);
|
81
|
-
|
82
|
+
geo_set_each_structure_until(set, g_hash_table_yield_point, NULL);
|
82
83
|
return self;
|
83
84
|
}
|
84
85
|
|
@@ -108,3 +109,6 @@ geo_set_each_structure_having_common_segment_id_with_point_until(GeoSet *set,
|
|
108
109
|
return rval;
|
109
110
|
}
|
110
111
|
|
112
|
+
void
|
113
|
+
init_point_set_o() {
|
114
|
+
}
|
data/ext/point_set.h
CHANGED
@@ -19,14 +19,14 @@
|
|
19
19
|
#ifndef POINT_SET_H
|
20
20
|
#define POINT_SET_H
|
21
21
|
|
22
|
-
#include
|
22
|
+
#include <common.h>
|
23
23
|
|
24
24
|
extern VALUE rb_point_set;
|
25
25
|
|
26
|
-
#define RB_POINT_SET(point_set_pointer,klass) Data_Wrap_Struct(klass, point_set_mark, geo_set_free, (point_set_pointer))
|
26
|
+
#define RB_POINT_SET(point_set_pointer,klass) ((point_set_pointer)->rbGeoSet = Data_Wrap_Struct(klass, point_set_mark, geo_set_free, (point_set_pointer)))
|
27
27
|
|
28
28
|
#define POINT_SET_P(pl) (!NIL_P((pl)) && rb_is_a((pl), rb_point_set))
|
29
|
-
#define CHECK_POINT_SET(pl) if (!POINT_SET_P((pl))) rb_raise(rb_eTypeError, "Expected
|
29
|
+
#define CHECK_POINT_SET(pl) if (!POINT_SET_P((pl))) rb_raise(rb_eTypeError, "Expected Geo::PointSet!")
|
30
30
|
|
31
31
|
void
|
32
32
|
point_set_mark(GeoSet *set);
|
data/ext/triangle.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_triangle;
|
22
22
|
|
@@ -91,17 +91,33 @@ rb_triangle_initialize(int argc, VALUE *argv, VALUE self) {
|
|
91
91
|
return self;
|
92
92
|
}
|
93
93
|
|
94
|
+
gchar*
|
95
|
+
triangle_inspect(Triangle *t) {
|
96
|
+
gchar *rval = calloc(1024, sizeof(gchar));
|
97
|
+
gchar *p1 = point_inspect(t->p1);
|
98
|
+
gchar *p2 = point_inspect(t->p2);
|
99
|
+
gchar *p3 = point_inspect(t->p3);
|
100
|
+
snprintf(rval, 1024, "<%s:%p p1=%s p2=%s p3=%s>",
|
101
|
+
rb_obj_classname(t->rbTriangle), t,
|
102
|
+
p1,
|
103
|
+
p2,
|
104
|
+
p3);
|
105
|
+
free(p1);
|
106
|
+
free(p2);
|
107
|
+
free(p3);
|
108
|
+
return rval;
|
109
|
+
}
|
110
|
+
|
94
111
|
VALUE
|
95
112
|
rb_triangle_inspect(VALUE self) {
|
96
|
-
gchar rval[1024];
|
97
113
|
Triangle *t;
|
114
|
+
gchar *str;
|
115
|
+
VALUE rval;
|
98
116
|
TRIANGLE(self, t);
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
rb_obj_classname(t->p3->rbPoint), t->p3, t->p3->x, t->p3->y);
|
104
|
-
return rb_str_new2(rval);
|
117
|
+
str = triangle_inspect(t);
|
118
|
+
rval = rb_str_new2(str);
|
119
|
+
free(str);
|
120
|
+
return rval;
|
105
121
|
}
|
106
122
|
|
107
123
|
VALUE
|
@@ -181,15 +197,9 @@ triangle_contains(Triangle *triangle, Point *point) {
|
|
181
197
|
Line *l13p = LINE_PARALLEL(lines[1], triangle->p2);
|
182
198
|
Line *l23p = LINE_PARALLEL(lines[2], triangle->p1);
|
183
199
|
gint rval = POINT_BETWEEN_PARALLEL_LINES(lines[0], l12p, point) && POINT_BETWEEN_PARALLEL_LINES(lines[1], l13p, point) && POINT_BETWEEN_PARALLEL_LINES(lines[2], l23p, point);
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
free(l13p->p2);
|
188
|
-
free(l23p->p1);
|
189
|
-
free(l23p->p2);
|
190
|
-
free(l12p);
|
191
|
-
free(l13p);
|
192
|
-
free(l23p);
|
200
|
+
line_free(l12p);
|
201
|
+
line_free(l13p);
|
202
|
+
line_free(l23p);
|
193
203
|
free_triangle_lines(lines);
|
194
204
|
return rval;
|
195
205
|
}
|
@@ -354,6 +364,23 @@ triangle_area(Triangle *me) {
|
|
354
364
|
return sin(acos(LINE_DOT(l1,l2) / (length1 * length2))) * length1 * length2 / 2.0;
|
355
365
|
}
|
356
366
|
|
367
|
+
static gint
|
368
|
+
triangle_cmp(Triangle *me, Triangle *other) {
|
369
|
+
gint tmp;
|
370
|
+
gdouble my_area;
|
371
|
+
gdouble other_area;
|
372
|
+
my_area = triangle_area(me);
|
373
|
+
other_area = triangle_area(other);
|
374
|
+
if (!DBL_EQL(my_area, other_area))
|
375
|
+
return CMP(my_area, other_area);
|
376
|
+
else if ((tmp = point_cmp(me->p1, other->p1)) != 0)
|
377
|
+
return tmp;
|
378
|
+
else if ((tmp = point_cmp(me->p2, other->p2)) != 0)
|
379
|
+
return tmp;
|
380
|
+
else
|
381
|
+
return point_cmp(me->p3, other->p3);
|
382
|
+
}
|
383
|
+
|
357
384
|
VALUE
|
358
385
|
rb_triangle_cmp(VALUE self, VALUE o) {
|
359
386
|
if (!TRIANGLE_P(o)) {
|
@@ -361,18 +388,9 @@ rb_triangle_cmp(VALUE self, VALUE o) {
|
|
361
388
|
} else {
|
362
389
|
Triangle *me;
|
363
390
|
Triangle *other;
|
364
|
-
gdouble my_area;
|
365
|
-
gdouble other_area;
|
366
391
|
TRIANGLE(self, me);
|
367
392
|
TRIANGLE(o, other);
|
368
|
-
|
369
|
-
other_area = triangle_area(other);
|
370
|
-
if (my_area > other_area)
|
371
|
-
return INT2NUM(1);
|
372
|
-
else if (my_area < other_area)
|
373
|
-
return INT2NUM(-1);
|
374
|
-
else
|
375
|
-
return INT2NUM(0);
|
393
|
+
return INT2NUM(triangle_cmp(me, other));
|
376
394
|
}
|
377
395
|
}
|
378
396
|
|
@@ -427,3 +445,7 @@ VALUE
|
|
427
445
|
rb_triangle_from_gpointer(gpointer l) {
|
428
446
|
return ( (Triangle *) l)->rbTriangle;
|
429
447
|
}
|
448
|
+
|
449
|
+
void
|
450
|
+
init_triangle_o() {
|
451
|
+
}
|