Dotted/Dashed Bezier Curves

It seems that CurveShape,FigureShape and related objects are limited to SOLID borders…

The problem is I need to draw Bezier Curves [curveshape order 0] as dotted or dashed lines. But since this is a “time” based equation, it isn’t easy to find the proper intervals to make these look good. the NSBEZIER in Cocoa has these… but if possible I’d like an xplat equation to do it in both OSX and WIN.

Drawing a dotted/dashed LINE is easy… it is the curveshape equivalent that I need

anyone?

anyone? :frowning:

I’ve searched the Internet… and all I can find is other apps that have this feature… but nothing that explains the math behind doing it

Dave have you seen this site yet? It’s not Bezier but you may be able to get closer? Bresenham Plots

If you have seen this again please disregard, but for others it has a rbp sample to draw dashed lines, circles, rectangles etc.

I have… and it is great code for lines, circles, round rects etc…

The problem is those shapes are all linear calculations and fit the Bresenham equation set… .

A Bezier curve doesn’t… the equation is non linear (note a circle is a linear equation in that it is based on evenly spaced DEGREES)
while Bezier is based on “time”

I sure hope time is nice & linear :stuck_out_tongue:

That small joke aside is what need is a “pen pattern” you can set the pen to & draw with that would result in a dashed line for the bezier ?

Yeah… but Xojo doesn’t support a Pen Pattern does it???

this would be PERFECT if I could do this

dim c as new curveshape

c.linestyle=curveshape.styledashed

The way I’ve done it (and since lost) is stepping through each sampled point and measuring the segment distance then comparing that to the dash pattern to see whether a line should be drawn or not. For extra accuracy interpolate on the segment for the exact dash length. And use doubles or floats instead of integers for the returned sample points.

Thanks for the plug Mike :slight_smile: Would this help you Dave? I’m guessing not, you probably know how to do this …

Bezier

Having not tried this before with Bezier, I would guess you could replace the drawing in this project with Core Graphics where you can set the pen style to dashes quite easily as demonstrated here. Core Graphic Dash Lines. Or use MacOsLib. Why Xojo doesn’t expose the plethora of basic Quartz drawing is really sad.

We use CoreGraphics paths to obtain dashed lines - but sadly it’s not x-plat.

And here’s a project that demonstrates how to use MacOsLib and Quartz drawing.

Core Graphics MacOsLib

Thanks Thomas… but everything in those demos are related (as far as I could tell) to straight lines and circle/arcs, and I can replicate those in pure Xojo… the problem is the equation for a BEZIER does not fit that mold.

for those of you not aware… this is the basic QUAD BEZIER equation (and it matches a CURVESHAPE of ORDER=1 perfectly)

  t=tt/range
  t2=t*t
  tm=(1-t)
  tm2=tm*tm
  t3=tm*t*2
  xx = tm2 * xpos(0) + t3 * xpos(2) + t2 * xpos(1)
  yy = tm2 * ypos(0) + t3 * ypos(2) + t2 * ypos(1)

where range is a value to determine precision (I use the max distance between any of the 3 points)
and TT=0 to RANGE

But XX and YY rarely come back as equidistance points

You might get better results if you use

tt = 0 to range step 0.1

and throw away any points that are duplicates.

I came up with a class to draw dashed Bezier curves (linear, quadratic, and cubic) using pure Xojo code. It includes scaling and translating the curve. PM me your email address and I’ll send it to you.

Hi Bradley, I’d like to see that too, and I think others as well. Could you post it somewhere?

In the meantime I made the non-accurate version of what I said above with Dave’s code.

[code]//to a Window (or Canvas) add this event

Sub Paint(g As Graphics, areas() As REALbasic.Rect)

g.ForeColor = &c000000
g.PenWidth = 2
g.PenHeight = 2

dim xpos() As double = Array(0.0, g.Width, 0.0) //control points
dim ypos() As double = Array(0.0, 0.0, g.Height)

dim dashes() As double = Array(10.0, 10.0, 20.0, 10.0) //~10 pixels on, 10 off, 20 on, 10 off, loop

//draw bezier curve xpos/ypos using dashes and 1000 segments
drawDashedBezier(g, xpos, ypos, dashes, 1000)

End Sub

//and add these 2 methods

Sub drawDashedBezier(g As Graphics, xpos() As double, ypos() As double, dashes() As Double, resolution As integer = 500)
if dashes.Ubound = -1 then dashes = Array(100.0, 0.0) //fix dashes() if no elements

//tracking vars
dim dashIsOn As boolean = true //treat first dashes() element as dash ON
dim summedDist As double = 0.0 //total curve distance traveled
dim curDashIdx As integer = 0 //current index into dashes()
dim nextDashPointDist As double = dashes(curDashIdx) //distance to end of current dash
dim dashCount As integer = dashes.Ubound + 1 //for wrapping curDashIdx
dim x0, y0, x1, y1 As double //segment endpoints
dim xDiff, yDiff, dist As double //temps

sampleBezier(0.0, xpos, ypos, x0, y0) //sample t=0.0 of curve xpos/ypos into point x0,y0

for i As integer = 1 to resolution

sampleBezier(i / resolution, xpos, ypos, x1, y1)   //sample t=i/res into x1,y1

xDiff = x1 - x0   //measure and sum distance
yDiff = y1 - y0
dist = Sqrt(xDiff * xDiff + yDiff * yDiff)
summedDist = summedDist + dist

while summedDist > nextDashPointDist   //while past the current dash distance
  dashIsOn = not dashIsOn                       //flip dash state
  curDashIdx = (curDashIdx + 1) mod dashCount   //step to next dash
  nextDashPointDist = nextDashPointDist + dashes(curDashIdx) //and add in it's distance
wend

if dashIsOn then g.DrawLine x0, y0, x1, y1   //draw segment if ON

x0 = x1 //roll coords
y0 = y1

next

End Sub

Sub sampleBezier(t As double, xpos() As double, ypos() As double, byref x As double, byref y As double)
dim t2, tm, tm2, t3 As double
t2=tt
tm=(1-t)
tm2=tm
tm
t3=tmt2
x = tm2 * xpos(0) + t3 * xpos(2) + t2 * xpos(1)
y = tm2 * ypos(0) + t3 * ypos(2) + t2 * ypos(1)
End Sub[/code]

Because lines only start or stop on sampled points the resolution needs to be high enough to approximate dash lengths, otherwise the pattern aliases. Using a high resolution is inefficient and ‘hardens’ the lines though.

Needs segment interpolation and possibly adaptive sampling. I think the Sqrt could be removed.

Where? I don’t have a website or anything like that. I suppose I could just break it down into a forum post, but not today.

Bradley… email it to me (you have my address)
and I will post it on my website (giving you all the credit of course)

I do not have your address.

sent you a private message…

GOT IT!

Here is a demo app with a Bezier class (similar but not the same as CURVESHAPE)
it will draw a LINEAR, QUAD or CUBIC Bezier curve as SOLID, DOTTED or DASHED line
(when drawing SOLID it actually does use a CURVESHAPE for speed)

If you find an issues, or improvements… please let me know

www.rdS.com/mybezier.xojo_xml_project.zip

unfortunatly this code is not related in any way to the code Bradley sent me.
Turns out his code divided the line into “X” segments and each segment changed length in a logrithmic manner…

this one is closer to what I was looking for… and mostly from scratch… although I did use the CUBIC equation from Bradley’s code…