OpenClonk
C4Rect.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Basic classes for rectangles and vertex outlines */
19 
20 #include "C4Include.h"
21 #include "lib/C4Rect.h"
22 #include "graphics/C4FacetEx.h"
23 #include "lib/StdCompiler.h"
24 #include "lib/StdAdaptors.h"
25 
27 {
28  x=y=Wdt=Hgt=0;
29 }
30 
32 {
33  pComp->Value(mkDefaultAdapt(x, 0)); pComp->Separator();
34  pComp->Value(mkDefaultAdapt(y, 0)); pComp->Separator();
35  pComp->Value(mkDefaultAdapt(Wdt, 0)); pComp->Separator();
36  pComp->Value(mkDefaultAdapt(Hgt, 0));
37 }
38 
40 {
42  tx=ty=0;
43 }
44 
45 void C4TargetRect::Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, int32_t iTX, int32_t iTY)
46 {
47  C4Rect::Set(iX,iY,iWdt,iHgt);
48  tx=iTX; ty=iTY;
49 }
50 
52 {
53  int32_t d;
54  // clip left
55  if ((d = x - rClip.x) < 0) { Wdt += d; x = rClip.x; }
56  else tx += d;
57  // clip top
58  if ((d = y - rClip.y) < 0) { Hgt += d; y = rClip.y; }
59  else ty += d;
60  // clip right
61  if ((d = (x+Wdt - rClip.x-rClip.Wdt)) > 0) Wdt -= d;
62  // clip bottom
63  if ((d = (y+Hgt - rClip.y-rClip.Hgt)) > 0) Hgt -= d;
64  // check validity
65  if (Wdt <= 0 || Hgt <= 0) return false;
66  // add target pos
67  tx += rClip.tx;
68  ty += rClip.ty;
69  // done
70  return true;
71 }
72 
74 {
75  // copy members
76  x=rSrc.X; y=rSrc.Y; Wdt=rSrc.Wdt; Hgt=rSrc.Hgt; tx=rSrc.TargetX; ty=rSrc.TargetY;
77 }
78 
80 {
81  C4Rect::CompileFunc(pComp); pComp->Separator();
82  pComp->Value(mkDefaultAdapt(tx,0)); pComp->Separator();
83  pComp->Value(mkDefaultAdapt(ty,0));
84 }
85 
86 void C4Rect::Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt)
87 {
88  x=iX; y=iY; Wdt=iWdt; Hgt=iHgt;
89 }
90 
91 bool C4Rect::Overlap(C4Rect &rTarget)
92 {
93  if (x+Wdt<=rTarget.x) return false;
94  if (x>=rTarget.x+rTarget.Wdt) return false;
95  if (y+Hgt<=rTarget.y) return false;
96  if (y>=rTarget.y+rTarget.Hgt) return false;
97  return true;
98 }
99 
100 void C4Rect::Intersect(const C4Rect &r2)
101 {
102  // Narrow bounds
103  if (r2.x > x)
104  if (r2.x + r2.Wdt < x + Wdt)
105  { x = r2.x; Wdt = r2.Wdt; }
106  else
107  { Wdt -= (r2.x - x); x = r2.x; }
108  else if (r2.x + r2.Wdt < x + Wdt)
109  Wdt = r2.x + r2.Wdt - x;
110  if (r2.y > y)
111  if (r2.y + r2.Hgt < y + Hgt)
112  { y = r2.y; Hgt = r2.Hgt; }
113  else
114  { Hgt -= (r2.y - y); y = r2.y; }
115  else if (r2.y + r2.Hgt < y + Hgt)
116  Hgt = r2.y + r2.Hgt - y;
117  // Degenerated? Will happen when the two rects don't overlap
118  if (Wdt < 0) Wdt = 0;
119  if (Hgt < 0) Hgt = 0;
120 }
121 
122 bool C4Rect::IntersectsLine(int32_t iX, int32_t iY, int32_t iX2, int32_t iY2)
123 {
124  // Easy cases first
125  if (Contains(iX, iY)) return true;
126  if (Contains(iX2, iY2)) return true;
127  if (iX < x && iX2 < x) return false;
128  if (iY < y && iY2 < y) return false;
129  if (iX >= x+Wdt && iX2 >= x+Wdt) return false;
130  if (iY >= y+Hgt && iY2 >= y+Hgt) return false;
131  // check some special cases
132  if (iX == iX2 || iY == iY2) return true;
133  // Check intersection left/right
134  int32_t iXI, iYI;
135  iXI = (iX < x ? x : x+Wdt);
136  iYI = iY + (iY2 - iY) * (iXI - iX) / (iX2 - iX);
137  if (iYI >= y && iYI < y+Hgt) return true;
138  // Check intersection up/down
139  iYI = (iY < y ? y : y+Hgt);
140  iXI = iX + (iX2 - iX) * (iYI - iY) / (iY2 - iY);
141  return iXI >= x && iXI < x+Wdt;
142 }
143 
144 void C4Rect::Add(const C4Rect &r2)
145 {
146  // Null? Don't do anything
147  if (!r2.Wdt || !r2.Hgt) return;
148  if (!Wdt || !Hgt)
149  {
150  *this = r2;
151  return;
152  }
153  // Expand bounds
154  if (r2.x < x)
155  if (r2.x + r2.Wdt > x + Wdt)
156  { x = r2.x; Wdt = r2.Wdt; }
157  else
158  { Wdt += (x - r2.x); x = r2.x; }
159  else if (r2.x + r2.Wdt > x + Wdt)
160  Wdt = r2.x + r2.Wdt - x;
161  if (r2.y < y)
162  if (r2.y + r2.Hgt > y + Hgt)
163  { y = r2.y; Hgt = r2.Hgt; }
164  else
165  { Hgt += (y - r2.y); y = r2.y; }
166  else if (r2.y + r2.Hgt > y + Hgt)
167  Hgt = r2.y + r2.Hgt - y;
168 }
169 
170 // ---- C4RectList ----
171 
172 
173 void C4RectList::ClipByRect(const C4Rect &rClip)
174 {
175  // split up all rectangles
176  for (size_t i = 0; i < GetCount(); ++i)
177  {
178  C4Rect *pTarget = &Get(i);
179  // any overlap?
180  if (rClip.x+rClip.Wdt <= pTarget->x) continue;
181  if (rClip.y+rClip.Hgt <= pTarget->y) continue;
182  if (rClip.x >= pTarget->x+pTarget->Wdt) continue;
183  if (rClip.y >= pTarget->y+pTarget->Hgt) continue;
184  // okay; split up rectangle
185  // first split will just reduce the target rectangle size
186  // if more splits are done, additional rectangles need to be added
187  int32_t iSplitCount = 0, iOver; C4Rect rcThis(*pTarget);
188  // clipped by right side
189  if ((iOver=rcThis.x+rcThis.Wdt-rClip.x-rClip.Wdt)>0)
190  {
191  pTarget->x += pTarget->Wdt - iOver; pTarget->Wdt = iOver; rcThis.Wdt -= iOver;
192  ++iSplitCount;
193  }
194  // clipped by obttom side
195  if ((iOver=rcThis.y+rcThis.Hgt-rClip.y-rClip.Hgt)>0)
196  {
197  if (iSplitCount) { AddRect(rcThis); pTarget = &Get(GetCount()-1); }
198  pTarget->y += pTarget->Hgt - iOver; pTarget->Hgt = iOver; rcThis.Hgt -= iOver;
199  ++iSplitCount;
200  }
201  // clipped by left side
202  if ((iOver=rClip.x-rcThis.x)>0)
203  {
204  if (iSplitCount) { AddRect(rcThis); pTarget = &Get(GetCount()-1); }
205  pTarget->Wdt = iOver; rcThis.Wdt -= iOver; rcThis.x = rClip.x;
206  ++iSplitCount;
207  }
208  // clipped by top side
209  if ((iOver=rClip.y-rcThis.y)>0)
210  {
211  if (iSplitCount) { AddRect(rcThis); pTarget = &Get(GetCount()-1); }
212  else ++iSplitCount;
213  pTarget->Hgt = iOver; /* rcThis.Hgt -= iOver; rcThis.y = rClip.y; not needed, since rcThis is no longer used */
214  }
215  // nothing split? This means this rectnagle is completely contained
216  if (!iSplitCount)
217  {
218  // make it vanish
219  RemoveIndexedRect(i); --i;
220  }
221  }
222  // concat rectangles if possible
223  bool fDone = false;
224  while (!fDone)
225  {
226  fDone=true;
227  for (size_t i = 0, cnt=GetCount(); i < cnt && fDone; ++i)
228  {
229  C4Rect &rc1 = Get(i);
230  for (size_t j = i+1; j < cnt; ++j)
231  {
232  C4Rect &rc2 = Get(j);
233  if (rc1.y == rc2.y && rc1.Hgt == rc2.Hgt)
234  {
235  if (rc1.x + rc1.Wdt == rc2.x)
236  {
237  rc1.Wdt += rc2.Wdt; RemoveIndexedRect(j); fDone=false; break;
238  }
239  else if (rc2.x + rc2.Wdt == rc1.x)
240  {
241  rc2.Wdt += rc1.Wdt; RemoveIndexedRect(i); fDone=false; break;
242  }
243  }
244  else if (rc1.x == rc2.x && rc1.Wdt == rc2.Wdt)
245  {
246  if (rc1.y + rc1.Hgt == rc2.y)
247  {
248  rc1.Hgt += rc2.Hgt; RemoveIndexedRect(j); fDone=false; break;
249  }
250  else if (rc2.y + rc2.Hgt == rc1.y)
251  {
252  rc2.Hgt += rc1.Hgt; RemoveIndexedRect(i); fDone=false; break;
253  }
254  }
255  }
256  }
257  }
258 }
259 
StdDefaultAdapt< T, D > mkDefaultAdapt(T &&rValue, const D &rDefault)
Definition: StdAdaptors.h:64
float Hgt
Definition: C4Facet.h:118
float Wdt
Definition: C4Facet.h:118
float Y
Definition: C4Facet.h:118
float X
Definition: C4Facet.h:118
Definition: C4Rect.h:28
bool Overlap(C4Rect &rTarget)
Definition: C4Rect.cpp:91
int32_t y
Definition: C4Rect.h:30
int32_t Hgt
Definition: C4Rect.h:30
int32_t Wdt
Definition: C4Rect.h:30
void CompileFunc(StdCompiler *pComp)
Definition: C4Rect.cpp:31
void Default()
Definition: C4Rect.cpp:26
bool IntersectsLine(int32_t iX, int32_t iY, int32_t iX2, int32_t iY2)
Definition: C4Rect.cpp:122
int32_t x
Definition: C4Rect.h:30
void Intersect(const C4Rect &r2)
Definition: C4Rect.cpp:100
void Add(const C4Rect &r2)
Definition: C4Rect.cpp:144
bool Contains(int32_t iX, int32_t iY) const
Definition: C4Rect.h:40
void Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt)
Definition: C4Rect.cpp:86
void AddRect(const C4Rect &rNewRect)
Definition: C4Rect.h:101
void ClipByRect(const C4Rect &rClip)
Definition: C4Rect.cpp:173
void RemoveIndexedRect(int32_t idx)
Definition: C4Rect.h:103
size_t GetCount() const
Definition: C4Rect.h:106
C4Rect & Get(size_t idx)
Definition: C4Rect.h:107
float TargetY
Definition: C4Facet.h:165
float TargetX
Definition: C4Facet.h:165
void Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, int32_t iTX, int32_t iTY)
Definition: C4Rect.cpp:45
int32_t tx
Definition: C4Rect.h:79
bool ClipBy(C4TargetRect &rClip)
Definition: C4Rect.cpp:51
void Default()
Definition: C4Rect.cpp:39
void CompileFunc(StdCompiler *pComp)
Definition: C4Rect.cpp:79
int32_t ty
Definition: C4Rect.h:79
virtual bool Separator(Sep eSep=SEP_SEP)
Definition: StdCompiler.h:119
void Value(const T &rStruct)
Definition: StdCompiler.h:161