// $Id: docrect.cpp 1282 2006-06-09 09:46:49Z alex $
/* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
================================XARAHEADERSTART===========================
 
               Xara LX, a vector drawing and manipulation program.
                    Copyright (C) 1993-2006 Xara Group Ltd.
       Copyright on certain contributions may be held in joint with their
              respective authors. See AUTHORS file for details.

LICENSE TO USE AND MODIFY SOFTWARE
----------------------------------

This file is part of Xara LX.

Xara LX is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 as published
by the Free Software Foundation.

Xara LX and its component source files are distributed in the hope
that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with Xara LX (see the file GPL in the root directory of the
distribution); if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA  02110-1301 USA


ADDITIONAL RIGHTS
-----------------

Conditional upon your continuing compliance with the GNU General Public
License described above, Xara Group Ltd grants to you certain additional
rights. 

The additional rights are to use, modify, and distribute the software
together with the wxWidgets library, the wxXtra library, and the "CDraw"
library and any other such library that any version of Xara LX relased
by Xara Group Ltd requires in order to compile and execute, including
the static linking of that library to XaraLX. In the case of the
"CDraw" library, you may satisfy obligation under the GNU General Public
License to provide source code by providing a binary copy of the library
concerned and a copy of the license accompanying it.

Nothing in this section restricts any of the rights you have under
the GNU General Public License.


SCOPE OF LICENSE
----------------

This license applies to this program (XaraLX) and its constituent source
files only, and does not necessarily apply to other Xara products which may
in part share the same code base, and are subject to their own licensing
terms.

This license does not apply to files in the wxXtra directory, which
are built into a separate library, and are subject to the wxWindows
license contained within that directory in the file "WXXTRA-LICENSE".

This license does not apply to the binary libraries (if any) within
the "libs" directory, which are subject to a separate license contained
within that directory in the file "LIBS-LICENSE".


ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
----------------------------------------------

Subject to the terms of the GNU Public License (see above), you are
free to do whatever you like with your modifications. However, you may
(at your option) wish contribute them to Xara's source tree. You can
find details of how to do this at:
  http://www.xaraxtreme.org/developers/

Prior to contributing your modifications, you will need to complete our
contributor agreement. This can be found at:
  http://www.xaraxtreme.org/developers/contribute/

Please note that Xara will not accept modifications which modify any of
the text between the start and end of this header (marked
XARAHEADERSTART and XARAHEADEREND).


MARKS
-----

Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
designs are registered or unregistered trademarks, design-marks, and/or
service marks of Xara Group Ltd. All rights in these marks are reserved.


      Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
                        http://www.xara.com/

=================================XARAHEADEREND============================
 */


#include "camtypes.h"
//#include "docrect.h" - in camtypes.h [AUTOMATICALLY REMOVED]
//#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]

DECLARE_SOURCE("$Revision: 1282 $");

/*
  $Log: rect.ctt $
Revision 1.20  1995/07/07  11:35:00  Jason
Fixed ABS macro definitions to be safe

Revision 1.19  1994/06/28  16:57:47  Rik
Added some code that shows how the hell the IsAdjacent function works

Revision 1.18  1994/03/03  11:38:12  Tim
Added a MakeEmpty function.

Revision 1.17  1994/01/20  17:09:23  Simon
Default constructor now creates an empty recatngle

Revision 1.16  1994/01/12  17:30:17  Rik
Improved region merging and region joining

Revision 1.15  1993/11/05  14:56:03  Rik
Blobs work, fixed DocRect probs, selecting blobs work

Revision 1.14  1993/08/12  11:17:48  Will
Global CheckIn for new DocCoord system.

Revision 1.13  1993/07/29  11:10:02  Will
Fixed problem with fuzzy adjacent test.

Revision 1.12  1993/07/21  21:08:29  Will
Split rect function was splitting the wrong rect.

Revision 1.11  1993/07/19  17:02:42  Will
Added some comments.
Added Fuzzy limit passed during IsAdjacent().

Revision 1.10  1993/07/15  17:04:10  Will
Added SplitRect function for BG rendering.

Revision 1.9  1993/07/14  17:34:25  Will
Added IsAdjacent function for region merging.

Revision 1.8  1993/07/12  12:58:11  Tim
Added a ContainsRect function.

Revision 1.7  1993/06/18  11:06:28  Tim
Made rectangle classes usable by tools by using the CAMAPI macro in the
class declaration.

Revision 1.6  1993/06/15  16:49:28  Tim
Altered Intersection and Union to return objects rather than object refs.

Revision 1.5  1993/06/10  10:29:35  Tim
Improved links for ADC generated help file.

Revision 1.4  1993/06/09  16:40:02  Tim
Moved class comment from .cpp file to .h file to conform to style guide.

Revision 1.3  1993/06/09  13:52:40  Tim
Revised use and meaning of empty/invalid rectangles.
Expanded comment headers to explain this.

Revision 1.2  1993/06/08  14:12:06  Tim
Added comments about non-re-entrancy of Union and Intersection.

*/


