Middlepoint on a curve created by AddPathCurve

Just starting out? Need help? Post your questions and find answers here.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Middlepoint on a curve created by AddPathCurve

Post by wilbert »

The easiest way I think is to do a close approximation of the curve with small line segments.
Count the length of all segments together, find out on which segment the midpoint is located and interpolate on that segment to find the interpolated location.
The endpoints of the segment on which the midpoint is located can be used to calculate the angle of the segment.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 544
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

Re: Middlepoint on a curve created by AddPathCurve

Post by bbanelli »

DK_PETER wrote:1. Could you try to reinstall DirectX 9c drivers and try again? You need them in Windows 10 too.
This one? https://www.microsoft.com/en-us/downloa ... x?id=34429
2. See if you can run it using OpenGL in subsystem.
Example works properly with OGL in both x86 and x64 version, yes!
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
User avatar
Didelphodon
PureBasic Expert
PureBasic Expert
Posts: 450
Joined: Sat Dec 18, 2004 11:56 am
Location: Vienna - Austria
Contact:

Re: Middlepoint on a curve created by AddPathCurve

Post by Didelphodon »

wilbert wrote:The easiest way I think is to do a close approximation of the curve with small line segments.
Count the length of all segments together, find out on which segment the midpoint is located and interpolate on that segment to find the interpolated location.
The endpoints of the segment on which the midpoint is located can be used to calculate the angle of the segment.
Sounds reasonable. You don't have a code example, do you? ;-P
Go, tell it on the mountains.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Middlepoint on a curve created by AddPathCurve

Post by wilbert »

Didelphodon wrote:You don't have a code example, do you? ;-P
No PureBasic code.
Years ago I did this one with ActionScript.
It uses the same approach to animate along a path in a linear speed.
Last edited by wilbert on Wed May 31, 2017 3:06 pm, edited 1 time in total.
Windows (x64)
Raspberry Pi OS (Arm64)
Little John
Addict
Addict
Posts: 4778
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Middlepoint on a curve created by AddPathCurve

Post by Little John »

wilbert wrote:The easiest way I think is to do a close approximation of the curve with small line segments.
Count the length of all segments together, find out on which segment the midpoint is located and interpolate on that segment to find the interpolated location.
That's a good idea. :-)
Below there is some code that does do so.
wilbert wrote:The endpoints of the segment on which the midpoint is located can be used to calculate the angle of the segment.
@Didelphodon:
I am too lazy now to calculate that angle, but I added a Debug message that contains a hint. :-)

Code: Select all

; tested with PB 5.42 beta 2 x64 on Windows 10

EnableExplicit

Structure PointD
   x.d
   y.d
EndStructure


Procedure DeCasteljau (x0.d, y0.d, x1.d, y1.d, x2.d, y2.d, x3.d, y3.d, t.d, *p.PointD)
   ; -- De Casteljau's algorithm
   ; <http://stackoverflow.com/questions/14174252/how-to-find-out-y-coordinate-of-specific-point-in-bezier-curve-in-canvas>, 2016-02-22
   ; in : x0, y0, x1, y1, x2, y2, x3, y3: see PB's AddPathCurve()
   ;      (x0, y0 = current position of the cursor)
   ;      t: rational number from the interval [0.0; 1.0]
   ; out: *p: Coordinates of the wanted point
   Protected.d Ax, Ay, Bx, By, Cx, Cy, Dx, Dy, Ex, Ey
   
   Ax = (1.0 - t) * x0  +  t * x1
   Ay = (1.0 - t) * y0  +  t * y1
   Bx = (1.0 - t) * x1  +  t * x2
   By = (1.0 - t) * y1  +  t * y2
   Cx = (1.0 - t) * x2  +  t * x3
   Cy = (1.0 - t) * y2  +  t * y3
   
   Dx = (1.0 - t) * Ax  +  t * Bx
   Dy = (1.0 - t) * Ay  +  t * By
   Ex = (1.0 - t) * Bx  +  t * Cx
   Ey = (1.0 - t) * By  +  t * Cy
   
   *p\x = (1.0 - t) * Dx  +  t * Ex
   *p\y = (1.0 - t) * Dy  +  t * Ey
EndProcedure


