PMap Does not work correctly?

General FreeBASIC programming questions.
Lothar Schirm
Posts: 437
Joined: Sep 28, 2013 15:08
Location: Germany

PMap Does not work correctly?

Post by Lothar Schirm »

I get unexpected results with PMap (FreeBASIC 1.09, Windows 11). What is wrong?

Code: Select all

ScreenRes 500, 500
View (10, 10) - (100, 100)
Window (0, 0) - (9, 9)
Print "Logical x=4.5, Physical x="; PMap(4.5, 0)   	'' Expected 55, result: 45.5 
Print "Logical y=4.5, Physical y="; PMap(4.5, 1)   	'' Expected 55, result: 44.5
Print "Physical x=55, Logical x="; PMap(55, 2) 			'' Expected 4.5, result: 5.43956
Print "Physical y=55, Logical y="; PMap(55, 3)   		'' Expected 4.5, result: 3.461593

Sleep
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: PMap Does not work correctly?

Post by fxm »

Expected purpose of 'PMAP':
- 'PMAP' allows to convert the coordinates modified by 'WINDOW' into coordinates in the current viewport, and vice versa.
- The current viewport can be either the declared graphics screen, or only a clipping region in the graphics screen when this one is declared by 'VIEW'.
- In all cases, the minimum coordinate value (xvmin or yvmin) in the current viewport is 0, and the maximum coordinate (xvmax or yvmax) is the offset value of the last pixel of the current viewport relative to the first of the current viewport.
- Example for 'SCREENRES width, height': xvmin=yvmin=0, xvmax=width-1, yvmax=height-1.
- Example for 'VIEW (x1, y1) - (x2, y2)': xvmin=yvmin=0, xvmax=x2-x1, yvmax=y2-y1.
- The modified coordinates declared by 'WINDOW SCREEN (xwmin, ywmin) - (xwmax, ywmax)' can be positive or negative, and xwmin corresponds to xvmin (0), ywmin corresponds to yvmin (0), xwmax corresponds to xvmax, ywmax corresponds to yvmax.

1)
It is preferable to use 'Window Screen' (y coordinates increasing from top to bottom), easier to analyze with your example ('View (10, 10) - (100, 100)').

2)
No graphic plotting problem between the different mappings ('ScreenRes' mapping, then 'View' mapping, then 'Window Screen' mapping):

Code: Select all

ScreenRes 500, 500             '' 'ScreenRes' mapping
Pset (10, 10)                  '' point #1
Pset (55, 55)                  '' point #2
Pset (100, 100)                '' point #3

View (10, 10) - (100, 100)     '' 'View' mapping
Pset (0, 0)                    '' point superimposed well at point #1
Pset (45, 45)                  '' point superimposed well at point #2
Pset (90, 90)                  '' point superimposed well at point #3

Window Screen (0, 0) - (9, 9)  '' 'Window Screen' mapping
Pset (0, 0)                    '' point superimposed well at point #1
Pset (4.5, 4.5)                '' point superimposed well at point #2
Pset (9, 9)                    '' point superimposed well at point #3

Sleep
- The points: (10, 10) in the 'ScreenRes' mapping, (0, 0) in the 'View' mapping, and (0, 0) in the 'Window Screen' mapping all overlap well.
- The points: (55, 55) in the 'ScreenRes' mapping, (45, 45) in the 'View' mapping, and (4.5, 4.5) in the 'Window Screen' mapping all overlap well.
- The points: (100, 100) in the 'ScreenRes' mapping, (90, 90) in the 'View' mapping, and (9, 9) in the 'Window Screen' mapping all overlap well.

3)
But it seems to me that there is a "bug?" (IMHO) in the 'Pmap' function only, that adds +1 pixel offset for the max value.
Maybe confusion between number of pixels (100 - 10 + 1 = 91) of the viewport, and number of intervals between pixels (100 - 10 = 90).

Code: Select all

ScreenRes 500, 500
View (10, 10) - (100, 100)
Window Screen (0, 0) - (9, 9)

Print "Logical x=0, Physical x="; PMap(0, 0)        '' Expected 0, result: 0 => OK
Print "Logical y=0, Physical y="; PMap(0, 1)        '' Expected 0, result: 0 => OK
Print "Logical x=4.5, Physical x="; PMap(4.5, 0)    '' Expected 45, result: 45.5 => NOK
Print "Logical y=4.5, Physical y="; PMap(4.5, 1)    '' Expected 45, result: 45.5 => NOK
Print "Logical x=9, Physical x="; PMap(9, 0)        '' Expected 90, result: 91 => NOK
Print "Logical y=9, Physical y="; PMap(9, 1)        '' Expected 90, result: 91 => NOK

