Author Topic: Thick LINE  (Read 4174 times)

0 Members and 1 Guest are viewing this topic.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Thick LINE
« on: November 28, 2019, 12:07:44 pm »
Hi.
When drawing in QB64, it is sometimes necessary to use a thick line. I developed this program for drawing it. The question is: How to do it better?


Thick line started from above:
Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2. cx = 400: cy = 300
  3.  
  4. 'fat circle test
  5. FOR c = 0 TO _PI(2) STEP .01
  6.     X = cx + SIN(c) * 200
  7.     Y = cy + COS(c) * 200
  8.     X2 = cx + SIN(c + .01) * 200
  9.     Y2 = cy + COS(c + .01) * 200
  10.     TLine X, Y, X2, Y2, &HFFFF0000, 15
  11.  
  12.  
  13. 'thick line
  14.     PCOPY 1, _DISPLAY
  15.     ex = _MOUSEX
  16.     ey = _MOUSEY
  17.     LINE (cx, cy)-(ex, ey), &HFFFF0000
  18.     TLine cx, cy, ex, ey, &H59FFE1CC, 10
  19.     _DISPLAY
  20.     _LIMIT 20
  21.  
  22.  
  23.  
  24.  
  25.  
  26. SUB TLine (x1, y1, x2, y2, kolor~&, size)
  27.     lenght = SQR((x2 - x1) ^ 2 + (y2 - y1) ^ 2)
  28.     angle = JK!(x1, y1, x2, y2, lenght)
  29.  
  30.     x3 = x1 + SIN(angle + _PI(.5)) * size 'Calculation of perpendicular vector. The default vector is X1, Y1 to X2, Y2. The JK function returns the angle of rotation of the vector, the perpendicular vector is shift by 90 degrees, (or PI /2) in radians.
  31.     y3 = y1 + COS(angle + _PI(.5)) * size
  32.     x4 = x2 + SIN(angle + _PI(.5)) * size
  33.     y4 = y2 + COS(angle + _PI(.5)) * size
  34.  
  35.     v = _NEWIMAGE(10, 10, 32)
  36.     d = _DEST
  37.     _DEST v
  38.     CLS , kolor~&
  39.     _DEST d
  40.     _MAPTRIANGLE (1, 1)-(9, 1)-(1, 9), v TO(x1, y1)-(x2, y2)-(x3, y3), _DEST, _SMOOTH
  41.     _MAPTRIANGLE (9, 1)-(1, 9)-(9, 9), v TO(x2, y2)-(x3, y3)-(x4, y4), _DEST, _SMOOTH
  42.     _FREEIMAGE v
  43.  
  44.  
  45.  
  46.  
  47.  
  48. FUNCTION JK! (cx, cy, px, py, R!)
  49.     LenX! = cx - px
  50.     LenY! = cy - py
  51.     jR! = 1 / R!
  52.     jX! = LenX! * jR!
  53.     jY! = LenY! * jR!
  54.  
  55.     sinusAlfa! = jX!
  56.     Alfa! = ABS(_ASIN(sinusAlfa!))
  57.  
  58.     Q = 1
  59.     IF px >= cx AND py >= cy THEN Q = 1 ' select angle to quadrant
  60.     IF px >= cx AND py <= cy THEN Q = 2
  61.     IF px <= cx AND py <= cy THEN Q = 3
  62.     IF px <= cx AND py >= cy THEN Q = 4
  63.     SELECT CASE Q
  64.         CASE 1: alfaB! = Alfa!
  65.         CASE 2: alfaB! = _PI / 2 + (_PI / 2 - Alfa!)
  66.         CASE 3: alfaB! = _PI + Alfa!
  67.         CASE 4: alfaB! = _PI(1.5) + (_PI / 2 - Alfa!)
  68.     END SELECT
  69.     JK! = alfaB!
  70.     IF JK! = 0 THEN BEEP
  71.  

