@@ -402,7 +402,9 @@ function Diag:has_point(x, y)
402
402
end
403
403
end
404
404
405
- Line = defclass (Line , Shape )
405
+ LineDrawer = defclass (LineDrawer , Shape )
406
+
407
+ Line = defclass (Line , LineDrawer )
406
408
Line .ATTRS {
407
409
name = " Line" ,
408
410
extra_points = { { label = " Curve Point" }, { label = " Second Curve Point" } },
@@ -431,18 +433,19 @@ function Line:init()
431
433
}
432
434
end
433
435
434
- function Line :plot_bresenham (x0 , y0 , x1 , y1 , thickness )
436
+ function LineDrawer :plot_bresenham (x0 , y0 , x1 , y1 , thickness )
435
437
local dx = math.abs (x1 - x0 )
436
438
local dy = math.abs (y1 - y0 )
437
439
local sx = x0 < x1 and 1 or - 1
438
440
local sy = y0 < y1 and 1 or - 1
439
- local err = dx - dy
440
441
local e2 , x , y
441
442
442
443
for i = 0 , thickness - 1 do
443
444
x = x0
444
445
y = y0 + i
445
- while true do
446
+ local err = dx - dy
447
+ local p = math.max (dx , dy )
448
+ while p >= 0 do
446
449
for j = - math.floor (thickness / 2 ), math.ceil (thickness / 2 ) - 1 do
447
450
if not self .arr [x + j ] then self .arr [x + j ] = {} end
448
451
if not self .arr [x + j ][y ] then
@@ -451,7 +454,7 @@ function Line:plot_bresenham(x0, y0, x1, y1, thickness)
451
454
end
452
455
end
453
456
454
- if x == x1 and y == y1 + i then
457
+ if sx * x >= sx * x1 and sy * y >= sy * ( y1 + i ) then
455
458
break
456
459
end
457
460
@@ -466,6 +469,7 @@ function Line:plot_bresenham(x0, y0, x1, y1, thickness)
466
469
err = err + dx
467
470
y = y + sy
468
471
end
472
+ p = p - 1
469
473
end
470
474
end
471
475
@@ -684,7 +688,137 @@ function FreeForm:point_in_polygon(x, y)
684
688
return inside
685
689
end
686
690
691
+ Star = defclass (Star , LineDrawer )
692
+ Star .ATTRS {
693
+ name = " Star" ,
694
+ texture_offset = 25 ,
695
+ button_chars = util .make_ascii_button (' *' , 15 ),
696
+ extra_points = { { label = " Main Axis" } }
697
+ }
698
+
699
+ function Star :init ()
700
+ self .options = {
701
+ hollow = {
702
+ name = " Hollow" ,
703
+ type = " bool" ,
704
+ value = false ,
705
+ key = " CUSTOM_H" ,
706
+ },
707
+ thickness = {
708
+ name = " Line thickness" ,
709
+ type = " plusminus" ,
710
+ value = 1 ,
711
+ enabled = { " hollow" , true },
712
+ min = 1 ,
713
+ max = function (shape ) if not shape .height or not shape .width then
714
+ return nil
715
+ else
716
+ return math.ceil (math.min (shape .height , shape .width ) / 2 )
717
+
718
+ end
719
+ end ,
720
+ keys = { " CUSTOM_T" , " CUSTOM_SHIFT_T" },
721
+ },
722
+ total_points = {
723
+ name = " Total points" ,
724
+ type = " plusminus" ,
725
+ value = 5 ,
726
+ min = 3 ,
727
+ max = 100 ,
728
+ keys = { " CUSTOM_B" , " CUSTOM_SHIFT_B" },
729
+ },
730
+ next_point_offset = {
731
+ name = " Next point offset" ,
732
+ type = " plusminus" ,
733
+ value = 2 ,
734
+ min = 1 ,
735
+ max = 100 ,
736
+ keys = { " CUSTOM_N" , " CUSTOM_SHIFT_N" },
737
+ },
738
+ }
739
+ end
740
+
741
+ function Star :has_point (x , y )
742
+ if 1 < ((x - self .center .x ) / self .center .x ) ^ 2 + ((y - self .center .y ) / self .center .y ) ^ 2 then return false end
743
+
744
+ local inside = 0
745
+ for l = 1 , self .options .total_points .value do
746
+ if x * self .lines [l ].slope .x - self .lines [l ].intercept .x < y * self .lines [l ].slope .y - self .lines [l ].intercept .y then
747
+ inside = inside + 1
748
+ else
749
+ inside = inside - 1
750
+ end
751
+ end
752
+ return self .threshold > 0 and inside > self .threshold or inside < self .threshold
753
+ end
754
+
755
+ function vmagnitude (point )
756
+ return math.sqrt (point .x * point .x + point .y * point .y )
757
+ end
758
+
759
+ function vnormalize (point )
760
+ local magnitude = vmagnitude (point )
761
+ return { x = point .x / magnitude , y = point .y / magnitude }
762
+ end
763
+
764
+ function add_offset (coord , offset )
765
+ return coord + (offset > 0 and math.floor (offset + 0.5 ) or math.ceil (offset - 0.5 ))
766
+ end
767
+
768
+ function Star :update (points , extra_points )
769
+ self .num_tiles = 0
770
+ self .points = copyall (points )
771
+ self .arr = {}
772
+ if # points < self .min_points then return end
773
+ self .threshold = self .options .total_points .value - 2 * self .options .next_point_offset .value
774
+ local top_left , bot_right = self :get_point_dims ()
775
+ self .height = bot_right .y - top_left .y
776
+ self .width = bot_right .x - top_left .x
777
+ if self .height == 1 or self .width == 1 then return end
778
+ self .center = { x = self .width * 0.5 , y = self .height * 0.5 }
779
+ local axes = {}
780
+
781
+ axes [1 ] = (# extra_points > 0 ) and { x = extra_points [1 ].x - self .center .x - top_left .x , y = extra_points [1 ].y - self .center .y - top_left .y } or { x = 0 , y = - self .center .y }
782
+ if vmagnitude (axes [1 ]) < 0.5 then axes [1 ].y = - self .center .y end
783
+ axes [1 ] = vnormalize (axes [1 ])
784
+
785
+ for a = 2 , self .options .total_points .value do
786
+ local angle = math.pi * (a - 1.0 ) * 2.0 / self .options .total_points .value
787
+ axes [a ] = { x = math.cos (angle ) * axes [1 ].x - math.sin (angle ) * axes [1 ].y , y = math.sin (angle ) * axes [1 ].x + math.cos (angle ) * axes [1 ].y }
788
+ end
789
+
790
+ local thickness = 1
791
+ if self .options .hollow .value then
792
+ thickness = self .options .thickness .value
793
+ end
794
+
795
+ self .lines = {}
796
+ for l = 1 , self .options .total_points .value do
797
+ local p1 = { x = self .center .x + axes [l ].x * self .width * 0.5 , y = self .center .y + axes [l ].y * self .height * 0.5 }
798
+ local next_axis = axes [(l - 1 + self .options .next_point_offset .value ) % self .options .total_points .value + 1 ]
799
+ local p2 = { x = self .center .x + next_axis .x * self .width * 0.5 , y = self .center .y + next_axis .y * self .height * 0.5 }
800
+ self .lines [l ] = { slope = { x = p2 .y - p1 .y , y = p2 .x - p1 .x }, intercept = { x = (p2 .y - p1 .y ) * p1 .x , y = (p2 .x - p1 .x ) * p1 .y } }
801
+ self :plot_bresenham (add_offset (top_left .x , p1 .x ), add_offset (top_left .y , p1 .y ), add_offset (top_left .x , p2 .x ), add_offset (top_left .y , p2 .y ), thickness )
802
+ self :plot_bresenham (add_offset (top_left .x , p2 .x ), add_offset (top_left .y , p2 .y ), add_offset (top_left .x , p1 .x ), add_offset (top_left .y , p1 .y ), thickness )
803
+ end
804
+
805
+ if not self .options .hollow .value or self .invert then
806
+ for x = top_left .x , bot_right .x do
807
+ if not self .arr [x ] then self .arr [x ] = {} end
808
+ for y = top_left .y , bot_right .y do
809
+ local value = self .arr [x ][y ] or (not self .options .hollow .value and self :has_point (x - top_left .x , y - top_left .y ))
810
+ if self .invert then
811
+ self .arr [x ][y ] = not value
812
+ else
813
+ self .arr [x ][y ] = value
814
+ end
815
+
816
+ self .num_tiles = self .num_tiles + (self .arr [x ][y ] and 1 or 0 )
817
+ end
818
+ end
819
+ end
820
+ end
687
821
-- module users can get shapes through this global, shape option values
688
822
-- persist in these as long as the module is loaded
689
823
-- idk enough lua to know if this is okay to do or not
690
- all_shapes = { Rectangle {}, Ellipse {}, Rows {}, Diag {}, Line {}, FreeForm {} }
824
+ all_shapes = { Rectangle {}, Ellipse {}, Rows {}, Diag {}, Line {}, FreeForm {}, Star {} }
0 commit comments