Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2009-01

ptInRect question

9 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Michael Van Canneyt

Hi,

I have a question regarding the following function:

function PtInRect(const Rect : TRect;const p : TPoint) : Boolean;
begin
  PtInRect:=(p.y>=Rect.Top) and
            (p.y<Rect.Bottom) and
            (p.x>=Rect.Left) and
            (p.x<Rect.Right);
end;

Is there a reason why the top/left sides are included (>=), and the left/bottom sides are not included ? I would expect them to be included as well.

Michael.

Reply by email

dmitry boyarintsev
to Michael Van Canneyt

AFAIK, Delphi compat.Here's the delphi code from Types unit.

function PtInRect(const Rect: TRect; const P: TPoint): Boolean;
begin
  Result := (P.X >= Rect.Left) and (P.X < Rect.Right) and (P.Y >= Rect.Top)
    and (P.Y < Rect.Bottom);
end;

Reply by email

dmitry boyarintsev
to dmitry boyarintsev

Delphi rectangles are used to wrap Win32 GDI calls.

here's a quote from msdn FillRect function:
-= start quote =-
When filling the specified rectangle, FillRect does not include the rectangle's right and bottom sides. GDI fills a rectangle up to, but not including, the right column and bottom row, regardless of the current mapping mode.
-= end of quote =-

so function ptInRect can be determined if point is inside filled rect or not.

Reply by email

dmitry boyarintsev
to Michael Van Canneyt
I found this out already, but why, what is the rationale ?

i have only one thought, about the reason for this:

if you follow the Microsoft GDI rules, then you'll get
width := r.Right - r.Left;

otherwise (if r.Right is also filled then drawn), you'll end-up with additional operation
width := r.Right - r.Left + 1;

Reply by email

Mattias Gaertner
to Michael Van Canneyt: I found this out already, but why, what is the rationale ? Michael.
Show quoted text 13 lines
On Fri, 30 Jan 2009, dmitry boyarintsev wrote: > AFAIK, Delphi compat.Here's the delphi code from Types unit. > > function PtInRect(const Rect: TRect; const P: TPoint): Boolean; > begin > Result := (P.X >= Rect.Left) and (P.X < Rect.Right) and (P.Y >= > Rect.Top) and (P.Y < Rect.Bottom); > end; I found this out already, but why, what is the rationale ?

A pixel is actually an area. It has a left and and right side. All coordinates refer to the left,top corner of a pixel.

Mattias

Reply by email

Graeme Geldenhuys
to Michael Van Canneyt: I have a question regarding the following function: function PtInRect(const Rect :…
Michael Van Canneyt wrote 12 lines
function PtInRect(const Rect : TRect;const p : TPoint) : Boolean; begin PtInRect:=(p.y>=Rect.Top) and (p.y<Rect.Bottom) and (p.x>=Rect.Left) and (p.x<Rect.Right); end; Is there a reason why the top/left sides are included (>=), and the left/bottom sides are not included ? I would expect them to be included as well.

I would guess to conform with Microsoft's GDI behaviour. GDI rectangles are drawn one pixel less than what you specified. Probably also relates to Mattias's answer, that a pixel also takes up a certain amount of space. I remember in fpGUI I had plenty of issues getting the GDI and X11 drawing backends to work identical. Hence I created a custom TfpgRect which includes the Width and Height values. In fpGUI I tried to make all Canvas drawing methods use Top,Left,Width and Height. This gave a more consistent and expected behaviour.

  TfpgRect = object  // not class for static allocations
    Top: TfpgCoord;
    Left: TfpgCoord;
    Width: TfpgCoord;
    Height: TfpgCoord;
    procedure SetRect(aleft, atop, awidth, aheight: TfpgCoord);
    function  Bottom: TfpgCoord;
    function  Right: TfpgCoord;
    procedure SetBottom(Value: TfpgCoord);
    procedure SetRight(Value: TfpgCoord);
  end;

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Hans-Peter Diettrich
to Michael Van Canneyt: I have a question regarding the following function: function PtInRect(const Rect :…
Is there a reason why the top/left sides are included (>=), and the left/bottom sides are not included ? I would expect them to be included as well.

There exist reasons, mostly the definition in the WinAPI.

Dunno how to explain the most important reason, but let me try it:

Take an arbitrary scale, e.g. for temparatures or dates, and try to map coordinates into differences. Easy? Not really, when you have to work with integral numbers. Do you want to paint points (pixels) *at* given coordinates (tick marks for the scale), or lines (distances) *between* two coordinates? Then you see that you can't do both at once, for a distance of 1 unit (painting: 1 pixel) :-(

On a 2D canvas a grid for cells of size=1 (pixel) either would fill the entire area or, when you fill the cells with pixels, there's no room left for grid lines.

As a practical compromise a canvas is painted in pixels, i.e. rectangles of size=1, so that a rectangle from (0,0) to (1,1) has a *size* of 1 pixel, and that single pixel is *located* at the coordinates (0,0). Now you see that the end coordinates of a rectangle are *not* part of the area of the rectangle.

One should understand that the transformation of rectangles, between origin/extent (XY)-(WH) and TopLeft/BottomRight (TL)-(BR) representation, includes an imaginary shift of half a pixel. I really would appreciate different data types for both representations, instead of the unique TRect record - then it were obvious, that PtInRect works with the (TL)-(BR) representation, and consequently has to exclude the bottom and right values from the area of the rectangle.

The same considerations apply to lines, as mentioned above. When the pen is moved to (x0,y0) on a canvas, and then consecutive lines are drawn to (x1,y1) and (x2,y2), the point (x1,y1) is excluded from the first line, and (x2,y2) is excluded from the second line. Nonetheless the pen is *located* at (x2,y2) afterwards. This way one can paint a rectangular border, with a PolyLine(T,L, T,R, B,R, B,L, T,L), without repainting the edges of the rectangle. When the lines are painted in different colors, the end points are painted in the color of the *next* line.

Imagine how complicated were the calculation of the "real" (not excluded) end points of a series of lines, when arbitrary world-coordinates are used, expressed in something different from integral pixel coordinates.

HTH
DoDi

Reply by email

Michael Van Canneyt
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 6 lines
Michael Van Canneyt schrieb: > Is there a reason why the top/left sides are included (>=), and the > left/bottom sides are not included ? I would expect them to be included as well. There exist reasons, mostly the definition in the WinAPI.

Thanks to you, and everyone else, for the answers.

All I really needed to know is whether the cursor is at an edge of a rectangle (above a selected object, in fact). And in that case it turns out that ptinrect is definitely out....

Michael.

Reply by email