Thick line is centered:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2. cx = 400: cy = 300
  3.  
  4. 'thick circle test
  5. FOR c = 0 TO _PI(2) STEP .01
  6.     X = cx + SIN(c) * 200
  7.     Y = cy + COS(c) * 200
  8.     X2 = cx + SIN(c + .01) * 200
  9.     Y2 = cy + COS(c + .01) * 200
  10.     TLine X, Y, X2, Y2, &HFFFF0000, 15
  11.  
  12.  
  13. 'Thick line
  14.     PCOPY 1, _DISPLAY
  15.     ex = _MOUSEX
  16.     ey = _MOUSEY
  17.     LINE (cx, cy)-(ex, ey), &HFFFF0000
  18.     TLine cx, cy, ex, ey, &H59FFE1CC, 10
  19.     _DISPLAY
  20.     _LIMIT 20
  21.  
  22.  
  23.  
  24.  
  25.  
  26. SUB TLine (x1, y1, x2, y2, kolor~&, size)
  27.     lenght = SQR((x2 - x1) ^ 2 + (y2 - y1) ^ 2)
  28.     angle = JK!(x1, y1, x2, y2, lenght)
  29.  
  30.     x5 = x1 + SIN(angle - _PI(.5)) * size / 2
  31.     y5 = y1 + COS(angle - _PI(.5)) * size / 2
  32.     x6 = x2 + SIN(angle - _PI(.5)) * size / 2
  33.     y6 = y2 + COS(angle - _PI(.5)) * size / 2
  34.  
  35.     x3 = x1 + SIN(angle + _PI(.5)) * size / 2 'Calculation of perpendicular vector. The default vector is X1, Y1 to X2, Y2. The JK function returns the angle of rotation of the vector, the perpendicular vector is shift by 90 degrees, (or PI /2) in radians.
  36.     y3 = y1 + COS(angle + _PI(.5)) * size / 2
  37.     x4 = x2 + SIN(angle + _PI(.5)) * size / 2
  38.     y4 = y2 + COS(angle + _PI(.5)) * size / 2
  39.  
  40.     v = _NEWIMAGE(10, 10, 32)
  41.     d = _DEST
  42.     _DEST v
  43.     CLS , kolor~&
  44.     _DEST d
  45.     _MAPTRIANGLE (1, 1)-(9, 1)-(1, 9), v TO(x5, y5)-(x6, y6)-(x3, y3), _DEST, _SMOOTH
  46.     _MAPTRIANGLE (9, 1)-(1, 9)-(9, 9), v TO(x6, y6)-(x3, y3)-(x4, y4), _DEST, _SMOOTH
  47.     _FREEIMAGE v
  48.  
  49.  
  50.  
  51.  
  52.  
  53. FUNCTION JK! (cx, cy, px, py, R!)
  54.     LenX! = cx - px
  55.     LenY! = cy - py
  56.     jR! = 1 / R!
  57.     jX! = LenX! * jR!
  58.     jY! = LenY! * jR!
  59.  
  60.     sinusAlfa! = jX!
  61.     Alfa! = ABS(_ASIN(sinusAlfa!))
  62.  
  63.     Q = 1
  64.     IF px >= cx AND py >= cy THEN Q = 1 ' select angle to quadrant
  65.     IF px >= cx AND py <= cy THEN Q = 2
  66.     IF px <= cx AND py <= cy THEN Q = 3
  67.     IF px <= cx AND py >= cy THEN Q = 4
  68.     SELECT CASE Q
  69.         CASE 1: alfaB! = Alfa!
  70.         CASE 2: alfaB! = _PI / 2 + (_PI / 2 - Alfa!)
  71.         CASE 3: alfaB! = _PI + Alfa!
  72.         CASE 4: alfaB! = _PI(1.5) + (_PI / 2 - Alfa!)
  73.     END SELECT
  74.     JK! = alfaB!
  75.     IF JK! = 0 THEN BEEP
  76.  

Corrected thread name and function due to wrong (english) name.
« Last Edit: November 28, 2019, 12:26:53 pm by Petr »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Thick LINE
« Reply #1 on: November 28, 2019, 12:52:05 pm »
Hi Petr,

I've been using this:
Code: QB64: [Select]
  1. SUB thic (x1, y1, x2, y2, thick, K AS _UNSIGNED LONG)
  2.     'need const PD2 = _PI(.5)
  3.     DIM t2 AS SINGLE, a AS SINGLE, x3 AS SINGLE, y3 AS SINGLE, x4 AS SINGLE, y4 AS SINGLE
  4.     DIM x5 AS SINGLE, y5 AS SINGLE, x6 AS SINGLE, y6 AS SINGLE
  5.     t2 = thick / 2
  6.     IF t2 < 1 THEN t2 = 1
  7.     a = _ATAN2(y2 - y1, x2 - x1)
  8.     x3 = x1 + t2 * COS(a + PD2)
  9.     y3 = y1 + t2 * SIN(a + PD2)
  10.     x4 = x1 + t2 * COS(a - PD2)
  11.     y4 = y1 + t2 * SIN(a - PD2)
  12.     x5 = x2 + t2 * COS(a + PD2)
  13.     y5 = y2 + t2 * SIN(a + PD2)
  14.     x6 = x2 + t2 * COS(a - PD2)
  15.     y6 = y2 + t2 * SIN(a - PD2)
  16.     ftri x6, y6, x4, y4, x3, y3, K
  17.     ftri x3, y3, x5, y5, x6, y6, K
  18.  
  19. '2019-11-20 Steve saves some time with STATIC and saves and restores last dest
  20. SUB ftri (x1, y1, x2, y2, x3, y3, K AS _UNSIGNED LONG)
  21.     DIM D AS LONG
  22.     STATIC a&
  23.     D = _DEST
  24.     IF a& = 0 THEN a& = _NEWIMAGE(1, 1, 32)
  25.     _DEST a&
  26.     PSET (0, 0), K
  27.     _DEST D
  28.     _MAPTRIANGLE _SEAMLESS(0, 0)-(0, 0)-(0, 0), a& TO(x1, y1)-(x2, y2)-(x3, y3)
  29.  

But with _MAPTRIANGLE you could fill with image, I think, like paintImage?

Oh, also there is question of whether to round the ends of the lines or not, part of the answer depends if you want to preserve clean transparencies or not.

I've also done circle rings and thick arcs attempting to preserve transparencies..
« Last Edit: November 28, 2019, 12:58:35 pm by bplus »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Thick LINE
« Reply #2 on: November 28, 2019, 01:20:37 pm »
Thank you, BPlus. Yes, it can be fill with images, but i test it now for colors. I was initially just making thick lines. Texturing is an added and welcome feature in addition. I see, ATAN2 easily replaces my JK function in two lines. How I struggled before I wrote it...
I started to calculate the angle from position 90 degrees lower than _ATAN2 and then I calculated the angles upside down (for the shift of SIN in X and for COS in Y), but that doesn't matter ....
Thank you for your solution. Basically, two functions can be constructed from this. One on solid lines, another on textured lines.

