A slightly different region implementation, not tested or anything

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15236 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini 2005-11-30 06:23:00 +00:00
parent 7e68917fe7
commit 5c2728e222
6 changed files with 1221 additions and 0 deletions

View File

@ -0,0 +1,529 @@
#include <string.h>
#include <stdlib.h>
#include "clipping.h"
#include "ClipRegion.h"
#include <Debug.h>
const static int32 kMaxPoints = 1024;
const static int32 kMaxVerticalExtent = 0x10000000;
const static int32 kMaxPositive = 0x7ffffffd;
const static int32 kMaxNegative = 0x80000003;
const static int32 kInitialDataSize = 8;
ClipRegion::ClipRegion()
:
fDataSize(0),
fData(NULL)
{
_Resize(kInitialDataSize);
_Invalidate();
}
ClipRegion::ClipRegion(const ClipRegion &region)
:
fDataSize(0),
fData(NULL)
{
*this = region;
}
ClipRegion::ClipRegion(const clipping_rect &rect)
:
fDataSize(0),
fData(NULL)
{
Set(rect);
}
ClipRegion::ClipRegion(const BRect &rect)
:
fDataSize(0),
fData(NULL)
{
Set(rect);
}
ClipRegion::ClipRegion(const clipping_rect *rects, const int32 &count)
:
fDataSize(0),
fData(NULL)
{
Set(rects, count);
}
ClipRegion::~ClipRegion()
{
free(fData);
}
void
ClipRegion::Set(const clipping_rect &rect)
{
if (!valid_rect(rect) || (fDataSize <= 1 && !_Resize(kInitialDataSize)))
_Invalidate();
else {
fCount = 1;
fData[0] = fBound = rect;
}
}
void
ClipRegion::Set(const BRect &rect)
{
Set(to_clipping_rect(rect));
}
void
ClipRegion::Set(const clipping_rect *rects, const int32 &count)
{
_Invalidate();
_Append(rects, count);
}
bool
ClipRegion::Intersects(const clipping_rect &rect) const
{
if (!rects_intersect(rect, fBound))
return false;
for (int32 c = 0; c < fCount; c++) {
if (rects_intersect(fData[c], rect))
return true;
}
return false;
}
bool
ClipRegion::Intersects(const BRect &rect) const
{
return Intersects(to_clipping_rect(rect));
}
bool
ClipRegion::Contains(const BPoint &pt) const
{
// If the point doesn't lie within the region's bounds,
// don't even try it against the region's rects.
if (!point_in(fBound, pt))
return false;
for (int32 c = 0; c < fCount; c++) {
if (point_in(fData[c], pt))
return true;
}
return false;
}
void
ClipRegion::OffsetBy(const int32 &dh, const int32 &dv)
{
if (fCount > 0) {
for (int32 c = 0; c < fCount; c++)
offset_rect(fData[c], dh, dv);
offset_rect(fBound, dh, dv);
}
}
void
ClipRegion::OffsetBy(const BPoint &point)
{
return OffsetBy((int32)point.x, (int32)point.y);
}
void
ClipRegion::IntersectWith(const clipping_rect &rect)
{
if (!rects_intersect(rect, fBound))
_Invalidate();
else
_IntersectWith(rect);
}
void
ClipRegion::IntersectWith(const BRect &rect)
{
IntersectWith(to_clipping_rect(rect));
}
void
ClipRegion::IntersectWith(const ClipRegion &region)
{
clipping_rect intersection = sect_rect(fBound, region.fBound);
if (fCount == 0 || region.fCount == 0 || !valid_rect(intersection))
_Invalidate();
else if (fCount == 1 && region.fCount == 1)
Set(intersection);
else if (fCount > 1 && region.fCount == 1)
_IntersectWith(region.fBound);
else if (fCount == 1 && region.fCount > 1) {
ClipRegion dest = region;
dest._IntersectWith(fBound);
_Adopt(dest);
} else
_IntersectWithComplex(region);
}
void
ClipRegion::Include(const clipping_rect &rect)
{
// The easy case first: if the rectangle completely contains
// ourself, the union is the rectangle itself.
if (rect.top <= fBound.top
&& rect.bottom >= fBound.bottom
&& rect.left <= fBound.left
&& rect.right >= fBound.right)
Set(rect);
else {
const ClipRegion region(rect);
_IncludeComplex(region);
}
}
void
ClipRegion::Include(const BRect &rect)
{
Include(to_clipping_rect(rect));
}
void
ClipRegion::Include(const ClipRegion &region)
{
if (region.fCount == 0)
return;
if (fCount == 0)
*this = region;
else if (region.fBound.top > fBound.bottom)
_Append(region);
else if (fBound.top > region.fBound.bottom)
_Append(region, true);
/*
else if (regionA->bound.left > regionB->bound.right)
OrRegionNoX(*regionB, *regionA, dest);
else if (regionB->bound.left > regionA->bound.right)
OrRegionNoX(*regionA, *regionB, dest);
*/
else if (region.fCount == 1)
Include(region.fBound);
else if (fCount == 1) {
ClipRegion dest = region;
dest.Include(fBound);
_Adopt(dest);
} else
_IncludeComplex(region);
}
void
ClipRegion::Exclude(const clipping_rect &rect)
{
const ClipRegion region(rect);
Exclude(region);
}
void
ClipRegion::Exclude(const BRect &rect)
{
const ClipRegion region(rect);
Exclude(region);
}
void
ClipRegion::Exclude(const ClipRegion &region)
{
if (fCount == 0)
return;
if (region.fCount == 0 || !rects_intersect(fBound, region.fBound))
*this = region;
else
_ExcludeComplex(region);
}
ClipRegion &
ClipRegion::operator=(const ClipRegion &region)
{
const int32 size = region.fDataSize > 0 ? region.fDataSize : kInitialDataSize;
if (_Resize(size, false)) {
fBound = region.fBound;
fCount = region.fCount;
memcpy(fData, region.fData, fCount * sizeof(clipping_rect));
} else
_Invalidate();
return *this;
}
// private methods
void
ClipRegion::_IntersectWithComplex(const ClipRegion &region)
{
ClipRegion dest(*this);
for (int32 f = 0; f < fCount; f++) {
for (int32 s = 0; s < region.fCount; s++) {
clipping_rect testRect = sect_rect(fData[f], region.fData[s]);
if (valid_rect(testRect))
dest._AddRect(testRect);
}
}
if (dest.fCount > 1)
dest._SortRects();
_Adopt(dest);
}
void
ClipRegion::_IntersectWith(const clipping_rect &rect)
{
ASSERT(rects_intersect(rect, fBound));
// The easy case first: We already know that the region intersects,
// with the passed rect, so we check if the rect completely contains
// the region.
// If it's the case, the intersection is exactly the region itself.
if (rect.top <= fBound.top && rect.bottom >= fBound.bottom
&& rect.left <= fBound.left && rect.right >= fBound.right)
return;
// Otherwise, we add the intersections of the region's rects
// with the passed rect
ClipRegion dest;
for (int32 x = 0; x < fCount; x++) {
clipping_rect testRect = sect_rect(rect, fData[x]);
if (valid_rect(testRect))
dest._AddRect(testRect);
}
_Adopt(dest);
}
void
ClipRegion::_IncludeComplex(const ClipRegion &region)
{
}
void
ClipRegion::_ExcludeComplex(const ClipRegion &region)
{
}
// Helper method to swap two rects
static inline void
SwapRects(clipping_rect &rect, clipping_rect &anotherRect)
{
clipping_rect tmpRect = rect;
rect = anotherRect;
anotherRect = tmpRect;
}
void
ClipRegion::_SortRects()
{
bool again;
if (fCount == 2) {
if (fData[0].top > fData[1].top)
SwapRects(fData[0], fData[1]);
} else if (fCount > 2) {
do {
again = false;
for (int32 c = 1; c < fCount; c++) {
if (fData[c - 1].top > fData[c].top) {
SwapRects(fData[c - 1], fData[c]);
again = true;
}
}
} while (again);
}
}
void
ClipRegion::_AddRect(const clipping_rect &rect)
{
ASSERT(fCount >= 0);
ASSERT(fDataSize >= 0);
ASSERT(valid_rect(rect));
// Should we just reallocate the memory and
// copy the rect ?
bool addRect = true;
if (fCount > 0) {
// Wait! We could merge the rect with one of the
// existing rectangles, if it's adiacent.
// We just check it against the last rectangle, since
// we are keeping them sorted by their "top" coordinates.
int32 last = fCount - 1;
if (rect.left == fData[last].left && rect.right == fData[last].right
&& rect.top == fData[last].bottom + 1) {
fData[last].bottom = rect.bottom;
addRect = false;
} else if (rect.top == fData[last].top && rect.bottom == fData[last].bottom) {
if (rect.left == fData[last].right + 1) {
fData[last].right = rect.right;
addRect = false;
} else if (rect.right == fData[last].left - 1) {
fData[last].left = rect.left;
addRect = false;
}
}
}
// We weren't lucky.... just add the rect as a new one
if (addRect) {
if (fDataSize <= fCount)
_Resize(fCount + 16);
fData[fCount] = rect;
fCount++;
}
_RecalculateBounds(rect);
}
void
ClipRegion::_RecalculateBounds(const clipping_rect &rect)
{
if (fCount <= 0)
return;
if (rect.top < fBound.top)
fBound.top = rect.top;
if (rect.left < fBound.left)
fBound.left = rect.left;
if (rect.right > fBound.right)
fBound.right = rect.right;
if (rect.bottom > fBound.bottom)
fBound.bottom = rect.bottom;
}
void
ClipRegion::_Append(const ClipRegion &region, const bool &aboveThis)
{
if (aboveThis) {
ClipRegion dest = region;
for (int32 c = 0; c < fCount; c++)
dest._AddRect(fData[c]);
_Adopt(dest);
} else {
for (int32 c = 0; c < region.fCount; c++)
_AddRect(region.fData[c]);
}
}
void
ClipRegion::_Append(const clipping_rect *rects, const int32 &count, const bool &aboveThis)
{
if (aboveThis) {
ClipRegion dest;
dest.Set(rects, count);
for (int32 c = 0; c < fCount; c++)
dest._AddRect(fData[c]);
_Adopt(dest);
} else {
for (int32 c = 0; c < count; c++)
_AddRect(rects[c]);
}
}
void
ClipRegion::_Invalidate()
{
fCount = 0;
fBound.left = kMaxPositive;
fBound.top = kMaxPositive;
fBound.right = kMaxNegative;
fBound.bottom = kMaxNegative;
}
bool
ClipRegion::_Resize(const int32 &newSize, const bool &keepOld)
{
if (!keepOld) {
free(fData);
fData = (clipping_rect *)malloc(newSize * sizeof(clipping_rect));
} else
fData = (clipping_rect *)realloc(fData, newSize * sizeof(clipping_rect));
if (fData == NULL)
return false;
fDataSize = newSize;
return true;
}
void
ClipRegion::_Adopt(ClipRegion &region)
{
free(fData);
fData = region.fData;
fDataSize = region.fDataSize;
fCount = region.fCount;
fBound = region.fBound;
region._Invalidate();
region.fDataSize = 0;
region.fData = NULL;
}

