2

Using code from question about picking nice rule/marker interval I created a code that renders rules on the graph.

image description

It has nice intervals of 0.1. But I don't like to display all the numbers, instead, I'd like to increase rule density but only mark every few rules. Like this:

image description

I created an algorithm that does so by multiplying rule interval by a number, then highlighting rules that can be divided by the result. I use fmod because the values can of course be float:

    // See https://stackoverflow.com/q/361681/607407 for algorithms
    double rule_spacing = tickSpacing(pixels_per_rule);
    // These are the highlighted rules - currently it should be every 2nd rule
    double important_steps = rule_spacing*2.0;
    // Getting the stard draw offset which should be bellow bottom graph corner
    double start = graph_math::roundTo(begin.y, rule_spacing);
    LOGMTRTTIINFO("Legend from "<<start<<" to "<<values.maxYValue<<" by "<<rule_spacing<<", numbers: "<<important_steps<<'\n');
    //Loop until on top
    while(start<=values.maxYValue) {
        int y = pixelForYValue(start);
        // HERE: calculating whether this is the NTH rule!
        float remainder = fmod(start, important_steps);
        LOGMTRTTIINFO("        "<<" legend at px"<<y<<" with marker "<<start<<" Marker remainder:"<<remainder<<'\n');
        if(remainder==0) {
            // Draw highlighted rule
        }
        else {
            // Draw normal rule
        }
    }

The problem is that fmod is rather unreliable. Check this log output where values that can be divided by 0.1 return 0.1 in fmod:

Legend from 95.9 to 96.3097 by 0.05, numbers (important_steps): 0.1
         legend at px240 with marker 95.9 Marker remainder:3.60822e-16
         legend at px211 with marker 95.95 Marker remainder:0.05
         legend at px181 with marker 96 Marker remainder:0.1
         legend at px152 with marker 96.05 Marker remainder:0.05
         legend at px123 with marker 96.1 Marker remainder:0.1
         legend at px93 with marker 96.15 Marker remainder:0.05
         legend at px64 with marker 96.2 Marker remainder:0.1
         legend at px35 with marker 96.25 Marker remainder:0.05
         legend at px5 with marker 96.3 Marker remainder:0.1

I guess I could outsmart this by adding important_steps==remainder, but isn't the function flawed if it actually returns the denominator, which should never happen for % (modulo)?

How do I overcome this with sufficient certainty? Testing snippet available.

Btw, this is how nicely it works once the important_steps is greater or equal to 1:

image description

Community
  • 1
  • 1

1 Answers1

0

Perhaps the best way to do this is to round to integers, and then check the difference, like this:

float quotient = start / important_step;
int quot_int = round(quotient);
if (abs(quotient - quot_int) < 1e-10)
{
    // Draw highlighted rule
}
else
{
    // Draw normal rule
}

EDIT: function round

int round(double x){return floor(x + 0.5);}
WhatsUp
  • 1,554
  • 9
  • 19
  • Are you sure this will work for super tiny numbers? I mean 1e-10 is not that small. – Tomáš Zato - Reinstate Monica Jan 12 '16 at 17:37
  • This 1e-10 is small enough, unless your `important_steps` is `1e10` times `rule_spacing`. Note that it is the QUOTIENT that we are rounding. Why don't you try it? – WhatsUp Jan 12 '16 at 20:24
  • It doesn't work, I can't figure why but the `abs( ... )` is always zero. I tried to declare `quit_int` as float to prevent some unwanted implicit cast but it didn't help. I created testing snippet here: http://ideone.com/EHPeyM – Tomáš Zato - Reinstate Monica Jan 13 '16 at 08:14
  • The problem is probably that `round` is not defined. You can add your own `round` function (see my edit). – WhatsUp Jan 13 '16 at 16:49