3

I am trying to draw a ruler, for any available iOS device, with accurate 1mm distances between start of lines/ticks. Usually i would get the PPI and calculate my distance of the pixels. Using Objective-C, it does not seem to work this way.

linesDist should contain my 1mm distance in "screen coordinate pixels".

Any ideas, how i can achieve this?

my basic code looks like this: RulerView.m, which is a UIView:

-(void)drawRect:(CGRect)rect
{
    [[UIColor blackColor] setFill];

    float linesDist = 3.0; // 1mm * ppi ??

    float linesWidthShort = 15.0;
    float linesWidthLong = 20.0;

    for (NSInteger i = 0, count = 0; i <= self.bounds.size.height; i = i + linesDist, count++)
    {
        bool isLong = (int)i % 5 == 0;

        float linesWidth = isLong ? linesWidthLong : linesWidthShort;
        UIRectFill( (CGRect){0, i, linesWidth, 1} );
    }
}

EDIT ppi detect (really ugly), based on the answer below:

float ppi = 0;
switch ((int)[UIScreen mainScreen].bounds.size.height) {
    case 568: // iPhone 5*
    case 667: // iPhone 6
        ppi = 163.0;
        break;

    case 736: // iPhone 6+
        ppi = 154.0;
        break;

    default:
        return;
        break;
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
BananaAcid
  • 3,221
  • 35
  • 38

2 Answers2

3

iPhones (with the possible exception of the iPhone6+) are 163 "logical" points per inch. Obviously phones from 4 onwards have double or more the resolution but that doesn't make any difference for the coordinate system.

1mm therefore is 163/25.4 or approximately 6.4. iPad is 5.2 points per mm, iPad mini is the same as iPhone.

-(void)drawRect:(CGRect)rect
{
    [[UIColor blackColor] setFill];
    float i;

    float linesDist = 163.0/25.4; // ppi/mm per inch (regular size iPad would be 132.0)

    float linesWidthShort = 15.0;
    float linesWidthLong = 20.0;

    for (i = 0, count = 0; i <= self.bounds.size.height; i = i + linesDist, count++)
    {
        bool isLong = (int)count % 5 == 0;

        float linesWidth = isLong ? linesWidthLong : linesWidthShort;
        UIRectFill( (CGRect){0, i, linesWidth, 1} );
    }
} 

You want to use a float for i in order to avoid rounding errors when adding the distances up and to avoid unnecessary conversions.

Markus Dheus
  • 576
  • 2
  • 8
  • Thanks for that :) Still feel a little unsure: do i need to check for 3 cases: iPad-normal, iPhone6+, rest and adjust the ppi/mm ? – BananaAcid Sep 07 '15 at 12:29
  • Yes, you need to special case for iPad and (possibly) iPhone 6+. Unfortunately it is not trivial to reliably make the distinction between iPad and iPad mini. – Markus Dheus Sep 07 '15 at 12:37
  • 1
    iPhone 6 seems to be work out to be about 154 ppi as far as logical points are concerned by the way. – Markus Dheus Sep 07 '15 at 12:47
0

I am not sure but, the screen size is calculated either in pixels or in points. You can consider either of them and do your math to create a scale which is equal or approximately equal to mm as 1 pixel = 0.26 mm and 1 point = 0.35 mm.

So in your case, draw a mark for every 1 mm which is nearly 3 points.

Try something like this:

UIView *markView = [[UIView alloc] initWithFrame:CGRectMake(x, y, 1, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];

// and increment the (x,y) coordinate for 3 points and draw a mark
Teja Nandamuri
  • 11,045
  • 6
  • 57
  • 109