View File

@ -0,0 +1,83 @@
#ifndef __CLIPREGION_H
#define __CLIPREGION_H
#include "Region.h" // for clipping_rect
class ServerLink;
class ClipRegion {
public:
ClipRegion();
ClipRegion(const ClipRegion &region);
ClipRegion(const BRegion &region);
ClipRegion(const clipping_rect &rect);
ClipRegion(const BRect &rect);
ClipRegion(const clipping_rect *rects, const int32 &count);
~ClipRegion();
clipping_rect Frame() const { return fBound; }
clipping_rect RectAt(const int32 &index) const
{
if (index >= 0 && index < fCount)
return fData[index];
clipping_rect rect = { 0, 0, -1, -1 };
return rect;
}
int32 CountRects() const { return fCount; }
void Set(const clipping_rect &rect);
void Set(const BRect &rect);
void Set(const clipping_rect *rects, const int32 &count);
bool Intersects(const clipping_rect &rect) const;
bool Intersects(const BRect &rect) const;
bool Intersects(const ClipRegion &region) const;
bool Contains(const BPoint &point) const;
void OffsetBy(const int32 &dx, const int32 &dy);
void OffsetBy(const BPoint &point);
void Include(const clipping_rect &rect);
void Include(const BRect &rect);
void Include(const ClipRegion &region);
void Exclude(const clipping_rect &rect);
void Exclude(const BRect &rect);
void Exclude(const ClipRegion &region);
void IntersectWith(const clipping_rect &rect);
void IntersectWith(const BRect &rect);
void IntersectWith(const ClipRegion &region);
ClipRegion &operator=(const ClipRegion &region);
status_t ReadFromLink(ServerLink &link);
status_t WriteToLink(ServerLink &link);
private:
int32 fCount;
int32 fDataSize;
clipping_rect fBound;
clipping_rect *fData;
void _Append(const ClipRegion &region, const bool &aboveThis = false);
void _Append(const clipping_rect *rects, const int32 &count, const bool &aboveThis = false);
void _IntersectWithComplex(const ClipRegion &region);
void _IntersectWith(const clipping_rect &rect);
void _IncludeComplex(const ClipRegion &region);
void _ExcludeComplex(const ClipRegion &region);
void _SortRects();
void _AddRect(const clipping_rect &rect);
void _RecalculateBounds(const clipping_rect &newRect);
void _Invalidate();
bool _Resize(const int32 &newSize, const bool &keepOld = true);
void _Adopt(ClipRegion &region);
};
#endif // __CLIPREGION_H