Here is the same program with your (BPlus) vector angle method. See, that in this case are variables X calculated as COS and Y as SIN, with my version it is X using SIN and Y using COS:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2. cx = 400: cy = 300
  3.  
  4. 'thick circle test
  5. FOR c = 0 TO _PI(2) STEP .1
  6.     X = cx + SIN(c) * 200
  7.     Y = cy + COS(c) * 200
  8.     X2 = cx + SIN(c + .1) * 200
  9.     Y2 = cy + COS(c + .1) * 200
  10.     TLine X, Y, X2, Y2, &HFFFF0000, 15
  11.  
  12.  
  13. TLine 100, 110, 560, 466, &H88FFFFFF, 60
  14.  
  15.  
  16.  
  17.  
  18. 'Thick line
  19.     PCOPY 1, _DISPLAY
  20.     ex = _MOUSEX
  21.     ey = _MOUSEY
  22.     LINE (cx, cy)-(ex, ey), &HFFFF0000
  23.     TLine cx, cy, ex, ey, &H59FFE1CC, 10
  24.     _DISPLAY
  25.     _LIMIT 20
  26.  
  27.  
  28.  
  29.  
  30.  
  31. SUB TLine (x1, y1, x2, y2, kolor~&, size)
  32.     lenght = SQR((x2 - x1) ^ 2 + (y2 - y1) ^ 2)
  33.     '    angle = JK!(x1, y1, x2, y2, lenght)
  34.     angle = JK2!(x1, y1, x2, y2)
  35.  
  36.     x5 = x1 + COS(angle - _PI(.5)) * size / 2
  37.     y5 = y1 + SIN(angle - _PI(.5)) * size / 2
  38.     x6 = x2 + COS(angle - _PI(.5)) * size / 2
  39.     y6 = y2 + SIN(angle - _PI(.5)) * size / 2
  40.  
  41.     x3 = x1 + COS(angle + _PI(.5)) * size / 2 'Calculation of perpendicular vector. The default vector is X1, Y1 to X2, Y2. The JK function returns the angle of rotation of the vector, the perpendicular vector is shift by 90 degrees, (or PI /2) in radians.
  42.     y3 = y1 + SIN(angle + _PI(.5)) * size / 2
  43.     x4 = x2 + COS(angle + _PI(.5)) * size / 2
  44.     y4 = y2 + SIN(angle + _PI(.5)) * size / 2
  45.  
  46.     v = _NEWIMAGE(100, 100, 32)
  47.     d = _DEST
  48.     _DEST v
  49.     CLS , kolor~&
  50.     _DEST d
  51.  
  52.     IF lenght THEN
  53.         _MAPTRIANGLE (1, 1)-(99, 1)-(1, 99), v TO(x5, y5)-(x6, y6)-(x3, y3), _DEST, _SMOOTH
  54.         _MAPTRIANGLE (99, 1)-(1, 99)-(99, 99), v TO(x6, y6)-(x3, y3)-(x4, y4), _DEST, _SMOOTH
  55.     END IF
  56.     _FREEIMAGE v
  57.  
  58.  
  59.  
  60. FUNCTION JK2! (x1, y1, x2, y2) 'X = cos, Y = sin              BPlus method
  61.     JK2! = _ATAN2(y1 - y2, x1 - x2)
  62.     IF JK2! < 0 THEN JK2! = _PI(2) + JK2!
  63.  

So textured lines:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2. cx = 400: cy = 300
  3.  
  4. texture = _NEWIMAGE(800, 90, 32)
  5. f = _LOADFONT("arial.ttf", 20, "monospace")
  6.  
  7. d = _DEST
  8. _DEST texture
  9. _FONT f, texture
  10. CLS , &HFF91EF11
  11. COLOR &HFF000000
  12. _PRINTSTRING (150, 35), "Thank you, BPlus alias B+!"
  13.  
  14.     TLineTex 566, 100, 110, 466, texture, 100
  15.     _DISPLAY
  16.  
  17.  
  18. SUB TLineTex (x1, y1, x2, y2, texture, size)
  19.     lenght = SQR((x2 - x1) ^ 2 + (y2 - y1) ^ 2)
  20.     '    angle = JK!(x1, y1, x2, y2, lenght)
  21.     angle = JK2!(x1, y1, x2, y2)
  22.  
  23.     x5 = x1 + COS(angle + _PI(.5)) * size / 2
  24.     y5 = y1 + SIN(angle + _PI(.5)) * size / 2
  25.     x6 = x2 + COS(angle + _PI(.5)) * size / 2
  26.     y6 = y2 + SIN(angle + _PI(.5)) * size / 2
  27.  
  28.     x3 = x1 + COS(angle - _PI(.5)) * size / 2 'Calculation of perpendicular vector. The default vector is X1, Y1 to X2, Y2. The JK function returns the angle of rotation of the vector, the perpendicular vector is shift by 90 degrees, (or PI /2) in radians.
  29.     y3 = y1 + SIN(angle - _PI(.5)) * size / 2
  30.     x4 = x2 + COS(angle - _PI(.5)) * size / 2
  31.     y4 = y2 + SIN(angle - _PI(.5)) * size / 2
  32.     W = _WIDTH(texture)
  33.     H = _HEIGHT(texture)
  34.  
  35.     IF lenght THEN
  36.         _MAPTRIANGLE (W - 1, H - 1)-(0, H - 1)-(W - 1, 0), texture TO(x5, y5)-(x6, y6)-(x3, y3), _DEST, _SMOOTH
  37.         _MAPTRIANGLE (0, H - 1)-(W - 1, 0)-(0, 0), texture TO(x6, y6)-(x3, y3)-(x4, y4), _DEST, _SMOOTH
  38.     END IF
  39.  
  40.  
  41.  
  42.  
  43. FUNCTION JK2! (x1, y1, x2, y2) 'X = cos, Y = sin
  44.     JK2! = _ATAN2(y1 - y2, x1 - x2)
  45.     IF JK2! < 0 THEN JK2! = _PI(2) + JK2!
  46.  
  47.  

 
