Drawing hundreds of lines within a datafield?

I'd like to have a simple map showing important trails near the actual GPS location for a better orientation. Estimated 25 trails defined by around 200 lines or so would need to draw up to 500 lines when updating the display. Additionally, other things have to be done as well, fetching the GPS position and orientation, rotating (and zooming) all coordinates, etc.
Is it realistic to do this stuff for a datafield or would it be to slow?

Does anyone has cool tipps for this project?

[IMG2=JSON]{"data-align":"none","data-size":"full","height":"242","width":"242","src":"https:\/\/sites.google.com\/site\/mrvogel\/Files\/Map.png?attredirects=0&d=1"}[/IMG2]

  • There's a few things to consider here, and that include the amount of data you need to store (likely getting it from the internet). Then with that data, you'll need to convert it into screen locations (x,y), and based on the amount of data and the math, you could get into problems with the watchdog timer, with or without the actual display. And with 500 lies, that seems like it would really make the screen a bit cluttered, even with different colors for various lines.

    If you are thinking any kind of user input, at best, that's only a tap on touch displays.

    Here's a rather simple example of what you're thinking, where I just show the current breadcrumb trail and mark laps on it: https://apps.garmin.com/en-US/apps/d741d7b4-8b26-401c-a5bd-0ac91891575d

    In it, I use a max of 100 locations when I display it and a few more for the dots for laps.
  • I have an app that does just this. I limit the number of points on my 935 to 400 between my track and a single course. Plus an addition up to 16 waypoints as simple circles. I also convert all my coordinates to meters from my start point so the math is much simpler, and then cache as screen coordinates. You don't want to be doing a bunch of calculations on each point every time they get drawn. Depending on the device, you will need to be smart about memory management. You probably don't want to have an array of location objects. In my case I have 2 arrays of floats for lat and lon. Objects are pretty expensive as are doubles. An array of 32 bit items (int's, floats) are pretty efficient. My calculations and drawing take between 0.1 and 0.3 seconds in onUpdate.
  • Thanks for all this tips, I was thinking about integers and in a first step I'd like to keep in mind that the earth is flat ;)
    That would simplify the calculation, which could be done like matrix multiplication:

    procedure rotate(x,y,angle)
    sa=sin(angle)
    ca=cos(angle)
    x'=x·ca - y·sa
    y'=x·sa + y·ca
    end

    procedure move(x,y,dx,dy)
    x'=x+dx
    y'=y+dy
    end

    procedure zoom(x,y,zoom)
    x'=x·zoom
    y'=y·zoom
    end

    procedure all(x,y)
    x'=x, y'=y
    move(x',y',-geoposx,-geoposy)
    rotate(x',y',-heading)
    zoom(x',y',zoomfactor)
    move(x',y',screenmidx,screenmidy)
    end;


    Not sure if the calculation could be done each second, otherwise the map wouldn't be accurate and I would have to decenter the arrow of the actual position (so I could calculate 20% of the screen coordinates every second, after 5 seconds I would copy the coordinates which are within the screen area into a array and could redraw these for 5 seconds).


    Anyhow it will take a while before I start this project as I haven't finished some other projects (BirdWatch, Foxrunner, Screeny , ShowRoom, SpeedRename, etc.) and beside this, I need to work from time to time...
    ...but thanks you for all your valuable comments - which helps me to do the first code lines in my head... :D

  • Meantime I had some time to start the project (in a first step I am writing the code in another programming language, because testing is much quicker and easier)...
    ...and I thought, it would be useful to do clipping, so lines outside the screen area are not needed to be drawn...

    So I did use the Cohen-Sutherland algorithm for a quick check and calculated the line distance (for the remaining lines) to the screen center (perfect for round screens), the code is seen below. This filters a lot of lines, so only a small part is needed to be drawn on the screen. But I am not sure it is worth doing these things to speed everything up.

    Therefore I'd like to ask you experts about your experiences about speed in the Connect IQ functions and libraries:

    1. How does the line (and other drawing) function(s) work?
    - would there be any problem when drawing invisible lines (e.g. between points -5000,-500 and 40000/100)?
    - what about speed? Does a clipped line need less (near zero) time to be drawn?
    - I would also need a lot of drawtext calls, most of them would draw outside the visible screen area - what about the speed in this case?

    2. maybe this has been already checked somewhere, can't remember - is there any timing known for different operations?
    - is there a difference using different variable types (e.g. integer vs. floating point)?
    - are any differences seen between different operations (bit shifting, logical operations, +-*/, square root, sin/cos/,...)?
    - would it be possible, that certain garmin devices would show a completely different behaviour (because of different CPU types, etc.)?

    Thanks for all your help!


    Procedure.f Distance(*p.point,*a1.point,*a2.point)

    ; [a2] becomes relative vector from [a1] to end of segment
    *a2\x-*a1\x;
    *a2\y-*a1\y;

    ; [p] becomes relative vector from [a1] to test point
    *p\x-*a1\x;
    *p\y-*a1\y;

    ; dist is the length of the [p] vector projected on the [a1>a2] vector times the length of the [a1>a2] vector
    dist = *p\x* *a2\x + *p\y * *a2\y;

    ; Distance to line is now the length of the relative point vector minus the length of its projection onto the line
    len.f = *p\x * *p\x + *p\y * *p\y - dist * dist / (*a2\x * *a2\x + *a2\y * *a2\y);;

    If len>0
    ProcedureReturn Sqr(len);
    Else
    ProcedureReturn 0
    EndIf

    EndProcedure
  • For actual answers, I'd wait for Brian.ConnectIQ to chime in, but I should be able give some guidance...

    It really doesn't matter how the drawing functions work or what happens when the line is outside of the viewport. The thing that matters is what the cost, if any, is associated with getting the line information to the graphics system and then the cost to cull the line. You can assume that these costs are non-zero, so the real question is whether or not you can do better. The cost of making a call into the VM alone is fairly significant. Since the ConnectIQ API doesn't have a call for batch processing render requests (Dc.drawLines(), .drawPoints(), ...), you're forced to push each primitive to the VM individually. This will be super-duper expensive. If you can find ways to minimize calls into the VM, you'll likely be saving time. This goes for both lines and text.

    As for the other questions, yes, in my experience there is a difference in performance between integer and floating point math. Like most other systems, integer operations are cheaper. Primitive integer operations are going to perform like you'd expect (bit operations are cheap, addition/subtraction are more expensive, multiply/divide are more expensive, mod is more expensive...). Calls to trigonometric functions are going to be expensive. If you can reduce their use by using lookup tables or approximations, that might be worthwhile (this will likely be a trade-off with memory usage or quality of results).

    Devices have different CPUs, so it is possible that we'd see differences in performance or differences in relative performance of operations. I don't believe that you'd see this among the current devices, but it could definitely happen in the future.
  • 100% agree with Travis!

    The individual draws are what can get you. But something to consider:

    Say you are drawing a breadcrumb trail. You got 1000 points, and could draw all 1000, but think about why you'd do that. On the screen, do you lose anything if you only do 500 (every other point), or every 200 (every 5th)?

    The code to do 1000 draws is straightforward, but with a bit of extra logic, you might get by with 200 draws, with zero impact on how the screen looks to the user. Drawing a few hundred lines, do you need all the detail for each line? That depends on how it looks on the screen for the user.

    Limit your draws when you can!
  • I'd fully agree with Jim on limiting the number of points. I have basic course functionality that limits the course points to 100. Even for a 20+ mile trail run, 100 course points gives me all the detail I really need to follow the course even on fairly windy trails. (I use Garmin Map Source to reduce GPS tracks to a max of 100 points). If you are doing track up vs North up, you'll likely also use a lot more resources.

    Definitely don't use doubles! They are significantly more processor intensive, not to mention memory intensive.
  • Former Member
    Former Member
    The underlying graphics framework is going to determine if the points of your line draw are within the view port before doing any rendering work. My gut says that you are better off just drawing all the lines and letting the native system make these calls. It seems unlikely that code running on the VM could outperform the clip checks that are in the native code.

    If you are translating points on the VM, and can somehow do the clip check prior to the translation, then that could save you time by avoiding a costly calculation.
  • Thanks for all your tips, this is a valuable input for me. I will do integer calculations only, even for rotating. So I will use 16 bit values for the coordinates which allows to cover an area of around 50x50 miles with high precision and allows to multiply with integers representing the needed sin/cos values for rotation.

    Before doing so, I need to extract some test data and 'normalize' the geocoordinates to 2D integer values - this will also take some time...