where : ibrtses delphi

# Delphi - snap and grid

#### disclaimer

the source code of this page may not appear correctly in certain browsers
due to special characters. Have a look at the source of this HTML page

## Objective

Scaled and/or scalable graphic, mainly vector graphic, can lead to uneven
coordinate numbers. The preferable even numbers can be achieved with the
implementation of a snap.
Examples for
```uneven numbers	even numbers instead
0.00001278	0
0.200142	0.2
0.399786	0.4
0.499121	0.5
```
related : Mapping world and screen

## Pixelsnap

The inter pixel distance may not become just any number, but has to be
restricted to even numbers :
```0.1 x 10^N	(1/10 based)
0.125 x 10^N	(1/8 based)
0.1667 x 10^N	(1/6 based)
0.2 x 10^N	(1/5 based)
0.25 x 10^N	(1/4 based)
0.333 x 10^N	(1/3 based)
0.4 x 10^N	(1/2.5 based)
0.5 x 10^N	(1/2 based)
0.6667 x 10^N	(2/3 based)
```
or similar, whereas N is integer

For a given drawing the interpixel snap is given :
```Var pixelsnap:float;
```
then each number to be displayed or stored is rounded to the nearest
multiple of the pixelsnap.
```function snappixel(x:float):float;
var i:integer;
begin
i:=round(x/pixelsnap);
result:=i*pixelsnap;
end;
```

## Object snap

Faster operation of the drawing application can be achieved when the
objects cannot be moved or placed at each pixel but only at a multiple
of a pixel. Values may be every 6th, 8th, 10th, 12th, 20th or so pixel.
The user has to concentrate less, the bigger the object snap. The pixel
snap and the object snap have to be adjusted for sensible numbers.

## Grid

drawing a grid poses the same problems as the snap does. Grid lines
should have a certain gap between them. The grid could be placed at
the object snap or a multiple.

## finding sensible numbers

after introducing the snap, the numbers are considered even at the small scale.
Still some care has to be taken when drawing a grid or ruler.
examples with 0.2 and 0.002 distance :
```-0.05	-0.1	-0.2	|	0.995	0.994
0.15	0.1	0.0	|	0.997	0.996
0.35	0.3	0.2	|	0.999	0.998
0.55	0.5	0.4	|	1.001	1.000
0.75	0.7	0.6	|	1.003	1.002
0.95	0.9	0.8	|	1.005	1.004
1.15	1.1	1.0	|	1.007	1.006
```
As can be seen, if zero is part of the range, it has to part of the grid.
It is therefore advisable to draw a grid top-down with decreasing distance

to get a grid with about 10 lines on a range -0.1 .. 1.1, use :

```findsnap(1.2,10);	//which gives 0.1

uses math;

function findsnap(range:float;divisions:integer):float;
var i,exponent:integer;
m,u,mantissa:extended;
begin
u:=abs(range/divisions);
// split mantissa and exponent but in decimal notation
exponent:=ceil(log10(u));
mantissa:=u/intpower(10,exponent);  // 0.1< mantissa <= 1.0
// now adjust the snap as case
if (mantissa<0.14) then m:=0.1;
if (mantissa>=0.14)and(mantissa<0.18) then m:=1/6;
if (mantissa>=0.18)and(mantissa<0.23)then m:=1/5;
if (mantissa>=0.23)and(mantissa<0.27)then m:=1/4;
if (mantissa>=0.27)and(mantissa<0.4)then m:=1/3;
if (mantissa>=0.4)and(mantissa<0.6)then m:=1/2;
if (mantissa>=0.6)then m:=1;
result:=m*intpower(10,exponent);
end;
```

## Application

assume a field of x:=0 .. pi and y:= -1.1 .. 1.1 has to be mapped
onto an image of 400x400 pixels.
the pixels have to be square, meaning the snap for x and y is the same.
``` var range, gridsnap,x,y:extended;
i:integer;
xlow,xhigh,ylow,yhigh:extended;  // the boundary

range:=max(2.2,pi);
gridsnap:=findsnap(range,20);
// make the field at least as big as requested
// lower x
i:=floor(0/gridsnap);
xlow:=i*gridsnap;
// upper x
i:=ceil(pi/gridsnap);
xhigh:=i*gridsnap;
// lower y
i:=floor(-1.1/gridsnap);
ylow:=i*gridsnap;
// upper y
i:=ceil(1.1/gridsnap);
yhigh:=i*gridsnap;
// draw the lines, map them to integer first
x:=xlow;
repeat
xs:=map(x);				//map them to integer
line(xs,0,xs,image.height-1);
x:=x+gridsnap;
until abs(x-xhigh)<0.001;
x:=ylow;
repeat
ys:=map(y);				//map them to integer
line(0,ys,image.width-1,ys);
y:=y+gridsnap;
until abs(y-yhigh)<0.001;

```

### findings

• using a snap changes the inter pixel distance and therefore the
scale of the drawing. Either the size of the drawing or the mapped
range on the drawing have to be adjusted.
• using EXTENDED as float gives the best result.
• when the pixels have to be square, the same snap has to be
applied for x and y.

Feedback is welcome