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