20 #include <tulip/TlpTools.h> 22 template<
typename Obj,
typename OTYPE>
23 tlp::Circle<Obj, OTYPE> & tlp::Circle<Obj, OTYPE>::merge(
const tlp::Circle<Obj, OTYPE> &c) {
24 Vector<Obj,2, OTYPE> p1(*
this);
25 Vector<Obj,2, OTYPE> p2(c);
26 Vector<Obj,2, OTYPE> c12=p2-p1;
27 double norm=c12.norm();
29 if (norm < 0.0000001) {
36 double dx=c12[0]/norm;
37 double dy=c12[1]/norm;
42 Obj tmpDist=p1.dist(p2)/2.;
44 if ( (tmpDist<radius) || (tmpDist<c.radius)) {
60 template<
typename Obj,
typename OTYPE>
61 bool tlp::Circle<Obj, OTYPE>::isIncludeIn(
const tlp::Circle<Obj, OTYPE> &c)
const {
62 Vector<Obj,2, OTYPE> dir=c-*
this;
63 return (dir.norm()+radius)<=c.radius;
66 template<
typename Obj,
typename OTYPE>
67 tlp::Circle<Obj, OTYPE> tlp::enclosingCircle(
const tlp::Circle<Obj, OTYPE> &c1,
const tlp::Circle<Obj, OTYPE> &c2) {
68 Vector<Obj,2, OTYPE> dir=c2-c1;
72 return Circle<Obj, OTYPE>(c1, std::max(c1.radius, c2.radius));
75 Vector<Obj, 2, OTYPE> ext1=c1-dir*c1.radius;
76 Vector<Obj, 2, OTYPE> ext2=c2+dir*c2.radius;
77 return Circle<Obj, OTYPE>((ext1+ext2)/Obj(2),(ext2-ext1).norm()/Obj(2));
80 template<
typename Obj,
typename OTYPE>
81 tlp::Circle<Obj, OTYPE> tlp::lazyEnclosingCircle(
const std::vector<tlp::Circle<Obj, OTYPE> > & circles) {
83 tlp::Vector<Obj,4, OTYPE> boundingBox;
85 typename std::vector< tlp::Circle<Obj, OTYPE> >::const_iterator it=circles.begin();
86 boundingBox[0]=(*it)[0]-(*it).radius;
87 boundingBox[1]=(*it)[1]-(*it).radius;
88 boundingBox[2]=(*it)[0]+(*it).radius;
89 boundingBox[3]=(*it)[1]+(*it).radius;
92 for (; it!=circles.end(); ++it) {
93 boundingBox[0] = std::min(boundingBox[0] , ((*it)[0]-(*it).radius));
94 boundingBox[1] = std::min(boundingBox[1] , ((*it)[1]-(*it).radius));
95 boundingBox[2] = std::max(boundingBox[2] , ((*it)[0]+(*it).radius));
96 boundingBox[3] = std::max(boundingBox[3] , ((*it)[1]+(*it).radius));
99 tlp::Vector<Obj,2, OTYPE> center;
100 center[0]=(boundingBox[0]+boundingBox[2])/2.;
101 center[1]=(boundingBox[1]+boundingBox[3])/2.;
102 Obj radius = std::max( (boundingBox[2]-boundingBox[0])/2., (boundingBox[3]-boundingBox[1])/2. );
103 tlp::Circle<Obj, OTYPE> result(center,radius);
106 for (
typename std::vector< tlp::Circle<Obj, OTYPE> >::const_iterator it=circles.begin(); it!=circles.end(); ++it)
112 template<
typename Obj,
typename OTYPE>
113 tlp::Circle<Obj, OTYPE> tlp::enclosingCircle(
const std::vector<tlp::Circle<Obj, OTYPE> > & circles) {
114 class OptimumCircleHull {
115 const std::vector<tlp::Circle<Obj, OTYPE> > *circles;
116 std::vector<unsigned> enclosedCircles;
119 tlp::Circle<Obj, OTYPE> result;
121 static tlp::Circle<Obj, OTYPE> enclosingCircle(
const tlp::Circle<Obj, OTYPE> &c1,
const tlp::Circle<Obj, OTYPE> &c2,
const tlp::Circle<Obj, OTYPE> &c3) {
131 Obj b = -b1*r2*a1*a1*b3+a3*a3*r2*r2*r2+b2*b2*r3*r3*r3+b1*b1*r3*r3*r3+b1*b1*r2*r2*r2+r1*r1*r1*b3*b3+r1*r1*r1*b2*b2+r2*r2*r2*b3*b3
132 +a1*a1*r3*r3*r3+a2*a2*r1*r1*r1+a2*a2*r3*r3*r3+a1*a1*r2*r2*r2+a3*a3*r1*r1*r1-b2*b2*r3*a3*a3-b2*b2*r3*b3*b3-2*b2*r3*r3*r3*b1
133 -b1*b1*r3*a3*a3-b1*b1*r3*b3*b3-b1*b1*r2*a2*a2+2*b1*b1*r2*b3*b3-b1*b1*r2*r3*r3-r1*b3*b3*b3*b2+r1*b3*b3*b3*b1
134 +2*r1*b2*b2*b3*b3-r1*b2*b2*r3*r3+r2*b3*b3*b3*b2-r2*b3*b3*b3*b1-b2*b2*b2*r3*b1+2*b2*b2*r3*b1*b1+b2*b2*b2*r3*b3
135 -b2*b2*r3*r1*r1+b1*b1*b1*r3*b3-b1*b1*b1*r3*b2-b1*b1*r3*r2*r2-b1*b1*r2*b2*b2-b1*b1*b1*r2*b3+b1*b1*b1*r2*b2
136 -2*b1*r2*r2*r2*b3-r1*b3*b3*b1*b1-2*r1*r1*r1*b3*b2-r1*b3*b3*r2*r2-r1*b3*b3*a1*a1+r1*b2*b2*b2*b1
137 -r1*b2*b2*b1*b1-r1*b2*b2*b2*b3-r1*b2*b2*a1*a1-r2*b3*b3*a2*a2-r2*b3*b3*b2*b2-r2*b3*b3*r1*r1
138 -b2*r3*b1*b1*b3+b2*r3*a2*a2*b3+b2*r3*r1*r1*b3-b2*r3*r2*r2*b3+b2*r3*a1*a1*b3-2*b2*r3*a1*a2*b3+a1*a3*b2*b2*r3
139 -2*a1*a3*b2*b1*r3-2*a1*a3*b2*b1*r2-2*a1*a3*b2*r1*b3+a1*a3*b2*b2*r1-2*a1*a3*b2*r2*b3-b2*r3*b1*a2*a2
140 +2*b2*r3*b1*a3*a3+2*b2*r3*b1*b3*b3+b1*r2*b2*a3*a3-b1*r2*b2*b3*b3+b1*r2*b2*r3*r3+r1*b3*b1*a2*a2
141 -r1*b3*b2*a3*a3+r1*b3*b2*r3*r3+r1*b3*b1*a3*a3-r1*b3*b1*r3*r3+r1*b2*b1*a2*a2+r1*b2*b1*a3*a3
142 -r1*b2*b1*b3*b3+r1*b2*b1*r3*r3+2*r2*b3*b1*a2*a2+r2*b3*b2*a3*a3-r2*b3*b2*r3*r3-r2*b3*b1*a3*a3
143 +r2*b3*b1*r3*r3+b2*r3*b1*r2*r2+4*b2*r3*a1*a2*b1+b1*r3*a2*a2*b3-b1*r3*b2*b2*b3
144 -b1*r3*r1*r1*b3+b1*r3*r1*r1*b2+b1*r3*r2*r2*b3+b1*r3*a1*a1*b3-b1*r3*a1*a1*b2-2*b1*r3*a1*a2*b3-b1*b1*r3*a1*a2
145 +b1*b1*r3*a1*a3+2*b1*r2*b2*b2*b3+b1*r2*r1*r1*b3-b1*r2*r1*r1*b2+b1*r2*a1*a1*b2
146 -2*b1*r2*a1*a2*b3+b1*b1*r2*a1*a2-b1*b1*r2*a1*a3-r1*b3*b1*b2*b2+2*r1*b3*b1*b1*b2+2*r1*b3*a1*a1*b2+r1*b3*b1*r2*r2
147 +r1*b3*b3*a1*a2-r1*b2*a2*a2*b3+r1*b2*r2*r2*b3-r1*b2*b1*r2*r2-2*r1*b2*a1*a2*b3-r2*b3*b1*b1*b2
148 +r2*b3*r1*r1*b2+r2*b3*a1*a1*b2+r2*b3*b3*a1*a2+4*r2*b3*a1*a3*b1-a1*a1*a3*a3*r3+2*a1*a1*a3*a3*r2+a1*a3*a3*a3*r1
149 -a1*a1*b3*b3*r3-a1*b3*b3*a3*r2+a1*r3*r3*a3*r2-a2*a1*a1*a3*r2+a2*b1*b1*a3*r2+a2*b3*b3*a3*r2
150 -a1*a3*a3*a2*r1+2*a1*a3*a3*a2*r3+2*a1*b3*b3*a2*r3+a1*b3*b3*a3*r1-2*a1*r3*r3*r3*a2-a1*a1*r3*r3*r2
151 -a2*a1*a1*a1*r3-a2*a2*a1*a1*r1+2*a2*a2*a1*a1*r3+a2*a1*a1*a1*r2-a2*a2*b1*b1*r1+2*a2*a2*a3*a3*r1-a2*a2*a3*a3*r3
152 -a2*a3*a3*a3*r1-a2*a2*b3*b3*r3-a2*a2*r1*r1*r3-2*a2*r1*r1*r1*a3+a1*r3*r3*a2*r1-a1*r3*r3*a3*r1
153 +2*a2*a1*a1*a3*r1+2*a2*b1*b1*a3*r1-a2*a3*a3*a1*r2-a2*b3*b3*a3*r1+a2*r1*r1*a1*r3-a2*r1*r1*a1*r2-a2*a2*r3*r3*r1
154 -a1*a3*a3*a3*r2+a2*a3*a3*a3*r2-a1*a1*r3*r2*r2+a1*a1*a1*r3*a3+a2*a2*a2*r1*a1-a2*a2*a2*r1*a3-a2*a2*a2*r3*a1+a2*a2*a2*r3*a3
155 -a1*a1*r2*a2*a2-a1*a1*r2*b2*b2-a1*a1*a1*r2*a3-2*a1*r2*r2*r2*a3-a3*a3*r1*a1*a1-a3*a3*r1*b1*b1-a3*a3*r1*r2*r2
156 -a3*a3*r2*a2*a2-a3*a3*r2*b2*b2-a3*a3*r2*r1*r1+a2*r3*r3*a1*r2+a2*r3*r3*a3*r1-2*a3*r2*b1*a2*b3
157 +a2*r1*r1*a3*r2-a2*r3*r3*a3*r2-a1*r3*a3*a2*a2-a1*r3*a3*r1*r1+a1*r3*a3*r2*r2+a2*r1*a1*b2*b2
158 -a2*r1*a1*r2*r2-a2*r1*a3*b2*b2+a2*r1*a3*r2*r2-2*a2*r1*b1*a3*b2-a2*r3*a1*b2*b2+a2*r3*a1*r2*r2
159 -a2*r3*a3*a1*a1+a2*r3*a3*b1*b1+a2*r3*a3*b2*b2+a2*r3*a3*r1*r1-a2*r3*a3*r2*r2-2*a2*r3*b1*a3*b2+2*a1*r2*a3*a2*a2
160 +2*a1*r2*a3*b2*b2+a1*r2*a3*r1*r1-a3*r1*a1*a2*a2+a3*r1*a1*r2*r2-2*a3*r1*b1*a2*b3
162 Obj tmp=a2*b3-a3*b2-a2*b1-a1*b3+a1*b2+a3*b1;
163 Obj d = sqrt((a2*a2+b2*b2-r2*r2-2*a2*a3+a3*a3-r3*r3-2*b3*b2+b3*b3+2*r3*r2)*
164 (b3*b3+b1*b1-r1*r1-r3*r3-2*b1*b3+2*r3*r1+a3*a3-2*a1*a3+a1*a1)*
165 (a1*a1-2*a1*a2-r1*r1+b1*b1+b2*b2-r2*r2-2*b2*b1+2*r2*r1+a2*a2)*
169 if (v<0)
return tlp::Circle<Obj, OTYPE>(0,0,0);
171 Obj aa = -2*a3*b2*b2*a1-2*a2*b3*b3*a1
172 -2*a1*a1*b3*b2+a3*a3*b2*b2+a2*a2*b3*b3-r1*r1*b3*b3-r1*r1*b2*b2+a2*a2*b1*b1+a3*a3*b1*b1-a2*a2*r1*r1
173 -a2*a2*r3*r3-a3*a3*r2*r2-2*a3*b2*a2*b3+2*a3*b2*a2*b1+2*a2*b3*a3*b1-2*b1*a2*a2*b3-a3*a3*r1*r1
174 -2*a3*a3*b2*b1+2*b1*r3*r3*b2+2*r1*r1*b3*b2+2*b3*b1*r2*r2-2*a2*b1*b1*a3+2*a2*a3*r1*r1-b2*b2*r3*r3-b1*b1*r3*r3
175 -b1*b1*r2*r2-r2*r2*b3*b3-a1*a1*r3*r3-a1*a1*r2*r2+a1*a1*b3*b3+a1*a1*b2*b2+2*b2*b2*r3*r1+2*b1*b1*r3*r2
176 +2*r1*b3*b3*r2-2*b2*r3*b1*r2-2*b2*r3*r1*b3+2*b2*r3*r2*b3+2*b1*r3*r1*b3-2*b1*r3*r1*b2
177 -2*b1*r3*r2*b3-2*b1*r2*r1*b3+2*b1*r2*r1*b2-2*r1*b2*r2*b3+2*a1*r3*r3*a2+2*a1*a1*r3*r2+2*a2*a2*r1*r3
178 +2*a1*r2*r2*a3+2*a3*a3*r1*r2-2*a1*r3*a2*r1+2*a1*r3*a3*r1+2*a2*r1*a1*r2-2*a2*r3*a1*r2
179 -2*a2*r3*a3*r1-2*a1*r2*a3*r1-2*a1*r3*a3*r2-2*a2*r1*a3*r2+2*a2*r3*a3*r2+2*a2*b3*a1*b2
180 +2*a3*b2*a1*b3+2*a2*b1*a1*b3-2*a2*b1*a1*b2-2*a1*b3*a3*b1+2*a1*b2*a3*b1;
182 Obj y = -0.5*(-2*a1*R*r2-2*a3*R*r1+2*a2*R*r1+2*a3*R*r2-2*a2*R*r3+a1*a3*a3+a1*b3*b3-a1*r3*r3
183 +a2*a1*a1+a2*b1*b1+a1*r2*r2+2*a1*R*r3-a3*b1*b1+a3*a2*a2+a3*b2*b2+a3*r1*r1-a3*r2*r2-a2*a3*a3-a2*b3*b3
184 -a2*r1*r1+a2*r3*r3-a1*a2*a2-a1*b2*b2-a3*a1*a1)/(a2*b3+a3*b1-a2*b1-a1*b3+a1*b2-a3*b2);
185 Obj x = 0.5*(-a1*a1*b3+a1*a1*b2+2*R*r2*b3+b1*a3*a3+b1*b3*b3+2*b1*R*r3-2*R*r1*b3+2*R*r1*b2+b1*r2*r2
186 -b2*a3*a3-b2*b3*b3+b2*r3*r3-2*b2*R*r3-b1*r3*r3-r2*r2*b3+a2*a2*b3-r1*r1*b2-b1*b2*b2+b1*b1*b2-b1*b1*b3
187 -b1*a2*a2+b2*b2*b3+r1*r1*b3-2*b1*R*r2)/(a2*b3+a3*b1-a2*b1-a1*b3+a1*b2-a3*b2);
188 return tlp::Circle<Obj, OTYPE>(x,y,R);
193 result=tlp::enclosingCircle((*circles)[b1],(*circles)[b2]);
196 unsigned selectedCircle=popBack();
199 if (!(*circles)[selectedCircle].isIncludeIn(result)) {
200 result=enclosingCircle((*circles)[b1],(*circles)[b2],(*circles)[selectedCircle]);
201 pushFront(selectedCircle);
204 pushBack(selectedCircle);
211 result=(*circles)[b1];
214 unsigned selectedCircle=popBack();
217 if (!(*circles)[selectedCircle].isIncludeIn(result)) {
220 pushFront(selectedCircle);
223 pushBack(selectedCircle);
229 result=Circle<Obj, OTYPE>(0,0,0);
232 unsigned selectedCircle=popBack();
235 if (!(*circles)[selectedCircle].isIncludeIn(result)) {
238 pushFront(selectedCircle);
241 pushBack(selectedCircle);
245 bool isEmpty()
const {
246 return first==(last+1)%enclosedCircles.size();
248 void pushFront(
unsigned c) {
249 first=(first+enclosedCircles.size()-1)%enclosedCircles.size();
250 enclosedCircles[first]=c;
253 unsigned result=enclosedCircles[last];
254 last=(last+enclosedCircles.size()-1)%enclosedCircles.size();
257 void pushBack(
unsigned c) {
258 last=(last+1)%enclosedCircles.size();
259 enclosedCircles[last]=c;
262 OptimumCircleHull():circles(NULL),first(0),last(0),b1(0),b2(0) {}
264 tlp::Circle<Obj, OTYPE> operator()(
const std::vector<tlp::Circle<Obj, OTYPE> > &circlesSet) {
266 enclosedCircles.resize(circlesSet.size()+1);
268 last=circlesSet.size()-1;
270 for (
unsigned i=0; i<circlesSet.size(); ++i)
271 enclosedCircles[i]=i;
273 for (
unsigned i=circlesSet.size(); i>0;) {
276 std::swap(enclosedCircles[idx],enclosedCircles[i]);
283 return OptimumCircleHull()(circles);
286 template <
typename Obj,
typename OTYPE>
287 std::ostream& tlp::operator<<(std::ostream &os,const tlp::Circle<Obj, OTYPE> &a) {
288 os <<
"((" << a[0] <<
"," << a[1] <<
")," << a.radius <<
")";
unsigned int randomUnsignedInteger(unsigned int max)
Returns a random unsigned integer in the range [0, max].