View File

@ -0,0 +1,348 @@
//------------------------------------------------------------------------------
// Copyright (c) 2003-2005, Haiku, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: Region.cpp
// Author: Stefano Ceccherini (burton666@libero.it)
// Description: Region class consisting of multiple rectangles
//
//------------------------------------------------------------------------------
// Notes: As now, memory is always allocated and never freed (except on destruction,
// or sometimes when a copy is made).
// This let us be a bit faster since we don't do many reallocations.
// But that means that even an empty region could "waste" much space, if it contained
// many rects before being emptied.
// I.E: a region which contains 24 rects allocates more than 24 * 4 * sizeof(int32)
// = 96 * sizeof(int32) bytes. If we call MakeEmpty(), that region will contain no rects,
// but it will still keep the allocated memory.
// This shouldnt' be an issue, since usually BRegions are just used for calculations,
// and don't last so long.
// Anyway, we can change that behaviour if we want, but BeOS's BRegion seems to behave exactly
// like this.
#include <cstdlib>
#include <cstring>
#include <new>
#include <Debug.h>
#include <Region.h>
#include <clipping.h>
#include <ClipRegion.h>
/*! \brief Initializes a region. The region will have no rects,
and its bound will be invalid.
*/
BRegion::BRegion()
:
fRegion(new (nothrow) ClipRegion)
{
}
/*! \brief Initializes a region to be a copy of another.
\param region The region to copy.
*/
BRegion::BRegion(const BRegion &region)
:
fRegion(new (nothrow) ClipRegion(*region.fRegion))
{
}
/*! \brief Initializes a region to contain a BRect.
\param rect The BRect to set the region to.
*/
BRegion::BRegion(const BRect rect)
:
fRegion(new (nothrow) ClipRegion(to_clipping_rect(rect)))
{
}
/*! \brief Frees the allocated memory.
*/
BRegion::~BRegion()
{
delete fRegion;
}
/*! \brief Returns the bounds of the region.
\return A BRect which represents the bounds of the region.
*/
BRect
BRegion::Frame() const
{
return fRegion ? to_BRect(fRegion->Frame()) : BRect();
}
/*! \brief Returns the bounds of the region as a clipping_rect (which has integer coordinates).
\return A clipping_rect which represents the bounds of the region.
*/
clipping_rect
BRegion::FrameInt() const
{
return fRegion ? fRegion->Frame() : to_clipping_rect(BRect());
}
/*! \brief Returns the regions's BRect at the given index.
\param index The index (zero based) of the wanted rectangle.
\return If the given index is valid, it returns the BRect at that index,
otherwise, it returns an invalid BRect.
*/
BRect
BRegion::RectAt(int32 index)
{
return fRegion ? to_BRect(fRegion->RectAt(index)) : BRect();
}
/*! \brief Returns the regions's clipping_rect at the given index.
\param index The index (zero based) of the wanted rectangle.
\return If the given index is valid, it returns the clipping_rect at that index,
otherwise, it returns an invalid clipping_rect.
*/
clipping_rect
BRegion::RectAtInt(int32 index)
{
return fRegion ? fRegion->RectAt(index) : to_clipping_rect(BRect());
}
/*! \brief Counts the region rects.
\return An int32 which is the total number of rects in the region.
*/
int32
BRegion::CountRects()
{
return fRegion ? fRegion->CountRects() : 0;
}
/*! \brief Set the region to contain just the given BRect.
\param newBounds A BRect.
*/
void
BRegion::Set(BRect newBounds)
{
Set(to_clipping_rect(newBounds));
}
/*! \brief Set the region to contain just the given clipping_rect.
\param newBounds A clipping_rect.
*/
void
BRegion::Set(clipping_rect newBounds)
{
if (fRegion)
fRegion->Set(newBounds);
else
fRegion = new (nothrow) ClipRegion(newBounds);
}
/*! \brief Check if the region has any area in common with the given BRect.
\param rect The BRect to check the region against to.
\return \ctrue if the region has any area in common with the BRect, \cfalse if not.
*/
bool
BRegion::Intersects(BRect rect) const
{
return fRegion ? fRegion->Intersects(to_clipping_rect(rect)) : false;
}
/*! \brief Check if the region has any area in common with the given clipping_rect.
\param rect The clipping_rect to check the region against to.
\return \ctrue if the region has any area in common with the clipping_rect, \cfalse if not.
*/
bool
BRegion::Intersects(clipping_rect rect) const
{
return fRegion ? fRegion->Intersects(rect) : false;
}
/*! \brief Check if the region contains the given BPoint.
\param pt The BPoint to be checked.
\return \ctrue if the region contains the BPoint, \cfalse if not.
*/
bool
BRegion::Contains(BPoint pt) const
{
return fRegion ? fRegion->Contains(pt) : false;
}
/*! \brief Check if the region contains the given coordinates.
\param x The \cx coordinate of the point to be checked.
\param y The \cy coordinate of the point to be checked.
\return \ctrue if the region contains the point, \cfalse if not.
*/
bool
BRegion::Contains(int32 x, int32 y)
{
if (fRegion == NULL)
return false;
const BPoint pt(x, y);
return fRegion->Contains(pt);
}
/*! \brief Prints the BRegion to stdout.
*/
void
BRegion::PrintToStream() const
{
if (fRegion == NULL)
return;
Frame().PrintToStream();
for (int32 c = 0; c < fRegion->CountRects(); c++) {
clipping_rect rect = fRegion->RectAt(c);
printf("data = BRect(l:%ld.0, t:%ld.0, r:%ld.0, b:%ld.0)\n",
rect.left, rect.top, rect.right, rect.bottom);
}
}
/*! \brief Offsets all region's rects, and bounds by the given values.
\param dh The horizontal offset.
\param dv The vertical offset.
*/
void
BRegion::OffsetBy(int32 dh, int32 dv)
{
if (fRegion != NULL)
fRegion->OffsetBy(dh, dv);
}
/*! \brief Empties the region, so that it doesn't include any rect, and invalidates its bounds.
*/
void
BRegion::MakeEmpty()
{
clipping_rect invalid = { 0, 0, -1, -1 };
Set(invalid);
}
/*! \brief Modifies the region, so that it includes the given BRect.
\param rect The BRect to be included by the region.
*/
void
BRegion::Include(BRect rect)
{
Include(to_clipping_rect(rect));
}
/*! \brief Modifies the region, so that it includes the given clipping_rect.
\param rect The clipping_rect to be included by the region.
*/
void
BRegion::Include(clipping_rect rect)
{
if (fRegion != NULL)
fRegion->Include(rect);
}
/*! \brief Modifies the region, so that it includes the area of the given region.
\param region The region to be included.
*/
void
BRegion::Include(const BRegion *region)
{
if (fRegion != NULL)
fRegion->Include(*region->fRegion);
}
/*! \brief Modifies the region, excluding the area represented by the given BRect.
\param rect The BRect to be excluded.
*/
void
BRegion::Exclude(BRect rect)
{
if (fRegion)
fRegion->Exclude(to_clipping_rect(rect));
}
/*! \brief Modifies the region, excluding the area represented by the given clipping_rect.
\param rect The clipping_rect to be excluded.
*/
void
BRegion::Exclude(clipping_rect rect)
{
if (fRegion)
fRegion->Exclude(rect);
}
/*! \brief Modifies the region, excluding the area contained in the given BRegion.
\param region The BRegion to be excluded.
*/
void
BRegion::Exclude(const BRegion *region)
{
if (fRegion)
fRegion->Exclude(*region->fRegion);
}
/*! \brief Modifies the region, so that it will contain just the area in common with the given BRegion.
\param region the BRegion to intersect to.
*/
void
BRegion::IntersectWith(const BRegion *region)
{
if (fRegion)
fRegion->IntersectWith(*region->fRegion);
}
/*! \brief Modifies the region to be a copy of the given BRegion.
\param region the BRegion to copy.
\return This function always returns \c *this.
*/
BRegion &
BRegion::operator=(const BRegion &region)
{
if (&region != this) {
delete fRegion;
fRegion = new (nothrow) ClipRegion(*region.fRegion);
}
return *this;
}

