Drawing lines of variable thickness

Just starting out? Need help? Post your questions and find answers here.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Drawing lines of variable thickness

Post by srod »

Hello all,

Have recently returned to programming after too many years in the wilderness and am new to PureBasic. What an excellent language.
Have made rapid gains in the space of a few weeks thanks to all the tips and snippets within these forums.

To the reason I am posting.

I am working upon what is becoming quite a nice little painting program which I am using as a learning platform.
Is it possible to draw / plot a line of variable thickness (rather than 1 pixel wide) ? I suspect that if it is possible then it might involve the Win API (which I am slowly coming to understand through these forums and PB itself.) Unfortunately, I don't know enough about hdc's, device contexts, brushes etc. to set about tackling this.
I am prepared to code such a procedure directly in PB but I can't help thinking that, with a little persuasion, Windows should be able to perform this task!

Thanks and keep up the excellent work.
LarsG
Enthusiast
Enthusiast
Posts: 713
Joined: Mon Jun 02, 2003 1:06 pm
Location: Norway
Contact:

Post by LarsG »

Don't know about WinAPI, but you can use a series of ovals or rects do draw thicker line.. :roll:

-Lars

AMD Athlon XP2400, 512 MB RAM, Hercules 3D Prophet 9600 256MB RAM, WinXP
PIII 800MHz, 320 MB RAM, Nvidia Riva Tnt 2 Mach 64 (32MB), WinXP + Linux
17" iMac, 1.8 GHz G5, 512 MB DDR-RAM, 80 GB HD, 64 MB Geforce FX 5200, SuperDrive, OSX
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Re: Drawing lines of variable thickness

Post by einander »

Hi srod:
Maybe this helps.
Is it possible to draw / plot a line of variable thickness

Code: Select all