For BPlus.JPG

« Last Edit: November 28, 2019, 02:11:01 pm by Petr »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Thick LINE
« Reply #3 on: November 28, 2019, 02:27:17 pm »
Yeah Petr, nice work with image!

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Thick LINE
« Reply #4 on: November 28, 2019, 07:33:36 pm »
Look at all that trig! I'm sure bplus would rewrite this using only vectors if forced...

(Nice work anyway!)

XD
You're not done when it works, you're done when it's right.

Offline SierraKen

  • Forum Resident
  • Posts: 1454
    • View Profile
Re: Thick LINE
« Reply #5 on: November 29, 2019, 05:05:44 pm »
Something for very, very beginners, that looks like using a chalk:
Use arrow keys and number key 1 to make smaller and 2 to make larger.
Esc to quit.

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2. X=400
  3. Y=300
  4. W=1
  5. IF A$=CHR$(0)+CHR$(72) THEN Y=Y-1 'Up arrow key.
  6. IF A$=CHR$(0)+CHR$(80) THEN Y=Y+1 'Down arrow key.
  7. IF A$=CHR$(0)+CHR$(77) THEN X=X+1 'Right arrow key.
  8. IF A$=CHR$(0)+CHR$(75) THEN X=X-1 'Left arrow key.
  9. IF A$="1" THEN W=W-1 'Make line thinner.
  10. IF A$="2" THEN W=W+1 'Make line thicker.
  11. IF A$=CHR$(27) THEN END 'Esc to quit.
  12. IF W>200 THEN W=200
  13. IF W<1 THEN W=1
  14. CIRCLE (X,Y),W,_RGB32(255,255,255) 'White circle is drawn.
  15.  
« Last Edit: November 29, 2019, 05:11:11 pm by SierraKen »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Thick LINE
« Reply #6 on: November 29, 2019, 06:30:38 pm »
Yeah, I remember doing thick lines with filled circles, I made a whole font with them.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Thick LINE
« Reply #7 on: November 29, 2019, 10:29:25 pm »
Heck, I thought I'd try this just by thinking outside the box -- how to make a thick line without using any math more complicated than basic addition or subtraction.  What I've played around with and came up with is this little snippet:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3. ThickLine 100, 100, 300, 300, 10, &HFFFF0000
  4. ThickLine 300, 100, 100, 300, 15, &HFF00FF00
  5. ThickLine 200, 400, 400, 300, 20, &HFF0000FF
  6.  
  7. SUB ThickLine (X1, Y1, X2, Y2, Thick, Kolor AS _UNSIGNED LONG)
  8.     Rise = Y2 - Y1: Runn = X2 - X1: Slope = Rise / Runn
  9.     FOR i = 0 TO Thick
  10.         X3 = X1 + i * Slope: Y3 = Y1 - ABS(i * Slope)
  11.         X4 = X2 + i * Slope: Y4 = Y2 - ABS(i * Slope)
  12.         LINE (X3, Y3)-(X4, Y4), Kolor
  13.     NEXT

I'm certain the math guys here can tell us why this doesn't work, and why it appears to give a dotted line pattern rather than a solid fill block, but I thought the results were pretty interesting, myself.  I personally dunno WHY it's doing what it's doing, but I kind of like it...

Anywho, I thought I'd share, just as a way to pass time and try something different than all the rest.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

FellippeHeitor

  • Guest
Re: Thick LINE
« Reply #8 on: November 29, 2019, 10:46:52 pm »
In trying it different, here's how I once did it:

Code: QB64: [Select]
  1. SUB thickLine (x1!, y1!, x2!, y2!, lineWidth%)
  2.     DIM angle%, distance%, halfThickness%
  3.     angle% = INT(_R2D(_ATAN2(y2! - y1!, x2! - x1!)))
  4.     distance% = _HYPOT((x2! - x1!), (y2! - y1!))
  5.     halfThickness% = lineWidth% / 2
  6.     IF halfThickness% < 1 THEN halfThickness% = 1
  7.     IF halfThickness% = 1 THEN
  8.         DRAW "bm" + STR$(x1!) + "," + STR$(y1!) + " TA" + STR$(-angle%) + " R" + STR$(distance%)
  9.     ELSE
  10.         DRAW "bm" + STR$(x1!) + "," + STR$(y1!) + " TA" + STR$(-angle%) + "U" + STR$(halfThickness%) + " R" + STR$(distance%) + "D" + STR$(halfThickness% * 2) + " L" + STR$(distance%) + "U" + STR$(halfThickness%) + " B R" + STR$(distance% / 2) + "P" + STR$(_DEFAULTCOLOR) + "," + STR$(_DEFAULTCOLOR)
  11.     END IF