View File

@ -0,0 +1,71 @@
/*******************************************************************************
/
/ File: Region.h
/
/ Description: BRegion represents an area that's composed of individual
/ rectangles.
/
/ Copyright 1992-98, Be Incorporated, All Rights Reserved
/
*******************************************************************************/
#ifndef _REGION_H
#define _REGION_H
#include <BeBuild.h>
#include <Rect.h>
namespace BPrivate {
class ServerLink;
};
/* Integer rect used to define a cliping rectangle. All bounds are included */
/* Moved from DirectWindow.h */
typedef struct {
int32 left;
int32 top;
int32 right;
int32 bottom;
} clipping_rect;
/*----- BRegion class --------------------------------------------*/
class ClipRegion;
class BRegion {
public:
BRegion();
BRegion(const BRegion &region);
BRegion(const BRect rect);
virtual ~BRegion();
BRegion &operator=(const BRegion &from);
BRect Frame() const;
clipping_rect FrameInt() const;
BRect RectAt(int32 index);
clipping_rect RectAtInt(int32 index);
int32 CountRects();
void Set(BRect newBounds);
void Set(clipping_rect newBounds);
bool Intersects(BRect r) const;
bool Intersects(clipping_rect r) const;
bool Contains(BPoint pt) const;
bool Contains(int32 x, int32 y);
void PrintToStream() const;
void OffsetBy(int32 dh, int32 dv);
void MakeEmpty();
void Include(BRect r);
void Include(clipping_rect r);
void Include(const BRegion*);
void Exclude(BRect r);
void Exclude(clipping_rect r);
void Exclude(const BRegion*);
void IntersectWith(const BRegion*);
/*----- Private or reserved -----------------------------------------*/
private:
ClipRegion *fRegion;
};
#endif /* _REGION_H */