Print "Physical x=0, Logical x="; PMap(0, 2)        '' Expected 0, result: 0 => OK
Print "Physical y=0, Logical y="; PMap(0, 3)        '' Expected 0, result: 0 => NOK
Print "Physical x=45, Logical x="; PMap(45, 2)      '' Expected 4.5, result: 4.45055 => NOK
Print "Physical y=45, Logical y="; PMap(45, 3)      '' Expected 4.5, result: 4.45055 => NOK
Print "Physical x=45.5, Logical x="; PMap(45.5, 2)  '' Expected 9/90*45.5, result: 4.5 => NOK
Print "Physical y=45.5, Logical y="; PMap(45.5, 3)  '' Expected 9/90*45.5, result: 4.5 => NOK
Print "Physical x=90, Logical x="; PMap(90, 2)      '' Expected 9, result: 8.901099 => NOK
Print "Physical y=90, Logical y="; PMap(90, 3)      '' Expected 9, result: 8.901099 => NOK
Print "Physical x=91, Logical x="; PMap(91, 2)      '' Expected 9/90*91, result: 9 => NOK
Print "Physical y=91, Logical y="; PMap(91, 3)      '' Expected 9/90*91, result: 9 => NOK

Sleep
See also the PMAP documentation' example:

Code: Select all

ScreenRes 640, 480
Window Screen (0, 0)-(100, 100)
Print "Logical x=50, Physical x="; PMap(50, 0)   '' 320  => NOK IMHO: 639/2 expected instead
Print "Logical y=50, Physical y="; PMap(50, 1)   '' 240  => NOK IMHO: 479/2 expected instead
Print "Physical x=160, Logical x="; PMap(160, 2) '' 25   => NOK IMHO: 100/639*160 expected instead
Print "Physical y=60, Logical y="; PMap(60, 3)   '' 12.5 => NOK IMHO: 100/479*60 expected instead
Sleep

Jeff, what is your opinion ?
(I wait a bit before filling in a bug report from this post)
Lothar Schirm
Posts: 437
Joined: Sep 28, 2013 15:08
Location: Germany

Re: PMap Does not work correctly?

Post by Lothar Schirm »

Thank you fxm! You wrote:
But it seems to me that there is a "bug?" (IMHO) in the 'Pmap' function only, that adds +1 pixel offset for the max value.
Maybe confusion between number of pixels (100 - 10 + 1 = 91) of the viewport, and number of intervals between pixels (100 - 10 = 90).
If I would have to calculate with 91 pixels instead of 90, I would expect to get the same incorrect values for x and y in my example above, but that is not the case. I get different values for x and y (logical) and x and y (physical).
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: PMap Does not work correctly?

Post by fxm »

Lothar Schirm wrote: Dec 16, 2022 15:16 If I would have to calculate with 91 pixels instead of 90, I would expect to get the same incorrect values for x and y in my example above, but that is not the case. I get different values for x and y (logical) and x and y (physical).

Because you used 'WINDOW' (y coordinates increasing from bottom to top) and not 'WINDOW SCREEN' (y coordinates increasing from top to bottom), while x coordinates are always increasing from left to right. The mid-range error (1 pixel / 2 = 0.5) is therefore either of the same sign on x and y (with 'WINDOW SCREEN'), or of opposite signs (with 'WINDOW').
Try your code with 'WINDOW SCREEN' and you will found the same wrong values:

Code: Select all

ScreenRes 500, 500
View (10, 10) - (100, 100)
Window  (0, 0) - (9, 9)
Print "Logical x=4.5, Physical x="; PMap(4.5, 0)   	'' Expected 45, result: 45.5 
Print "Logical y=4.5, Physical y="; PMap(4.5, 1)   	'' Expected 45, result: 44.5
Window Screen (0, 0) - (9, 9)
Print "Logical x=4.5, Physical x="; PMap(4.5, 0)   	'' Expected 45, result: 45.5 
Print "Logical y=4.5, Physical y="; PMap(4.5, 1)   	'' Expected 45, result: 45.5

Sleep
SARG
Posts: 1766
Joined: May 27, 2005 7:15
Location: FRANCE

Re: PMap Does not work correctly?

Post by SARG »

I don't think there is a bug, unless I'm really wrong.

Code: Select all

view (10,10)-(100,100)  --> width = 100 - 10 + 1 = 91

window screen (0,0)-(9,9)
pset(9,9) is just in bottom/left corner

0__1__2__3__4__5__6__7__8__9 --> width = 9


pmap (cordx,0) = (cordx - win_x) * ( view_width  / win_width )

pmap(9,0) = (9 - 0) * ( 91 / 9 ) = 91
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: PMap Does not work correctly?

Post by fxm »

But in the mapping window defined by 'View (10, 10) - (100, 100)', the point (91, 91) is of one pixel outside the clipping region (for each coordinate).
It is the points (90, 90) in the View mapping and (9, 9) in the Window mapping that overlap.
See my helping code in 2).

Note:
view (10,10)-(100,100) --> width = 100 - 10 + 1 = 91 width = 100 - 10 = 90
like for:
0__1__2__3__4__5__6__7__8__9 --> width = 9
SARG
Posts: 1766
Joined: May 27, 2005 7:15
Location: FRANCE