/**********************************************************************************************

>    BOOL DocRect::IsAdjacent() const

     Author: 	Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
     Created:   14/7/93
     Inputs:	The Fuzzy limit in MILLIPOINTS.  
     Outputs:   - 
     
     Returns:   TRUE if the rectangles are adjacent within a Fuzzy limit.
     			
     Purpose:	To check for adjacent rectangles.

     Errors:	

**********************************************************************************************/  

BOOL DocRect::IsAdjacent(const DocRect& Rect, MILLIPOINT Fuzzy) const
{
	// Check for an an empty rectangle
	if (IsEmpty())
		return FALSE;

    // Detect an invalid rectangle
	ENSURE(IsValid(), "DocRect::IsAdjacent() was called on\nan invalid rectangle.");  

#if 0
	// This is the expansion of the rampant return statement below

	// Near top or bottom
	BOOL NearBot = (ABS(Rect.hi.y - lo.y)) <= Fuzzy;
	BOOL NearTop = (ABS(Rect.lo.y - hi.y)) <= Fuzzy;

	// Near left or right
	BOOL NearLeft  = (ABS(Rect.hi.x - lo.x)) <= Fuzzy;
	BOOL NearRight = (ABS(Rect.lo.x - hi.x)) <= Fuzzy;

	// Overlaps
	BOOL OverLeft  = (ABS(Rect.lo.x - lo.x)) <= Fuzzy;
	BOOL OverRight = (ABS(Rect.hi.x - hi.x)) <= Fuzzy;
	BOOL OverTop   = (ABS(Rect.hi.y - hi.y)) <= Fuzzy;
	BOOL OverBot   = (ABS(Rect.lo.y - lo.y)) <= Fuzzy;

	// Adjacent to the top or bottom?
	BOOL TopOrBot    = (NearTop || NearBot) && OverLeft && OverRight;
	BOOL LeftOrRight = (NearLeft || NearRight) && OverTop && OverBot;

	return (TopOrBot || LeftOrRight);
#endif

	// This is explained more carefully in the section above that is excluded from the build
	return (( ((ABS(Rect.lo.x - lo.x))<=Fuzzy) && ((ABS(Rect.hi.x - hi.x))<=Fuzzy) &&
			 (((ABS(Rect.hi.y - lo.y))<=Fuzzy) || ((ABS(Rect.lo.y - hi.y))<=Fuzzy)) ) ||
	        ( ((ABS(Rect.lo.y - lo.y))<=Fuzzy) && ((ABS(Rect.hi.y - hi.y))<=Fuzzy) &&
			 (((ABS(Rect.hi.x - lo.x))<=Fuzzy) || ((ABS(Rect.lo.x - hi.x))<=Fuzzy)) ));
}