Procedure.d Distance (*p0.PointD, *p1.PointD)
   ; in : Coordinates of two points
   ; out: Distance between both points
   Protected.d dx, dy
   
   dx = *p1\x - *p0\x
   dy = *p1\y - *p0\y
   ProcedureReturn Sqr(dx*dx + dy*dy)
EndProcedure


Procedure MidPoint (x0.d, y0.d, x1.d, y1.d, x2.d, y2.d, x3.d, y3.d, n.i, *m.PointD)
   ; in : x0, y0, x1, y1, x2, y2, x3, y3: see PB's AddPathCurve()
   ;      (x0, y0 = current position of the cursor)
   ;      n: number of line segments for approximation
   ;         (the higher this number, the more precise will be the result)
   ; out: *m: Coordinates of the midpoint of the curve
   Protected i.i, t.d, t0.d, t1.d, halfLen.d=0.0, temp.d=0.0
   Protected p0.PointD, p1.PointD
   
   ; get approximately half the length of the curve
   DeCasteljau(x0, y0, x1, y1, x2, y2, x3, y3, 0.0, @p0)
   For i = 1 To n
      t = i / n
      DeCasteljau(x0, y0, x1, y1, x2, y2, x3, y3, t, @p1)
      halfLen + Distance(@p0, @p1)
      CopyStructure(@p1, @p0, PointD)
   Next
   halfLen / 2.0
   
   ; get the segment where the midpoint of the length of the curve is located
   DeCasteljau(x0, y0, x1, y1, x2, y2, x3, y3, 0.0, @p0)
   For i = 1 To n
      t = i / n
      DeCasteljau(x0, y0, x1, y1, x2, y2, x3, y3, t, @p1)
      temp + Distance(@p0, @p1)
      If temp > halfLen
         t0 = (i - 1) / n
         t1 = t
         Break
      EndIf   
      CopyStructure(@p1, @p0, PointD)
   Next
   
   ; calculate approximately the coordinates of the midpoint
   *m\x = p0\x + (p1\x - p0\x) / 2
   *m\y = p0\y + (p1\y - p0\y) / 2
   
   Debug "The midpoint is between t0 = " + StrD(t0, 2) + " and t1 = " + StrD(t1, 2) + "."
   Debug "It is approximately located at Mx = " + StrD(*m\x, 2) + ", My = " + StrD(*m\y, 2) + "."
   Debug "(Use p0 and p1 together with Atan2() to get the angle of the segment that contains the midpoint.)"
EndProcedure


; -- Demo
Define.d x0, y0, x1, y1, x2, y2, x3, y3
Define.i i
Define p.PointD

x0 =  50 : y0 = 100
x1 =  90 : y1 =  30
x2 = 250 : y2 = 180
x3 = 350 : y3 = 100

