Author Topic: Enclose a Random Set of Points, Voronoi to Border  (Read 3520 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Enclose a Random Set of Points, Voronoi to Border
« on: March 25, 2019, 05:25:07 pm »
Code: QB64: [Select]
  1. _TITLE "Enclose a random set of points then Voronoi to border"
  2. CONST xmax = 800
  3. CONST ymax = 600
  4. SCREEN _NEWIMAGE(xmax, ymax, 32)
  5. _SCREENMOVE 300, 20
  6.  
  7. TYPE PointType
  8.     x AS INTEGER
  9.     y AS INTEGER
  10.     K AS _UNSIGNED LONG
  11.     connectX AS INTEGER
  12.     connectY AS INTEGER
  13. DIM SHARED dotsBg&, nPoints
  14. dotsBg& = _NEWIMAGE(xmax, ymax, 32)
  15. nPoints = 13 '<<<<<<<<<<< actually less points makes for more interesting shapes!
  16. REDIM SHARED p(1 TO nPoints) AS PointType
  17. WHILE _KEYDOWN(27) = 0
  18.     REDIM p(1 TO nPoints) AS PointType
  19.     _DEST dotsBg&
  20.     CLS
  21.     FOR i = 1 TO nPoints
  22.  
  23.         'test circle points, supposed to be most difficult
  24.         'toggle comments this whole block to try random dots or dots on a circle
  25.  
  26.         'ca = _PI(2 / (nPoints - 1))
  27.         'IF i = 1 THEN 'need one off the border for painting interior
  28.         '    p(i).x = xmax / 2: p(i).y = ymax / 2
  29.         'ELSE
  30.         '    p(i).x = xmax / 2 + 200 * COS(ca * i)
  31.         '    p(i).y = ymax / 2 + 200 * SIN(ca * i)
  32.         'END IF
  33.         p(i).x = INT(RND * (xmax - 20)) + 10
  34.         p(i).y = INT(RND * (ymax - 20)) + 10
  35.  
  36.  
  37.         p(i).K = _RGB32(200 * RND + 30, 200 * RND + 20, 200 * RND + 10)
  38.         fcirc p(i).x, p(i).y, 2, p(i).K
  39.     NEXT
  40.     _DEST 0
  41.     qSort 1, nPoints, p()
  42.     curPoint = 1
  43.     plot
  44.     _DELAY 1
  45.     'main event: going from farthest left to right find points that contiain interior with convex polygon
  46.     'This loop does the top section
  47.     DO
  48.         lowestAngle = _PI(2): saveI = 0
  49.         FOR i = curPoint + 1 TO nPoints
  50.             testAngle = _ATAN2(p(i).y - p(curPoint).y, p(i).x - p(curPoint).x)
  51.             IF testAngle < lowestAngle THEN lowestAngle = testAngle: saveI = i
  52.         NEXT
  53.         IF saveI THEN
  54.             p(curPoint).connectX = p(saveI).x: p(curPoint).connectY = p(saveI).y
  55.             curPoint = saveI
  56.         ELSE 'point B
  57.             PRINT "Screwed!"
  58.             _DISPLAY
  59.             EXIT DO
  60.         END IF
  61.         plot
  62.         _DISPLAY
  63.         _LIMIT 1
  64.     LOOP UNTIL curPoint = nPoints
  65.  
  66.     'main even part 2: going back right to left find the points that contain the interior with a convex ploygon
  67.     'This loop does the bottom section
  68.     curPoint = nPoints
  69.     DO
  70.         lowestAngle = _PI(2): saveI = 0
  71.         FOR i = curPoint - 1 TO 1 STEP -1
  72.             testAngle = _ATAN2(p(curPoint).y - p(i).y, p(curPoint).x - p(i).x)
  73.             IF testAngle < lowestAngle THEN lowestAngle = testAngle: saveI = i
  74.         NEXT
  75.         IF saveI THEN
  76.             p(curPoint).connectX = p(saveI).x: p(curPoint).connectY = p(saveI).y
  77.             curPoint = saveI
  78.         ELSE 'point B
  79.             PRINT "Screwed!"
  80.             _DISPLAY
  81.             EXIT DO
  82.         END IF
  83.         plot
  84.         _DISPLAY
  85.         _LIMIT 1
  86.     LOOP UNTIL curPoint = 1
  87.  
  88.     'note: if a dot happens to sit on the border the paint is going to leak blue
  89.     ' FIXED dots are on separate Bg image
  90.  
  91.     ' find an interior point (not connected) and paint from there
  92.     FOR i = 1 TO nPoints
  93.         IF p(i).connectX = 0 THEN PAINT (p(i).x, p(i).y), _RGB32(0, 0, 255), _RGB32(255, 255, 255)
  94.     NEXT
  95.  
  96.     'the blue paint is to tell us which points to Voronoi
  97.     maxD = xmax + ymax
  98.     FOR x = p(1).x TO p(nPoints).x
  99.         FOR y = 0 TO ymax
  100.             IF POINT(x, y) = _RGB32(0, 0, 255) THEN 'a Voronoi point to color the same as closest point
  101.                 d = maxD
  102.                 FOR i = 1 TO nPoints 'looking for closet point to x, y
  103.                     a = ABS(p(i).x - x)
  104.                     b = ABS(p(i).y - y)
  105.                     IF a + b < d THEN d = a + b: kkl = i
  106.                 NEXT
  107.                 PSET (x, y), p(kkl).K 'set x, y the same as closets point color
  108.             END IF
  109.         NEXT
  110.         _DISPLAY
  111.     NEXT
  112.     _DELAY 5
  113.  
  114. SUB plot
  115.     CLS
  116.     _PUTIMAGE , dotsBg&, 0 'dots were causing Paints to bleed
  117.     FOR i = 1 TO nPoints
  118.         'note x can not = 0
  119.         IF p(i).connectX THEN thic p(i).x, p(i).y, p(i).connectX, p(i).connectY, 1, _RGB32(255, 255, 255)
  120.     NEXT
  121.     _PRINTSTRING (5, 5), "Points:" + STR$(nPoints)
  122.  
  123. 'now scan or sort on x
  124. SUB qSort (start AS LONG, finish AS LONG, a() AS PointType)
  125.     DIM Hi AS LONG, Lo AS LONG, Middle AS INTEGER
  126.     Hi = finish: Lo = start
  127.     Middle = a((Lo + Hi) / 2).x 'find middle of array
  128.     DO
  129.         DO WHILE a(Lo).x < Middle: Lo = Lo + 1: LOOP
  130.         DO WHILE a(Hi).x > Middle: Hi = Hi - 1: LOOP
  131.         IF Lo <= Hi THEN
  132.             SWAP a(Lo), a(Hi)
  133.             Lo = Lo + 1: Hi = Hi - 1
  134.         END IF
  135.     LOOP UNTIL Lo > Hi
  136.     IF Hi > start THEN qSort start, Hi, a()
  137.     IF Lo < finish THEN qSort Lo, finish, a()
  138.  
  139. SUB thic (x1, y1, x2, y2, thick, K AS _UNSIGNED LONG)
  140.     pd2 = _PI(.5)
  141.     t2 = thick / 2
  142.     IF t2 < 1 THEN t2 = 1
  143.     a = _ATAN2(y2 - y1, x2 - x1)
  144.     x3 = x1 + t2 * COS(a + pd2)
  145.     y3 = y1 + t2 * SIN(a + pd2)
  146.     x4 = x1 + t2 * COS(a - pd2)
  147.     y4 = y1 + t2 * SIN(a - pd2)
  148.     x5 = x2 + t2 * COS(a + pd2)
  149.     y5 = y2 + t2 * SIN(a + pd2)
  150.     x6 = x2 + t2 * COS(a - pd2)
  151.     y6 = y2 + t2 * SIN(a - pd2)
  152.     ftri x6, y6, x4, y4, x3, y3, K
  153.     ftri x3, y3, x5, y5, x6, y6, K
  154.  
  155. SUB ftri (x1, y1, x2, y2, x3, y3, K AS _UNSIGNED LONG)
  156.     a& = _NEWIMAGE(1, 1, 32)
  157.     _DEST a&
  158.     PSET (0, 0), K
  159.     _DEST 0
  160.     _MAPTRIANGLE _SEAMLESS(0, 0)-(0, 0)-(0, 0), a& TO(x1, y1)-(x2, y2)-(x3, y3)
  161.     _FREEIMAGE a& '<<< this is important!
  162.  
  163. SUB fcirc (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  164.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  165.     DIM X AS INTEGER, Y AS INTEGER
  166.  
  167.     Radius = ABS(R)
  168.     RadiusError = -Radius
  169.     X = Radius
  170.     Y = 0
  171.  
  172.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  173.  
  174.     ' Draw the middle span here so we don't draw it twice in the main loop,
  175.     ' which would be a problem with blending turned on.
  176.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  177.  
  178.     WHILE X > Y
  179.         RadiusError = RadiusError + Y * 2 + 1
  180.         IF RadiusError >= 0 THEN
  181.             IF X <> Y + 1 THEN
  182.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  183.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  184.             END IF
  185.             X = X - 1
  186.             RadiusError = RadiusError - X * 2
  187.         END IF
  188.         Y = Y + 1
  189.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  190.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  191.     WEND
  192.  
  193.  
Enclose Random Set of Points.PNG


OK and do some not so random points too, 12 points around circle and center:
 
Enclose Random Circle Option.PNG
« Last Edit: March 25, 2019, 11:58:40 pm by bplus »