Draw a line code not working

Hi davebollinger - my build number is 2017.3068.

I’ll update to the latest now and try the code again.

I only realised now there is no auto-update for Corona??

Have updated to latest build 2017.3086 but still get the same behaviour:

Jun 07 05:32:46.256 Copyright (C) 2009-2017 C o r o n a L a b s I n c . Version: 3.0.0 Build: 2017.3086 Jun 07 05:32:46.271 Loading project from: ~/Dropbox/Archive Rene/Corona/Bouncing balls Jun 07 05:32:46.271 Project sandbox folder: ~/Library/Application Support/Corona Simulator/Bouncing balls-595A9E7EAC84D232BD3AEB40A40A4AA9 Jun 07 05:32:46.274 Platform: iPhone / x86\_64 / 10.12.5 / AMD Radeon Pro 455 OpenGL Engine / 2.1 ATI-1.51.8 / 2017.3086 / en-GB | DE | en\_DE | en Jun 07 05:33:05.042 moved began 324 408 324 408 Jun 07 05:33:05.066 moved append 324 408 Jun 07 05:33:05.074 moved append 324 408 Jun 07 05:33:05.104 moved append 324 408 Jun 07 05:33:05.104 moved append 324 408 moved append 324 408 Jun 07 05:33:05.107 moved append 324 408 Jun 07 05:33:05.141 moved append 324 408 Jun 07 05:33:05.141 moved append 324 408 moved append 324 408 moved append 324 408 Jun 07 05:33:05.172 moved append 324 408 Jun 07 05:33:05.173 moved append 324 408 moved append 324 408 moved append 324 408 Jun 07 05:33:05.201 moved append 324 408 Jun 07 05:33:05.201 moved append 324 408 moved append 324 408 Jun 07 05:33:05.206 moved append 324 408 Jun 07 05:33:05.237 moved append 324 408 Jun 07 05:33:05.238 moved append 324 408 moved append 324 408 Jun 07 05:33:05.238 moved append 324 408 Jun 07 05:33:05.241 moved append 320 408 Jun 07 05:33:05.260 moved append 320 408 Jun 07 05:33:05.261 moved append 312 408 moved append 312 408 moved append 304 408 Jun 07 05:33:05.278 moved append 304 408 Jun 07 05:33:05.278 moved append 296 408 moved append 296 408 moved append 288 408

This is my config file:

-- -- For more information on config.lua see the Project Configuration Guide at: -- https://docs.coronalabs.com/guide/basics/configSettings -- application = { content = { width = 320, height = 480, scale = "letterbox", fps = 60, --[[imageSuffix = { ["@2x"] = 2, ["@4x"] = 4, }, --]] }, }

In the Corona Simulator, iPhone 5 is selected.

Not sure why I’m not getting the same behaviour on my machine as SGS does on his, using the same code.

So when your device is continually reporting “324 408” are you moving the mouse around?  The fact that the event.y value stays at 408 would imply you managed to draw a completely vertical line.

Have you tried different simulator skins and also do a device build and test it on your phone/tablet.

Different simulator skins didn’t fix the interrupted-line-behaviour although with other skins I did get fractional touch event x/y.

A DEVICE BUILD FINALLY FIXED THE INTERRUPTED-LINE BEHAVIOUR AND CREATED THE EXPECTED SMOOTH-LINES!!

I created builds for my iPhone 7 Plus and for my iPad Pro. The behaviour on the iPhone was still a bit odd, for example tapping didn’t always properly append the existing line but sometimes started a new line. The behaviour on the iPad Pro was flawless.

So, in summary: SGS’s code works fine when I do an iOS device build and test it on my iPhone 7 Plus and iPad Pro. For some reason, when I run the code in the Simulator, however, I get interrupted lines.

Thanks again SGS for your code and your discussion points!

Perhaps it would be worth for me to submit the odd Simulator behaviour as an issue / bug fix candidate somewhere?

I’m guessing you are using a Mac?  I use a PC and this might explain why it works for me in sim but not you.  I would submit it as a Mac sim bug.

Yes that’s right, I’m using a Mac. I wonder if @horacebury does, too, who had the same issue when he ran your code in his sim.

Just to be clear… We used to not pass fractional values. A bug was reported and we now pass fractional values… if the operating system pass them to us.  Fractional values are expected.

Rob

Yes that’s right, I’m using a Mac. I wonder if @horacebury does, too, who had the same issue when he ran your code in his sim.

I was going to ask this (but had to be at work) and yes, I’m using a 2016 Mac Pro.

I have noticed that touch events are fired  continuously when pressing on the track pad but only when moving if a double-tap (to cause a an OS-touch-and-drag). However, all touch events will pass fractional values, as Rob says.

I’ve found that building for Corona Live and testing on device resolved a lot of confusion.