OpenWindow(0, 0, 0, 400, 200, "Midpoint of bezier curve", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CanvasGadget(0, 0, 0, 400, 200)

; AddPathCurve(): red line
If StartVectorDrawing(CanvasVectorOutput(0))
   MovePathCursor(x0, y0)
   AddPathCurve(x1, y1, x2, y2, x3, y3)
   VectorSourceColor(RGBA(255, 0, 0, 255))
   StrokePath(10)
   StopVectorDrawing()
EndIf

; DeCasteljau() for t = 0.5: blue circle
DeCasteljau(x0, y0, x1, y1, x2, y2, x3, y3, 0.5, @p)
If StartVectorDrawing(CanvasVectorOutput(0))
   AddPathCircle(p\x, p\y, 5)
   VectorSourceColor(RGBA(0, 0, 255, 255))
   StrokePath(2)
   StopVectorDrawing()
EndIf

; Midpoint of the curve: green circle
MidPoint(x0, y0, x1, y1, x2, y2, x3, y3, 10, @p)
If StartVectorDrawing(CanvasVectorOutput(0))
   AddPathCircle(p\x, p\y, 5)
   VectorSourceColor(RGBA(0, 255, 0, 255))
   StrokePath(2)
   StopVectorDrawing()
EndIf

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Image
Last edited by Little John on Mon Feb 22, 2016 11:12 pm, edited 1 time in total.
User avatar
Didelphodon
PureBasic Expert
PureBasic Expert
Posts: 450
Joined: Sat Dec 18, 2004 11:56 am
Location: Vienna - Austria
Contact:

Re: Middlepoint on a curve created by AddPathCurve

Post by Didelphodon »

@All: Thx for all your efforts
Go, tell it on the mountains.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Middlepoint on a curve created by AddPathCurve

Post by srod »

Nice one Little John. I think that shows quite nicely that putting t=1/2 does not, in all but the simplest cases, give the proper mid-point of the bezier.
I may look like a mule, but I'm not a complete ass.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: Middlepoint on a curve created by AddPathCurve

Post by RASHAD »

For approximation 0.00001 (Near perfect)

Code: Select all

Global length.f, i.f
Global Dim XY.f(1)

Procedure.f BezierMidPoint(x1,y1,x2,y2,x3,y3,x4,y4,approx.f)
  xx=x1
  yy=y1  
  cx.f=3*(x2-x1)
  bx.f=3*(x3-x2)-cx
  ax.f=x4-x1-cx-bx
  cy.f=3*(y2-y1)
  by.f=3*(y3-y2)-cy
  ay.f=y4-y1-cy-by  
  length = 0.0
  Repeat
    i+approx
    x=((ax*i+bx)*i+cx)*i+x1
    y=((ay*i+by)*i+cy)*i+y1
    If i>0
      length = length + Sqr(Pow(x-xx, 2) + Pow(y-yy, 2))
    EndIf    
    xx=x
    yy=y
  Until i > 1
  llength.f = length
  xx=x1
  yy=y1
  length = 0.0
  i.f = 0.0
  Repeat
    i+approx
    x=((ax*i+bx)*i+cx)*i+x1
    y=((ay*i+by)*i+cy)*i+y1
    If i>0
      length = length + Sqr(Pow(x-xx, 2) + Pow(y-yy, 2))
      If length > llength/2
        xy(0) = x
        xy(1) = y 
        Break
      EndIf
    EndIf    
    xx=x
    yy=y
  Until i > 1
EndProcedure 

BezierMidPoint(50,100,90,30,250,180,350,100,0.00001)
Debug xy(0)
Debug xy(1)
OpenWindow(0, 0, 0, 400, 200, "Midpoint of bezier curve", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CanvasGadget(0, 0, 0, 400, 200)

If StartVectorDrawing(CanvasVectorOutput(0))
   MovePathCursor(50,100)
   AddPathCurve(90,30,250,180,350,100)
   VectorSourceColor($FF0005EB)
   StrokePath(10)
   ResetPath()
   VectorSourceColor($FF14EB00)
   AddPathCircle(xy(0),xy(1),5)
   StrokePath(2)
   StopVectorDrawing()
EndIf

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Egypt my love
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Middlepoint on a curve created by AddPathCurve

Post by wilbert »

Little John wrote:That's a good idea. :-)
Below there is some code that does do so.
Nice work :D
What I like about De Casteljau's algorithm is that at places where the curve changes a lot the calculated points are closer together and where the curve doesn't change that much they are further apart.
As a result of this you don't need thousands of points to get a rather good approximation as you did demonstrate with your example which does a pretty good job with only 10 line segments.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Didelphodon
PureBasic Expert
PureBasic Expert
Posts: 450
Joined: Sat Dec 18, 2004 11:56 am
Location: Vienna - Austria
Contact:

Middlepoint on a curve created by AddPathCurve

Post by Didelphodon »

@RASHAD, Little John: How would your approach apply to a curve/path consisting of more points? As I mentioned, my curves can have an undefined number of points.
Go, tell it on the mountains.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: Middlepoint on a curve created by AddPathCurve

Post by RASHAD »

Hi Didelphodon

- The Blue Boxes are your nodes
- Pick one node before each two Control nodes and another after etch two(The Black circles)
- The Green Circles are the mid points of each segment
This is the way I use to do such things
Here I used approximation 0.005 for speed but it is still sufficient

Code: Select all

Global length.f, i.f
Global Dim XY.f(1)

Procedure.f BezierMidPoint(x1,y1,x2,y2,x3,y3,x4,y4,approx.f)
  xx=x1
  yy=y1 
  cx.f=3*(x2-x1)
  bx.f=3*(x3-x2)-cx
  ax.f=x4-x1-cx-bx
  cy.f=3*(y2-y1)
  by.f=3*(y3-y2)-cy
  ay.f=y4-y1-cy-by 
  length = 0.0
  Repeat
    i+approx
    x=((ax*i+bx)*i+cx)*i+x1
    y=((ay*i+by)*i+cy)*i+y1
    If i>0
      length = length + Sqr(Pow(x-xx, 2) + Pow(y-yy, 2))
    EndIf   
    xx=x
    yy=y
  Until i > 1
  llength.f = length
  xx=x1
  yy=y1
  length = 0.0
  i.f = 0.0
  Repeat
    i+approx
    x=((ax*i+bx)*i+cx)*i+x1
    y=((ay*i+by)*i+cy)*i+y1
    If i>0
      length = length + Sqr(Pow(x-xx, 2) + Pow(y-yy, 2))
      If length > llength/2
        xy(0) = x
        xy(1) = y
        Break
      EndIf
    EndIf   
    xx=x
    yy=y
  Until i > 1
EndProcedure

BezierMidPoint(50,100,90,30,250,180,350,100,0.005)
centx1.f = xy(0)
centy1.f = xy(1)
BezierMidPoint(350,100,400, 60, 450, 290, 550, 200,0.005)
centx2.f = xy(0)
centy2.f = xy(1) 
 
  If OpenWindow(0, 0, 0, 600, 350, "VectorDrawing", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    CanvasGadget(0, 0, 0, 600, 350)

    If StartVectorDrawing(CanvasVectorOutput(0))

      MovePathCursor(50, 100)
      AddPathCurve(90, 30, 250, 180, 350, 100)
      VectorSourceColor($FF0003F1)
      StrokePath(10)
      ResetPath()
      VectorSourceColor($FF14EB00)
      AddPathCircle(centx1,centy1,5)
      StrokePath(2)
      VectorSourceColor($FF0003F1)
      MovePathCursor(350, 100)
      AddPathCurve(400, 60, 450, 290, 550, 200)
      StrokePath(10)
      ResetPath()
      VectorSourceColor($FF14EB00)
      AddPathCircle(centx2,centy2,5)
      StrokePath(2)
      ResetPath()
      VectorSourceColor($FF000000)
      AddPathCircle(50,100,5)
      AddPathCircle(350,100,5)
      AddPathCircle(550,200,5)
      FillPath()
      ResetPath()
      VectorSourceColor($FFF11700)
      AddPathBox(90,30,10,10)
      AddPathBox(250,180,10,10)
      AddPathBox(400,60,10,10)
      AddPathBox(450,290,10,10)
      FillPath()   
      StopVectorDrawing()
    EndIf
   
    Repeat
      Event = WaitWindowEvent()
    Until Event = #PB_Event_CloseWindow
  EndIf
Egypt my love
Little John
Addict
Addict
Posts: 4778
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Middlepoint on a curve created by AddPathCurve

Post by Little John »

Didelphodon wrote:@RASHAD, Little John: How would your approach apply to a curve/path consisting of more points? As I mentioned, my curves can have an undefined number of points.
How do you use PB's AddPathCurve() for such a curve with multiple points? Can you post a working code example?
User avatar
Didelphodon
PureBasic Expert
PureBasic Expert
Posts: 450
Joined: Sat Dec 18, 2004 11:56 am
Location: Vienna - Austria
Contact:

Re: Middlepoint on a curve created by AddPathCurve

Post by Didelphodon »

Little John wrote:
Didelphodon wrote:@RASHAD, Little John: How would your approach apply to a curve/path consisting of more points? As I mentioned, my curves can have an undefined number of points.
How do you use PB's AddPathCurve() for such a curve with multiple points? Can you post a working code example?
At least with the txt-output of Graphviz the included Bezier curves can be drawn perfectly equal with the following code ...

Code: Select all

Procedure AddPathBezierCurve(List Points.struct_Point(), xDisplacement.d = 0, yDisplacement.d = 0)
	ForEach Points()
		If (Not ListIndex(Points()))
			MovePathCursor(xDisplacement + Points()\x, yDisplacement + Points()\y)
		Else
			Select (ListSize(Points()) - ListIndex(Points()))
				Case 1
					x1.i = xDisplacement + Points()\x
					y1.i = yDisplacement + Points()\y
					x2.i = xDisplacement + Points()\x
					y2.i = yDisplacement + Points()\y
					x3.i = xDisplacement + Points()\x
					y3.i = yDisplacement + Points()\y
					AddPathCurve(x1, y1, x2, y2, x3, y3)
					; AddPathLine(x1, y1)
				Case 2
					x1.i = xDisplacement + Points()\x
					y1.i = yDisplacement + Points()\y
					NextElement(Points())
					x2.i = xDisplacement + Points()\x
					y2.i = yDisplacement + Points()\y
					x3.i = xDisplacement + Points()\x
					y3.i = yDisplacement + Points()\y
					AddPathCurve(x1, y1, x2, y2, x3, y3)
				Default
					x1.i = xDisplacement + Points()\x
					y1.i = yDisplacement + Points()\y
					NextElement(Points())
					x2.i = xDisplacement + Points()\x
					y2.i = yDisplacement + Points()\y
					NextElement(Points())
					x3.i = xDisplacement + Points()\x
					y3.i = yDisplacement + Points()\y
					AddPathCurve(x1, y1, x2, y2, x3, y3)
			EndSelect
		EndIf
	Next
EndProcedure
Of course there's a finishing draw of the path needed - ie. StrokePath
Go, tell it on the mountains.
User avatar
Didelphodon
PureBasic Expert
PureBasic Expert
Posts: 450
Joined: Sat Dec 18, 2004 11:56 am
Location: Vienna - Austria
Contact:

Re: Middlepoint on a curve created by AddPathCurve

Post by Didelphodon »

Thx again for all of your contributions! Based on various code-examples in this thread I was able to hack together something that covers all the features I initially needed.

Here's the code I'm currently using ...

Code: Select all

CompilerIf Not Defined(struct_Point, #PB_Structure)
	Structure struct_Point
		x.d
		y.d
	EndStructure
CompilerEndIf
Procedure DeCasteljau (x0.d, y0.d, x1.d, y1.d, x2.d, y2.d, x3.d, y3.d, t.d, *p.struct_Point)
	; -- De Casteljau's algorithm
	; <http://stackoverflow.com/questions/14174252/how-to-find-out-y-coordinate-of-specific-point-in-bezier-curve-in-canvas>, 2016-02-22
	; in : x0, y0, x1, y1, x2, y2, x3, y3: see PB's AddPathCurve()
	;      (x0, y0 = current position of the cursor)
	;      t: rational number from the interval [0.0; 1.0]
	; out: *p: Coordinates of the wanted point
	Protected.d Ax, Ay, Bx, By, Cx, Cy, Dx, Dy, Ex, Ey
	
	Ax = (1.0 - t) * x0  +  t * x1
	Ay = (1.0 - t) * y0  +  t * y1
	Bx = (1.0 - t) * x1  +  t * x2
	By = (1.0 - t) * y1  +  t * y2
	Cx = (1.0 - t) * x2  +  t * x3
	Cy = (1.0 - t) * y2  +  t * y3
	
	Dx = (1.0 - t) * Ax  +  t * Bx
	Dy = (1.0 - t) * Ay  +  t * By
	Ex = (1.0 - t) * Bx  +  t * Cx
	Ey = (1.0 - t) * By  +  t * Cy
	
	*p\x = (1.0 - t) * Dx  +  t * Ex
	*p\y = (1.0 - t) * Dy  +  t * Ey
EndProcedure
Procedure.d Distance (*p0.struct_Point, *p1.struct_Point)
	; in : Coordinates of two points
	; out: Distance between both points
	Protected.d dx, dy
	
	dx = *p1\x - *p0\x
	dy = *p1\y - *p0\y
	ProcedureReturn Sqr(dx*dx + dy*dy)
EndProcedure
Procedure AddPathBezierCurve(List Points.struct_Point(), xDisplacement.d = 0, yDisplacement.d = 0)
	ForEach Points()
		If (Not ListIndex(Points()))
			MovePathCursor(xDisplacement + Points()\x, yDisplacement + Points()\y)
		Else
			Select (ListSize(Points()) - ListIndex(Points()))
				Case 1
					x1.i = xDisplacement + Points()\x
					y1.i = yDisplacement + Points()\y
					x2.i = xDisplacement + Points()\x
					y2.i = yDisplacement + Points()\y
					x3.i = xDisplacement + Points()\x
					y3.i = yDisplacement + Points()\y
					AddPathCurve(x1, y1, x2, y2, x3, y3)
					; AddPathLine(x1, y1)
				Case 2
					x1.i = xDisplacement + Points()\x
					y1.i = yDisplacement + Points()\y
					NextElement(Points())
					x2.i = xDisplacement + Points()\x
					y2.i = yDisplacement + Points()\y
					x3.i = xDisplacement + Points()\x
					y3.i = yDisplacement + Points()\y
					AddPathCurve(x1, y1, x2, y2, x3, y3)
				Default
					x1.i = xDisplacement + Points()\x
					y1.i = yDisplacement + Points()\y
					NextElement(Points())
					x2.i = xDisplacement + Points()\x
					y2.i = yDisplacement + Points()\y
					NextElement(Points())
					x3.i = xDisplacement + Points()\x
					y3.i = yDisplacement + Points()\y
					AddPathCurve(x1, y1, x2, y2, x3, y3)
			EndSelect
		EndIf
	Next
EndProcedure 
Global _gl_GetBezierCurveMiddleAngleP0.struct_Point
Global _gl_GetBezierCurveMiddleAngleP1.struct_Point
Procedure.d GetBezierCurveMiddleAngle()
	ProcedureReturn Degree(ATan2(_gl_GetBezierCurveMiddleAngleP1\x - _gl_GetBezierCurveMiddleAngleP0\x, _gl_GetBezierCurveMiddleAngleP1\y - _gl_GetBezierCurveMiddleAngleP0\y))
EndProcedure
Procedure GetBezierCurveMiddle(*Middle.struct_Point, List Points.struct_Point(), lineSegmentsForApproximation.i = 10, xDisplacement.d = 0, yDisplacement.d = 0)
	length.d = 0
	ForEach Points()
		If (Not ListIndex(Points()))
			x0.d = xDisplacement + Points()\x
			y0.d = yDisplacement + Points()\y
		Else
			Select (ListSize(Points()) - ListIndex(Points()))
				Case 1
					x1.d = xDisplacement + Points()\x
					y1.d = yDisplacement + Points()\y
					x2.d = xDisplacement + Points()\x
					y2.d = yDisplacement + Points()\y
					x3.d = xDisplacement + Points()\x
					y3.d = yDisplacement + Points()\y
				Case 2
					x1.d = xDisplacement + Points()\x
					y1.d = yDisplacement + Points()\y
					NextElement(Points())
					x2.d = xDisplacement + Points()\x
					y2.d = yDisplacement + Points()\y
					x3.d = xDisplacement + Points()\x
					y3.d = yDisplacement + Points()\y
				Default
					x1.d = xDisplacement + Points()\x
					y1.d = yDisplacement + Points()\y
					NextElement(Points())
					x2.d = xDisplacement + Points()\x
					y2.d = yDisplacement + Points()\y
					NextElement(Points())
					x3.d = xDisplacement + Points()\x
					y3.d = yDisplacement + Points()\y
			EndSelect
			DeCasteljau(x0, y0, x1, y1, x2, y2, x3, y3, 0.0, @p0.struct_Point)
			For i.i = 1 To lineSegmentsForApproximation
				t.d = i / lineSegmentsForApproximation
				DeCasteljau(x0, y0, x1, y1, x2, y2, x3, y3, t, @p1.struct_Point)
				length + Distance(@p0, @p1)
				CopyStructure(@p1, @p0, struct_Point)
			Next i
			x0 = x3
			y0 = y3
		EndIf
	Next
	length2.d = length / 2
	hlength.d = 0
	ForEach Points()
		If (Not ListIndex(Points()))
			x0.d = xDisplacement + Points()\x
			y0.d = yDisplacement + Points()\y
		Else
			Select (ListSize(Points()) - ListIndex(Points()))
				Case 1
					x1.d = xDisplacement + Points()\x
					y1.d = yDisplacement + Points()\y
					x2.d = xDisplacement + Points()\x
					y2.d = yDisplacement + Points()\y
					x3.d = xDisplacement + Points()\x
					y3.d = yDisplacement + Points()\y
				Case 2
					x1.d = xDisplacement + Points()\x
					y1.d = yDisplacement + Points()\y
					NextElement(Points())
					x2.d = xDisplacement + Points()\x
					y2.d = yDisplacement + Points()\y
					x3.d = xDisplacement + Points()\x
					y3.d = yDisplacement + Points()\y
				Default
					x1.d = xDisplacement + Points()\x
					y1.d = yDisplacement + Points()\y
					NextElement(Points())
					x2.d = xDisplacement + Points()\x
					y2.d = yDisplacement + Points()\y
					NextElement(Points())
					x3.d = xDisplacement + Points()\x
					y3.d = yDisplacement + Points()\y
			EndSelect
			DeCasteljau(x0, y0, x1, y1, x2, y2, x3, y3, 0.0, @p0.struct_Point)
			For i.i = 1 To lineSegmentsForApproximation
				t.d = i / lineSegmentsForApproximation
				DeCasteljau(x0, y0, x1, y1, x2, y2, x3, y3, t, @p1.struct_Point)
				hlength + Distance(@p0, @p1)
				If hlength > length2
					t0.d = (i - 1) / lineSegmentsForApproximation
					t1.d = t
					Break 2
				EndIf   
				CopyStructure(@p1, @p0, struct_Point)
			Next i
			x0 = x3
			y0 = y3
		EndIf
	Next
	*Middle\x = p0\x + (p1\x - p0\x) / 2
	*Middle\y = p0\y + (p1\y - p0\y) / 2
	CopyStructure(p0, _gl_GetBezierCurveMiddleAngleP0, struct_Point)
	CopyStructure(p1, _gl_GetBezierCurveMiddleAngleP1, struct_Point)
EndProcedure 
And here is an image that takes advantage of this code - it's entirely drawn using the vector drawing library ...
Image

Absolutely perfect would be to have the text following the curve but I can already live quite comfortably with the current solution thx to you guys. :-)
Go, tell it on the mountains.
Little John
Addict
Addict
Posts: 4778
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Middlepoint on a curve created by AddPathCurve

Post by Little John »

Oops, I'm too slow. :-) While I was writing an answer, you posted again ...
Well, here is my reply, I hope that it's understandable.

Code: Select all

Procedure AddPathBezierCurve(List Points.struct_Point(), xDisplacement.d = 0, yDisplacement.d = 0)
   Protected halfLen.d=0.0, temp.d=0.0
   
   ForEach Points()
      If (Not ListIndex(Points()))
         MovePathCursor(xDisplacement + Points()\x, yDisplacement + Points()\y)
      Else
         Select (ListSize(Points()) - ListIndex(Points()))
            Case 1
               [...]
               AddPathCurve(x1, y1, x2, y2, x3, y3)
               halfLen + <length of this Bezier segment As shown before>
            Case 2
               [...]
               AddPathCurve(x1, y1, x2, y2, x3, y3)
               halfLen + <length of this Bezier segment As shown before>
            Default
               [...]
               AddPathCurve(x1, y1, x2, y2, x3, y3)
               halfLen + <length of this Bezier segment As shown before>
         EndSelect
      EndIf
   Next
   halfLen / 2
   
   ForEach Points()
      If (Not ListIndex(Points()))
         ; MovePathCursor(xDisplacement + Points()\x, yDisplacement + Points()\y)
      Else
         Select (ListSize(Points()) - ListIndex(Points()))
            Case 1
               [...]
               temp + <length of this Bezier segment As shown before>
               If temp > halfLen
                  Break
               EndIf   
            Case 2
               [...]
               temp + <length of this Bezier segment As shown before>
               If temp > halfLen
                  Break
               EndIf   
            Default
               [...]
               temp + <length of this Bezier segment As shown before>
               If temp > halfLen
                  Break
               EndIf   
         EndSelect
      EndIf
   Next
   excess = temp - halfLen
   ; The Break took place in the Bezier segment where the midpoint of the whole curve is.
   ; Now investigate that segment similar as shown before. However, now don't look for
   ; the midpoint of that segment, but for <length of that segment> - excess. 
EndProcedure
Your image looks impressive. Image
Absolutely perfect would be to have the text following the curve [...]
You might want to look at Danilo's DrawBezierText().
Post Reply