View File

@ -0,0 +1,172 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2004, Haiku, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: clipping.h
// Author: Stefano Ceccherini (burton666@libero.it)
// Description: Helper methods to manipulate clipping_rects
//------------------------------------------------------------------------------
#ifndef __CLIPPING_H
#define __CLIPPING_H
#include <Region.h>
#include <SupportDefs.h>
/* Some methods to manipulate clipping_rects.
basically you can do almost everything you do with
BRects, just that clipping_rects can only have integer
coordinates (a thing that makes these perfect for drawing
calculations).
*/
// Returns the union of the given rects.
static inline clipping_rect
union_rect(const clipping_rect &r1, const clipping_rect &r2)
{
clipping_rect rect;
rect.left = min_c(r1.left, r2.left);
rect.top = min_c(r1.top, r2.top);
rect.right = max_c(r1.right, r2.right);
rect.bottom = max_c(r1.bottom, r2.bottom);
return rect;
}
// Returns the intersection of the given rects.
// The caller should check if the returned rect is valid. If it isn't valid,
// then the two rectangles don't intersect.
static inline clipping_rect
sect_rect(const clipping_rect &r1, const clipping_rect &r2)
{
clipping_rect rect;
rect.left = max_c(r1.left, r2.left);
rect.top = max_c(r1.top, r2.top);
rect.right = min_c(r1.right, r2.right);
rect.bottom = min_c(r1.bottom, r2.bottom);
return rect;
}
// Adds the given offsets to the given rect.
static inline void
offset_rect(clipping_rect &rect, int32 x, int32 y)
{
rect.left += x;
rect.top += y;
rect.right += x;
rect.bottom += y;
}
// Converts the given clipping_rect to a BRect
static inline BRect
to_BRect(const clipping_rect &rect)
{
return BRect((float)rect.left, (float)rect.top, (float)rect.right, (float)rect.bottom);
}
// Converts the given BRect to a clipping_rect.
static inline clipping_rect
to_clipping_rect(const BRect &rect)
{
clipping_rect clipRect;
clipRect.left = (int32)floor(rect.left);
clipRect.top = (int32)floor(rect.top);
clipRect.right = (int32)ceil(rect.right);
clipRect.bottom = (int32)ceil(rect.bottom);
return clipRect;
}
// Checks if the given point lies in the given rect's area
static inline bool
point_in(const clipping_rect &rect, int32 px, int32 py)
{
if (px >= rect.left && px <= rect.right
&& py >= rect.top && py <= rect.bottom)
return true;
return false;
}
// Same as above, but it accepts a BPoint parameter
static inline bool
point_in(const clipping_rect &rect, const BPoint &pt)
{
if (pt.x >= rect.left && pt.x <= rect.right
&& pt.y >= rect.top && pt.y <= rect.bottom)
return true;
return false;
}
// Checks if the rect is valid
static inline bool
valid_rect(const clipping_rect &rect)
{
if (rect.left <= rect.right && rect.top <= rect.bottom)
return true;
return false;
}
// Checks if the two rects intersect.
static inline bool
rects_intersect(const clipping_rect &rectA, const clipping_rect &rectB)
{
// We behave like BRect::Intersects() does:
// we return false if one of the two rects is not valid
if (!valid_rect(rectA) || !valid_rect(rectB))
return false;
// TODO: Is there a better algorithm ?
// the one we used is faster than
// ' return valid_rect(sect_rect(rectA, rectB)); ', though.
return !(rectA.left > rectB.right || rectA.top > rectB.bottom
|| rectA.right < rectB.left || rectA.bottom < rectB.top);
}
// Returns the width of the given rect.
static inline int32
rect_width(const clipping_rect &rect)
{
return rect.right - rect.left;
}
// Returns the height of the given rect.
static inline int32
rect_height(const clipping_rect &rect)
{
return rect.bottom - rect.top;
}
#endif // __CLIPPING_H

View File

@ -0,0 +1,18 @@
#include "clipping.h"
#include "Region.h"
#include <stdio.h>
int main()
{
BRegion region(BRect(10, 10, 20, 20));
BRegion other(BRect(15, 15, 50, 19));
region.IntersectWith(&other);
if (region.Intersects(other.Frame()))
printf("Okay!\n");
region.PrintToStream();
}