-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfunctions.bi
1620 lines (1269 loc) · 43.5 KB
/
functions.bi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
'functions declarations
declare function _abtp (x1 as integer,y1 as integer,x2 as integer,y2 as integer) as single
declare function add_point (head as point_proto ptr ptr, x as single, y as single) as point_proto ptr
declare function average_color (rgb_values() as Ulong) as Ulong
declare function calculate_centroid (head as point_proto ptr) as point_proto
declare function dist (x1 as single, y1 as single, x2 as single, y2 as single) as single
declare function find_nearest_point (array() as polygon_proto, user_mouse as mouse_proto, view_area as view_area_proto) as temp_point_proto
declare function get_pixel_color (x as integer, y as integer, img_name as any ptr) as ULong
'fbGFXAddon by D.J. Peters
declare function ImageScale (byval s as fb.Image ptr, _
byval w as integer, _
byval h as integer) as fb.Image ptr
declare function pDistance (x as single, y as single, _
x1 as single, y1 as single, _
x2 as single, y2 as single,_
view_area as view_area_proto) as temp_point_proto
'converts a string of RGB values in only one variable containing
'Unsigned Lonv values (32 bit platform independent)
declare function string_to_rgb (rgb_input as string) as ULong
'Bmp load by noop
declare function Load_bmp( ByRef filename As Const String ) As Any Ptr
declare function calculate_bounds (head as point_proto ptr, centroid as point_proto) as segment_proto
declare function is_overlap( Ax1 as single, Ay1 as single, _
Ax2 as single, Ay2 as single, _
Bx1 as single, By1 as single, _
Bx2 as single, By2 as single ) as boolean
declare function get_average_color ( head as point_proto ptr, _
view_area as view_area_proto, _
img_name as any ptr) as ULong
'subs declarations______________________________________________________
declare sub add_polygon (array() as polygon_proto)
declare sub draw_centroid (centroid as point_proto, stroke_color as Ulong, view_area as view_area_proto)
declare sub draw_list_points (head as point_proto ptr, x as integer, y as integer)
declare Sub export_as_svg (array() as polygon_proto, file_name as string)
declare Sub fill_polygon (head as point_proto ptr, ByVal c As ULong, view_area as view_area_proto, settings as settings_proto)
declare sub draw_highlighted_points(head as point_proto ptr, ByVal c As ULong, w as Ulong)
declare sub keyboard_listener (input_mode as proto_input_mode ptr, _
user_mouse as mouse_proto, _
view_area as view_area_proto ptr, _
settings as settings_proto ptr, _
key() as key_proto)
declare sub mouse_listener (user_mouse as mouse_proto ptr, _
view_area as view_area_proto ptr)
declare Sub pop_values_in_array (array() as integer,_
eval as integer)
declare Sub delete_all_points (head as point_proto ptr)
declare sub quicksort(array() as temp_point_proto, _left as integer, _right as integer )
declare Sub draw_vertices(head as point_proto ptr, ByVal c As ULong, view_area as view_area_proto)
declare sub reset_key_status(key as key_proto ptr)
declare sub save_as_lpe_file(array() as polygon_proto, file_name as string)
declare sub draw_wireframe (head as point_proto ptr, ByVal c As ULong, _
view_area as view_area_proto, _
settings as settings_proto, _
close_path as boolean)
declare sub pop_polygon(array() as polygon_proto, polygon as polygon_proto)
declare sub load_lpe_file(filename as string, polygons() as polygon_proto)
declare sub create_random_polygons (polygons() as polygon_proto,_
max_polygons as integer, _
max_nodes as integer, _
artwork_max_w as integer, _
artwork_max_h as integer,_
view_area as view_area_proto, _
img_name as any ptr)
declare sub draw_bounds (bounds as segment_proto, _
view_area as view_area_proto)
declare sub load_whole_txt_file (Byref fn As String, filearr() As String)
declare sub draw_button (x as integer, y as integer, w as integer,_
h as integer, label as string,_
is_selected as boolean)
declare sub draw_bottom_info ( console_message as string, _
view_area as view_area_proto, _
user_mouse as mouse_proto, _
settings as settings_proto, _
timer_begin as double, _
on_screen_help() as string)
declare sub load_icon_set ( bmp() as Ulong ptr, w as integer, _
h as integer, cols as integer, rows as integer, _
Byref bmp_path as string)
declare sub draw_mouse_pointer ( x as integer, y as integer, _
lbtn_pressed as boolean, _
is_snap_point_available as boolean, _
input_mode as proto_input_mode, _
icon_set() as Ulong ptr)
declare sub mark_selected_nodes ( x1 as integer, y1 as integer, _
x2 as integer, y2 as integer, _
array() as polygon_proto)
declare sub unmark_all_nodes ( array() as polygon_proto)
declare sub move_selected_node(x_offset as integer, y_offset as integer, array() as polygon_proto)
declare function delete_selected_node (node as point_proto ptr) as point_proto ptr
declare function count_selected_nodes (head as point_proto ptr) as integer
declare sub get_selection_bounds (user_mouse as mouse_proto ptr)
'_______________________________________________________________________
'FUNCTIONS______________________________________________________________
function _abtp (x1 as integer,y1 as integer,x2 as integer,y2 as integer) as single
return -Atan2(y2-y1,x2-x1)
end function
function add_point(head as point_proto ptr ptr, x as single, y as single) as point_proto ptr
dim as point_proto ptr p = callocate(sizeof(point_proto))
p->x = x
p->y = y
p->is_selected = false
p->next_p = *head
*head = p
return p
end function
'Average color function:
'given an array of rgb colors values as argument
'returns the average color using the arithmetic mean
function average_color(rgb_values() as Ulong) as Ulong
dim as integer r, g, b, c, arraylen
arraylen = UBound(rgb_values) - LBound(rgb_values) + 1
r = 0 : g = 0 : b = 0
for c = Lbound(rgb_values) to Ubound(rgb_values)
'get & sum each r, g, b value
r += rgb_values(c) shr 16
g += rgb_values(c) shr 8 and &hFF
b += rgb_values(c) and &hFF
next c
r = r \ (arraylen)
g = g \ (arraylen)
b = b \ (arraylen)
return rgb(r,g,b)
end function
function calculate_centroid (head as point_proto ptr) as point_proto
'some part of this function is a
'translation from a C implementation by squeamish ossifrage
'https://stackoverflow.com/questions/19766485/how-to-calculate-centroid-of-polygon-in-c
dim centroid as point_proto
dim as single a, cx, cy, t
dim as integer i, i1
redim preserve x(0 to 0) as Long
redim preserve y(0 to 0) as Long
i = 0
while head <> NULL
if (head->next_p <> NULL) then
x(i) = head->x
y(i) = head->y
redim preserve x(0 to Ubound(x)+1)
redim preserve y(0 to Ubound(y)+1)
end if
head = head->next_p
i+=1
wend
'this is the translated part
'First calculate the polygon's signed area A
a = 0.0
i1 = 1
for i = 0 to (Ubound(x)-1) step 1
a += x(i) * y(i1) - x(i1) * y(i)
i1 = (i1 + 1) mod (Ubound(x))
next i
a *= 0.5
' Now calculate the centroid coordinates Cx and Cy */
cx = cy = 0.0
i1 = 1
for i = 0 to (Ubound(x)-1) step 1
t = x(i)*y(i1) - x(i1)*y(i)
cx += (x(i)+x(i1)) * t
cy += (y(i)+y(i1)) * t
i1 = (i1 + 1) mod (Ubound(x))
next i
cx = cx / (6.0 * a)
cy = cy / (6.0 * a)
centroid.x = cx
centroid.y = cy
return centroid
end function
function dist (x1 as single, y1 as single, x2 as single, y2 as single) as single
return Sqr(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)))
end function
function find_nearest_point (array() as polygon_proto, user_mouse as mouse_proto, view_area as view_area_proto) as temp_point_proto
dim as integer i, j, min_dist, temp_dist, k
dim as point_proto ptr head
'store all segments of all polygons in an array
'and find the distance of line to pointer for each
redim preserve segments(0 to 0) as segment_proto
redim preserve points(0 to 0) as temp_point_proto
dim close_point as point_proto
for j = 0 to Ubound(array) - 1
if (array(j).first_point) <> NULL then
head = array(j).first_point
close_point.x = head->x
close_point.y = head->y
else
continue for
end if
while head->next_p <> NULL
segments(i).x1 = head->x
segments(i).y1 = head->y
points(i).x = head->x
points(i).y = head->y
redim preserve points(0 to (Ubound(points)+1))
if (head->next_p->next_p <> NULL) then
segments(i).x2 = head->next_p->x
segments(i).y2 = head->next_p->y
else
'join last segment to the beginning of the path
segments(i).x2 = close_point.x
segments(i).y2 = close_point.y
end if
redim preserve segments(0 to (Ubound(segments)+1))
i+=1
head = head->next_p
wend
next j
redim preserve nearest_points(0 to (Ubound(segments)+1)) as temp_point_proto
for i = 0 to Ubound(nearest_points)-1
nearest_points(i) = pDistance (user_mouse.abs_x, user_mouse.abs_y, _
segments(i).x1, _
segments(i).y1, _
segments(i).x2, _
segments(i).y2, _
view_area)
next i
quicksort (nearest_points(), Lbound(nearest_points), Ubound(nearest_points))
for i = 0 to Ubound(points)-1
points(i).distance = dist(points(i).x, points(i).y, user_mouse.abs_x, user_mouse.abs_y)
next i
quicksort (points(), Lbound(points), Ubound(points))
if UBound(points) > 0 then
if (points(1).distance < MIN_SNAP_TO_SNAP_DIST) then
return points(1)
else
if UBound(nearest_points) > 0 then
return nearest_points(1)
else
return nearest_points(0)
end if
end if
end if
end function
function get_pixel_color (x as integer, y as integer, img_name as any ptr) as ULong
dim p as Uinteger
p = point(x,y, img_name)
return p
end function
'fbGFXAddon by D.J. Peters
function ImageScale(byval s as fb.Image ptr, _
byval w as integer, _
byval h as integer) as fb.Image ptr
#macro SCALELOOP()
for ty = 0 to t->height-1
' address of the row
pr=ps+(y shr 20)*sp
x=0 ' first column
for tx = 0 to t->width-1
*pt=pr[x shr 20]
pt+=1 ' next column
x+=xs ' add xstep value
next
pt+=tp ' next row
y+=ys ' add ystep value
next
#endmacro
' no source image
if s =0 then return 0
' source widh or height legal ?
if s->width <1 then return 0
if s->height<1 then return 0
' target min size ok ?
if w<2 then w=1
if h<2 then h=1
' create new scaled image
dim as fb.Image ptr t=ImageCreate(w,h,RGB(0,0,0))
' x and y steps in fixed point 12:20
dim as FIXED xs=&H100000*(s->width /t->width ) ' [x] [S]tep
dim as FIXED ys=&H100000*(s->height/t->height) ' [y] [S]tep
dim as integer x,y,ty,tx
select case as const s->bpp
case 1 ' color palette
dim as ubyte ptr ps=cptr(ubyte ptr,s)+32 ' [p]ixel [s]ource
dim as uinteger sp=s->pitch ' [s]ource [p]itch
dim as ubyte ptr pt=cptr(ubyte ptr,t)+32 ' [p]ixel [t]arget
dim as uinteger tp=t->pitch - t->width ' [t]arget [p]itch
dim as ubyte ptr pr ' [p]ointer [r]ow
SCALELOOP()
case 2 ' 15/16 bit
dim as ushort ptr ps=cptr(ushort ptr,s)+16
dim as uinteger sp=(s->pitch shr 1)
dim as ushort ptr pt=cptr(ushort ptr,t)+16
dim as uinteger tp=(t->pitch shr 1) - t->width
dim as ushort ptr pr
SCALELOOP()
case 4 ' 24/32 bit
dim as ulong ptr ps=cptr(uinteger ptr,s)+8
dim as uinteger sp=(s->pitch shr 2)
dim as ulong ptr pt=cptr(uinteger ptr,t)+8
dim as uinteger tp=(t->pitch shr 2) - t->width
dim as ulong ptr pr
SCALELOOP()
end select
return t
#undef SCALELOOP
end function
Function Load_bmp( ByRef filename As Const String ) As Any Ptr
'Bmp load by noop
'http://www.freebasic.net/forum/viewtopic.php?t=24586
Dim As Long filenum, bmpwidth, bmpheight
Dim As Any Ptr img
'' open BMP file
filenum = FreeFile()
If Open( filename For Binary Access Read As #filenum ) <> 0 Then Return NULL
'' retrieve BMP dimensions
Get #filenum, 19, bmpwidth
Get #filenum, 23, bmpheight
Close #filenum
'' create image with BMP dimensions
img = ImageCreate( bmpwidth, Abs(bmpheight) )
If img = NULL Then Return NULL
'' load BMP file into image buffer
If BLoad( filename, img ) <> 0 Then ImageDestroy( img ): Return NULL
Return img
End Function
'SUBS
sub add_polygon(array() as polygon_proto)
array(Ubound(array)).first_point = callocate(sizeof(point_proto))
redim preserve array(Lbound(array) to Ubound(array)+1)
end sub
sub draw_centroid(centroid as point_proto, stroke_color as Ulong, view_area as view_area_proto)
dim as integer x_offset, y_offset
x_offset = centroid.x * view_area.zoom + view_area.x
y_offset = centroid.y * view_area.zoom + view_area.y
line (x_offset - 2, y_offset)-step(4,0), stroke_color
line (x_offset, y_offset - 2)-step(0,4), stroke_color
end sub
Sub export_as_svg (array() as polygon_proto, file_name as string)
Dim i as integer
Dim head as point_proto ptr
Dim ff As UByte
ff = FreeFile
Open file_name for output As #ff
'SVG file header info
Print #ff, "<?xml version='1.0' standalone='no'?>"
Print #ff, "<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>"
Print #ff, "<svg version='1.1' xmlns='http://www.w3.org/2000/svg'>"
Print #ff, "<desc>" + APP_NAME + APP_VERSION + " - Export file</desc>"
for i = 0 to Ubound(array)-1
dim as Ubyte r, g, b
r = array(i).fill_color shr 16 and &hFF
g = array(i).fill_color shr 8 and &hFF
b = array(i).fill_color and &hFF
Print #ff, "<polygon fill='rgb(" + str(r) + "," + str(g) + "," + str(b) + ")' "
'hex(array(i).fill_color shr 16 and &hFF) + _
'hex(array(i).fill_color shr 8 and &hFF) +_
'hex(array(i).fill_color and &hFF) + "'"
Print #ff, "points='"
head = array(i).first_point
'ignore first one pointer values since it's only a link to data
while head->next_p <> NULL
Print #ff, str(head->x) + "," + str(head->y) + " "
head = head->next_p
wend
Print #ff, "' />"
next i
Print #ff, "</svg>"
Close #ff
end sub
Sub save_as_lpe_file(array() as polygon_proto, file_name as string)
Dim as integer i, j
dim as Ubyte r, g, b
Dim head as point_proto ptr
Dim ff As UByte
ff = FreeFile
Open file_name for output As #ff
for i = 0 to Ubound(array)-1
dim line_output as string
r = array(i).fill_color shr 16 'and &hFF
g = array(i).fill_color shr 8 and &hFF
b = array(i).fill_color and &hFF
'save RGB values in
'line_output = line_output + str(hex(array(i).fill_color shr 16 and &hFF)) + _
line_output = str(r) + "," + str(g) + "," + str(b) + "; "
'str(hex(array(i).fill_color shr 8 and &hFF)) +_
'str(hex(array(i).fill_color and &hFF)) + "; "
head = array(i).first_point
redim temp_array(0 to 0) as point_proto
'ignore first one pointer values since it's only a link to data
while head->next_p <> NULL
'Print #ff, str(head->x) + "," + str(head->y)
temp_array(Ubound(temp_array)).x = head->x
temp_array(Ubound(temp_array)).y = head->y
head = head->next_p
redim preserve temp_array(0 to Ubound(temp_array)+1) as point_proto
wend
for j = 0 to Ubound(temp_array) -1
line_output = line_output + str(temp_array(j).x) + "," + str(temp_array(j).y) + "; "
next j
Print #ff, line_output
next i
Close #ff
end sub
Sub draw_vertices(head as point_proto ptr, ByVal c As ULong, view_area as view_area_proto)
while head <> NULL
if (head->next_p <> NULL) then
'highlight the selected node
if head->is_selected then
circle (head->x*view_area.zoom + view_area.x , _
head->y*view_area.zoom + view_area.y ), 3, C_BLUE,,,,F
end if
circle (head->x*view_area.zoom + view_area.x , _
head->y*view_area.zoom + view_area.y), 2,C_WHITE,,,,F
end if
head = head->next_p
wend
End Sub
function calculate_bounds (head as point_proto ptr, centroid as point_proto) as segment_proto
dim bounds as segment_proto
dim i as integer
bounds.x1 = centroid.x
bounds.x2 = centroid.x
bounds.y1 = centroid.y
bounds.y2 = centroid.y
i = 0
while head <> NULL
if (head->next_p <> NULL) then
if head->x < bounds.x1 then bounds.x1 = head->x
if head->y < bounds.y1 then bounds.y1 = head->y
if head->x > bounds.x2 then bounds.x2 = head->x
if head->y > bounds.y2 then bounds.y2 = head->y
end if
head = head->next_p
i+=1
wend
return bounds
end function
Sub fill_polygon(head as point_proto ptr, ByVal c As ULong, view_area as view_area_proto, settings as settings_proto)
'translation of a c snippet by Angad
'source of c code:
'http://code-heaven.blogspot.it/2009/10/simple-c-program-for-scan-line-polygon.html
' Thanks to MrSwiss for the corrections on the below code for 64/32 compiler
redim preserve a(0 to 0, 0 to 1) as Long
Dim As Long i, j, k, dy, dx, x, y, temp
i = 0
while head <> NULL
if (head->next_p <> NULL) then
a(i, 0) = head->x*view_area.zoom + view_area.x
a(i, 1) = head->y*view_area.zoom + view_area.y
redim preserve a(0 to Ubound(a)+1, 0 to 1)
end if
head = head->next_p
i+=1
wend
Dim As Long xi(0 to Ubound(a, 1))
Dim As Single slope(0 to Ubound(a, 1))
'join first and last vertex
a(Ubound(a, 1), 0) = a(0, 0)
a(Ubound(a, 1), 1) = a(0, 1)
For i = 0 To Ubound(a, 1) - 1
dy = a(i+1, 1) - a(i, 1)
dx = a(i+1, 0) - a(i, 0)
If (dy = 0) Then slope(i) = 1.0
If (dx = 0) Then slope(i) = 0.0
If (dy <> 0) AndAlso (dx <> 0) Then slope(i) = dx / dy
Next i
For y = 0 to SCR_H - 1
k = 0
' using FB's short-cut operators (which C doesn't have!)
For i = 0 to Ubound(a, 1) - 1
If (a(i, 1) <= y AndAlso a(i+1, 1) > y) OrElse _
(a(i, 1) > y AndAlso a(i+1, 1) <= y) Then
xi(k) = CLng(a(i, 0) + slope(i) * (y - a(i, 1)))
k += 1
End If
Next i
For j = 0 to k - 2
'Arrange x-intersections in order
For i = 0 To k - 2
If (xi(i) > xi(i + 1)) Then
temp = xi(i)
xi(i) = xi(i + 1)
xi(i + 1) = temp
End If
Next i
Next j
'line filling
For i = 0 To k - 2 Step 2
Line (xi(i), y)-(xi(i + 1) + 1, y), c
Next i
Next y
End Sub
sub keyboard_listener( input_mode as proto_input_mode ptr, _
user_mouse as mouse_proto, _
view_area as view_area_proto ptr,_
settings as settings_proto ptr, _
key() as key_proto)
dim i as integer
'keyboard key released listener
for i = 0 to Ubound(key)-1
if multikey (key(i).code) then
key(i).is_down = true
else
key(i).is_down = false
end if
if (key(i).is_down = false) and (key(i).old_is_down = true) then
key(i).is_released = true
end if
next i
for i = 0 to Ubound(key)-1
if (key(i).is_released) then
select case key(i).code
'show / hide on screen help
case SC_F1
settings->is_help_visible = not settings->is_help_visible
view_area->refresh = true
reset_key_status(@key(i))
'show / hide debug info
case SC_D
settings->is_debug = not settings->is_debug
view_area->refresh = true
reset_key_status(@key(i))
'show / hide centroids of polygons
case SC_C
settings->is_centroid_visible = not settings->is_centroid_visible
view_area->refresh = true
reset_key_status(@key(i))
'show / hide wireframe
case SC_W
settings->is_wireframe_visible = not settings->is_wireframe_visible
view_area->refresh = true
reset_key_status(@key(i))
'show / hide bitmap
case SC_B
settings->is_bitmap_visible = not settings->is_bitmap_visible
view_area->refresh = true
reset_key_status(@key(i))
'show / hide alpha bitmap overlayed
case SC_X
settings->is_alpha_bitmap_visible = _
not settings->is_alpha_bitmap_visible
view_area->refresh = true
reset_key_status(@key(i))
'export as SVG
case SC_E
*input_mode = input_export_as_svg
reset_key_status(@key(i))
'save in a file
case SC_S
*input_mode = input_save_as_lpe_file
reset_key_status(@key(i))
'delete all
case SC_DELETE
if *input_mode = input_selection then
*input_mode = input_erase_polygon
elseif *input_mode = input_direct_selection then
*input_mode = input_delete_node
end if
view_area->refresh = true
reset_key_status(@key(i))
'show / hide vertices
case SC_Q
settings->is_vertex_visible = not settings->is_vertex_visible
view_area->refresh = true
reset_key_status(@key(i))
'selection mode
case SC_V
*input_mode = input_selection
reset_key_status(@key(i))
'pen tool
case SC_P
if (*input_mode <> input_add_polygon) then
*input_mode = input_add_polygon
end if
reset_key_status(@key(i))
'load lpe file
case SC_L
if (multikey(SC_CONTROL)) then
*input_mode = input_load_lpe_file
end if
reset_key_status(@key(i))
'create random polygons
case SC_R
if (multikey(SC_CONTROL)) then
*input_mode = input_create_random_polygons
end if
reset_key_status(@key(i))
'direct selection
case SC_A
*input_mode = input_direct_selection
reset_key_status(@key(i))
case SC_UP
'direct selection - node selected + UP key
if *input_mode = input_direct_selection then
*input_mode = input_move_node_up
end if
reset_key_status(@key(i))
case SC_DOWN
'direct selection - node selected + DOWN key
if *input_mode = input_direct_selection then
*input_mode = input_move_node_down
end if
reset_key_status(@key(i))
case SC_LEFT
'direct selection - node selected + LEFT key
if *input_mode = input_direct_selection then
*input_mode = input_move_node_left
end if
reset_key_status(@key(i))
case SC_RIGHT
'direct selection - node selected + RIGHT key
if *input_mode = input_direct_selection then
*input_mode = input_move_node_right
end if
reset_key_status(@key(i))
end select
end if
key(i).old_is_down = key(i).is_down
next i
'this is for the hand ovverride tool
if multikey (SC_SPACE) then
settings->is_hand_active = true
else
settings->is_hand_active = false
end if
if ((multikey(SC_LSHIFT)) or (multikey(SC_LSHIFT))) then
settings->is_snap_active = false
else
settings->is_snap_active = true
end if
end sub
sub draw_list_points(head as point_proto ptr, x as integer, y as integer)
dim as integer c = 0
while (head <> NULL)
draw string (x + c*100, y), ">" +str(hex(head)), C_DARK_GRAY
draw string (x + c*100, y+8), " " + str(int(head->x)) + "," + str(int(head->y)), C_DARK_GRAY
head = head->next_p
c += 1
wend
end sub
Sub delete_all_points (head as point_proto ptr)
dim temp as point_proto ptr
while (head <> NULL)
temp = Head
head = temp->next_p
deallocate(temp)
wend
end sub
sub mark_selected_nodes ( x1 as integer, y1 as integer, _
x2 as integer, y2 as integer, _
array() as polygon_proto)
dim i as integer
dim head as point_proto ptr
for i = 0 to Ubound(array)-1
head = array(i).first_point
while head->next_p <> NULL
if head->x > x1 and head->y > y1 and _
head->x < x2 and head->y < y2 then
head->is_selected = true
end if
head = head->next_p
wend
next i
end sub
sub mouse_listener(user_mouse as mouse_proto ptr, view_area as view_area_proto ptr)
static old_is_lbtn_pressed as boolean = false
static old_is_rbtn_pressed as boolean = false
static as integer old_x, old_y
static store_xy as boolean = false
static begin_store_xy as boolean = false
dim as integer scalechange
user_mouse->abs_x = int(user_mouse->x / view_area->zoom + (-view_area->x / view_area->zoom))
user_mouse->abs_y = int(user_mouse->y / view_area->zoom + (-view_area->y / view_area->zoom))
user_mouse->old_abs_x = int(user_mouse->old_x / view_area->zoom + (-view_area->x / view_area->zoom))
user_mouse->old_abs_y = int(user_mouse->old_y / view_area->zoom + (-view_area->y / view_area->zoom))
if User_Mouse->old_wheel < User_Mouse->wheel and view_area->zoom < 4 then
view_area->zoom *= 2.0f
end if
if User_Mouse->old_wheel > User_Mouse->wheel and view_area->zoom > 0.25 then
view_area->zoom *= 0.5f
end if
'recognize if the left button has been pressed
if User_Mouse->buttons and 1 then
User_Mouse->is_lbtn_pressed = true
user_mouse->drag_x2 = user_mouse->abs_x
user_mouse->drag_y2 = user_mouse->abs_y
else
User_Mouse->is_lbtn_pressed = false
end if
'recognize if the right button has been pressed
if User_Mouse->buttons and 2 then
User_Mouse->is_rbtn_pressed = true
else
User_Mouse->is_rbtn_pressed = false
end if
'recognize if the left button has been released
if old_is_lbtn_pressed = false and User_Mouse->is_lbtn_pressed and store_xy = false then
store_xy = true
end if
if store_xy then
user_mouse->old_x = user_mouse->x
user_mouse->old_y = user_mouse->y
store_xy = false
begin_store_xy = false
end if
'recognize if the left button has been released
if old_is_lbtn_pressed and User_Mouse->is_lbtn_pressed = false then
User_Mouse->is_lbtn_released = true
end if
'recognize if the right button has been released
if old_is_rbtn_pressed and User_Mouse->is_rbtn_pressed = false then
User_Mouse->is_rbtn_released = true
end if
'recognize drag
if (User_Mouse->is_lbtn_pressed) and CBool((old_x <> user_mouse->x) or (old_y <> user_mouse->y)) then
user_mouse->is_dragging = true
'cuspid node
if multikey(SC_ALT) then
user_mouse->oppo_x = user_mouse->old_oppo_x
user_mouse->oppo_y = user_mouse->old_oppo_y
'normal node
else
user_mouse->oppo_x = User_Mouse->old_x - _
cos (_abtp (User_Mouse->old_x, User_Mouse->old_y, User_Mouse->x, User_Mouse->y)) * _
(dist(User_Mouse->old_x, User_Mouse->old_y, User_Mouse->x, User_Mouse->y))
user_mouse->oppo_y = User_Mouse->old_y - _
-sin(_abtp (User_Mouse->old_x, User_Mouse->old_y, User_Mouse->x, User_Mouse->y)) * _
(dist(User_Mouse->old_x, User_Mouse->old_y, User_Mouse->x, User_Mouse->y))
user_mouse->old_oppo_x = user_mouse->oppo_x
user_mouse->old_oppo_y = user_mouse->oppo_y
end if
else
user_mouse->is_dragging = false
end if
if user_mouse->is_dragging and begin_store_xy = false then
begin_store_xy = true
user_mouse->drag_x1 = user_mouse->abs_x
user_mouse->drag_y1 = user_mouse->abs_y
end if
'store the old wheel state
User_Mouse->old_wheel = User_Mouse->wheel
'store the old state of left button
old_is_lbtn_pressed = User_Mouse->is_lbtn_pressed
'store the old state of left button
old_is_rbtn_pressed = User_Mouse->is_rbtn_pressed
end sub
sub pop_values_in_array(array() as integer, eval as integer)
'given a monodimensional re-dimmable array, pops all the data
'that are equal to eval and resizes the array
dim as integer i, j
'transverse whole array, if the array(i) value
'matches the eval, shift non-eval values of the array on the left.
for i = Lbound(array) to Ubound(array)
if array(i) = eval then
for j = (i + 1) to Ubound(array)
if array(j) <> eval then
swap array(j), array (i)
exit for
end if
next j
end if
next i
'find new first eval value location
for i = Lbound(array) to Ubound(array)
if array(i) = eval then
exit for
end if
next i
'redim the array
redim preserve array(Lbound(array) to i-1) as integer
end sub
sub quicksort(array() as temp_point_proto, _left as integer, _right as integer )
dim as integer i, j
dim as single x, y
i = _left
j = _right
x = array((_left + _right)\2).distance
do
while ((array(i).distance < x) and (i < _right))
i +=1
wend
while ((x < array(j).distance) and (j > _left))
j -=1
wend
if (i <=j) then
'y = array(i)
swap array(i), array (j)
'array(j) = y
i += 1
j -= 1
end if
loop while (i <= j)
if (_left < j) then quicksort (array(), _left, j)
if (i < _right) then quicksort (array(), i, _right)
end sub
function pDistance (x as single, y as single, _
x1 as single, y1 as single, _
x2 as single, y2 as single, _
view_area as view_area_proto) as temp_point_proto
'translated from https://stackoverflow.com/questions/849211/
'shortest-distance-between-a-point-and-a-line-segment
dim as single A, B, C, D, xx, yy, dot, len_sq, param
dim nearest_point as temp_point_proto
A = x - x1
B = y - y1
C = x2 - x1
D = y2 - y1
dot = A * C + B * D
len_sq = C * C + D * D
param = -1