/*********************************************************************************************

>    DocRect DocRect::Union(const DocRect& R)

     Author: 	Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
     Created:   17/5/93
     Inputs:	R - the rectangle to join with the object.
     Outputs:   - 
     
     Returns:   The simple union (bounding box).
     			
     Purpose:	Compute union of two rectangles.
     			
     			If one of the rectangles involved is invalid, the other is returned as the
     			result.  In the case of both being invalid, one of the invalid rectangles
     			is returned as the result.  It is undefined which rectangle is returned in
     			this case.

     Errors:	None.

**********************************************************************************************/  

DocRect DocRect::Union(const DocRect& R) const
{
	// Special cases for invalid rectangles...
	if (!IsValid()  ||  IsEmpty())
		return R;
	if (!R.IsValid()  ||  R.IsEmpty())
		return *this;
		
	// Return the result
	DocRect U;
	U.lo.x = min(lo.x, R.lo.x);
	U.lo.y = min(lo.y, R.lo.y);
	U.hi.x = max(hi.x, R.hi.x);
	U.hi.y = max(hi.y, R.hi.y);
	return U;
}



/*********************************************************************************************

>    DocRect DocRect::Intersection(const DocRect& R)

     Author: 	Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
     Created:   17/5/93
     Inputs:	R - the rectangle to intersect with.
     Outputs:   - 
     
     Returns:   The intersection.
     			
     Purpose:	Compute intersection of two rectangles.

     			If one of the rectangles involved is invalid, the other is returned as the
     			result.  In the case of both being invalid, one of the invalid rectangles
     			is returned as the result.  It is undefined which rectangle is returned in
     			this case.

     Errors:	None.

**********************************************************************************************/  

DocRect DocRect::Intersection(const DocRect& R) const
{
	// Special cases for invalid rectangles...
	if (!IsValid())
		return R;
	if (!R.IsValid())
		return *this;
	
	// Special cases when empty rectangles
	if (IsEmpty())
		return *this;
	if (R.IsEmpty())
		return R;

	// Return the result
	DocRect I;
	I.lo.x = max(lo.x, R.lo.x);
	I.lo.y = max(lo.y, R.lo.y);
	I.hi.x = min(hi.x, R.hi.x);
	I.hi.y = min(hi.y, R.hi.y);
	return I;
}



/*********************************************************************************************

>    INT32 DocRect::SplitRect(const DocRect& R, DocRect* SubRects)

     Author: 	Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
     Created:   14/7/93
     Inputs:	R is the rectangle to intersect with, SubRects is an array of DocRect to fill.  
     Outputs:   Puts any sub-rects into SubRects. 
     
     Returns:   The number of subrectangles found. 0 for no intersection.
     			
     Purpose:	Splits a rectangle into sub-rectangles which all exclude the interecting
     			rectangle R.  The number of sub-rects generated depends on how the rectangles
     			intersect.
     				 _______________________       	 ___________________
	            	|                       |      	|                   |
     				| *this    A            |      	| *this    A        |
     				|_ _ _  ________  _ _ _ |      	|_ _ _ _ _  ________|__________
     				|      |        |       |      	|          |        |          |
     				|  B   |   R    |   C   |      	|    B     |        |          |
     				|_ _ _ |________| _ _ _ |      	|__________|________| R        |
     				|                       |      	           |                   |
                    |          D    Index=4 |      	           |           Index=2 |
     				|_______________________|      	           |___________________|
     Errors:	

**********************************************************************************************/  

INT32 DocRect::SplitRect(const DocRect& R, DocRect* SubRects)
{
	if (!this->IsIntersectedWith(R))
		return 0;	// No intersection  

	INT32 Index = 0;

	if (R.hi.y < hi.y)
		SubRects[Index++] = DocRect(lo.x, R.hi.y, hi.x, hi.y);	// Sub-Rect A
		
	if (R.lo.y > lo.y)
		SubRects[Index++] = DocRect(lo.x, lo.y, hi.x, R.lo.y);	// Sub-Rect D

	INT32 Ry0 = max(R.lo.y, lo.y);
	INT32 Ry1 = min(R.hi.y, hi.y);
	
	if (R.lo.x > lo.x)
		SubRects[Index++] = DocRect(lo.x, Ry0, R.lo.x, Ry1);			// Sub-Rect B		

	if (R.hi.x < hi.x)
		SubRects[Index++] = DocRect(R.hi.x, Ry0, hi.x, Ry1);			// Sub-Rect C		

	return Index;
}



