Author Topic: Drawing the Connecting (Minor) Arcs of Intersecting Circles  (Read 4635 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
A preliminary for advanced Celtic Knot (hopefully):
Code: QB64: [Select]
  1. _TITLE "The Intersection of Two Circles" 'trans from SmallBASIC 2019-07-03 B+
  2. 'dang there is a case where one circle is inside the other
  3.  
  4. CONST xmax = 800
  5. CONST ymax = 600
  6. CONST red = &HFFFF0000
  7. CONST blu = &HFF0000FF
  8. CONST yel = &HFFFFFF00
  9. CONST whi = &HFFFFFFFF
  10. CONST bla = &HFF000000
  11.  
  12. SCREEN _NEWIMAGE(xmax, ymax, 32)
  13. _SCREENMOVE 300, 60
  14. DIM xx1, yy1, rr1, xx2, yy2, rr2, iix1, iiy1, iix2, iiy2, keyh AS LONG, xr1, yr1, xr2, yr2, ttl$, d, a1to1, a2to1, a1to2, a2to2
  15. DIM a1Start, a1End, a2Start, a2End
  16.  
  17.     CLS
  18.     ttl$ = "Testing 2 Circle Intersect"
  19.     'test code for intersect
  20.     '   1st circle
  21.     mBox "Click screen for first circle origin, then click again for it's radius", ttl$
  22.     getClick xx1, yy1, keyh
  23.     CIRCLE (xx1, yy1), 2, red
  24.     getClick xr1, yr1, keyh
  25.     rr1 = distance(xr1, yr1, xx1, yy1)
  26.     CIRCLE (xx1, yy1), rr1, red
  27.  
  28.     '  2nd circle
  29.     mBox "Click screen for 2nd circle origin, then click again for it's radius", ttl$
  30.     getClick xx2, yy2, keyh
  31.     CIRCLE (xx2, yy2), 2, blu
  32.     getClick xr2, yr2, keyh
  33.     rr2 = distance(xr2, yr2, xx2, yy2)
  34.     CIRCLE (xx2, yy2), rr2, blu
  35.  
  36.     intersect2Circles xx1, yy1, rr1, xx2, yy2, rr2, iix1, iiy1, iix2, iiy2
  37.  
  38.     IF iix1 = iix2 AND iix1 = 0 THEN
  39.         BEEP: mBox "There is no intersection in this case.", ttl$
  40.     ELSE
  41.         CIRCLE (iix1, iiy1), 2, yel
  42.         CIRCLE (iix2, iiy2), 2, yel
  43.         LINE (iix1, iiy1)-(iix2, iiy2), yel
  44.         PSET (iix1, iiy1), whi
  45.         PSET (iix2, iiy2), whi
  46.  
  47.  
  48.         mBox "Here is a line through the intersection points, next we will show the 'eye lens' of two connecting arcs.", ttl$
  49.         'now the whole point of this exercise is get information for drawing an arcs
  50.         ' we need to translate a point on a circle to it's radian measure in the circle at distance of radius of course
  51.  
  52.         'let's try to draw the eye shape of two arcs coming together at the intersect
  53.         CLS
  54.         minorArc xx1, yy1, rr1, rAngle(xx1, yy1, iix1, iiy1), rAngle(xx1, yy1, iix2, iiy2), red
  55.         minorArc xx2, yy2, rr2, rAngle(xx2, yy2, iix1, iiy1), rAngle(xx2, yy2, iix2, iiy2), blu
  56.         _DELAY 4
  57.  
  58.     END IF
  59.  
  60. 'given a circles origin, radius and point on the circumference return the arc measure of that point
  61. FUNCTION rAngle (coX, coY, circumX, circumY)
  62.     rAngle = _ATAN2(circumY - coY, circumX - coX)
  63.     IF rAngle < 0 THEN rAngle = rAngle + _PI(2)
  64.  
  65. 'given two arc angles I want the one that draws the smaller arc drawn
  66. SUB minorArc (x, y, r, ra1, ra2, c AS _UNSIGNED LONG)
  67.     DIM raStart, raStop
  68.  
  69.     'which has smaller arc meansure
  70.     IF ra1 < ra2 THEN
  71.         IF ra2 - ra1 < _PI THEN raStart = ra1: raStop = ra2 ELSE raStart = ra2: raStop = ra1
  72.     ELSE
  73.         IF ra1 - ra2 < _PI THEN raStart = ra2: raStop = ra1 ELSE raStart = ra1: raStop = ra2
  74.     END IF
  75.     arc x, y, r, raStart, raStop, c
  76.  
  77.  
  78. SUB intersect2Circles (x1, y1, r1, x2, y2, r2, ix1, iy1, ix2, iy2)
  79.     'x1, y1 origin of circle 1 with radius r1
  80.     'x2, y2 origin of circle 2 with radius r2
  81.     'ix1, iy1 is the first point of intersect
  82.     'ix2, iy2 is the 2nd point of intersect
  83.     'if ix1 = ix2 = iy1 = iy2 = 0 then no points returned
  84.  
  85.     DIM d, a, h, Px, pY
  86.     d = distance(x1, y1, x2, y2) 'distance between two origins
  87.     IF r1 + r2 < d THEN
  88.         'PRINT "The circles are too far apart to intersect.": END
  89.         'some signal ???    if ix1 = ix2 = iy1 = iy2 = 0 then no points returned
  90.         ix1 = 0: ix2 = 0: iy1 = 0: iy2 = 0
  91.         EXIT SUB
  92.     END IF
  93.     IF (d < r1 AND r2 + d < r1) OR (d < r2 AND r1 + d < r2) THEN 'one circle is inside the other = no intersect
  94.         ix1 = 0: ix2 = 0: iy1 = 0: iy2 = 0
  95.         EXIT SUB
  96.         'IF ABS(r1 - r2) > 3 THEN
  97.         '    PRINT "No intersect, same center (or nearly so) and different radii (or seemingly so).": END
  98.         'ELSE
  99.         '    PRINT "Infinite intersect, the circles are the same (or nearly so).": END
  100.         'END IF
  101.  
  102.     END IF
  103.     'results
  104.     a = (r1 ^ 2 - r2 ^ 2 + d ^ 2) / (2 * d)
  105.     Px = x1 + a * (x2 - x1) / d
  106.     pY = y1 + a * (y2 - y1) / d
  107.     h = (r1 ^ 2 - a ^ 2) ^ .5
  108.     ix1 = INT(Px - h * (y2 - y1) / d)
  109.     iy1 = INT(pY + h * (x2 - x1) / d)
  110.     'circle x1,y1,2,1 filled
  111.     'PRINT: PRINT "Intersect pt1: "; x1; ", "; y1
  112.     ix2 = INT(Px + h * (y2 - y1) / d)
  113.     iy2 = INT(pY - h * (x2 - x1) / d)
  114.     'circle x2,y2,2,1 filled
  115.     'PRINT: PRINT "Intersect pt2: "; x2; ", "; y2
  116.     'line x1,y1,x2,y2
  117.  
  118. SUB arc (x, y, r, raStart, raStop, c AS _UNSIGNED LONG)
  119.     'x, y origin, r = radius, c = color
  120.  
  121.     'raStart is first angle clockwise from due East = 0 degrees
  122.     ' arc will start drawing there and clockwise until raStop angle reached
  123.  
  124.     DIM al, a
  125.     IF raStop < raStart THEN
  126.         arc x, y, r, raStart, _PI(2), c
  127.         arc x, y, r, 0, raStop, c
  128.     ELSE
  129.         ' modified to easier way suggested by Steve
  130.         'Why was the line method not good? I forgot.
  131.         al = _PI * r * r * (raStop - raStart) / _PI(2)
  132.         FOR a = raStart TO raStop STEP 1 / al
  133.             PSET (x + r * COS(a), y + r * SIN(a)), c
  134.         NEXT
  135.     END IF
  136.  
  137. FUNCTION distance (x1, y1, x2, y2)
  138.     distance = ((x1 - x2) ^ 2 + (y1 - y2) ^ 2) ^ .5
  139.  
  140. '2019-03-02 added more clearing for mb at start
  141. SUB getClick (mx, my, kh AS LONG)
  142.     DIM mb, i
  143.     mb = _MOUSEBUTTON(1)
  144.     WHILE mb
  145.         WHILE _MOUSEINPUT: WEND '<<<<<<<<<<<<<<<<<<<<  clear previous mb
  146.         mb = _MOUSEBUTTON(1)
  147.     WEND
  148.     _KEYCLEAR 'clear previous key presses
  149.     mx = -1: my = -1: kh = 0
  150.     DO WHILE mx = -1 AND my = -1
  151.         kh = _KEYHIT
  152.         IF kh = 27 OR (kh > 31 AND kh < 126) THEN _KEYCLEAR: EXIT SUB
  153.         i = _MOUSEINPUT: mb = _MOUSEBUTTON(1)
  154.         'IF mb THEN
  155.         DO WHILE mb 'wait for release
  156.             kh = _KEYHIT
  157.             IF kh = 27 OR (kh > 31 AND kh < 126) THEN EXIT SUB
  158.             i = _MOUSEINPUT: mb = _MOUSEBUTTON(1): mx = _MOUSEX: my = _MOUSEY
  159.             _LIMIT 1000
  160.         LOOP
  161.         _LIMIT 1000
  162.     LOOP
  163.  
  164.  
  165. 'title$ limit is 55 chars, all lines are 58 chars max
  166. ' 2019-03-02 fix clearing of key and mb, maybe
  167. SUB mBox (m$, title$)
  168.  
  169.     'first screen dimensions items to restore at exit
  170.     DIM curRow AS INTEGER, curCol AS INTEGER
  171.     DIM curScrn AS LONG, backScrn AS LONG, mbx AS LONG 'some handles
  172.     DIM ti AS INTEGER, limit AS INTEGER 'ti = text index for t$(), limit is number of chars per line
  173.     DIM i AS INTEGER, j AS INTEGER, ff AS _BIT, add AS _BYTE 'index, flag and
  174.     DIM bxH AS INTEGER, bxW AS INTEGER 'first as cells then as pixels
  175.     DIM mb AS INTEGER, mx AS INTEGER, my AS INTEGER, mi AS INTEGER, grabx AS INTEGER, graby AS INTEGER
  176.     DIM tlx AS INTEGER, tly AS INTEGER 'top left corner of message box
  177.     DIM lastx AS INTEGER, lasty AS INTEGER, r AS INTEGER, kh AS LONG
  178.     DIM b$, c$, tail$, d$
  179.  
  180.     '2019-03-02 add this to clear old mb or keypress
  181.     mb = _MOUSEBUTTON(1)
  182.     WHILE mb
  183.         WHILE _MOUSEINPUT: WEND '<<<<<<<<<<<<<<<<<<<<  clear previous mouse activity
  184.         mb = _MOUSEBUTTON(1)
  185.     WEND
  186.     _KEYCLEAR 'clear previous key presses
  187.  
  188.     DBLU = &HFF000066
  189.     LBLU = &HFFB0A0FF
  190.     BLK = &HFF000000
  191.     WHT = &HFFFFFFFF
  192.  
  193.     curRow = CSRLIN
  194.     curCol = POS(0)
  195.     sw = _WIDTH
  196.     sh = _HEIGHT
  197.     fg = _DEFAULTCOLOR
  198.     bg = _BACKGROUNDCOLOR
  199.     'screen snapshot
  200.     curScrn = _DEST
  201.     backScrn = _NEWIMAGE(sw, sh, 32)
  202.     _PUTIMAGE , curScrn, backScrn
  203.  
  204.     'setup t$() to store strings with ti as index, linit 58 chars per line max, b$ is for build
  205.     REDIM t$(0): ti = 0: limit = 58: b$ = ""
  206.     FOR i = 1 TO LEN(m$)
  207.         c$ = MID$(m$, i, 1)
  208.         'are there any new line signals, CR, LF or both? take CRLF or LFCR as one break but dbl LF or CR means blank line
  209.         SELECT CASE c$
  210.             CASE CHR$(13) 'load line
  211.                 IF MID$(m$, i + 1, 1) = CHR$(10) THEN i = i + 1
  212.                 t$(ti) = b$: b$ = "": ti = ti + 1: REDIM _PRESERVE t$(ti)
  213.             CASE CHR$(10)
  214.                 IF MID$(m$, i + 1, 1) = CHR$(13) THEN i = i + 1
  215.                 t$(ti) = b$: b$ = "": ti = ti + 1: REDIM _PRESERVE t$(ti)
  216.             CASE ELSE
  217.                 IF c$ = CHR$(9) THEN c$ = SPACE$(4): add = 4 ELSE add = 1
  218.                 IF LEN(b$) + add > limit THEN
  219.                     tail$ = "": ff = 0
  220.                     FOR j = LEN(b$) TO 1 STEP -1 'backup until find a space, save the tail end for next line
  221.                         d$ = MID$(b$, j, 1)
  222.                         IF d$ = " " THEN
  223.                             t$(ti) = MID$(b$, 1, j - 1): b$ = tail$ + c$: ti = ti + 1: REDIM _PRESERVE t$(ti)
  224.                             ff = 1 'found space flag
  225.                             EXIT FOR
  226.                         ELSE
  227.                             tail$ = d$ + tail$ 'the tail grows!
  228.                         END IF
  229.                     NEXT
  230.                     IF ff = 0 THEN 'no break? OK
  231.                         t$(ti) = b$: b$ = c$: ti = ti + 1: REDIM _PRESERVE t$(ti)
  232.                     END IF
  233.                 ELSE
  234.                     b$ = b$ + c$ 'just keep building the line
  235.                 END IF
  236.         END SELECT
  237.     NEXT
  238.     t$(ti) = b$
  239.     bxH = ti + 3: bxW = limit + 2
  240.  
  241.     'draw message box
  242.     mbx = _NEWIMAGE(60 * 8, (bxH + 1) * 16, 32)
  243.     _DEST mbx
  244.     COLOR DBLU, WHT
  245.     LOCATE 1, 1: PRINT LEFT$(SPACE$((bxW - LEN(title$) - 3) / 2) + title$ + SPACE$(bxW), bxW)
  246.     COLOR _RGB32(225, 225, 255), _RGB32(200, 0, 0)
  247.     LOCATE 1, bxW - 2: PRINT " X "
  248.     COLOR DBLU, LBLU
  249.     LOCATE 2, 1: PRINT SPACE$(bxW);
  250.     FOR r = 0 TO ti
  251.         LOCATE 1 + r + 2, 1: PRINT LEFT$(SPACE$((bxW - LEN(t$(r))) / 2) + t$(r) + SPACE$(bxW), bxW);
  252.     NEXT
  253.     LOCATE 1 + bxH, 1: PRINT SPACE$(limit + 2);
  254.  
  255.     'now for the action
  256.     _DEST curScrn
  257.  
  258.     'convert to pixels the top left corner of box at moment
  259.     bxW = bxW * 8: bxH = bxH * 16
  260.     tlx = (sw - bxW) / 2: tly = (sh - bxH) / 2
  261.     lastx = tlx: lasty = tly
  262.     'now allow user to move it around or just read it
  263.     WHILE 1
  264.         CLS
  265.         _PUTIMAGE , backScrn
  266.         _PUTIMAGE (tlx, tly), mbx, curScrn
  267.         _DISPLAY
  268.         WHILE _MOUSEINPUT: WEND
  269.         mx = _MOUSEX: my = _MOUSEY: mb = _MOUSEBUTTON(1)
  270.         IF mb THEN
  271.             IF mx >= tlx AND mx <= tlx + bxW AND my >= tly AND my <= tly + 16 THEN 'mouse down on title bar
  272.                 IF mx >= tlx + bxW - 24 THEN EXIT WHILE
  273.                 grabx = mx - tlx: graby = my - tly
  274.                 DO WHILE mb 'wait for release
  275.                     mi = _MOUSEINPUT: mb = _MOUSEBUTTON(1)
  276.                     mx = _MOUSEX: my = _MOUSEY
  277.                     IF mx - grabx >= 0 AND mx - grabx <= sw - bxW AND my - graby >= 0 AND my - graby <= sh - bxH THEN
  278.                         'attempt to speed up with less updates
  279.                         IF ((lastx - (mx - grabx)) ^ 2 + (lasty - (my - graby)) ^ 2) ^ .5 > 10 THEN
  280.                             tlx = mx - grabx: tly = my - graby
  281.                             CLS
  282.                             _PUTIMAGE , backScrn
  283.                             _PUTIMAGE (tlx, tly), mbx, curScrn
  284.                             lastx = tlx: lasty = tly
  285.                             _DISPLAY
  286.                         END IF
  287.                     END IF
  288.                     _LIMIT 600
  289.                 LOOP
  290.             END IF
  291.         END IF
  292.         kh = _KEYHIT
  293.         SELECT CASE kh
  294.             CASE 27, 13, 32: _DELAY .2: EXIT WHILE
  295.         END SELECT
  296.         _LIMIT 60
  297.     WEND
  298.     'put things back
  299.     COLOR fg, bg: CLS
  300.     _PUTIMAGE , backScrn
  301.     _DISPLAY
  302.     _FREEIMAGE backScrn
  303.     _FREEIMAGE mbx
  304.     _KEYCLEAR
  305.     LOCATE curRow, curCol
  306.  
  307.  

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Drawing the Connecting (Minor) Arcs of Intersecting Circles
« Reply #1 on: July 04, 2019, 05:20:00 pm »
Very useful. Thank You, Bplus!

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Drawing the Connecting (Minor) Arcs of Intersecting Circles
« Reply #2 on: July 05, 2019, 02:41:29 am »
Good!
I find it very instructive.
A magistral teaching about geometry on a 2D plan with a little of trigonometry
Programming isn't difficult, only it's  consuming time and coffee

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Drawing the Connecting (Minor) Arcs of Intersecting Circles
« Reply #3 on: July 05, 2019, 10:41:20 am »
Thanks guys, can you see I might use it for advanced Celtic Knots?

Still a little blurry for me yet... hope to test today.

I've printed out my Celtic knot skeleton (BTW remember to use a white background when you do that!) and have been staring at it for some time last night.


« Last Edit: July 05, 2019, 10:55:14 am by bplus »

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Drawing the Connecting (Minor) Arcs of Intersecting Circles
« Reply #4 on: July 05, 2019, 10:53:59 am »
Awesome! I like geometry a lot.
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: Drawing the Connecting (Minor) Arcs of Intersecting Circles
« Reply #5 on: July 06, 2019, 06:03:56 pm »
I am in awe...

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Drawing the Connecting (Minor) Arcs of Intersecting Circles
« Reply #6 on: July 07, 2019, 10:11:10 am »
Thanks, with such encouragement you may see more :D