Re: PMap Does not work correctly?

Post by SARG »

I looked at the C code for gfxlib, there is a difference when calculating pmap and coordinates for pset : 1 is substracted from view width.
I don't know if it's intended, maybe nobody used pmap in such conditions until now :-)

Code: Select all

function used by pset to get coordinates

void fb_hTranslateCoord(FB_GFXCTX *context, float fx, float fy, int *x, int *y)
{
	if (context->flags & CTX_WINDOW_ACTIVE) {
		fx = ((fx - context->win_x) * (context->view_w - 1)) / context->win_w;
		fy = ((fy - context->win_y) * (context->view_h - 1)) / context->win_h;
	}
	
	*x = CINT(fx);
	*y = CINT(fy);
	
	
function fb_GfxPMap returning PMAP
	switch (func) {
		case 0:
			if (context->flags & CTX_WINDOW_ACTIVE)
				coord = ((coord - context->win_x) * context->view_w) / context->win_w;
			break;
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: PMap Does not work correctly?

Post by fxm »

SARG wrote: Dec 16, 2022 19:04 ... maybe nobody used pmap in such conditions until now :-)
Before today, I had never used 'PMAP' !
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: PMap Does not work correctly?

Post by fxm »

SARG wrote: Dec 16, 2022 19:04 I looked at the C code for gfxlib, there is a difference when calculating pmap and coordinates for pset : 1 is substracted from view width.

Code: Select all

function used by pset to get coordinates

void fb_hTranslateCoord(FB_GFXCTX *context, float fx, float fy, int *x, int *y)
{
	if (context->flags & CTX_WINDOW_ACTIVE) {
		fx = ((fx - context->win_x) * (context->view_w - 1)) / context->win_w;
		fy = ((fy - context->win_y) * (context->view_h - 1)) / context->win_h;
	}
	
	*x = CINT(fx);
	*y = CINT(fy);
	
	
function fb_GfxPMap returning PMAP
	switch (func) {
		case 0:
			if (context->flags & CTX_WINDOW_ACTIVE)
				coord = ((coord - context->win_x) * context->view_w) / context->win_w;
			break;

Looking at the code you are reporting and assuming the first part (for pset) is correct, it looks like 'context->view_w' and 'context->view_h' are expressed as number of pixels in the considered dimension of the viewport and not as number of intervals between pixels, while 'context->win_w' and 'context->win_h' are well expressed as ranges from the 'Window' command.

If this is true, then the term '-1' applied to 'context->view_w' and 'context->view_h' is missing in the second part (for pmap) for all expressions that use them.
SARG
Posts: 1766
Joined: May 27, 2005 7:15
Location: FRANCE

Re: PMap Does not work correctly?

Post by SARG »

fxm wrote: Dec 17, 2022 8:36 Looking at the code you are reporting and assuming the first part (for pset) is correct
Sure : in pset function there is call to fb_hTranslateCoord(context, fx, fy, &x, &y).

In fact it seems that only the most left (and bottom) coordinate in pmap is wrongly calculated because the values are floats rounded to floor.
So with the example pmap(x,0) x * 91 / 9
1 --> 10.11 --> 10
2 --> 20.22 -->20
....
8 --> 80.88 -->80
9 --> 91 -->91
fxm wrote:If this is true, then the term '-1' applied to 'context->view_w' and 'context->view_h' is missing in the second part (for pmap) for all expressions that use them.
Yes it should solve the issue (All the other values of pmap staying inchanged).
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: PMap Does not work correctly?

Post by fxm »

??
PMAP always returns a SINGLE variable !
SARG
Posts: 1766
Joined: May 27, 2005 7:15
Location: FRANCE

Re: PMap Does not work correctly?

Post by SARG »

fxm wrote: Dec 17, 2022 11:33 ??
PMAP always returns a SINGLE variable !
Indeed but how do you set pixel at 80.88 ? obviously you need to use an integer (whole value).
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: PMap Does not work correctly?

Post by fxm »

It is the 'Pset' instruction that rounds the passed values (wirth 'Cint').
SARG
Posts: 1766
Joined: May 27, 2005 7:15
Location: FRANCE

Re: PMap Does not work correctly?

Post by SARG »

fxm wrote: Dec 17, 2022 12:49 It is the 'Pset' instruction that rounds the passed values (wirth 'Cint').
No they are passed to pset by fb_htransaltecoord.

What I said, if you use the values returned by pmap using int() the only time it's wrong is with the most left coordinate.

int(pmap(8,0)) -->80 correct
but int(pmap(9,0)) --> 91 wrong

So the problem may not be seen.

Anyway I agree it's a bug and why returning a float.
SARG
Posts: 1766
Joined: May 27, 2005 7:15
Location: FRANCE

Re: PMap Does not work correctly?

Post by SARG »

Sorry I repeat at least twice left coordinate but it's right coordinate.....
Post Reply