drawArc Wrong After Calling ActivityMonitor

Hello all together,

this is my first post :D

I have a stragne behavior with drawArc.
It is very simple: In the function onUpdate() i would like to draw a arc.
But this is only possible above the call to get infos from ActivityMonitor???
Especially to set the "degreeStart". 270 dergee must be on position 6 o´clock.
All given degreeStart numbers are always somewhere between 7 and 9 o`clock.
(for sure on top of my code is "using Toybox.ActivityMonitor as ActMonitor;" defined)

Wrong working code:
var actsteps;
var stepGoal;

stepGoal = ActMonitor.getInfo().stepGoal;
actsteps = ActMonitor.getInfo().steps;

dc.drawArc(width / 2, height / 2, 70, 0, 270, 90);


works fine! Here is 270 deree at the 6 o`clock position.
var actsteps;
var stepGoal;

dc.drawArc(width / 2, height / 2, 70, 0, 270, 90);

stepGoal = ActMonitor.getInfo().stepGoal;
actsteps = ActMonitor.getInfo().steps;


This code is also reproducible in the "Analog" sample.

Is this a bug or a feature?
  • I'm not clear on what problem you are seeing.

    But take a look at this post. https://forums.garmin.com/showthread.php?365954-Coding-a-round-progress-bar&p=926359#post926359

    The code I posted is for showing "hours", but I have another watchface where I do about the same things for info from ActivityMonitor (steps vs goal, floors vs goal, intense minutes vs goals.).

    12 o'clock is 90 degrees, 3 o'clock 0 degrees. I draw a clockwise arc starting at 12 o'clock What I do is figure out the arc end (0 degrees to 360 degrees), Then flip it vertically (360-the value from above) (clockwise is going 0-359-358, etc), and then turn it 90 degrees to account for 12 o'clock being 90 degrees.

    I don't think ActivityMonitor is involved, but what may be involved is the version of the SDK you are using (I assume you are seeing this in the sim).

    I'm using 2.2.1, but in some earlier versions, there were some odd things with draw arc. It would look strange in the sim, but fine when sideloaded to a watch. Have you tried a sideload to see what happens on the watch (and which watch)? What version of the SDK are you using?
  • I cannot reproduce a problem...

    using Toybox.Lang as Lang;
    using Toybox.System as Sys;
    using Toybox.Application as App;
    using Toybox.WatchUi as Ui;
    using Toybox.Timer as Timer;
    using Toybox.Graphics as Gfx;

    class MyView extends Ui.View
    {
    function initialize() {
    View.initialize();
    }

    hidden var _M_timer;

    function onShow() {
    _M_timer = new Timer.Timer();
    _M_timer.start(self.method(:onTimer), 100, true);
    }

    function onHide() {
    _M_timer.stop();
    _M_timer = null;
    }

    function onTimer() {
    Ui.requestUpdate();
    }

    function onUpdate(dc) {
    dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
    dc.clear();

    // update angle to be 0-360
    var now = Sys.getTimer();

    // ensure we have a positive value
    if (now < 0) {
    now = now & 0x7fffffff;
    }

    // number of milliseconds for two sweep of the arc.
    // one sweep is drawn clockwise, the other is drawn
    // counter-clockwise...
    var cycle = 2 * 5000;

    var milliseconds = now % cycle;

    // this will be a value from 0 to 720
    var degrees = 720.0 * milliseconds / cycle;

    var direction;
    if (degrees < 360.0) {
    direction = Gfx.ARC_CLOCKWISE;
    }
    else {
    direction = Gfx.ARC_COUNTER_CLOCKWISE;
    degrees -= 360.0;
    }

    var locX = 0;
    var locY = 0;
    var width = dc.getWidth();
    var height = dc.getHeight();

    var cx = locX + width / 2;
    var cy = locY + height / 2;

    var r = (width < height ? width : height) / 3;
    var penWidth = r / 4;

    // drawArc expects radius to be to the middle of the pen
    // stroke, but we want it to be the outside edge
    r -= (penWidth + 1) / 2;

    dc.setColor(Gfx.COLOR_RED, Gfx.COLOR_TRANSPARENT);
    dc.setPenWidth(penWidth);

    dc.drawArc(cx, cy, r, direction, 90, 90 - degrees.toNumber());
    }
    }

    class MyApp extends App.AppBase
    {
    function initialize() {
    AppBase.initialize();
    }

    function getInitialView() {
    return [ new MyView() ];
    }
    }
  • it works sideloaded on my watch, but not in simulator

    Hi there,

    thanks for your replys,

    @jim_m_58
    first i have select as target device the Fenix3 / SDK 1.3x. The simulator shows the wrong arc.
    Then i select the Chronus as target device / SDK 2.1x. The Simulator shows the wrong arc.

    BUT the sideloaded app works correct! (build for Chronus/2.1x on my Fenix3)
    You give me the crucial note.

    Hmm. Thats ok but not nice.


    @TRAVIS.VITEK
    You have forget the ActivityMonitor!
    I add the code to your sample and as the result, the startpoint of your arc are wrong!

    using Toybox.Lang as Lang;
    using Toybox.System as Sys;
    using Toybox.Application as App;
    using Toybox.WatchUi as Ui;
    using Toybox.Timer as Timer;
    using Toybox.Graphics as Gfx;
    using Toybox.ActivityMonitor as ActMonitor;

    class MyView extends Ui.View
    {
    function initialize() {
    View.initialize();
    }

    hidden var _M_timer;

    function onShow() {
    _M_timer = new Timer.Timer();
    _M_timer.start(self.method(:onTimer), 100, true);
    }

    function onHide() {
    _M_timer.stop();
    _M_timer = null;
    }

    function onTimer() {
    Ui.requestUpdate();
    }

    function onUpdate(dc) {
    dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
    dc.clear();

    var actsteps = 0;
    var stepGoal = 0;

    stepGoal = ActMonitor.getInfo().stepGoal;
    actsteps = ActMonitor.getInfo().steps;




    // update angle to be 0-360
    var now = Sys.getTimer();

    // ensure we have a positive value
    if (now < 0) {
    now = now & 0x7fffffff;
    }

    // number of milliseconds for two sweep of the arc.
    // one sweep is drawn clockwise, the other is drawn
    // counter-clockwise...
    var cycle = 2 * 5000;

    var milliseconds = now % cycle;

    // this will be a value from 0 to 720
    var degrees = 720.0 * milliseconds / cycle;

    var direction;
    if (degrees < 360.0) {
    direction = Gfx.ARC_CLOCKWISE;
    }
    else {
    direction = Gfx.ARC_COUNTER_CLOCKWISE;
    degrees -= 360.0;
    }

    var locX = 0;
    var locY = 0;
    var width = dc.getWidth();
    var height = dc.getHeight();

    var cx = locX + width / 2;
    var cy = locY + height / 2;

    var r = (width < height ? width : height) / 3;
    var penWidth = r / 4;

    // drawArc expects radius to be to the middle of the pen
    // stroke, but we want it to be the outside edge
    r -= (penWidth + 1) / 2;

    dc.setColor(Gfx.COLOR_RED, Gfx.COLOR_TRANSPARENT);
    dc.setPenWidth(penWidth);

    dc.drawArc(cx, cy, r, direction, 90, 90 - degrees.toNumber());
    }
    }

    class MyApp extends App.AppBase
    {
    function initialize() {
    AppBase.initialize();
    }

    function getInitialView() {
    return [ new MyView() ];
    }
    }
  • Hi there,

    thanks for your replys,

    @jim_m_58
    first i have select as target device the Fenix3 / SDK 1.3x. The simulator shows the wrong arc.
    Then i select the Chronus as target device / SDK 2.1x. The Simulator shows the wrong arc.

    BUT the sideloaded app works correct! (build for Chronus/2.1x on my Fenix3)
    You give me the crucial note.

    Hmm. Thats ok but not nice.


    @TRAVIS.VITEK
    You have forget the ActivityMonitor!
    I add the code to your sample and as the result, the startpoint of your arc are wrong!

    using Toybox.Lang as Lang;
    using Toybox.System as Sys;
    using Toybox.Application as App;
    using Toybox.WatchUi as Ui;
    using Toybox.Timer as Timer;
    using Toybox.Graphics as Gfx;
    using Toybox.ActivityMonitor as ActMonitor;

    class MyView extends Ui.View
    {
    function initialize() {
    View.initialize();
    }

    hidden var _M_timer;

    function onShow() {
    _M_timer = new Timer.Timer();
    _M_timer.start(self.method(:onTimer), 100, true);
    }

    function onHide() {
    _M_timer.stop();
    _M_timer = null;
    }

    function onTimer() {
    Ui.requestUpdate();
    }

    function onUpdate(dc) {
    dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
    dc.clear();

    var actsteps = 0;
    var stepGoal = 0;

    stepGoal = ActMonitor.getInfo().stepGoal;
    actsteps = ActMonitor.getInfo().steps;




    // update angle to be 0-360
    var now = Sys.getTimer();

    // ensure we have a positive value
    if (now < 0) {
    now = now & 0x7fffffff;
    }

    // number of milliseconds for two sweep of the arc.
    // one sweep is drawn clockwise, the other is drawn
    // counter-clockwise...
    var cycle = 2 * 5000;

    var milliseconds = now % cycle;

    // this will be a value from 0 to 720
    var degrees = 720.0 * milliseconds / cycle;

    var direction;
    if (degrees < 360.0) {
    direction = Gfx.ARC_CLOCKWISE;
    }
    else {
    direction = Gfx.ARC_COUNTER_CLOCKWISE;
    degrees -= 360.0;
    }

    var locX = 0;
    var locY = 0;
    var width = dc.getWidth();
    var height = dc.getHeight();

    var cx = locX + width / 2;
    var cy = locY + height / 2;

    var r = (width < height ? width : height) / 3;
    var penWidth = r / 4;

    // drawArc expects radius to be to the middle of the pen
    // stroke, but we want it to be the outside edge
    r -= (penWidth + 1) / 2;

    dc.setColor(Gfx.COLOR_RED, Gfx.COLOR_TRANSPARENT);
    dc.setPenWidth(penWidth);

    dc.drawArc(cx, cy, r, direction, 90, 90 - degrees.toNumber());
    }
    }

    class MyApp extends App.AppBase
    {
    function initialize() {
    AppBase.initialize();
    }

    function getInitialView() {
    return [ new MyView() ];
    }
    }


    I was able to reproduce this using the above source code. I have created a ticket that will be prioritized this week.

    Thank you!

    -Coleman
  • You have forget the ActivityMonitor!

    I can't say I forgot ActivityMonitor. Your original post didn't make it very clear (at least not clear to me) what the actual problem was, so I omitted it.

    Travis
  • thanks

    @TRAVIS.VITEK
    thank you very much for your help and the ticket creation :o
    Please excuse my comment. I have not expressed myself clearly.

    Greetings from Germany/Hannover
  • Hey Everyone,

    We have tracked down what we believe is the issue with drawArc in the sim. We believe it is going to be fixed once we've done some updates to the version of Visual Studio we are using. Once we can test the fix and confirm it, we will let you know. For now, I'm going to move this post into our Bug Reports forum.

    Thanks,
    -Coleman
  • Former Member
    Former Member over 8 years ago
    FYI: There is not a bug in drawArc here. There is a bug in ActivityMonitor.getInfo(), that is being caused by something bad happening at the windows compiler level.

    This is causing this code to fail and always take the bottom path:
    if (degrees < 360.0) {
    direction = Gfx.ARC_CLOCKWISE;
    }
    else {
    direction = Gfx.ARC_COUNTER_CLOCKWISE;
    degrees -= 360.0;
    }


    If you print out the values being passed to drawArc, you will see that they are incorrect when degrees < 360.0.

    Travis may recall reporting an issue a while ago where calling ActivityMonitor.getInfo() caused "if(3.0 < 1.0)" to evaluate as true. This is the same issue.
  • Travis may recall reporting an issue a while ago where calling ActivityMonitor.getInfo() caused "if(3.0 < 1.0)" to evaluate as true. This is the same issue.

    I do recall this.

    Just to be sure that I understand what is going on... Something in ActivityMonitor.getInfo() is messing with application state in some way that has an effect on later floating point calculations/comparisons? As a result, the block of code doing the floating point compare I wrote produces incorrect behavior. If we eliminate that code, we see wonky behavior in Dc.drawArc() for the same reason.

    To verify, I've reduced the test case further and can demonstrate the problem.

    function onUpdate(dc) {
    dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
    dc.clear();

    dc.setColor(Gfx.COLOR_RED, Gfx.COLOR_TRANSPARENT);
    dc.setPenWidth(20);

    var stepGoal = ActMonitor.getInfo().stepGoal;

    // works best on a 218x218 display
    dc.drawArc(109, 109, 90, Gfx.ARC_COUNTER_CLOCKWISE, 90, 180);
    }


    If I move the ActivityMonitor.getInfo() call below dc.drawArc(), the problem does go away. Given this, it seems that there is something else that the framework is doing to reset this application state back to normal.

    Is my understanding correct?

    Travis
  • Former Member
    Former Member over 8 years ago
    I think your understanding is accurate.