#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# Drawing dashed lines

edited January 2014 Posts: 82

Hi all,
Below you can find my take on a function for drawing dashed lines. Now I'm just curious if any of you perhaps know a shorter, more efficient way of doing this?

``````function draw()
background(255)
xx,yy = CurrentTouch.x,CurrentTouch.y+50

noStroke()
fill(255, 0, 0, 255)
ellipse(xx, yy, 20)

stroke(0)
strokeWidth(4)
lineCapMode(SQUARE)
dashed(0,0,xx,yy, 20)
end

function dashed(x1, y1, x2, y2, seg)
local length = math.sqrt((x2-x1)^2 + (y2-y1)^2)
-- n, integer number of segements in length
local n = math.floor(length/seg)
local angle = math.atan((y2-y1)/(x2-x1))
-- dx, dy, leftover length shorter than segmentsize seg
local dx = (length-n*seg)*math.cos(angle)
local dy = (length-n*seg)*math.sin(angle)

local u1,v1,u2,v2
if length-n*seg>=seg/2 then
-- Draw extra segment if leftover is long enough
m = 1
else
-- Else, draw a shorter ending segment
m = 0
u1 = x1 + (x2-x1-dx)
v1 = y1 + (y2-y1-dy)
u2,v2 = x2,y2
line(u1,v1,u2,v2)
end

-- Draw all the line segments
for i = 0,n-1+m do
u1 = x1 + i/n*(x2-x1-dx)
v1 = y1 + i/n*(y2-y1-dy)
u2 = x1 + (i+.5)/n*(x2-x1-dx)
v2 = y1 + (i+.5)/n*(y2-y1-dy)
line(u1,v1,u2,v2)
end
end
``````
Tagged:

• Posts: 1,595

If the lines have to all be the same size, I suggest a texture with a tile map on a mesh. Otherwise make a variable number called n and check if n is a multiple of 2 by doing

``````if (n%2) == 0 then
Draw
end
``````

This will draw a line every other time creating a dashed line, sizes may vary a lot.

• Posts: 1,976

Not sure about the speed difference, but I made a much smaller function with the same result using some built-in functions to calculate things in less lines.

``````function setup()
FPS = 0
parameter.watch("FPS")
parameter.boolean("Use New Dashed Function", false)
parameter.integer("Spacing", 10, 30, 20)
end

function draw()
FPS = FPS * 0.9 + 0.1 / DeltaTime

background(255)
xx,yy = CurrentTouch.x,CurrentTouch.y+50

noStroke()
fill(255, 0, 0, 255)
ellipse(xx, yy, 20)

stroke(0)
strokeWidth(4)
lineCapMode(SQUARE)
if Use_New_Dashed_Function then
dashed(0,0,xx,yy, Spacing)
else
oldDashed(0,0,xx,yy, Spacing)
end
end

function oldDashed(x1, y1, x2, y2, seg)
local length = math.sqrt((x2-x1)^2 + (y2-y1)^2)
-- n, integer number of segements in length
local n = math.floor(length/seg)
local angle = math.atan((y2-y1)/(x2-x1))
-- dx, dy, leftover length shorter than segmentsize seg
local dx = (length-n*seg)*math.cos(angle)
local dy = (length-n*seg)*math.sin(angle)

local u1,v1,u2,v2
if length-n*seg>=seg/2 then
-- Draw extra segment if leftover is long enough
m = 1
else
-- Else, draw a shorter ending segment
m = 0
u1 = x1 + (x2-x1-dx)
v1 = y1 + (y2-y1-dy)
u2,v2 = x2,y2
line(u1,v1,u2,v2)
end

-- Draw all the line segments
for i = 0,n-1+m do
u1 = x1 + i/n*(x2-x1-dx)
v1 = y1 + i/n*(y2-y1-dy)
u2 = x1 + (i+.5)/n*(x2-x1-dx)
v2 = y1 + (i+.5)/n*(y2-y1-dy)
line(u1,v1,u2,v2)
end
end

function dashed(x1, y1, x2, y2, spacing)
local length = vec2(x1, y1):dist(vec2(x2, y2)) -- Length of dashed line
local dir = vec2(x2 - x1, y2 - y1):normalize() -- UV direction pf dashed line
for i = 0, length, spacing do  -- Iterate through the spacing
if i >= length - spacing / 2 then -- Checks if the dash is at the end
line(x1 + dir.x * i, y1 + dir.y * i, x2, y2) -- Trims dash to fit length smoothly
else -- Dash is not at the end
line(x1 + dir.x * i, y1 + dir.y * i, x1 + dir.x * i + dir.x * (spacing / 2), y1 + dir.y * i + dir.y * (spacing / 2)) -- Draw the dash as normal
end
end
end
``````
• edited January 2014 Posts: 140

@Kjell Modulo is your friend here. Figure out how long a dash and a break are and modulo by that number. Then draw or not draw according to where in the pattern you are. E.g. if you want a 10-point dash and 5-point space, then do (pseudocode)

``````if N%15 < 10 then draw end
``````
• edited January 2014 Posts: 521

You can use a shader, leave it as an exercise to fix colors and width ``````function dashed(x1,y1,x2,y2,seg)
local m = mesh()
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
uniform highp float seg;

void main() {
highp float d = 1.0/(seg-.5);
if(mod(vTexCoord.x,d) > (d*.5)) { discard; }
gl_FragColor = vColor;
}
]]
local a, b = vec2(x1,y1),vec2(x2,y2)
local v = b - a
local p = a + v * .5
m:draw()
end
``````
• edited January 2014 Posts: 82

Haha, it seems that my code doesn't even work right when `x2,y2 < x1,y1`, so I'm gonna take a good look at all of your options.

Edit: I'm gonna go with @SkyTheCoder's way here, I didn't really think of just using the built-in vector functions. Looking back, it's amazing how I managed to write so much code to accomplish this.

@tnlogy Your code seems to work fine to, but I'm not that familiar with shaders yet, so I rather not use them. But in the end, are meshes a faster way of drawing lines? Or is the line function of Codea already a mesh at heart?

Also, thank you all for your input!

• Posts: 521

Yes, meshes are faster according to earlier tests, I think line is implemented in a shader, but I guess it is slower since it handles many special cases such as cap mode? Also, if you want to draw a line for several frames, you can store the mesh value m in my example and only call m:draw() in the draw function. Or add thousands of line to id with addRect. You can return to the code if you run into performance issues.

A fragment shader as above is called for every pixel on the rectangle I've defined with a vTexCoord going from x = 0 to x=1. Probably better to define a complementary color than to use discard, since it is a bit slower than to draw the pixel.

• Posts: 3,297

@tnlogy oh! You can draw negative colors to the screen with shaders? What happens if the result is <0 or >255?

• Posts: 5,396

@Jmv38 - shaders automatically restrict the result to be between 0 and 1 (as a fraction of 255)

• Posts: 3,297

@ignatz cool!

• edited January 2014 Posts: 5,396

@Jmv38 - yes and no. This restriction can lead to false colours.

eg if you get an answer of (510, 100, 100), then restricting the color gives you (255, 100, 100), which dramatically reduces just the red.

Instead, you could scale all the numbers down to get (255, 50, 50)

But I'm not sure there is any perfect way of handling boundary conditions.