And an example using it:
Code: QB64: [Select]
  1. CONST false = 0, true = NOT false
  2.  
  3. DIM x1, y1, x2, y2
  4. DIM mouseDown AS _BYTE
  5. DIM totalDots AS INTEGER
  6. DIM thickness AS INTEGER
  7.  
  8. thickness = 10
  9.  
  10. SCREEN _NEWIMAGE(800, 600, 32)
  11.  
  12.     WHILE _MOUSEINPUT: thickness = thickness + _MOUSEWHEEL: WEND
  13.  
  14.     IF thickness < 1 THEN thickness = 1
  15.  
  16.         IF NOT mouseDown THEN
  17.             mouseDown = true
  18.             totalDots = totalDots + 1
  19.             IF totalDots > 2 THEN totalDots = 1
  20.             SELECT CASE totalDots
  21.                 CASE 1
  22.                     x1 = _MOUSEX
  23.                     y1 = _MOUSEY
  24.                 CASE 2
  25.                     x2 = _MOUSEX
  26.                     y2 = _MOUSEY
  27.             END SELECT
  28.         END IF
  29.     ELSE
  30.         mouseDown = false
  31.     END IF
  32.  
  33.     CLS
  34.     PRINT "Click to set the initial line coordinate,"
  35.     PRINT "click again to set the final line coordinate."
  36.     PRINT "Use the mousewheel to make the line thicker/thinner."
  37.     PRINT "Current thickness:"; thickness
  38.  
  39.     IF totalDots = 1 THEN
  40.         PSET (x1, y1)
  41.     ELSE
  42.         thickLine x1, y1, x2, y2, thickness
  43.     END IF
  44.     _DISPLAY
  45.     _LIMIT 30
  46.  
  47. SUB thickLine (x1!, y1!, x2!, y2!, lineWidth%)
  48.     DIM angle%, distance%, halfThickness%
  49.     angle% = INT(_R2D(_ATAN2(y2! - y1!, x2! - x1!)))
  50.     distance% = _HYPOT((x2! - x1!), (y2! - y1!))
  51.     halfThickness% = lineWidth% / 2
  52.     IF halfThickness% < 1 THEN halfThickness% = 1
  53.     IF halfThickness% = 1 THEN
  54.         DRAW "bm" + STR$(x1!) + "," + STR$(y1!) + " TA" + STR$(-angle%) + " R" + STR$(distance%)
  55.     ELSE
  56.         DRAW "bm" + STR$(x1!) + "," + STR$(y1!) + " TA" + STR$(-angle%) + "U" + STR$(halfThickness%) + " R" + STR$(distance%) + "D" + STR$(halfThickness% * 2) + " L" + STR$(distance%) + "U" + STR$(halfThickness%) + " B R" + STR$(distance% / 2) + "P" + STR$(_DEFAULTCOLOR) + "," + STR$(_DEFAULTCOLOR)
  57.     END IF

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Thick LINE
« Reply #9 on: November 29, 2019, 10:57:53 pm »
Here's another attempt at something different -- this one starts with the single line, then simply pads it thicker as many times as we want it to.

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3.  
  4. ThickLine 100, 100, 300, 300, 10, &HFFFF0000
  5. ThickLine 300, 100, 100, 300, 35, &HFF00FF00
  6. ThickLine 200, 400, 400, 300, 30, &HFF0000FF
  7.  
  8.  
  9.  
  10. SUB ThickLine (X1, Y1, X2, Y2, Thick, Kolor AS _UNSIGNED LONG)
  11.     STATIC temp
  12.     STATIC m AS _MEM, m1 AS _MEM
  13.     D = _DEST
  14.     IF temp = 0 THEN temp = _NEWIMAGE(_WIDTH, _HEIGHT, 32): _DEST temp ELSE _DEST temp: CLS , 0
  15.     m = _MEMIMAGE(temp)
  16.     m1 = _MEM(Array())
  17.     LINE (X1, Y1)-(X2, Y2), Kolor
  18.     FOR i = 1 TO Thick
  19.         FOR x = 0 TO _WIDTH - 1
  20.             FOR y = 0 TO _HEIGHT - 1
  21.                 IF _MEMGET(m, m.OFFSET + (y * _WIDTH + x) * 4, _UNSIGNED LONG) <> 0 THEN
  22.                     _MEMPUT m1, m1.OFFSET + (y * _WIDTH + x + 1) * 4, Kolor
  23.                     _MEMPUT m1, m1.OFFSET + (y * _WIDTH + x - 1) * 4, Kolor
  24.                     _MEMPUT m1, m1.OFFSET + ((y + 1) * _WIDTH + x) * 4, Kolor
  25.                     _MEMPUT m1, m1.OFFSET + ((y - 1) * _WIDTH + x) * 4, Kolor
  26.                 END IF
  27.             NEXT
  28.         NEXT
  29.         o = 0
  30.         DO UNTIL o >= m.SIZE
  31.             IF _MEMGET(m1, m1.OFFSET + o, _UNSIGNED LONG) <> 0 THEN _MEMPUT m, m.OFFSET + o, Kolor
  32.             o = o + 4
  33.         LOOP
  34.         _PUTIMAGE , temp, D: SLEEP 'comment this line out if you don't want to watch the process at work
  35.     NEXT
  36.     _DEST D
  37.     _PUTIMAGE , temp, D

