1 /*
2 XLiFE++ is an extended library of finite elements written in C++
3 Copyright (C) 2014 Lunéville, Eric; Kielbasiewicz, Nicolas; Lafranche, Yvon; Nguyen, Manh-Ha; Chambeyron, Colin
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 /*!
18 \file geometries1D.cpp
19 \authors N. Kielbasiewicz, Y. Lafranche
20 \since 18 oct 2012
21 \date 29 jul 2015
22
23 \brief This file contains the implementation of methods of classes defined in geometries1D.hpp
24 */
25
26 #include "geometries1D.hpp"
27
28 namespace xlifepp
29 {
30
31 //===========================================================
32 //
33 // Curve and child classes member functions
34 //
35 //===========================================================
36
37 //! default curve is inside the bounding box [0,1]
Curve()38 Curve::Curve()
39 : Geometry(BoundingBox(0.,1.), 1)
40 {
41 // funh_=0;
42 }
43
buildParam(const Parameter & p)44 void Curve::buildParam(const Parameter& p)
45 {
46 trace_p->push("Curve::buildParam");
47 ParameterKey key=p.key();
48
49 switch (key)
50 {
51 case _pk_side_names:
52 {
53 if (p.type()==_string) { sideNames_.resize(1,p.get_s()); }
54 else if (p.type()==_stringVector) { sideNames_=p.get_sv(); }
55 else { error("param_badtype",words("value",p.type()),words("param key",key)); }
56 break;
57 }
58 default: Geometry::buildParam(p); break;
59 }
60 trace_p->pop();
61 }
62
buildDefaultParam(ParameterKey key)63 void Curve::buildDefaultParam(ParameterKey key)
64 {
65 trace_p->push("Curve::buildDefaultParam");
66 switch (key)
67 {
68 case _pk_side_names: sideNames_.resize(0); break;
69 default: Geometry::buildDefaultParam(key); break;
70 }
71 trace_p->pop();
72 }
73
getParamsKeys()74 std::set<ParameterKey> Curve::getParamsKeys()
75 {
76 std::set<ParameterKey> params=Geometry::getParamsKeys();
77 params.insert(_pk_side_names);
78 return params;
79 }
80
81 //! default is segment [0,1]
Segment()82 Segment::Segment() : Curve(), p1_(0.), p2_(1.), n_(2)
83 {
84 shape_=_segment;
85 computeMB();
86 }
87
build(const std::vector<Parameter> & ps)88 void Segment::build(const std::vector<Parameter>& ps)
89 {
90 trace_p->push("Segment::build");
91 shape_=_segment;
92 std::set<ParameterKey> params=getParamsKeys(), usedParams;
93 // managing params
94 for (number_t i=0; i < ps.size(); ++i)
95 {
96 ParameterKey key=ps[i].key();
97 buildParam(ps[i]);
98 if (params.find(key) != params.end()) { params.erase(key); }
99 else
100 {
101 if (usedParams.find(key) == usedParams.end())
102 { error("geom_unexpected_param_key", words("param key",key), words("shape",_segment)); }
103 else { warning("param_already_used", words("param key",key)); }
104 }
105 usedParams.insert(key);
106 // user must use nnodes or hsteps, not both
107 if (key==_pk_hsteps && usedParams.find(_pk_nnodes) != usedParams.end())
108 { error("param_conflict", words("param key",key), words("param key",_pk_nnodes)); }
109 if (key==_pk_nnodes && usedParams.find(_pk_hsteps) != usedParams.end())
110 { error("param_conflict", words("param key",key), words("param key",_pk_hsteps)); }
111 // if user sets v1 or v2, and xmin or xmax, and vice versa it is an error
112 if ((key==_pk_xmin || key==_pk_xmax) && usedParams.find(_pk_v1) != usedParams.end())
113 { error("param_conflict", words("param key",key), words("param key",_pk_v1)); }
114 if ((key==_pk_xmin || key==_pk_xmax) && usedParams.find(_pk_v2) != usedParams.end())
115 { error("param_conflict", words("param key",key), words("param key",_pk_v2)); }
116 if ((key==_pk_v1 || key==_pk_v2) && usedParams.find(_pk_xmin) != usedParams.end())
117 { error("param_conflict", words("param key",key), words("param key",_pk_xmin)); }
118 if ((key==_pk_v1 || key==_pk_v2) && usedParams.find(_pk_xmax) != usedParams.end())
119 { error("param_conflict", words("param key",key), words("param key",_pk_xmax)); }
120 }
121
122 // if hsteps is not used, nnodes is used instead and there is no default value
123 if (params.find(_pk_hsteps) != params.end()) { params.erase(_pk_hsteps); }
124
125 // (v1,v2) or (xmin,xmax) has to be set (no default values)
126 if (params.find(_pk_v1) != params.end() && params.find(_pk_v2) != params.end() &&
127 params.find(_pk_xmin) != params.end() && params.find(_pk_xmax) != params.end())
128 { error("param_missing","v1, v2, xmin, xmax"); }
129 if (params.find(_pk_v1) != params.end() && params.find(_pk_v2) == params.end()) { error("param_missing","v1"); }
130 if (params.find(_pk_v2) != params.end() && params.find(_pk_v1) == params.end()) { error("param_missing","v2"); }
131 if (params.find(_pk_xmin) != params.end() && params.find(_pk_xmax) == params.end()) { error("param_missing","xmin"); }
132 if (params.find(_pk_xmax) != params.end() && params.find(_pk_xmin) == params.end()) { error("param_missing","xmax"); }
133
134 if (params.find(_pk_xmin) != params.end()) { params.erase(_pk_xmin); params.erase(_pk_xmax); }
135 if (params.find(_pk_v1) != params.end()) { params.erase(_pk_v1); params.erase(_pk_v2); }
136 std::set<ParameterKey>::const_iterator it_p;
137 for (it_p=params.begin(); it_p != params.end(); ++it_p) { buildDefaultParam(*it_p); }
138 boundingBox=BoundingBox(p1_,p2_);
139 computeMB();
140 trace_p->pop();
141 }
142
buildParam(const Parameter & p)143 void Segment::buildParam(const Parameter& p)
144 {
145 trace_p->push("Segment::buildParam");
146 ParameterKey key=p.key();
147 switch (key)
148 {
149 case _pk_v1:
150 {
151 switch (p.type())
152 {
153 case _pt: p1_=p.get_pt(); break;
154 case _integer: p1_=Point(real_t(p.get_i())); break;
155 case _real: p1_=Point(p.get_r()); break;
156 default: error("param_badtype",words("value",p.type()),words("param key",key));
157 }
158 break;
159 }
160 case _pk_v2:
161 {
162 switch (p.type())
163 {
164 case _pt: p2_=p.get_pt(); break;
165 case _integer: p2_=Point(real_t(p.get_i())); break;
166 case _real: p2_=Point(p.get_r()); break;
167 default: error("param_badtype",words("value",p.type()),words("param key",key));
168 }
169 break;
170 }
171 case _pk_xmin:
172 {
173 switch (p.type())
174 {
175 case _integer: p1_=Point(real_t(p.get_i())); break;
176 case _real: p1_=Point(p.get_r()); break;
177 default: error("param_badtype",words("value",p.type()),words("param key",key));
178 }
179 break;
180 }
181 case _pk_xmax:
182 {
183 switch (p.type())
184 {
185 case _integer: p2_=Point(real_t(p.get_i())); break;
186 case _real: p2_=Point(p.get_r()); break;
187 default: error("param_badtype",words("value",p.type()),words("param key",key));
188 }
189 break;
190 }
191 case _pk_nnodes:
192 {
193 switch (p.type())
194 {
195 case _integer:
196 {
197 number_t n=p.get_n();
198 n_=n > 2 ? n : 2;
199 break;
200 }
201 default: error("param_badtype",words("value",p.type()),words("param key",key));
202 }
203 break;
204 }
205 case _pk_hsteps:
206 {
207 switch (p.type())
208 {
209 case _integer: h_=std::vector<real_t>(2,real_t(p.get_n())); break;
210 case _real: h_=std::vector<real_t>(2,p.get_r()); break;
211 case _realVector:
212 {
213 h_=p.get_rv();
214 if (h_.size() != 2) { error("bad_size"); }
215 break;
216 }
217 default: error("param_badtype",words("value",p.type()),words("param key",key));
218 }
219 break;
220 }
221 default: Curve::buildParam(p); break;
222 }
223 trace_p->pop();
224 }
225
buildDefaultParam(ParameterKey key)226 void Segment::buildDefaultParam(ParameterKey key)
227 {
228 trace_p->push("Segment::buildDefaultParam");
229 switch (key)
230 {
231 case _pk_nnodes: n_=2; break;
232 default: Curve::buildDefaultParam(key); break;
233 }
234 trace_p->pop();
235 }
236
getParamsKeys()237 std::set<ParameterKey> Segment::getParamsKeys()
238 {
239 std::set<ParameterKey> params=Curve::getParamsKeys();
240 params.insert(_pk_v1);
241 params.insert(_pk_v2);
242 params.insert(_pk_xmin);
243 params.insert(_pk_xmax);
244 params.insert(_pk_nnodes);
245 params.insert(_pk_hsteps);
246 return params;
247 }
248
Segment(const Parameter & p1,const Parameter & p2)249 Segment::Segment(const Parameter& p1, const Parameter& p2) : Curve()
250 {
251 std::vector<Parameter> ps(2);
252 ps[0]=p1; ps[1]=p2;
253 build(ps);
254 }
255
Segment(const Parameter & p1,const Parameter & p2,const Parameter & p3)256 Segment::Segment(const Parameter& p1, const Parameter& p2, const Parameter& p3) : Curve()
257 {
258 std::vector<Parameter> ps(3);
259 ps[0]=p1; ps[1]=p2; ps[2]=p3;
260 build(ps);
261 }
262
Segment(const Parameter & p1,const Parameter & p2,const Parameter & p3,const Parameter & p4)263 Segment::Segment(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4) : Curve()
264 {
265 std::vector<Parameter> ps(4);
266 ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4;
267 build(ps);
268 }
269
Segment(const Parameter & p1,const Parameter & p2,const Parameter & p3,const Parameter & p4,const Parameter & p5)270 Segment::Segment(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4,
271 const Parameter& p5) : Curve()
272 {
273 std::vector<Parameter> ps(5);
274 ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5;
275 build(ps);
276 }
277
asString() const278 string_t Segment::asString() const
279 {
280 string_t s("Segment (");
281 s += p1_.toString() +", " + p2_.toString() + ")";
282 return s;
283 }
284
reverse()285 Segment& Segment::reverse()
286 {
287 std::swap(p1_,p2_);
288 if (h_.size()==2) { std::swap(h_[0],h_[1]); }
289 return *this;
290 }
291
operator ~(const Segment & s)292 Segment operator~(const Segment& s)
293 {
294 Segment s2=s;
295 s2.reverse();
296 return s2;
297 }
298
boundNodes() const299 std::vector<const Point*> Segment::boundNodes() const
300 {
301 std::vector<const Point*> nodes(2);
302 nodes[0]=&p1_; nodes[1]=&p2_;
303 return nodes;
304 }
305
nodes()306 std::vector<Point*> Segment::nodes()
307 {
308 std::vector<Point*> nodes(2);
309 nodes[0]=&p1_; nodes[1]=&p2_;
310 return nodes;
311 }
312
nodes() const313 std::vector<const Point*> Segment::nodes() const
314 {
315 std::vector<const Point*> nodes(2);
316 nodes[0]=&p1_; nodes[1]=&p2_;
317 return nodes;
318 }
319
curves() const320 std::vector<std::pair<ShapeType,std::vector<const Point*> > > Segment::curves() const
321 {
322 std::vector<std::pair<ShapeType,std::vector<const Point*> > > curves(1);
323 curves[0]=std::make_pair(_segment,boundNodes());
324 return curves;
325 }
326
327 //! default ellipse arc is quarter of circle of center (0,0,0) and radius 1
EllArc()328 EllArc::EllArc() : Curve(), c_(0.,0.), a_(1.,0.), p1_(1.,0.), p2_(0.,1.), n_(2)
329 {
330 shape_=_ellArc;
331 computeMB();
332 }
333
build(const std::vector<Parameter> & ps)334 void EllArc::build(const std::vector<Parameter>& ps)
335 {
336 trace_p->push("EllArc::build");
337 shape_=_ellArc;
338 std::set<ParameterKey> params=getParamsKeys(), usedParams;
339 // managing params
340 for (number_t i=0; i < ps.size(); ++i)
341 {
342 ParameterKey key=ps[i].key();
343 buildParam(ps[i]);
344 if (params.find(key) != params.end()) { params.erase(key); }
345 else
346 {
347 if (usedParams.find(key) == usedParams.end())
348 { error("geom_unexpected_param_key", words("param key",key), words("shape",_ellArc)); }
349 else { warning("param_already_used", words("param key",key)); }
350 }
351 usedParams.insert(key);
352 // user must use nnodes or hsteps, not both
353 if (key==_pk_hsteps && usedParams.find(_pk_nnodes) != usedParams.end())
354 { error("param_conflict", words("param key",key), words("param key",_pk_nnodes)); }
355 if (key==_pk_nnodes && usedParams.find(_pk_hsteps) != usedParams.end())
356 { error("param_conflict", words("param key",key), words("param key",_pk_hsteps)); }
357 }
358
359 // if hsteps is not used, nnodes is used instead and there is no default value
360 if (params.find(_pk_hsteps) != params.end()) { params.erase(_pk_hsteps); }
361
362 // center, v1 and v2 have to be set
363 // apogee is optional (default value is v1)
364 if (params.find(_pk_center) != params.end()) { error("param_missing","center"); }
365 if (params.find(_pk_v1) != params.end()) { error("param_missing","v1"); }
366 if (params.find(_pk_v2) != params.end()) { error("param_missing","v2"); }
367
368 std::set<ParameterKey>::const_iterator it_p;
369 for (it_p=params.begin(); it_p != params.end(); ++it_p) { buildDefaultParam(*it_p); }
370 computeBB();
371 computeMB();
372 trace_p->pop();
373 }
374
buildParam(const Parameter & p)375 void EllArc::buildParam(const Parameter& p)
376 {
377 trace_p->push("EllArc::buildParam");
378 ParameterKey key=p.key();
379 switch (key)
380 {
381 case _pk_center:
382 {
383 switch (p.type())
384 {
385 case _pt: c_=p.get_pt(); break;
386 case _integer: c_=Point(real_t(p.get_i())); break;
387 case _real: c_=Point(p.get_r()); break;
388 default: error("param_badtype",words("value",p.type()),words("param key",key));
389 }
390 break;
391 }
392 case _pk_apogee:
393 {
394 switch (p.type())
395 {
396 case _pt: a_=p.get_pt(); break;
397 case _integer: a_=Point(real_t(p.get_i())); break;
398 case _real: a_=Point(p.get_r()); break;
399 default: error("param_badtype",words("value",p.type()),words("param key",key));
400 }
401 break;
402 }
403 case _pk_v1:
404 {
405 switch (p.type())
406 {
407 case _pt: p1_=p.get_pt(); break;
408 case _integer: p1_=Point(real_t(p.get_i())); break;
409 case _real: p1_=Point(p.get_r()); break;
410 default: error("param_badtype",words("value",p.type()),words("param key",key));
411 }
412 break;
413 }
414 case _pk_v2:
415 {
416 switch (p.type())
417 {
418 case _pt: p2_=p.get_pt(); break;
419 case _integer: p2_=Point(real_t(p.get_i())); break;
420 case _real: p2_=Point(p.get_r()); break;
421 default: error("param_badtype",words("value",p.type()),words("param key",key));
422 }
423 break;
424 }
425 case _pk_nnodes:
426 {
427 switch (p.type())
428 {
429 case _integer:
430 {
431 number_t n=p.get_n();
432 n_=n > 2 ? n : 2;
433 break;
434 }
435 default: error("param_badtype",words("value",p.type()),words("param key",key));
436 }
437 break;
438 }
439 case _pk_hsteps:
440 {
441 switch (p.type())
442 {
443 case _integer: h_=std::vector<real_t>(2,real_t(p.get_n())); break;
444 case _real: h_=std::vector<real_t>(2,p.get_r()); break;
445 case _realVector:
446 {
447 h_=p.get_rv();
448 if (h_.size() != 2) { error("bad_size"); }
449 break;
450 }
451 default: error("param_badtype",words("value",p.type()),words("param key",key));
452 }
453 break;
454 }
455 default: Curve::buildParam(p); break;
456 }
457 trace_p->pop();
458 }
459
buildDefaultParam(ParameterKey key)460 void EllArc::buildDefaultParam(ParameterKey key)
461 {
462 trace_p->push("EllArc::buildDefaultParam");
463 switch (key)
464 {
465 case _pk_nnodes: n_=2; break;
466 case _pk_apogee: a_=p1_; break;
467 default: Curve::buildDefaultParam(key); break;
468 }
469 trace_p->pop();
470 }
471
getParamsKeys()472 std::set<ParameterKey> EllArc::getParamsKeys()
473 {
474 std::set<ParameterKey> params=Curve::getParamsKeys();
475 params.insert(_pk_v1);
476 params.insert(_pk_v2);
477 params.insert(_pk_center);
478 params.insert(_pk_apogee);
479 params.insert(_pk_nnodes);
480 params.insert(_pk_hsteps);
481 return params;
482 }
483
EllArc(const Parameter & p1,const Parameter & p2,const Parameter & p3)484 EllArc::EllArc(const Parameter& p1, const Parameter& p2, const Parameter& p3) : Curve()
485 {
486 std::vector<Parameter> ps(3);
487 ps[0]=p1; ps[1]=p2; ps[2]=p3;
488 build(ps);
489 }
490
EllArc(const Parameter & p1,const Parameter & p2,const Parameter & p3,const Parameter & p4)491 EllArc::EllArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4) : Curve()
492 {
493 std::vector<Parameter> ps(4);
494 ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4;
495 build(ps);
496 }
497
EllArc(const Parameter & p1,const Parameter & p2,const Parameter & p3,const Parameter & p4,const Parameter & p5)498 EllArc::EllArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4,
499 const Parameter& p5) : Curve()
500 {
501 std::vector<Parameter> ps(5);
502 ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5;
503 build(ps);
504 }
505
EllArc(const Parameter & p1,const Parameter & p2,const Parameter & p3,const Parameter & p4,const Parameter & p5,const Parameter & p6)506 EllArc::EllArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4,
507 const Parameter& p5, const Parameter& p6) : Curve()
508 {
509 std::vector<Parameter> ps(6);
510 ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5; ps[5]=p6;
511 build(ps);
512 }
513
EllArc(const Parameter & p1,const Parameter & p2,const Parameter & p3,const Parameter & p4,const Parameter & p5,const Parameter & p6,const Parameter & p7)514 EllArc::EllArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4,
515 const Parameter& p5, const Parameter& p6, const Parameter& p7) : Curve()
516 {
517 std::vector<Parameter> ps(7);
518 ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5; ps[5]=p6; ps[6]=p7;
519 build(ps);
520 }
521
asString() const522 string_t EllArc::asString() const
523 {
524 string_t s("Elliptic arc (bounds = {");
525 s += p1_.toString() +", " + p2_.toString() + "}, center = " + c_.toString() + ", apogee = " + a_.toString() + ")";
526 return s;
527 }
528
reverse()529 EllArc& EllArc::reverse()
530 {
531 std::swap(p1_,p2_);
532 if (h_.size()==2) { std::swap(h_[0],h_[1]); }
533 return *this;
534 }
535
operator ~(const EllArc & e)536 EllArc operator~(const EllArc& e)
537 {
538 EllArc e2=e;
539 e2.reverse();
540 return e2;
541 }
542
computeMB()543 void EllArc::computeMB()
544 {
545 Point i=(p1_+p2_)/2.;
546 real_t r=c_.distance(a_);
547 Point p=c_+(r/c_.distance(i))*(i-c_);
548 minimalBox= MinimalBox(p1_,p2_,p1_+p-i);
549 }
550
computeBB()551 void EllArc::computeBB()
552 {
553 Point cp1=p1_-c_;
554 Point cp2=p2_-c_;
555 real_t r=c_.distance(a_);
556 real_t h;
557
558 Point ph=projectionOnStraightLine(p2_, c_, p1_, h);
559 Point pp1=ph;
560 Point pp2=c_+(r/c_.distance(p1_))*p1_;
561 Point pp3=p2_;
562 if (dot(ph-c_,cp1) < 0.)
563 {
564 Point pt=c_+p2_-ph;
565 pp3=(r/c_.distance(pt))*pt;
566 }
567 boundingBox=BoundingBox(pp1, pp2, pp3);
568 }
569
boundNodes() const570 std::vector<const Point*> EllArc::boundNodes() const
571 {
572 std::vector<const Point*> nodes(2);
573 nodes[0]=&p1_; nodes[1]=&p2_;
574 return nodes;
575 }
576
nodes()577 std::vector<Point*> EllArc::nodes()
578 {
579 std::vector<Point*> nodes(4);
580 nodes[0]=&c_; nodes[1]=&a_; nodes[2]=&p1_; nodes[3]=&p2_;
581 return nodes;
582 }
583
nodes() const584 std::vector<const Point*> EllArc::nodes() const
585 {
586 std::vector<const Point*> nodes(4);
587 nodes[0]=&c_; nodes[1]=&a_; nodes[2]=&p1_; nodes[3]=&p2_;
588 return nodes;
589 }
590
curves() const591 std::vector<std::pair<ShapeType,std::vector<const Point*> > > EllArc::curves() const
592 {
593 std::vector<std::pair<ShapeType,std::vector<const Point*> > > curves(1);
594 curves[0]=std::make_pair(_ellArc,boundNodes());
595 return curves;
596 }
597
598 //! default circular arc is quarter of circle of center (0,0,0) and radius 1
CircArc()599 CircArc::CircArc() : Curve(), c_(0.,0.), p1_(1.,0.), p2_(0.,1.), n_(2)
600 {
601 shape_=_circArc;
602 computeMB();
603 }
604
build(const std::vector<Parameter> & ps)605 void CircArc::build(const std::vector<Parameter>& ps)
606 {
607 trace_p->push("CircArc::build");
608 shape_=_circArc;
609 std::set<ParameterKey> params=getParamsKeys(), usedParams;
610 // managing params
611 for (number_t i=0; i < ps.size(); ++i)
612 {
613 ParameterKey key=ps[i].key();
614 buildParam(ps[i]);
615 if (params.find(key) != params.end()) { params.erase(key); }
616 else
617 {
618 if (usedParams.find(key) == usedParams.end())
619 { error("geom_unexpected_param_key", words("param key",key), words("shape",_circArc)); }
620 else { warning("param_already_used", words("param key",key)); }
621 }
622 usedParams.insert(key);
623 // user must use nnodes or hsteps, not both
624 if (key==_pk_hsteps && usedParams.find(_pk_nnodes) != usedParams.end())
625 { error("param_conflict", words("param key",key), words("param key",_pk_nnodes)); }
626 if (key==_pk_nnodes && usedParams.find(_pk_hsteps) != usedParams.end())
627 { error("param_conflict", words("param key",key), words("param key",_pk_hsteps)); }
628 }
629
630 // if hsteps is not used, nnodes is used instead and there is no default value
631 if (params.find(_pk_hsteps) != params.end()) { params.erase(_pk_hsteps); }
632
633 // center, v1 and v2 have to be set
634 if (params.find(_pk_center) != params.end()) { error("param_missing","center"); }
635 if (params.find(_pk_v1) != params.end()) { error("param_missing","v1"); }
636 if (params.find(_pk_v2) != params.end()) { error("param_missing","v2"); }
637
638 std::set<ParameterKey>::const_iterator it_p;
639 for (it_p=params.begin(); it_p != params.end(); ++it_p) { buildDefaultParam(*it_p); }
640 computeBB();
641 computeMB();
642 trace_p->pop();
643 }
644
buildParam(const Parameter & p)645 void CircArc::buildParam(const Parameter& p)
646 {
647 trace_p->push("CircArc::buildParam");
648 ParameterKey key=p.key();
649 switch (key)
650 {
651 case _pk_center:
652 {
653 switch (p.type())
654 {
655 case _pt: c_=p.get_pt(); break;
656 case _integer: c_=Point(real_t(p.get_i())); break;
657 case _real: c_=Point(p.get_r()); break;
658 default: error("param_badtype",words("value",p.type()),words("param key",key));
659 }
660 break;
661 }
662 case _pk_v1:
663 {
664 switch (p.type())
665 {
666 case _pt: p1_=p.get_pt(); break;
667 case _integer: p1_=Point(real_t(p.get_i())); break;
668 case _real: p1_=Point(p.get_r()); break;
669 default: error("param_badtype",words("value",p.type()),words("param key",key));
670 }
671 break;
672 }
673 case _pk_v2:
674 {
675 switch (p.type())
676 {
677 case _pt: p2_=p.get_pt(); break;
678 case _integer: p2_=Point(real_t(p.get_i())); break;
679 case _real: p2_=Point(p.get_r()); break;
680 default: error("param_badtype",words("value",p.type()),words("param key",key));
681 }
682 break;
683 }
684 case _pk_nnodes:
685 {
686 switch (p.type())
687 {
688 case _integer:
689 {
690 number_t n=p.get_n();
691 n_=n > 2 ? n : 2;
692 break;
693 }
694 default: error("param_badtype",words("value",p.type()),words("param key",key));
695 }
696 break;
697 }
698 case _pk_hsteps:
699 {
700 switch (p.type())
701 {
702 case _integer: h_=std::vector<real_t>(2,real_t(p.get_n())); break;
703 case _real: h_=std::vector<real_t>(2,p.get_r()); break;
704 case _realVector:
705 {
706 h_=p.get_rv();
707 if (h_.size() != 2) { error("bad_size"); }
708 break;
709 }
710 default: error("param_badtype",words("value",p.type()),words("param key",key));
711 }
712 break;
713 }
714 default: Curve::buildParam(p); break;
715 }
716 trace_p->pop();
717 }
718
buildDefaultParam(ParameterKey key)719 void CircArc::buildDefaultParam(ParameterKey key)
720 {
721 trace_p->push("CircArc::buildDefaultParam");
722 switch (key)
723 {
724 case _pk_nnodes: n_=2; break;
725 default: Curve::buildDefaultParam(key); break;
726 }
727 trace_p->pop();
728 }
729
getParamsKeys()730 std::set<ParameterKey> CircArc::getParamsKeys()
731 {
732 std::set<ParameterKey> params=Curve::getParamsKeys();
733 params.insert(_pk_v1);
734 params.insert(_pk_v2);
735 params.insert(_pk_center);
736 params.insert(_pk_nnodes);
737 params.insert(_pk_hsteps);
738 return params;
739 }
740
CircArc(const Parameter & p1,const Parameter & p2,const Parameter & p3)741 CircArc::CircArc(const Parameter& p1, const Parameter& p2, const Parameter& p3) : Curve()
742 {
743 std::vector<Parameter> ps(3);
744 ps[0]=p1; ps[1]=p2; ps[2]=p3;
745 build(ps);
746 }
747
CircArc(const Parameter & p1,const Parameter & p2,const Parameter & p3,const Parameter & p4)748 CircArc::CircArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4) : Curve()
749 {
750 std::vector<Parameter> ps(4);
751 ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4;
752 build(ps);
753 }
754
CircArc(const Parameter & p1,const Parameter & p2,const Parameter & p3,const Parameter & p4,const Parameter & p5)755 CircArc::CircArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4,
756 const Parameter& p5) : Curve()
757 {
758 std::vector<Parameter> ps(5);
759 ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5;
760 build(ps);
761 }
762
CircArc(const Parameter & p1,const Parameter & p2,const Parameter & p3,const Parameter & p4,const Parameter & p5,const Parameter & p6)763 CircArc::CircArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4,
764 const Parameter& p5, const Parameter& p6) : Curve()
765 {
766 std::vector<Parameter> ps(6);
767 ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5; ps[5]=p6;
768 build(ps);
769 }
770
computeMB()771 void CircArc::computeMB()
772 {
773 Point i=(p1_+p2_)/2.;
774 real_t r=c_.distance(p1_);
775 Point p=c_+(r/c_.distance(i))*(i-c_);
776 minimalBox= MinimalBox(p1_,p2_,p1_+p-i);
777 }
778
computeBB()779 void CircArc::computeBB()
780 {
781 Point cp1=p1_-c_;
782 Point cp2=p2_-c_;
783 real_t r=c_.distance(p1_);
784 real_t h;
785
786 Point ph=projectionOnStraightLine(p2_, c_, p1_, h);
787 Point pp1=ph;
788 Point pp2=c_+(r/c_.distance(p1_))*p1_;
789 Point pp3=p2_;
790 if (dot(ph-c_,cp1) < 0.)
791 {
792 Point pt=c_+p2_-ph;
793 pp3=(r/c_.distance(pt))*pt;
794 }
795 boundingBox=BoundingBox(pp1, pp2, pp3);
796 }
797
asString() const798 string_t CircArc::asString() const
799 {
800 string_t s("Circular arc (bounds = {");
801 s += p1_.toString() +", " + p2_.toString() + "}, center = " + c_.toString() + ")";
802 return s;
803 }
804
reverse()805 CircArc& CircArc::reverse()
806 {
807 std::swap(p1_,p2_);
808 if (h_.size()==2) { std::swap(h_[0],h_[1]); }
809 return *this;
810 }
811
operator ~(const CircArc & c)812 CircArc operator~(const CircArc& c)
813 {
814 CircArc c2=c;
815 c2.reverse();
816 return c2;
817 }
818
boundNodes() const819 std::vector<const Point*> CircArc::boundNodes() const
820 {
821 std::vector<const Point*> nodes(2);
822 nodes[0]=&p1_; nodes[1]=&p2_;
823 return nodes;
824 }
825
nodes()826 std::vector<Point*> CircArc::nodes()
827 {
828 std::vector<Point*> nodes(3);
829 nodes[0]=&c_; nodes[1]=&p1_; nodes[2]=&p2_;
830 return nodes;
831 }
832
nodes() const833 std::vector<const Point*> CircArc::nodes() const
834 {
835 std::vector<const Point*> nodes(3);
836 nodes[0]=&c_; nodes[1]=&p1_; nodes[2]=&p2_;
837 return nodes;
838 }
839
curves() const840 std::vector<std::pair<ShapeType,std::vector<const Point*> > > CircArc::curves() const
841 {
842 std::vector<std::pair<ShapeType,std::vector<const Point*> > > curves(1);
843 curves[0]=std::make_pair(_circArc,boundNodes());
844 return curves;
845 }
846
measure() const847 real_t CircArc::measure() const
848 {
849 real_t theta;
850 real_t radius=c_.distance(p1_);
851 real_t scal=dot(p1_-c_,p2_-c_);
852 if (std::abs(scal) < theEpsilon) { return 0.5*pi_*radius; }
853 theta=std::atan(norm2(crossProduct(p1_-c_,p2_-c_))/scal);
854 if (theta < 0) { theta+=pi_; }
855 return theta;
856 }
857
asString() const858 string_t SetOfPoints::asString() const
859 {
860 string_t s("SetOfPoints (");
861 s += tostring(pts_.size()) + " points)";
862 return s;
863 }
864
nodes()865 std::vector<Point*> SetOfPoints::nodes()
866 {
867 std::vector<Point*> nodes(pts_.size());
868 for (size_t i=0; i < pts_.size(); i++) { nodes[i]=&pts_[i]; }
869 return nodes;
870 }
871
nodes() const872 std::vector<const Point*> SetOfPoints::nodes() const
873 {
874 std::vector<const Point*> nodes(pts_.size());
875 for (size_t i=0; i < pts_.size(); i++) { nodes[i]=&pts_[i]; }
876 return nodes;
877 }
878
measure() const879 real_t SetOfPoints::measure() const
880 {
881 real_t length=0;
882 for (number_t i=1; i < pts_.size(); ++i)
883 {
884 length += pts_[i-1].distance(pts_[i]);
885 }
886 return length;
887 }
888
889 } // end of namespace xlifepp
890