Could the different behaviours in the mouse coordinates “precision” be related to differences in hardware/os?
Maybe some systems might sync the mouse to the display refresh rate while others simply dispatch them as they come. Or maybe some pc/mac have specialized circuita to control the mouse while others rely on the os…
Just a thought…

The difference in behaviors is very likely going to vary between hardware and OS. We are dependent on the values returned by the OS.

Rob

@Rob, if you are using a Mac, just drop my code into main.lua and see if you get continual (on Windows) or broken lines (on Mac)?

You’re creating lots of curves in the line, so you need to check the distance between each additional point on the line; If it is too short, don’t add it - i.e.: if the distance between the last added point and the new one is less than, say, 1, don’t add it.

To further improve the code, I would not bother with having variables like ‘lineAlreadyCreated’ but simply use the fact that the ‘line’ variable is either nil or not.

Further, I believe you should be destroying the whole line and recreating it and that each version of the line should be created by passing in a table of x,y values, which is what will be maintained when you’re adding points - not the line itself.

Try this:

local group, pts, line = display.newGroup(), {}, nil local function length( ax, ay, bx, by ) local width, height = bx-ax, by-ay return (width\*width + height\*height)^0.5 end function group:touch(event) if (event.phase == "began") then pts[#pts+1] = event.x pts[#pts+1] = event.y group.hasFocus = true display.currentStage:setFocus( group ) return true elseif (group.hasFocus) then if (event.phase == "moved") then if (length( pts[#pts-1], pts[#pts], event.x, event.y ) \> 1) then if (line) then line:removeSelf() line = nil end pts[#pts+1] = event.x pts[#pts+1] = event.y line = display.newLine( unpack( pts ) ) line:setStrokeColor (1,1,1) line.strokeWidth = 20 end else group.hasFocus = false display.currentStage:setFocus( nil ) end return true end return false end Runtime:addEventListener( "touch", group )

Thank you so much @horacebury! Your code does exactly what I had in mind.

Can I ask for my understanding: What’s the reason why it’s better to destroy the line and recreate it each time, rather than appending to it? Is it because the Corona line:append command is buggy? I would have thought the line:append command is intended for just the kind of use cases that I was trying to implement.

Sorry @horacebury but I have to disagree.

  1. A “moved” event will only fire it the touch point has actually moved from the previous touch point

  2. Agreed

  3. Destroying the line on each “moved” update and redrawing it as that is massively inefficient.  It is like reading a page of text and for each new word you read you start at the beginning of the page again!

FYI, here is a simplified version for you (so you can learn).  Don’t ever have 20+ lines of code when 10 does the job!

local line = nil touchListener = function(event)   if event.phase == "moved" then     if line then       line:append(event.x,event.y)     else       line = display.newLine(event.xStart, event.yStart, event.x, event.y)       line:setStrokeColor (1,1,1)       line.strokeWidth = 20       lineAlreadyCreated = true     end   elseif event.phase == "ended" then     line:append(event.x,event.y)   end   return true end Runtime:addEventListener("touch", touchListener)

And here is the output from the above code

Sorry, SGS, while I totally respect what you do here on the forums and the code you write, I also have to disagree this time. As that is the case, I guess the burden is on me seeing as you’ve provided smaller code.

1. A “moved” event will only fire it the touch point has actually moved from the previous touch point

 

This is true, though the granularity of the points could be almost on top of each other. It is definitely possible to produce touch event values where there two consecutive move phase locations are less than 1 pixel or point apart. This, in my estimation, is causing the ‘folding’ (for want of a better description) in the original code. It does not happen in my code, though I see it happening in your code as well. I’m not sure why it’s not evident in your screenshot, but copy/pasting your code into a brand new main.lua and running it cold produced the same result as Rene found.

 

3. Destroying the line on each “moved” update and redrawing it as that is massively inefficient.  It is like reading a page of text and for each new word you read you start at the beginning of the page again!

 

I do agree here. I was posting code which went quite a bit further than really necessary, I’ll admit. For example, the use of the .hasFocus value is to handle situations where the touch event moved over another object which could handle touch events and was not sensibly filtering input. In that case, you could easily find the touch event being picked up by another touch handler and everything would go wrong. Therefore, I always include that logic, even in the smallest examples.

 

Having said that, the reason to delete the line and recreate it again is because I’m used to thinking that way because in my typical situation it is logical. Without needlessly going into detail, I will say that the number of points used to render various things should be controlled or things will eventually go wrong.

 

I will say that the code could be improved not to delete the line but the problem of one touch being too close to the previous still needs to be handled. I would comment, though, that any decent device these days should be able to delete a line and recreate it without issue. I certainly wouldn’t do it with anything more complex.

 

FYI, here is a simplified version for you (so you can learn).  Don’t ever have 20+ lines of code when 10 does the job!

 

Of course, that’s a great starting point and I kinda wish I’d provided simpler code now. Having said that, here’s a version of my code which does not delete the line. It doesn’t really reduce the number of code lines but it won’t have the performance issue and the points used to build the line will not be excessive (One flaw is that it is no longer possible to retrieve the list of x,y values which build the line, which I consider a requirement - even for learning):

local group, pt, line = display.newGroup(), {}, nil local function length( ax, ay, bx, by ) local width, height = bx-ax, by-ay return (width\*width + height\*height)^0.5 end function group:touch(event) if (event.phase == "began") then group.hasFocus = true display.currentStage:setFocus( group ) pt = { x=event.x, y=event.y } return true elseif (group.hasFocus) then if (event.phase == "moved") then if (length( pt.x, pt.y, event.x, event.y ) \> 1) then pt = { x=event.x, y=event.y } if (line == nil) then line = display.newLine( event.xStart, event.yStart, pt.x, pt.y ) line:setStrokeColor (1,1,1) line.strokeWidth = 20 else line:append( pt.x, pt.y ) end end else group.hasFocus = false display.currentStage:setFocus( nil ) end return true end return false end Runtime:addEventListener( "touch", group )

Always good to debate!  

I don’t get this “folding” you are referring to with my code - as you saw from the screenshot - so I didn’t have to code around it.  The joys of debugging eh?

  1. A lot depends on the canvas resolution and the device resolution if a distance check is required or not.  A 320 x 400 canvas on HD device definitely would but a 640 x 1136 canvas on an iPhone 5 would be pointless as there would be parity between screen and canvas pixels.  Personally, I usually check for a delta movement of more than 5px before acting on “moved” events.

  2. Absolutely, I would always use a focus check and display.currentStage:setFocus() in production code - I was keeping it simple for the OP to concentrate on just the drawing.

  3. If the OP wants to save the drawing as a jpg then storing point data is not required.  But if the drawing was to be editable then I agree that storing the point data has merit.

  4. I wouldn’t use a line to do this if it was me as the result isn’t great - no anti-aliasing for example.  But we could get into much more complicated principles which may be too much.

When answering questions I try and apply the most simple and precise code to achieve what the OP wants. Not necessarily “fully decorated” code which is what you provided.  Neither are necessarily wrong, they are just slightly different approaches.

I think the folding (for want of a better term) is happening when the touch moves relatively slowly. On my machine it happens at any simulator zoom level, at any touch speed. My app is running as a screen size of 720x1024 (or something close to that, I’m not on my machine right now.)

  1. Points for learning vs production. I wonder if I’ve been posting overly-complex code? (Ouch)

  2. True. We don’t know as he didn’t state, but I always assume the data is important. Certainly is in my inputs.

Agreed on posting teaching code. I tend to post the most robust code I can because if anyone can take from it, I want them to be able to reuse it and not have to ask why it breaks in another situation.

@rene.anderson Do you have any more questions about the discussion above?

Having said that, we’re going a long way to describe how to draw a line!

This thread shows everything that is right with coronalabs, thank you guys and everyone else who helps us all out so much, and go so far insanely into detail, that anyone can understand.

Thank you so much horacebury and Sphere Game Studios for your input! Although drawing a line is a very simple task, I feel it is well worth exploring thoroughly for its fundamental nature - and as the debate shows, I think, it’s not quite as straightforward as one might initially think. And keeping in mind, we’re not even talking about beautiful lines here (the kind you see in the game Blek, for instance) but very basic, prototypical (ugly) line drawing.

Sphere Game Studios - thank you so much for your simplified code! On my machine, however, it produces the same strange behaviour as my original code did. Here is a link to a screen video of it (It’s not possible to upload a video directly into this post, is it? Only images?). As the mouse moves faster the line gets more continuous, but at low mouse speeds the line keeps breaking up. I’d like to find the reason for this but it might take me a while to figure it out. Maybe it has to do with configuration?

In regards to the need to store point data - well, it turns out I’d like to be able to determine whether the line intersects with other display objects on the screen, for example a circle. I haven’t worked out the code for this but I did wonder whether I will need to write code that stores the point data in a table as the line is drawn, or whether the Corona engine stores the point data automatically and whether there be an API to read the point data of a line object that has been drawn, or an API that determines whether two display objects intersect.

horacebury, could I ask why you’ve used a “return false” (rather than ‘return true’) at the end of your code (third to last line)? What purpose does the ‘return false’ have?

And horacebuy, I’d love to know more about the advantages you see in the approach of destroying and recreating lines, as opposed to appending. You mentioned it has something to do with retaining control?

Sphere Game Studios - you mentioned if the drawing was to be editable then you wouldn’t use a line to do that. Can I ask what you would use instead? I’d love to find out more.