Once again, not perfect results (the 3rd test line ends up almost looking like a 3D blue box of sorts, for my display), but they're interesting (to me at least)! 
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Thick LINE
« Reply #10 on: November 30, 2019, 12:24:02 am »
Thick line, thick arc and font:
Code: QB64: [Select]
  1. _TITLE "Bplus font" 'B+ 2019-11-29 trans from
  2. ' Plasma Deluxe.bas  SmallBASIC 0.12.6 [B+=MGA] 2016-05-16
  3.  
  4. CONST xmax = 1200, ymax = 600, pi = 3.141592654
  5. DIM SHARED dr, thick, lx, ly
  6. SCREEN _NEWIMAGE(xmax, ymax, 32)
  7. clr = &HFFAACCFF
  8. post i, i, 10, clr, "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvXxYyZz1234567890?!.,"
  9. post 0, i + 20, 20, clr, "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvXxYyZz1234567890?!.,"
  10. post 0, i + 50, 30, clr, "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvXxYyZz1234567890?!.,"
  11. post 0, i + 90, 40, clr, "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvXxYyZz1234567890?!.,"
  12.  
  13. WHILE _KEYDOWN(27) = 0
  14.     COLOR 0, 0: CLS
  15.     b = RND ^ 2: c = RND ^ 2: d = RND ^ 2
  16.     FOR i = 1 TO 400
  17.         post i, i, 100, clr, "Bplus Font"
  18.         clr = _RGB32(127 + 127 * SIN(b * i), 127 + 127 * SIN(c * i), 127 + 127 * SIN(d * i))
  19.         _DISPLAY
  20.         _LIMIT 60
  21.     NEXT
  22.  
  23.  
  24. SUB post (x, y, scale, fore AS _UNSIGNED LONG, mess$)
  25.     'local lm,i,c,p1,p2,p3,p4,px,gf
  26.     thick = 1 / 40 * scale
  27.     dr = scale / 6 - thick / 2
  28.     gf = .04 * scale
  29.     COLOR fore
  30.     p1 = .16 * scale: p2 = .32 * scale: p3 = .48 * scale: p4 = .64 * scale
  31.     lm = LEN(mess$): py = y + .5 * thick
  32.     IF lm * scale * .5 + x - xmax > 0 THEN BEEP 'draw it anyway
  33.     FOR i = 1 TO lm
  34.         c$ = MID$(mess$, i, 1)
  35.         px = x + (i - 1) * scale * .5 + .5 * thick
  36.         SELECT CASE c$
  37.             CASE "a": ac px + p1, py + p3, 0, 360: lx = px + p2: ly = py + p2 - gf: tl 0, p2: tl 0, 2 * gf
  38.             CASE "b": ac px + p1, py + p3, 0, 360: lx = px: ly = py: tl 0, p4
  39.             CASE "c": ac px + p1, py + p3, 40, 320
  40.             CASE "d": ac px + p1, py + p3, 0, 360: lx = px + p2: ly = py: tl 0, p4
  41.             CASE "e": ac px + p1, py + p3, 45, 360: lx = px: ly = py + p3: tl p2, 0
  42.             CASE "f": ac px + p2, py + p1 + gf, 180, 270: lx = px: ly = py + p2: tl p2, 0: lx = px + p1: ly = py + p1: tl 0, p3
  43.             CASE "g": ac px + p1, py + p3, 0, 360: lx = px + p2: ly = py + p2: tl 0, p2: ac px + p1, py + p4, 0, 90: lx = px: ly = py + p4 + p1: tl p1, 0
  44.             CASE "h": ac px + p1, py + p3, 180, 360: lx = px: ly = py: tl 0, p4: lx = px + p2: ly = py + p3: tl 0, p1
  45.             CASE "i": lx = px + p1 - gf: ly = py + p2: tl gf, 0: tl 0, p2: tl -gf, 0: tl 2 * gf, 0
  46.                 lx = px + p1 - gf: ly = py + p1: tl gf, 0: tl 0, -gf: tl -gf, 0: tl 0, gf
  47.             CASE "j": lx = px + p1 - gf: ly = py + p2: tl gf, 0: tl 0, p2: ac px, py + p4, 0, 120
  48.                 lx = px + p1 - gf: ly = py + p1: tl gf, 0: tl 0, -gf: tl -gf, 0: tl 0, gf
  49.             CASE "k": lx = px: ly = py: tl 0, p4: lx = px + p2: ly = py + p2: tl -p2, p1: tl p2, p1
  50.             CASE "l": lx = px + p1 - gf: ly = py: tl gf, 0: tl 0, p4: tl gf, 0: tl -2 * gf, 0
  51.             CASE "m": lx = px: ly = py + p2: tl 0, p2: lx = px + p1: ly = py + p4: tl 0, -p2: tl -p1, p1: lx = px + p2: ly = py + p4: tl 0, -p2: tl -p1, p1
  52.             CASE "n": ac px + p1, py + p3, 180, 360: lx = px: ly = py + p2 - gf: tl 0, p2 + gf: lx = px + p2: ly = py + p3: tl 0, p1
  53.             CASE "o": ac px + p1, py + p3, 0, 360
  54.             CASE "p": ac px + p1, py + p3, 0, 360: lx = px: ly = py + p2 - gf: tl 0, p4 - 2 * gf
  55.             CASE "q": ac px + p1, py + p3, 0, 360: lx = px + p2: ly = py + p2 - gf: tl 0, p4 - 2 * gf: tl 2 * gf, 0
  56.             CASE "r": lx = px: ly = py + p2: tl 0, p2: ac px + p1, py + p3, 180, 340
  57.             CASE "s": dr = 1 / 12 * scale: ac px + .5 * p1, py + p2 + dr, 90, 270: ac px + 1.5 * p1, py + p3 + dr, 270, 450: dr = 1 / 6 * scale
  58.                 lx = px + .5 * p1: ly = py + p2: tl p1 * 1.5, 0: lx = px: ly = py + p4: tl p1 * 1.5, 0: lx = px + .5 * p1: ly = py + p3: tl p1, 0
  59.             CASE "t": lx = px + p1: ly = py: tl 0, p4: tl 2 * gf, 0: lx = px: ly = py + p2: tl p2, 0
  60.             CASE "u": ac px + p1, py + p3, 0, 180: lx = px: ly = py + p2: tl 0, p1 * 1.5: lx = px + p2: ly = py + p2: tl 0, p2 + gf
  61.             CASE "v": lx = px: ly = py + p2: tl p1, p2 + gf: tl p1, -p2 - 1.5 * gf
  62.             CASE "w": lx = px - gf: ly = py + p2: tl gf + p1 * .5, p2: tl .5 * p1, -p2: tl p1 * .5, p2: tl p1 * .5 + gf, -p2
  63.             CASE "x": lx = px: ly = py + p2: tl p2, p2: lx = px: ly = py + p4: tl p2, -p2
  64.             CASE "y": lx = px: ly = py + p2: tl p1, p2: lx = px + p2: ly = py + p2: tl -p2, p3 + gf
  65.             CASE "z": lx = px: ly = py + p2: tl p2, 0: tl -p2, p2: tl p2, 0
  66.             CASE "A": lx = px: ly = py + p4: tl p1 - gf, -p4: tl 2 * gf, 0: tl p1 - gf, p4: lx = px + p1 - 2 * gf: ly = py + p2: tl p1, 0
  67.             CASE "B": ac px + p1, py + p1, 270, 450: ac px + p1, py + p3, 270, 450
  68.                 lx = px: ly = py: tl 0, p4: tl p1, 0: lx = px: ly = py + p2: tl p1, 0: lx = px: ly = py: tl p1, 0
  69.             CASE "C": ac px + p1, py + p1, 180, 320: ac px + p1, py + p3, 40, 180: lx = px: ly = py + p1: tl 0, p2
  70.             CASE "D": ac px + p1, py + p1, 270, 360: ac px + p1, py + p3, 0, 90
  71.                 lx = px + p1: ly = py: tl -p1, 0: tl 0, p4: tl p1, 0: lx = px + p2: ly = py + p1: tl 0, p2
  72.             CASE "E": lx = px + p2: ly = py: tl -p2, 0: tl 0, p4: tl p2, 0: lx = px: ly = py + p2: tl p1 + 2 * gf, 0
  73.             CASE "F": lx = px + p2: ly = py: tl -p2, 0: tl 0, p4: lx = px: ly = py + p2: tl p1 + 2 * gf, 0
  74.             CASE "G": ac px + p1, py + p1, 180, 345: ac px + p1, py + p3, 0, 180
  75.                 lx = px: ly = py + p1: tl 0, p2: lx = px + p2: ly = py + p4 + gf: tl 0, -p2 - gf: tl -p1, 0
  76.             CASE "H": lx = px: ly = py: tl 0, p4: tl 0, -p2: tl p2, 0: tl 0, p2: tl 0, -p4
  77.             CASE "I": lx = px + p1 * .5: ly = py: tl p1, 0: lx = px + p1 * .5: ly = py + p4: tl p1, 0: lx = px + p1: ly = py: tl 0, p4
  78.             CASE "J": ac px + p1, py + p3, 0, 180: lx = px + p1 * 1.5: ly = py: tl p1 * .5, 0: tl 0, p3
  79.             CASE "K": lx = px: ly = py: tl 0, p4: lx = px + p2: ly = py: tl -p2, p2: tl p2, p2
  80.             CASE "L": lx = px: ly = py: tl 0, p4: tl p2, 0
  81.             CASE "M": lx = px: ly = py + p4: tl 0, -p4: tl p1, p2: tl p1, -p2: tl 0, p4
  82.             CASE "N": lx = px: ly = py + p4: tl 0, -p4: tl p2, p4: tl 0, -p4
  83.             CASE "O": ac px + p1, py + p1, 180, 360: ac px + p1, py + p3, 0, 180: lx = px: ly = py + p1: tl 0, p2: lx = px + p2: ly = py + p1: tl 0, p2
  84.             CASE "P": ac px + p1, py + p1, 270, 450: lx = px + p1: ly = py: tl -p1, 0: tl 0, p4: lx = px: ly = py + p2: tl p1, 0
  85.             CASE "Q": ac px + p1, py + p1, 180, 360: ac px + p1, py + p3, 0, 180
  86.                 lx = px: ly = py + p1: tl 0, p2: lx = px + p2: ly = py + p1: tl 0, p2: lx = px + p1: ly = py + p2: tl p1 + gf, p2 + gf
  87.             CASE "R": ac px + p1, py + p1, 270, 450: lx = px + p1: ly = py: tl -p1, 0: tl 0, p4: lx = px: ly = py + p2: tl p1, 0: tl p1, p2
  88.             CASE "S": ac px + p1, py + p1, 90, 360: ac px + p1, py + p3, 270, 540
  89.             CASE "T": lx = px: ly = py: tl p2, 0: lx = px + p1: ly = py: tl 0, p4
  90.             CASE "U": ac px + p1, py + p3, 0, 180: lx = px: ly = py: tl 0, p3: lx = px + p2: ly = py: tl 0, p3
  91.             CASE "V": lx = px: ly = py: tl p1, p4: tl p1, -p4
  92.             CASE "W": lx = px - gf: ly = py: tl gf, p4: tl p1, -p2: tl p1, p2: tl gf, -p4
  93.             CASE "X": lx = px: ly = py: tl p2, p4: lx = px + p2: ly = py: tl -p2, p4
  94.             CASE "Y": lx = px: ly = py: tl p1, p2: tl 0, p2: lx = px + p2: ly = py: tl -p1, p2
  95.             CASE "Z": lx = px: ly = py: tl p2, 0: tl -p2, p4: tl p2, 0
  96.  
  97.             CASE "0": ac px + p1, py + p1, 180, 360: ac px + p1, py + p3, 0, 180: lx = px: ly = py + p1: tl 0, p2: tl p2, -p2: tl 0, p2
  98.             CASE "1": lx = px: ly = py + p1: tl p1, -p1: tl 0, p4: tl -p1, 0: tl p2, 0
  99.             CASE "2": ac px + p1, py + p1, 180, 360: lx = px + p2: ly = py + p1: tl -p2, p3: tl p2, 0
  100.             CASE "3": ac px + p1, py + p1, 180, 450: ac px + p1, py + p3, 270, 540
  101.             CASE "4": lx = px + p1: ly = py: tl -p1, p2: tl p2, 0: tl 0, p2: lx = px + p2: ly = py: tl 0, p2
  102.             CASE "5": ac px + p1, py + p3, 270, 520: lx = px + p1: tl -p1, 0: tl 0, -p2: tl p2, 0
  103.             CASE "6": ac px + p1, py + p3, 0, 360: lx = px: ly = py + p3: tl p1, -p3
  104.             CASE "7": lx = px: ly = py: tl p2, 0: tl -p1, p4
  105.             CASE "8": ac px + p1, py + p1, 0, 360: ac px + p1, py + p3, 0, 360
  106.             CASE "9": ac px + p1, py + p1, 0, 360: lx = px + p2: ly = py + p1: tl -p1, p3
  107.             CASE ".": lx = px: ly = py + p4: tl gf, 0: tl 0, -gf: tl -gf, 0: tl 0, gf
  108.             CASE "!": lx = px: ly = py + p4: tl gf, 0: tl 0, -gf: tl -gf, 0: tl 0, gf:: lx = px: ly = py: tl 0, p2
  109.             CASE ",": lx = px + gf: ly = py + p4: tl -gf, 0: tl 0, -gf: tl gf, 0: tl 0, gf: tl -gf, .5 * p1 + gf
  110.             CASE "?": lx = px + p1: ly = py + p4: tl gf, 0: tl 0, -gf: tl -gf, 0: tl 0, gf: ac px + p1, py + p1, 180, 450: lx = px + p1: ly = py + p2: tl 0, p1 - gf
  111.         END SELECT
  112.     NEXT
  113.  
  114. 'ac is for arc, x,y is radius center, das=degree angle start, dae=degree angle end
  115. SUB ac (x, y, das, dae)
  116.     'note dr, drawing radius has to be global, use COLOR globally sets color
  117.     'note thick also made globals by POST sub
  118.     'local a,x1,y1,stepper
  119.     IF dr THEN
  120.         IF INT(thick) = 0 THEN stepper = 1 / (dr * pi) ELSE stepper = (thick / 2) / (dr * pi / 2)
  121.         FOR a = das TO dae STEP stepper
  122.             x1 = dr * COS(_D2R(a)): y1 = dr * SIN(_D2R(a))
  123.             'IF INT(thick) < 1 THEN PSET (x + x1, y + y1) ELSE fcirc x + x1, y + y1, thick, _DEFAULTCOLOR
  124.             fcirc x + x1, y + y1, thick, _DEFAULTCOLOR
  125.         NEXT
  126.     END IF
  127.  
  128. 'tl stands for thick line in the LINE STEP x,y format
  129. SUB tl (stepx, stepy) 'tl=thickline
  130.     'lastx, lasty globals for last drawn position
  131.     'thick has to be global
  132.     'note thick=0 still draws a line, use COLOR so line is drawn from this global
  133.     'local length,dx,dy,i
  134.     length = ((stepx) ^ 2 + (stepy) ^ 2) ^ .5
  135.     IF length THEN
  136.         dx = stepx / (length * 2): dy = stepy / (length * 2)
  137.         FOR i = 0 TO length * 2
  138.             fcirc lx + dx * i, ly + dy * i, thick, _DEFAULTCOLOR
  139.         NEXT
  140.     END IF
  141.     lx = lx + stepx: ly = ly + stepy
  142.  
  143. SUB fcirc (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  144.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  145.     DIM X AS INTEGER, Y AS INTEGER
  146.     Radius = ABS(R): RadiusError = -Radius: X = Radius: Y = 0
  147.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  148.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  149.     WHILE X > Y
  150.         RadiusError = RadiusError + Y * 2 + 1
  151.         IF RadiusError >= 0 THEN
  152.             IF X <> Y + 1 THEN
  153.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  154.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  155.             END IF
  156.             X = X - 1
  157.             RadiusError = RadiusError - X * 2
  158.         END IF
  159.         Y = Y + 1
  160.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  161.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  162.     WEND
  163.  
« Last Edit: November 30, 2019, 12:26:34 am by bplus »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Thick LINE
« Reply #11 on: November 30, 2019, 05:06:35 am »
Thank you all for your examples! Now (after lunch) I will deal with a thick-line program, that ends thick line with an arc.