Procedure Lin(x,y,x1,y1,Gros,Color)
   hDC=GETDC_(WindowID())
   pen=CreatePen_(#Ps_Solid,GROS,color)  
   hPenOld=SelectObject_(hDC,pen)
   MoveToEx_(hDC,x,y,0):LineTo_(hDC,x1,y1) 
   DeleteObject_(pen)
   DeleteObject_(hPenOld)
EndProcedure

;_____________________________________________
_X=GetSystemMetrics_(#SM_CXSCREEN)-8 : _Y=GetSystemMetrics_(#SM_CYSCREEN)-68
OpenWindow(0,0,0,_X,_Y,#WS_OVERLAPPEDWINDOW | #WS_MAXIMIZE,"")

lin(50,200,300,400,15,#red)
MessageRequester("","DONE",0)
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Excellent. I was (with the aid of Petzold's book) almost there and experimenting with the very same function calls. You've just saved me a whole heap of trial and error!

Problem now is that I am drawing on an image. Will the same code work if I replace the window handle with that of an image ?

Thanks.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Got it!

The code doesn't work with an image, but it does with an image gadget!

Thanks again LarsG and einander. Thiis is better than any text book!
LarsG
Enthusiast
Enthusiast
Posts: 713
Joined: Mon Jun 02, 2003 1:06 pm
Location: Norway
Contact:

Post by LarsG »

Don't know why you're thanking me.. it's Einander who had the cool function.. 8)

-Lars

AMD Athlon XP2400, 512 MB RAM, Hercules 3D Prophet 9600 256MB RAM, WinXP
PIII 800MHz, 320 MB RAM, Nvidia Riva Tnt 2 Mach 64 (32MB), WinXP + Linux
17" iMac, 1.8 GHz G5, 512 MB DDR-RAM, 80 GB HD, 64 MB Geforce FX 5200, SuperDrive, OSX
Puffolino
User
User
Posts: 49
Joined: Thu Jan 05, 2012 12:27 am

Re: Drawing lines of variable thickness

Post by Puffolino »

Has anyone found a solution which can be used to draw thick lines on images as well as to the printer? Maybe even OS independent?

All non-windows specific procedures for drawing lines in the forum which work also for printing have some disadvantages (very slow, not working for all angles or using the faulty circle command etc.)

Code: Select all

Procedure thickLineXY(start_x,start_y,end_x,end_y,thickness,whatcolor)

	thickness>>1

	err_x=0
	err_y=0
	inc_x=0
	inc_y=0

	delta_x=end_x - start_x;
	delta_y=end_y - start_y;


	If (delta_x>0)
		inc_x=1
	ElseIf (delta_x=0)
		inc_x=0
	Else
		inc_x=-1
	EndIf
	If (delta_y>0)
		inc_y=1
	ElseIf (delta_y=0)
		inc_y=0
	Else
		inc_y=-1
	EndIf

	delta_x=Abs(delta_x);
	delta_y=Abs(delta_y);

	If (delta_x>delta_y)
		distance=delta_x;
	Else
		distance=delta_y;
	EndIf

	For  xyz=0 To  distance+1 Step 1

		; modified to place a circle at the pixel location to get a thick line

		;Plot(start_x,start_y,whatcolor)
		Circle(start_x,start_y,thickness,whatcolor)

		err_x=err_x + delta_x
		err_y=err_y + delta_y

		If (err_x>distance)
			err_x=err_x - distance
			start_x=start_x + inc_x
		EndIf

		If (err_y>distance)
			err_y=err_y - distance
			start_y=start_y +inc_y
		EndIf

	Next

EndProcedure
Procedure ClipLine(x1.w, y1.w, x2.w, y2.w, color,thickness.w)

	; Draw line here with stupid PB Line command syntax
	w=x2 - x1
	h=y2 - y1
	If wh
		w=w+1
	Else
		h=h+1
		If w=h
			w=w+1
		EndIf
	EndIf

	extra=0
	For i.w=1 To thickness
		If w>h
			y1=y1+extra
		Else
			x1=x1+extra
		EndIf
		Line(x1, y1, w, h,color)
		If extra<0
			extra=extra-1
		Else
			extra=extra+1
		EndIf
		extra=-extra
	Next
	
EndProcedure

ProcedureDLL.l ColorBlending(Color1.l, Color2.l, Blend.f)
	
	Protected Red, Green, Blue, Red2, Green2, Blue2

	Red=Color1 & $FF
	Green=Color1 >> 8 & $FF
	Blue=Color1 >> 16
	Red2=Color2 & $FF
	Green2=Color2 >> 8 & $FF
	Blue2=Color2 >> 16

	Red=Red * Blend + Red2 *(1-Blend)
	Green=Green * Blend + Green2 *(1-Blend)
	Blue=Blue * Blend + Blue2 *(1-Blend)

	ProcedureReturn(Red | Green <<8 | Blue << 16)
	
EndProcedure
Procedure NormalL(X,Y, x3, y3, Color, Thickness=1)
	
	Width=x3-X
	Hight=y3-Y
	Protected SignX, SignY, n, nn, Thick.f, x2.f, y2.f, Color_Found.l, Application.f, Hypo.f

	If Width >= 0
		SignX=1
	Else
		SignX=-1
		Width=- Width
	EndIf
	If Hight >= 0
		SignY=1
	Else
		SignY=-1
		Hight=- Hight
	EndIf


	Thick.f=Thickness / 2

	Hypo.f=Sqr(Width * Width + Hight * Hight)
	CosPhi.f=Width / Hypo
	SinPhi.f=-Sin(ACos(CosPhi))


	For n=-Thickness To Width + Thickness
		For nn=-Thickness To Hight + Thickness


			x2=n * CosPhi - nn * SinPhi
			y2=Abs(n * SinPhi + nn * CosPhi)

			If y2 <= Thick + 0.5
				Application= 0.5 + Thick - y2
				If Application>1
					Application=1
				EndIf
				If x2>-1 And x2<Hypo + 1
					If x2<0
						Application *(1 + x2)
					ElseIf x2>Hypo
						Application *(1 - x2 + Hypo)
					EndIf
				Else
					Application=0
				EndIf
				If Application>0
					If Application<1
						Color_Found=Point(X + n * SignX, Y + nn * SignY)
						Plot(X + n * SignX, Y + nn * SignY, ColorBlending(Color, Color_Found, Application))
					Else
						Plot(X + n * SignX, Y + nn * SignY, Color)
					EndIf
				EndIf
			EndIf
		Next
	Next

EndProcedure

Procedure LineAA(X, Y, Width, Hight, Color, Thickness=1)
	
	Protected SensX, SensY, n, nn, Epaisseur.f, x2.f, y2.f, Couleur_Fond.l, Application.f, Distance.f
	; On mets la droite toujours dans le même sens pour l'analyse
	; La sauvegarde du sens permettra de dessiner la droite ensuite dans le bon sens
	If Width >= 0
		SensX=1
	Else
		SensX=-1
		Width=- Width
	EndIf
	If Hight >= 0
		SensY=1
	Else
		SensY=-1
		Hight=- Hight
	EndIf


	; Demi épaisseur de la ligne
	Epaisseur.f=Thickness / 2

	; calcul pour le changement de repère qui permet de connaitre l'épaisseur du trait et de gérer l'AA
	Distance.f=Sqr(Width * Width + Hight * Hight)
	CosAngle.f=Width / Distance
	SinAngle.f=-Sin(ACos(CosAngle))

	; Dessin de la ligne
	For n=-Thickness To Width + Thickness
		For nn=-Thickness To Hight + Thickness

			; changement de base
			; les y représentent l'épaisseur de la ligne
			x2=n * CosAngle - nn * SinAngle
			y2=Abs(n * SinAngle + nn * CosAngle)

			If y2 <= Epaisseur + 0.5
				Application= 0.5 + Epaisseur - y2
				If Application>1
					Application=1
				EndIf
				If x2>-1 And x2<Distance + 1
					If x2<0
						Application *(1 + x2)
					ElseIf x2>Distance
						Application *(1 - x2 + Distance)
					EndIf
				Else
					Application=0
				EndIf
				If Application>0
					If Application<1
						Couleur_Fond=Point(X + n * SensX, Y + nn * SensY)
						Plot(X + n * SensX, Y + nn * SensY, ColorBlending(Color, Couleur_Fond, Application))
					Else
						Plot(X + n * SensX, Y + nn * SensY, Color)
					EndIf
				EndIf
			EndIf

		Next
	Next

EndProcedure

OpenWindow(0, 0, 0, 500, 500, "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget)

CreateImage(0, 500, 500)
StartDrawing(ImageOutput(0))

#repeat=99
#angle=35

For i=0 To 3

	t=ElapsedMilliseconds()

	For m=0 To #repeat
		p=0

		For n=0 To #angle
			If n&3=0 : p+1 : EndIf
			Select i
			Case 0
				ClipLine(120,120,120+Sin(n*#PI/#angle*2)*100,120+Cos(n*#PI/#angle*2)*100,#Red,p); 1s
			Case 1
				thickLineXY(350,120,350+Sin(n*#PI/#angle*2)*100,120+Cos(n*#PI/#angle*2)*100,p,#Red); 15s
			Case 2
				NormalL(120,350,120+Sin(n*#PI/#angle*2)*100,350+Cos(n*#PI/#angle*2)*100,#Red,p); 15s
			Case 3
				LineAA(350,350,Sin(n*#PI/#angle*2)*100,Cos(n*#PI/#angle*2)*100,#Red,p); 15s
			EndSelect
		Next n
	Next m

	t-ElapsedMilliseconds()

	Select i
	Case 0
		DrawText(200,30,Str(-t))
	Case 1
		DrawText(430,30,Str(-t))
	Case 2
		DrawText(200,240,Str(-t))
	Case 3
		DrawText(430,240,Str(-t))
	EndSelect

Next i

StopDrawing()
ImageGadget(0, 0, 0, 300, 300, ImageID(0))

Repeat
	Event=WaitWindowEvent()
Until Event=#PB_Event_CloseWindow
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Drawing lines of variable thickness

Post by srod »

Wow, one of my first postings! :)
I may look like a mule, but I'm not a complete ass.
User avatar
kernadec
Enthusiast
Enthusiast
Posts: 146
Joined: Tue Jan 05, 2010 10:35 am

Re: Drawing lines of variable thickness

Post by kernadec »

Hi
PureBasic now has a range of functions and 3D animations very magical
but I think it's time to power with PB native 2DDrawing and CanvasGadget
draw a BOX with an angle
draw an Ellipse with an angle
draw an ARC with an angle would welcome
draw a LINE mode with Thickness and Styles
the thicknesses and styles also applied to ARC BOX ELLIPSE

Goodday
Puffolino
User
User
Posts: 49
Joined: Thu Jan 05, 2012 12:27 am

Re: Drawing lines of variable thickness

Post by Puffolino »

I thought to use a workaround meanwhile, by drawing multiple standard lines (instead of the slow and ugly circles), but my quick try has holes like a cheese :P

Code: Select all

Procedure MyLineXY(x1,y1,x2,y2,Color,Thickness=1)
	
	#FineShift=10
	#FineMore=1
	#FineOne=1<<(#FineShift-#FineMore-1)
	#FineTwo=2<<(#FineShift-#FineMore-1)

	Protected n,h,w,sx,sy
	Protected hypo.f,dx.f,dy.f
	
	w=x2-x1
	h=y2-y1

	If w>=0
		sx=1
	Else
		sx=-1
		w=-w
	EndIf
	If h>= 0
		sy=1
	Else
		sy=-1
		h=-h
	EndIf

	hypo.f=Sqr(w*w+h*h)
	dy=w/hypo
	dx=-Sin(ACos(dy))*sx
	dy=dy*sy
		
	x1=x1<<#FineShift-(dx*Thickness)/#FineOne
	y1=y1<<#FineShift-(dy*Thickness)/#FineOne
	x2=x2<<#FineShift-(dx*Thickness)/#FineOne
	y2=y2<<#FineShift-(dy*Thickness)/#FineOne
	
	x0=dx*#FineTwo
	y0=dy*#FineTwo
	
	For n=0 To Thickness<<#FineMore
		LineXY(x1>>#FineShift,y1>>#FineShift,x2>>#FineShift,y2>>#FineShift,#Blue)
		x1+x0
		y1+y0
		x2+x0
		y2+y0
	Next n

EndProcedure
Post Reply