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.
data/ext/line_set.c ADDED
@@ -0,0 +1,596 @@
1
+
2
+ #include "common.h"
3
+
4
+ VALUE rb_line_set;
5
+
6
+ static gboolean
7
+ line_set_reindex(GeoSet *line_set);
8
+
9
+ static void
10
+ g_hash_table_mark_line(gpointer key, gpointer value, gpointer user_data) {
11
+ rb_gc_mark( ( (Line *) key )->rbLine);
12
+ }
13
+
14
+ void
15
+ line_set_mark(GeoSet *set) {
16
+ g_hash_table_foreach(set->table, g_hash_table_mark_line, NULL);
17
+ }
18
+
19
+ VALUE
20
+ rb_line_set_alloc(VALUE class) {
21
+ GeoSet *set = new_geo_set();
22
+ return RB_LINE_SET(set, class);
23
+ }
24
+
25
+ VALUE
26
+ rb_line_set_insert(VALUE self, VALUE line) {
27
+ GeoSet *me;
28
+ Line *l;
29
+ CHECK_LINE(line);
30
+ GEO_SET(self, me);
31
+ LINE(line, l);
32
+ geo_set_insert(me, (gpointer ) l);
33
+ return self;
34
+ }
35
+
36
+ VALUE
37
+ rb_line_set_include(VALUE self, VALUE line) {
38
+ GeoSet *me;
39
+ Line *t;
40
+ CHECK_LINE(line);
41
+ LINE(line, t);
42
+ GEO_SET(self, me);
43
+ return GBOOL2RB(g_hash_table_lookup_extended(me->table, (gpointer) t, NULL, NULL));
44
+ }
45
+
46
+ VALUE
47
+ rb_line_set_delete(VALUE self, VALUE line) {
48
+ GeoSet *me;
49
+ Line *t;
50
+ CHECK_LINE(line);
51
+ GEO_SET(self, me);
52
+ LINE(line, t);
53
+ return geo_set_delete(me, (gpointer) t, line);
54
+ }
55
+
56
+ static void
57
+ g_hash_table_yield_line(gpointer key, gpointer value, gpointer user_data) {
58
+ rb_yield(( (Line *) key )->rbLine);
59
+ }
60
+
61
+ VALUE
62
+ rb_line_set_each(VALUE self) {
63
+ GeoSet *set;
64
+ GEO_SET(self, set);
65
+ geo_set_foreach(set, g_hash_table_yield_line);
66
+ return self;
67
+ }
68
+
69
+ static gpointer
70
+ line_set_intersection(GeoSet *set, gpointer set_line_gp, gpointer line_gp) {
71
+ Intersection *intersection;
72
+ Line *set_line = (Line *) set_line_gp;
73
+ Line *line = (Line *) line_gp;
74
+ if ((intersection = line_intersection(set_line, line)) != NULL)
75
+ return intersection;
76
+ return NULL;
77
+ }
78
+
79
+ gboolean
80
+ line_set_intersects(GeoSet *set, Line *line) {
81
+ Intersection *intersection;
82
+ LINE_SET_REINDEX(set);
83
+ intersection = geo_set_each_structure_having_common_segment_id_with_line_until(set, line, line_set_intersection, line);
84
+ if (intersection != NULL)
85
+ free_intersection(intersection);
86
+ return GBOOL2RB(intersection != NULL);
87
+ }
88
+
89
+ VALUE
90
+ rb_line_set_intersects(VALUE self, VALUE l) {
91
+ GeoSet *set;
92
+ Line *line;
93
+ CHECK_LINE(l);
94
+ GEO_SET(self, set);
95
+ LINE(l, line);
96
+ if (line_set_intersects(set, line)) {
97
+ return Qtrue;
98
+ } else {
99
+ return Qfalse;
100
+ }
101
+ }
102
+
103
+ static gpointer
104
+ line_set_closest_intersection_in_segments(GeoSet *set, gpointer segment_line_gp, gpointer user_data) {
105
+ gpointer *args = (gpointer *) user_data;
106
+ gdouble *closest_distance = (gdouble *) args[0];
107
+ Intersection **closest_intersection = (Intersection **) args[1];
108
+ Line *line = (Line *) args[2];
109
+ Line *segment_line = (Line *) segment_line_gp;
110
+ Intersection *this;
111
+ gdouble this_distance;
112
+ if ((this = line_intersection(segment_line, line)) != NULL) {
113
+ this_distance = INTERSECTION_DISTANCE(this, line->p1);
114
+ if (*closest_intersection == NULL) {
115
+ *closest_intersection = this;
116
+ *closest_distance = this_distance;
117
+ } else if (this_distance < *closest_distance) {
118
+ free_intersection(*closest_intersection);
119
+ *closest_intersection = this;
120
+ *closest_distance = this_distance;
121
+ } else {
122
+ free_intersection(this);
123
+ }
124
+ }
125
+ return NULL;
126
+ }
127
+
128
+ static Intersection*
129
+ line_set_closest_intersection(GeoSet *set, Line *line) {
130
+ Intersection *closest = NULL;
131
+ double closest_distance = -1;
132
+ gpointer args[3] = { &closest_distance, &closest, line };
133
+ LINE_SET_REINDEX(set);
134
+ geo_set_each_structure_having_common_segment_id_with_line_until(set, line, line_set_closest_intersection_in_segments, args);
135
+ return closest;
136
+ }
137
+
138
+ static void
139
+ line_set_slide(GeoSet *set, Line *line, gint ttl) {
140
+ ZERO_DISTANCE_CHECK(line->p1, line->p2);
141
+ Intersection *intersection = line_set_closest_intersection(set, line);
142
+ if (intersection != NULL) {
143
+ Point touchPoint;
144
+ Point destOne;
145
+ Point destTwo;
146
+ gdouble distanceLeft;
147
+ gdouble errorOne;
148
+ gdouble errorTwo;
149
+ /*
150
+ * The line we want to adjust against. If the intersection is with a line of zero
151
+ * length, then it is against ourselves. Otherwise with the intersecting line.
152
+ */
153
+ gboolean zero_intersection = intersection->type == itLINE && ZERO_DISTANCE_P(intersection->with->p1, intersection->with->p2);
154
+ gdouble adjustment_length = zero_intersection ? DISTANCE(line->p1, line->p2) : DISTANCE(intersection->with->p1, intersection->with->p2);
155
+ gdouble adjustment_xunit = zero_intersection ? \
156
+ (line->p2->x - line->p1->x) / adjustment_length : \
157
+ (intersection->with->p2->x - intersection->with->p1->x) / adjustment_length;
158
+ gdouble adjustment_yunit = zero_intersection ? \
159
+ (line->p2->y - line->p1->y) / adjustment_length : \
160
+ (intersection->with->p2->y - intersection->with->p1->y) / adjustment_length;
161
+ /*
162
+ * Calculate where we actually touch the other line.
163
+ */
164
+ if (intersection->type == itLINE) {
165
+ if (DISTANCE(intersection->line->p1, line->p1) <
166
+ DISTANCE(intersection->line->p2, line->p1)) {
167
+ touchPoint = *(intersection->line->p1);
168
+ } else {
169
+ touchPoint = *(intersection->line->p2);
170
+ }
171
+ } else {
172
+ touchPoint = *(intersection->point);
173
+ }
174
+ if (intersection->type == itPOINT) {
175
+ /*
176
+ * If we intersected with a point, move the touch point back towards the start point to not actually touch the other line.
177
+ */
178
+ if (line->p1->x > touchPoint.x)
179
+ touchPoint.x += MIN(1, line->p1->x - touchPoint.x);
180
+ if (line->p1->x < touchPoint.x)
181
+ touchPoint.x -= MIN(1, touchPoint.x - line->p1->x);
182
+ if (line->p1->y > touchPoint.y)
183
+ touchPoint.y += MIN(1, line->p1->y - touchPoint.y);
184
+ if (line->p1->y < touchPoint.y)
185
+ touchPoint.y -= MIN(1, touchPoint.y - line->p1->y);
186
+ } else {
187
+ /*
188
+ * If we intersected with a line, move perpendicular to our adjustment-line.
189
+ */
190
+ if (rand() < RAND_MAX / 2) {
191
+ touchPoint.x += adjustment_yunit;
192
+ touchPoint.y -= adjustment_xunit;
193
+ } else {
194
+ touchPoint.x -= adjustment_yunit;
195
+ touchPoint.y += adjustment_xunit;
196
+ }
197
+ }
198
+ /*
199
+ * Now that we wont use the intersection anymore, lets free it.
200
+ */
201
+ free_intersection(intersection);
202
+ /*
203
+ * If the ttl is reached then we just set the line's p2 to the touchPoint.
204
+ */
205
+ if (ttl < 1) {
206
+ line->p2->x = touchPoint.x;
207
+ line->p2->y = touchPoint.y;
208
+ } else {
209
+ /*
210
+ * Otherwise we calculate two alternate destinations.
211
+ *
212
+ * If we intersected with a zero length line, then we just go ahead in our
213
+ * original direction, otherwise we follow the intersecting line.
214
+ *
215
+ */
216
+ destOne = touchPoint;
217
+ destTwo = touchPoint;
218
+ distanceLeft = DISTANCE(line->p1, line->p2) - DISTANCE(&touchPoint, line->p1);
219
+ if (zero_intersection) {
220
+ destOne.x += adjustment_xunit * distanceLeft;
221
+ destOne.y += adjustment_yunit * distanceLeft;
222
+ destTwo.x += adjustment_xunit * distanceLeft;
223
+ destTwo.y += adjustment_yunit * distanceLeft;
224
+ } else {
225
+ destOne.x += adjustment_xunit * distanceLeft;
226
+ destOne.y += adjustment_yunit * distanceLeft;
227
+ destTwo.x -= adjustment_xunit * distanceLeft;
228
+ destTwo.y -= adjustment_yunit * distanceLeft;
229
+ }
230
+ /*
231
+ * And select the one with the least error.
232
+ */
233
+ errorOne = DISTANCE(line->p2, &destOne);
234
+ errorTwo = DISTANCE(line->p2, &destTwo);
235
+ if (DBL_EQL(errorOne, errorTwo)) {
236
+ line->p2->x = touchPoint.x;
237
+ line->p2->y = touchPoint.y;
238
+ } else {
239
+ if (errorOne < errorTwo) {
240
+ line->p2->x = destOne.x;
241
+ line->p2->y = destOne.y;
242
+ } else if (errorOne > errorTwo) {
243
+ line->p2->x = destTwo.x;
244
+ line->p2->y = destTwo.y;
245
+ }
246
+ line->p1->x = touchPoint.x;
247
+ line->p1->y = touchPoint.y;
248
+ /*
249
+ * And slide along, in case something else gets in the way.
250
+ */
251
+ line_set_slide(set, line, ttl - 1);
252
+ }
253
+ }
254
+ }
255
+ }
256
+
257
+ VALUE
258
+ rb_line_set_slide(VALUE self, VALUE l) {
259
+ GeoSet *set;
260
+ Line *line;
261
+ CHECK_LINE(l);
262
+ GEO_SET(self, set);
263
+ LINE(l, line);
264
+ line_set_slide(set, line, 3);
265
+ return line->p2->rbPoint;
266
+ }
267
+
268
+ static void
269
+ g_hash_table_intersection_free_endpoint(gpointer key, gpointer data, gpointer user_data) {
270
+ gpointer *arg_wrapper = (gpointer *) user_data;
271
+
272
+ gpointer *original_args = (gpointer *) arg_wrapper[0];
273
+ gdouble *max_distance = (gdouble *) original_args[1];
274
+ Line *tmpLine = (Line *) original_args[3];
275
+
276
+ *(tmpLine->p1) = *( (Point *) arg_wrapper[1] );
277
+ *(tmpLine->p2) = *( (Point *) key);
278
+
279
+ if (*max_distance < 0 || DISTANCE(tmpLine->p1, tmpLine->p2) < *max_distance) {
280
+ if (!line_set_intersects((GeoSet *) original_args[4], tmpLine)) {
281
+ rb_ary_push(*( (VALUE *) original_args[2] ), ( (Point *) key )->rbPoint);
282
+ }
283
+ }
284
+ }
285
+
286
+ static void
287
+ g_hash_table_intersection_free_endpoints(gpointer key, gpointer data, gpointer user_data) {
288
+ gpointer my_args[2];
289
+ gpointer *given_args = (gpointer *) user_data;
290
+ GeoSet *table = (GeoSet *) given_args[0];
291
+ my_args[0] = user_data;
292
+ my_args[1] = key;
293
+ g_hash_table_foreach(table->table, g_hash_table_intersection_free_endpoint, (gpointer) my_args);
294
+ }
295
+
296
+ static VALUE
297
+ line_set_intersection_free_endpoints(GeoSet *set, GeoSet *origins, GeoSet *endpoints, gdouble max_distance) {
298
+ VALUE rval = rb_ary_new();
299
+ Line *line = new_line_with_coordinates(0,0,0,0);
300
+ gpointer args[5] = { endpoints, &max_distance, &rval, line, set };
301
+ g_hash_table_foreach(origins->table, g_hash_table_intersection_free_endpoints, args);
302
+ free(line->p1);
303
+ free(line->p2);
304
+ free(line);
305
+ return rval;
306
+ }
307
+
308
+ static gpointer
309
+ line_set_count_intersections(GeoSet *set, gpointer segment_line_gp, gpointer user_data) {
310
+ gpointer *args = (gpointer *) user_data;
311
+ Line *segment_line = (Line *) segment_line_gp;
312
+ gint *rval = (gint *) args[0];
313
+ Line *line = (Line *) args[1];
314
+ Intersection *intersection = line_intersection(line, segment_line);
315
+ if (intersection != NULL) {
316
+ free_intersection(intersection);
317
+ (*rval)++;
318
+ }
319
+ return NULL;
320
+ }
321
+
322
+ static gint
323
+ line_set_n_intersections_with_line(GeoSet *set, Line *line) {
324
+ gint rval = 0;
325
+ gpointer args[2] = { &rval, line };
326
+ LINE_SET_REINDEX(set);
327
+ geo_set_each_structure_having_common_segment_id_with_line_until(set, line, line_set_count_intersections, args);
328
+ return rval;
329
+ }
330
+
331
+ VALUE
332
+ rb_line_set_n_intersections(VALUE self, VALUE line) {
333
+ GeoSet *me;
334
+ Line *l;
335
+ CHECK_LINE(line);
336
+ GEO_SET(self, me);
337
+ LINE(line, l);
338
+ return INT2NUM(line_set_n_intersections_with_line(me, l));
339
+ }
340
+
341
+ static void
342
+ g_hash_table_each_intersection(gpointer key, gpointer value, gpointer user_data) {
343
+ gpointer *args = (gpointer *) user_data;
344
+ Intersection *intersection = line_intersection((Line *) key, (Line *) args[0]);
345
+ if (intersection != NULL) {
346
+ ((GFunc) args[1])(intersection, args[2]);
347
+ free_intersection(intersection);
348
+ }
349
+ }
350
+
351
+ void
352
+ line_set_each_intersection(GeoSet *set, Line *line, GFunc func, gpointer user_data) {
353
+ gpointer args[3] = { line, func, user_data };
354
+ g_hash_table_foreach(set->table, g_hash_table_each_intersection, args);
355
+ }
356
+
357
+ static gpointer
358
+ line_set_collect_intersections_in_rb_ary(GeoSet *set, gpointer segment_line_gp, gpointer user_data) {
359
+ gpointer *args = (gpointer *) user_data;
360
+ Line *segment_line = (Line *) segment_line_gp;
361
+ Line *line = (Line *) args[0];
362
+ VALUE *rval = (VALUE *) args[1];
363
+ Intersection *intersection = line_intersection(segment_line, line);
364
+ if (intersection != NULL) {
365
+ rb_ary_push(*rval, rb_ary_new3(2, rb_intersection(intersection, line->p1), intersection->with->rbLine));
366
+ }
367
+ return NULL;
368
+ }
369
+
370
+ static VALUE
371
+ line_set_intersections(GeoSet *set, Line *line) {
372
+ VALUE rval = rb_ary_new();
373
+ gpointer args[2] = { line, &rval };
374
+ LINE_SET_REINDEX(set);
375
+ geo_set_each_structure_having_common_segment_id_with_line_until(set, line, line_set_collect_intersections_in_rb_ary, args);
376
+ return rval;
377
+ }
378
+
379
+ VALUE
380
+ rb_line_set_intersections(VALUE self, VALUE l) {
381
+ GeoSet *me;
382
+ Line *line;
383
+ CHECK_LINE(l);
384
+ GEO_SET(self, me);
385
+ LINE(l, line);
386
+ return line_set_intersections(me, line);
387
+ }
388
+
389
+ VALUE
390
+ rb_line_set_intersection_free_endpoints(int argc, VALUE *argv, VALUE self) {
391
+ GeoSet *me;
392
+ GeoSet *ops;
393
+ GeoSet *eps;
394
+ VALUE origins;
395
+ VALUE endpoints;
396
+ VALUE rval;
397
+ gdouble max_distance;
398
+ gboolean created_ops = FALSE;
399
+ if (argc == 2) {
400
+ origins = argv[0];
401
+ endpoints = argv[1];
402
+ max_distance = -1;
403
+ } else if (argc == 3) {
404
+ origins = argv[0];
405
+ endpoints = argv[1];
406
+ max_distance = NUM2DBL(argv[2]);
407
+ } else {
408
+ rb_raise(rb_eTypeError, "Arguments to %s#intersection_free_endpoints have to be (Geo::Point | Geo::PointSet, Geo::PointSet [, Number])");
409
+ }
410
+ if (POINT_P(origins)) {
411
+ ops = new_geo_set();
412
+ Point *p;
413
+ POINT(origins, p);
414
+ geo_set_insert(ops, p);
415
+ created_ops = TRUE;
416
+ } else if (POINT_SET_P(origins)) {
417
+ GEO_SET(origins, ops);
418
+ } else {
419
+ rb_raise(rb_eTypeError, "Arguments to %s#intersection_free_endpoints have to be (Geo::Point | Geo::PointSet, Geo::PointSet [, Number])");
420
+ }
421
+ CHECK_POINT_SET(endpoints);
422
+ GEO_SET(self, me);
423
+ GEO_SET(endpoints, eps);
424
+ rval = line_set_intersection_free_endpoints(me, ops, eps, max_distance);
425
+ if (created_ops)
426
+ geo_set_free(ops);
427
+ return rval;
428
+ }
429
+
430
+ VALUE
431
+ rb_line_set_closest_intersection(VALUE self, VALUE l) {
432
+ GeoSet *set;
433
+ Line *line;
434
+ Line *with;
435
+ Intersection *intersection;
436
+ VALUE rval;
437
+ CHECK_LINE(l);
438
+ GEO_SET(self, set);
439
+ LINE(l, line);
440
+ if ((intersection = line_set_closest_intersection(set, line)) != NULL) {
441
+ with = intersection->with;
442
+ rval = rb_ary_new3(2, rb_intersection(intersection, line->p1), with->rbLine);
443
+ } else {
444
+ rval = Qnil;
445
+ }
446
+ return rval;
447
+ }
448
+
449
+ VALUE
450
+ rb_line_set_clone(VALUE self) {
451
+ GeoSet *me;
452
+ GEO_SET(self, me);
453
+ return RB_LINE_SET(geo_set_clone(me), CLASS(self));
454
+ }
455
+
456
+ VALUE
457
+ rb_line_set_structures_in_segment(VALUE self, VALUE x, VALUE y) {
458
+ return rb_geo_set_structures_in_segment(self, x, y, rb_line_from_gpointer);
459
+ }
460
+
461
+ void
462
+ g_hash_table_clone_line_value_into_rb_value(gpointer key, gpointer value, gpointer user_data) {
463
+ Line *l = (Line *) value;
464
+ Line *new_line = new_line_with_coordinates(l->p1->x, l->p1->y, l->p2->x, l->p2->y);
465
+ RB_POINT(new_line->p1, rb_point);
466
+ RB_POINT(new_line->p2, rb_point);
467
+ rb_ary_push(*( (VALUE *) user_data ), RB_LINE(new_line, rb_line));
468
+ }
469
+
470
+ /*
471
+ * Below is the hell you have to go through to get the segment index to work or line sets.
472
+ */
473
+
474
+ static void
475
+ g_hash_table_call_handle_bounds(gpointer key, gpointer value, gpointer user_data) {
476
+ Point bottom_left;
477
+ Point top_right;
478
+ Line *line = (Line *) key;
479
+ LINE_BOUNDS(line, &bottom_left, &top_right);
480
+ geo_set_handle_bounds((GeoSet *) user_data, &bottom_left, &top_right);
481
+ }
482
+
483
+ static void
484
+ line_set_bound_finder(GeoSet *set) {
485
+ g_hash_table_foreach(set->table, g_hash_table_call_handle_bounds, set);
486
+ }
487
+
488
+ gpointer
489
+ geo_set_each_segment_id_of_intersection_until(GeoSet *set, Line *segment_line, gpointer user_data) {
490
+ gpointer *args = (gpointer *) user_data;
491
+ Line *line = (Line *) args[0];
492
+ geo_set_segment_id_handler handler = (geo_set_segment_id_handler) args[1];
493
+ gpointer handler_args = args[2];
494
+ GHashTable *seen_segment_ids = args[3];
495
+ Intersection *intersection;
496
+ gpointer rval = NULL;
497
+ if ((intersection = line_intersection(line, segment_line)) != NULL) {
498
+ if (intersection->type == itPOINT) {
499
+ rval = geo_set_each_segment_id_for_point_until(set, intersection->point, seen_segment_ids, handler, handler_args);
500
+ }
501
+ free_intersection(intersection);
502
+ }
503
+ return rval;
504
+ }
505
+
506
+ /*
507
+ * Will call handler with set, segment id and user_data for each segment id of line in set.
508
+ */
509
+ gpointer
510
+ geo_set_each_segment_id_of_line_until(GeoSet *set, Line *line, geo_set_segment_id_handler handler, gpointer user_data) {
511
+ Point bottom_left;
512
+ Point top_right;
513
+ GHashTable *seen_segment_ids = g_hash_table_new(g_direct_hash, g_direct_equal);
514
+ gpointer args[4] = { line, handler, user_data, seen_segment_ids };
515
+ gpointer rval = NULL;
516
+ LINE_BOUNDS(line, &bottom_left, &top_right);
517
+ rval = geo_set_each_segment_line_until(set, &bottom_left, &top_right, geo_set_each_segment_id_of_intersection_until, args);
518
+ if (rval == NULL)
519
+ rval = geo_set_each_segment_id_for_point_until(set, line->p1, seen_segment_ids, handler, user_data);
520
+ if (rval == NULL)
521
+ rval = geo_set_each_segment_id_for_point_until(set, line->p2, seen_segment_ids, handler, user_data);
522
+ g_hash_table_destroy(seen_segment_ids);
523
+ return rval;
524
+ }
525
+
526
+ gpointer
527
+ geo_set_each_structure_having_common_segment_id_with_line_until(GeoSet *set,
528
+ Line *line,
529
+ geo_set_structure_handler handler,
530
+ gpointer user_data) {
531
+ gpointer rval = NULL;
532
+ GHashTable *seen_structures = g_hash_table_new(g_direct_hash, g_direct_equal);
533
+ gpointer args[3] = { seen_structures, handler, user_data };
534
+ rval = geo_set_each_segment_id_of_line_until(set, line, geo_set_each_structure_in_segment_id_until, args);
535
+ g_hash_table_destroy(seen_structures);
536
+ return rval;
537
+ }
538
+
539
+ VALUE
540
+ rb_line_set_lines_with_common_segment_id(VALUE self, VALUE l) {
541
+ GeoSet *me;
542
+ Line *line;
543
+ VALUE rval;
544
+ gpointer args[2];
545
+ CHECK_LINE(l);
546
+ GEO_SET(self, me);
547
+ LINE(l, line);
548
+ LINE_SET_REINDEX(me);
549
+ rval = rb_ary_new();
550
+ args[0] = &rval;
551
+ args[1] = rb_line_from_gpointer;
552
+ geo_set_each_structure_having_common_segment_id_with_line_until(me, line, geo_set_insert_structure_into_rb_ary, args);
553
+ return rval;
554
+ }
555
+
556
+ static void
557
+ g_hash_table_each_segment_id_for_line(gpointer key, gpointer value, gpointer user_data) {
558
+ gpointer *args = (gpointer *) user_data;
559
+ geo_set_each_segment_id_of_line_until((GeoSet *) args[0],
560
+ (Line *) key,
561
+ (geo_set_segment_id_handler) args[1],
562
+ (Line *) key);
563
+ }
564
+
565
+ static void
566
+ line_set_segment_finder(GeoSet *set) {
567
+ gpointer args[2] = { set, geo_set_insert_into_segment };
568
+ g_hash_table_foreach(set->table, g_hash_table_each_segment_id_for_line, args);
569
+ }
570
+
571
+ static gboolean
572
+ line_set_reindex(GeoSet *line_set) {
573
+ return geo_set_reindex(line_set, line_set_bound_finder, line_set_segment_finder);
574
+ }
575
+
576
+ VALUE
577
+ rb_line_set_segment_ids_for_line(VALUE self, VALUE l) {
578
+ GeoSet *me;
579
+ Line *line;
580
+ VALUE rval;
581
+ CHECK_LINE(l);
582
+ GEO_SET(self, me);
583
+ LINE(l, line);
584
+ LINE_SET_REINDEX(me);
585
+ rval = rb_ary_new();
586
+ geo_set_each_segment_id_of_line_until(me, line, geo_set_insert_segment_id_into_rb_ary, &rval);
587
+ return rval;
588
+ }
589
+
590
+ VALUE
591
+ rb_line_set_reindex(VALUE self) {
592
+ GeoSet *me;
593
+ GEO_SET(self, me);
594
+ return GBOOL2RB(line_set_reindex(me));
595
+ }
596
+
data/ext/line_set.h ADDED
@@ -0,0 +1,87 @@
1
+
2
+ #ifndef LINE_SET_H
3
+ #define LINE_SET_H
4
+
5
+ #include "common.h"
6
+
7
+ extern VALUE rb_line_set;
8
+
9
+ #define RB_LINE_SET(line_set_pointer,klass) Data_Wrap_Struct(klass, line_set_mark, geo_set_free, (line_set_pointer))
10
+ #define LINE_SET_REINDEX(set) if (set->index_dirty) line_set_reindex(set)
11
+
12
+ typedef gboolean
13
+ (*line_set_line_handler)(GeoSet *set, Line *line, gpointer user_data);
14
+
15
+ void
16
+ line_set_mark(GeoSet *set);
17
+
18
+ VALUE
19
+ rb_line_set_alloc(VALUE class);
20
+
21
+ VALUE
22
+ rb_line_set_insert(VALUE self, VALUE line);
23
+
24
+ VALUE
25
+ rb_line_set_include(VALUE self, VALUE line);
26
+
27
+ VALUE
28
+ rb_line_set_delete(VALUE self, VALUE line);
29
+
30
+ VALUE
31
+ rb_line_set_each(VALUE self);
32
+
33
+ VALUE
34
+ rb_line_set_intersects(VALUE self, VALUE l);
35
+
36
+ VALUE
37
+ rb_line_set_slide(VALUE self, VALUE l);
38
+
39
+ VALUE
40
+ rb_line_set_intersections(VALUE self, VALUE l);
41
+
42
+ VALUE
43
+ rb_line_set_intersection_free_endpoints(int argc, VALUE *argv, VALUE self);
44
+
45
+ VALUE
46
+ rb_line_set_closest_intersection(VALUE self, VALUE l);
47
+
48
+ VALUE
49
+ rb_line_set_clone(VALUE self);
50
+
51
+ VALUE
52
+ rb_line_set_n_intersections(VALUE self, VALUE line);
53
+
54
+ VALUE
55
+ rb_line_set_reindex(VALUE self);
56
+
57
+ void
58
+ g_hash_table_clone_line_value_into_rb_value(gpointer key, gpointer value, gpointer user_data);
59
+
60
+ VALUE
61
+ rb_line_set_segment_lines(VALUE self, VALUE line);
62
+
63
+ void
64
+ line_set_each_intersection(GeoSet *set, Line *line, GFunc func, gpointer user_data);
65
+
66
+ VALUE
67
+ rb_line_set_structures_in_segment(VALUE self, VALUE x, VALUE y);
68
+
69
+ VALUE
70
+ rb_line_set_segment_ids_for_line(VALUE self, VALUE l);
71
+
72
+ VALUE
73
+ rb_line_set_lines_with_common_segment_id(VALUE self, VALUE l);
74
+
75
+ gpointer
76
+ geo_set_each_segment_id_of_intersection_until(GeoSet *set, Line *segment_line, gpointer user_data);
77
+
78
+ gpointer
79
+ geo_set_each_segment_id_of_line_until(GeoSet *set, Line *line, geo_set_segment_id_handler handler, gpointer user_data);
80
+
81
+ gpointer
82
+ geo_set_each_structure_having_common_segment_id_with_line_until(GeoSet *set,
83
+ Line *line,
84
+ geo_set_structure_handler handler,
85
+ gpointer user_data);
86
+
87
+ #endif