/***********************************************************************************************

>	void DocRect::IncludePoint(const DocCoord& Point)

	Author:		Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
	Created:	27/5/93
	Inputs:		Point - coordinate to include into this rectangle.
	Outputs:	-
	Returns:	-
	Purpose:	Expand a rectangle so that it includes the given point.
	Errors:		An assertion failure if the rectangle is invalid.
	SeeAlso:	-

***********************************************************************************************/

void DocRect::IncludePoint(const DocCoord& Point)
{
    // Detect an invalid rectangle
	ENSURE(IsValid(), "DocRect::IncludePoint() was called on an \ninvalid rectangle.");  

	// Extend lower corner to include point if necessary
	lo.x = min(lo.x, Point.x);
	lo.y = min(lo.y, Point.y);
	
	// Extend upper corner to include point if necessary
	// (remember upper corner is exclusive)
	hi.x = max(hi.x, (INT32)(Point.x + 1L));
	hi.y = max(hi.y, (INT32)(Point.y + 1L));
}

// extra functions specific to the DocRect class

/*
$Log: docrect.def $
Revision 1.1  1995/09/12  17:08:12  Ed
Initial revision

*/

#if !defined(EXCLUDE_FROM_XARLIB)

DECLARE_SOURCE("$Revision: 1282 $");

#include "userrect.h"
//#include "oilrect.h" - in camtypes.h [AUTOMATICALLY REMOVED]

/********************************************************************************************
>	DocRect DocRect::ToSpread(Spread* pSpread, View* pView)

	Author:		Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
	Created:	6/9/95
	Inputs:		pSpread - 
				pView   -
	Returns:	DocRect
	Purpose:	Convert a DocRect to a SpreadRect (AKA DocRect)
********************************************************************************************/

DocRect DocRect::ToSpread(Spread* pSpread, View* pView)
{
	return DocRect( this->lo.ToSpread(pSpread,pView), this->hi.ToSpread(pSpread,pView) );
}


/********************************************************************************************
>	DocRect DocRect::ToDoc(Spread* pSpread, View* pView)

	Author:		Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
	Created:	6/9/95
	Inputs:		pSpread - 
				pView   -
	Returns:	DocRect
	Purpose:	Convert a SpreadRect (AKA DocRect) to a DocRect
********************************************************************************************/

DocRect DocRect::ToDoc(Spread* pSpread, View* pView)
{
	return DocRect( this->lo.ToDoc(pSpread,pView), this->hi.ToDoc(pSpread,pView) );
}


/********************************************************************************************
>	UserRect DocRect::ToUser(Spread* pSpread)

	Author:		Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
	Created:	11/9/95
	Inputs:		pSpread - 
	Returns:	UserRect
	Purpose:	Convert a SpreadRect (AKA DocRect) to a UserRect
********************************************************************************************/

UserRect DocRect::ToUser(Spread* pSpread)
{
	return UserRect( this->lo.ToUser(pSpread), this->hi.ToUser(pSpread) );
}


/********************************************************************************************
>	OilRect DocRect::ToOil(Spread* pSpread, View* pView)

	Author:		Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
	Created:	6/9/95
	Inputs:		pSpread - 
				pView   -
	Returns:	DocRect
	Purpose:	Convert a SpreadRect (AKA DocRect) to an OilRect
********************************************************************************************/

OilRect DocRect::ToOil(Spread* pSpread, View* pView)
{
	return OilRect( this->lo.ToOil(pSpread,pView), this->hi.ToOil(pSpread,pView) );
}

#endif	// EXCLUDE_FROM_XARLIB
