text: ﻿//---------------------------------------------------------------------------
  /*
  	TVP2 ( T Visual Presenter 2 )  A script authoring tool
  	Copyright (C) 2000 W.Dee <dee@kikyou.info> and contributors
  
  	See details of license at "license.txt"
  */
  //---------------------------------------------------------------------------
  // Complex Rectangle Class
  //---------------------------------------------------------------------------
  
  #ifndef ComplexRectUnitH
  #define ComplexRectUnitH
  
  #include <stdlib.h>
  
  #ifndef __TJSTYPES_H__
  	typedef int tjs_int;
  	typedef unsigned int tjs_uint;
  #endif
  
  //---------------------------------------------------------------------------
  // tTVPRect - intersection and union
  //---------------------------------------------------------------------------
  struct tTVPRect;
  extern bool TVPIntersectRect(tTVPRect *dest, const tTVPRect &src1,
  	const tTVPRect &src2);
  extern bool TVPUnionRect(tTVPRect *dest, const tTVPRect &src1, const tTVPRect &src2);
  //---------------------------------------------------------------------------
  
  
  /*[*/
  
  //---------------------------------------------------------------------------
  // tTVPRect - simple rectangle structure
  //---------------------------------------------------------------------------
  #pragma pack(push, 4)
  struct tTVPPoint
  {
  	tjs_int x;
  	tjs_int y;
  };
  #pragma pack(pop)
  //---------------------------------------------------------------------------
  struct tTVPPointD
  {
  	double x;
  	double y;
  };
  //---------------------------------------------------------------------------
  struct tTVPRect
  {
  	tTVPRect(tjs_int l, tjs_int t, tjs_int r, tjs_int b)
  		{ left = l, top = t, right = r, bottom =b; }
  
  	tTVPRect() {};
  
  	union
  	{
  		struct
  		{
  			tjs_int left;
  			tjs_int top;
  			tjs_int right;
  			tjs_int bottom;
  		};
  
  		struct
  		{
  			// capital style
  			tjs_int Left;
  			tjs_int Top;
  			tjs_int Right;
  			tjs_int Bottom;
  		};
  
  		struct
  		{
  			tTVPPoint upper_left;
  			tTVPPoint bottom_right;
  		};
  
  		tjs_int array[4];
  	};
  
  	tjs_int get_width() const { return right - left; }
  	tjs_int get_height() const { return bottom - top; }
  
  	void set_width(tjs_int w) { right = left + w; }
  	void set_height(tjs_int h) { bottom = top + h; }
  
  	void add_offsets(tjs_int x, tjs_int y)
  	{
  		left += x; right += x;
  		top += y; bottom += y;
  	}
  
  	void set_offsets(tjs_int x, tjs_int y)
  	{
  		tjs_int w = get_width();
  		tjs_int h = get_height();
  		left = x;
  		top = y;
  		right = x + w;
  		bottom = y + h;
  	}
  
  	void set_size(tjs_int w, tjs_int h)
  	{
  		right = left + w;
  		bottom = top + h;
  	}
  
  	void clear()
  	{
  		left = top = right = bottom = 0;
  	}
  
  	bool is_empty() const
  	{
  		return left >= right || top >= bottom;
  	}
  
  	bool do_union(const tTVPRect & ref)
  	{
  		if(ref.is_empty()) return false;
  		if(left > ref.left) left = ref.left;
  		if(top > ref.top) top = ref.top;
  		if(right < ref.right) right = ref.right;
  		if(bottom < ref.bottom) bottom = ref.bottom;
  		return true;
  	}
  #ifndef __TP_STUB_H__
  	bool clip(const tTVPRect &ref)
  	{
  		// Clip (take the intersection of) the rectangle with rectangle. 
  		// returns whether the rectangle remains.
  		return TVPIntersectRect(this, *this, ref);
  	}
  #endif
  	bool intersects_with_no_empty_check(const tTVPRect & ref) const
  	{
  		// returns wether this has intersection with "ref"
  		return !(
  			left >= ref.right ||
  			top >= ref.bottom ||
  			right <= ref.left ||
  			bottom <= ref.top );
  	}
  
  	bool intersects_with(const tTVPRect & ref) const
  	{
  		// returns wether this has intersection with "ref"
  		if(ref.is_empty() || is_empty()) return false;
  		return intersects_with_no_empty_check(ref);
  	}
  
  	bool included_in_no_empty_check(const tTVPRect & ref) const
  	{
  		// returns wether this is included in "ref"
  		return
  			ref.left <= left &&
  			ref.top <= top &&
  			ref.right >= right &&
  			ref.bottom >= bottom;
  	}
  
  	bool included_in(const tTVPRect & ref) const
  	{
  		// returns wether this is included in "ref"
  		if(ref.is_empty() || is_empty()) return false;
  		return included_in_no_empty_check(ref);
  	}
  
  public: // comparison operators for sorting
  	bool operator < (const tTVPRect & rhs) const
  		{ return top < rhs.top || (top == rhs.top && left < rhs.left); }
  	bool operator > (const tTVPRect & rhs) const
  		{ return top > rhs.top || (top == rhs.top && left > rhs.left); }
  
  	// comparison methods
  	bool operator == (const tTVPRect & rhs) const
  		{ return top == rhs.top && left == rhs.left && right == rhs.right && bottom == rhs.bottom; }
  	bool operator != (const tTVPRect & rhs) const { return !this->operator ==(rhs); }
  };
  //---------------------------------------------------------------------------
  
  /*]*/
  
  
  //---------------------------------------------------------------------------
  // tTVPRegionRect : a class for a rectangle in region
  //---------------------------------------------------------------------------
  class tTVPRegionRect;
  extern tTVPRegionRect * TVPAllocateRegionRect();
  extern void TVPDeallocateRegionRect(tTVPRegionRect * rect);
  //---------------------------------------------------------------------------
  class tTVPRegionRect : public tTVPRect
  {
  public: // data members
  	tTVPRegionRect * Prev; // previous link
  	tTVPRegionRect * Next; // next link
  
  public: // new and delete
  	void * operator new (size_t size) { return TVPAllocateRegionRect(); }
  	void operator delete (void * p) { TVPDeallocateRegionRect((tTVPRegionRect*)p); }
  
  public: // constructors and destructor
  	tTVPRegionRect() {;};
  	tTVPRegionRect(const tTVPRect &r) : tTVPRect(r) {;};
  	~tTVPRegionRect() {;};
  
  public: // link operations
  	void LinkAfter(tTVPRegionRect * r)
  	{
  		// Insert this after r.
  		tTVPRegionRect * n = r->Next;
  		r->Next = this;
  		n->Prev = this;
  		Prev = r;
  		Next = n;
  	}
  
  	void LinkBefore(tTVPRegionRect * r)
  	{
  		// Insert this before r.
  		tTVPRegionRect * p = r->Prev;
  		r->Prev = this;
  		p->Next = this;
  		Prev = p;
  		Next = r;
  	}
  
  	void Unlink()
  	{
  		// unchain from the link list
  		tTVPRegionRect *prev = Prev;
  		tTVPRegionRect *next = Next;
  		prev->Next = next;
  		next->Prev = prev;
  	}
  
  };
  //---------------------------------------------------------------------------
  
  
  
  
  //---------------------------------------------------------------------------
  // tTVPComplexRect
  //---------------------------------------------------------------------------
  class tTVPComplexRect
  {
  public: // iterator
  	class tIterator
  	{
  	private: // data members
  		const tTVPRegionRect * Head;
  		const tTVPRegionRect * Current;
  
  	public: // constructor and destructor
  		tIterator() : Head(NULL), Current(NULL) {;}
  		tIterator(const tTVPRegionRect * head) : Head(head), Current(NULL) {;}
  
  	public: // operator function (data access)
  		const tTVPRect & operator * () const { return *Current; }
  		const tTVPRect * operator -> () const { return Current; }
  
  		const tTVPRegionRect & Get() const { return *Current; }
  
  	public: // stepping forward; this object supports only forward step.
  			// method step returns true if stepping successful,
  			// otherwise returns false (when already at last of the list)
  			// sample:
  			//   tTVPComplexRect::tIterator it = rects.GetIterator();
  			//   while(it.Step()) { .. do something with it .. }
  		bool Step()
  		{
  			// Step forward
  			if(!Head) return false;
  			if(!Current) { Current = Head; return true; }
  			if(Current->Next == Head) { return false; }
  			Current = Current->Next;
  			return true;
  		}
  	};
  
  private: // data members
  	tTVPRegionRect * Head; // head of the link list
  	tTVPRegionRect * Current; // a rectangle which is touched last time
  	tjs_int Count; // rectangle Count
  	tTVPRect Bound; // bounding rectangle
  	bool BoundValid; // whether the bounding rectangle is ready to use
  
  public: // constructors and destructors
  	tTVPComplexRect();
  	tTVPComplexRect(const tTVPComplexRect & ref);
  	~tTVPComplexRect();
  
  public: // storage management
  	void Clear();
  
  private: // storage management
  	void FreeAllRectangles(); // free all rectangles
  	void Init(); // initialize internal states
  	void SetCount(tjs_int count); // grow or shrink rectangle storage area
  	bool Insert(const tTVPRect & rect); // insert inplace
  	void Remove(tTVPRegionRect * rect); // remove a rectangle
  	void Merge(const tTVPComplexRect & rects); // merge non-overlaped complex rectangle
  public:
  	tjs_int GetCount() const { return Count; }
  
  public: // logical operations
  	void Or(const tTVPRect &r);
  	void Or(const tTVPComplexRect &ref);
  	void Sub(const tTVPRect &r);
  	void Sub(const tTVPComplexRect &ref);
  	void And(const tTVPRect &r);
  
  public: // operation utilities
  	void CopyWithOffsets(const tTVPComplexRect &ref, const tTVPRect &clip,
  		tjs_int ofsx, tjs_int ofsy); 
  
  public: // bounding rectangle
  	const tTVPRect & GetBound() const
  		{ (const_cast<tTVPComplexRect *>(this))->EnsureBound(); return Bound; }
  
  	void Unite()
  	{
  		// make union (bounding) one rectangle
  		tTVPRect r(GetBound());
  		Clear();
  		Or(r);
  	}
  
  private: 
  	void EnsureBound() { if(!BoundValid) CalcBound(); }
  	void CalcBound();
  
  private: // geometric rectangle operations
  	tjs_int GetRectangleIntersectionCode(const tTVPRect &r, const tTVPRect &rr)
  	{
  		// Retrieve condition code which represents
  		// how two rectangles have the intersection.
  		tjs_int cond;
  		if(rr.left   <= r.left   && rr.right   >= r.left   )
  			cond =  8; else cond = 0;
  		if(rr.left   <= r.right  && rr.right   >= r.right  )
  			cond |= 4;
  		if(rr.top    <= r.top    && rr.bottom  >= r.top    )
  			cond |= 2;
  		if(rr.top    <= r.bottom && rr.bottom  >= r.bottom )
  			cond |= 1;
  			/*
  					   +8             +4
  
  					+------+ +---+ +------+
  					|rr    | |rr | |    rr|     +2
  					|    +-----------+    |
  					+----|-+ +---+ +-|----+
  					+----|-+       +-|----+
  					|rr  | |   r   | |  rr|
  					+----|-+       +-|----+
  					+----|-+ +---+ +-|----+
  					|    +-----------+    |     +1
  					|rr    | | rr| |    rr|
  					+------+ +---+ +------+
  			*/
  		return cond;
  	}
  
  	void RectangleSub(tTVPRegionRect *r, const tTVPRect *rr);
  
  public:
  	void AddOffsets(tjs_int x, tjs_int y);
  
  public: // iterator
  	tIterator GetIterator() const
  		{ if(Count) return tIterator(Head); else return tIterator(NULL); }
  
  public: // debug
  	void DumpChain();
  };
  //---------------------------------------------------------------------------
  
  //---------------------------------------------------------------------------
  // tTVPComplexRectIterator : iterator for walking over rectangles
  //---------------------------------------------------------------------------
  //---------------------------------------------------------------------------
  
  
  #endif
  