/* XLiFE++ is an extended library of finite elements written in C++ Copyright (C) 2014 Lunéville, Eric; Kielbasiewicz, Nicolas; Lafranche, Yvon; Nguyen, Manh-Ha; Chambeyron, Colin This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /*! \file geometries1D.cpp \authors N. Kielbasiewicz, Y. Lafranche \since 18 oct 2012 \date 29 jul 2015 \brief This file contains the implementation of methods of classes defined in geometries1D.hpp */ #include "geometries1D.hpp" namespace xlifepp { //=========================================================== // // Curve and child classes member functions // //=========================================================== //! default curve is inside the bounding box [0,1] Curve::Curve() : Geometry(BoundingBox(0.,1.), 1) { // funh_=0; } void Curve::buildParam(const Parameter& p) { trace_p->push("Curve::buildParam"); ParameterKey key=p.key(); switch (key) { case _pk_side_names: { if (p.type()==_string) { sideNames_.resize(1,p.get_s()); } else if (p.type()==_stringVector) { sideNames_=p.get_sv(); } else { error("param_badtype",words("value",p.type()),words("param key",key)); } break; } default: Geometry::buildParam(p); break; } trace_p->pop(); } void Curve::buildDefaultParam(ParameterKey key) { trace_p->push("Curve::buildDefaultParam"); switch (key) { case _pk_side_names: sideNames_.resize(0); break; default: Geometry::buildDefaultParam(key); break; } trace_p->pop(); } std::set Curve::getParamsKeys() { std::set params=Geometry::getParamsKeys(); params.insert(_pk_side_names); return params; } //! default is segment [0,1] Segment::Segment() : Curve(), p1_(0.), p2_(1.), n_(2) { shape_=_segment; computeMB(); } void Segment::build(const std::vector& ps) { trace_p->push("Segment::build"); shape_=_segment; std::set params=getParamsKeys(), usedParams; // managing params for (number_t i=0; i < ps.size(); ++i) { ParameterKey key=ps[i].key(); buildParam(ps[i]); if (params.find(key) != params.end()) { params.erase(key); } else { if (usedParams.find(key) == usedParams.end()) { error("geom_unexpected_param_key", words("param key",key), words("shape",_segment)); } else { warning("param_already_used", words("param key",key)); } } usedParams.insert(key); // user must use nnodes or hsteps, not both if (key==_pk_hsteps && usedParams.find(_pk_nnodes) != usedParams.end()) { error("param_conflict", words("param key",key), words("param key",_pk_nnodes)); } if (key==_pk_nnodes && usedParams.find(_pk_hsteps) != usedParams.end()) { error("param_conflict", words("param key",key), words("param key",_pk_hsteps)); } // if user sets v1 or v2, and xmin or xmax, and vice versa it is an error if ((key==_pk_xmin || key==_pk_xmax) && usedParams.find(_pk_v1) != usedParams.end()) { error("param_conflict", words("param key",key), words("param key",_pk_v1)); } if ((key==_pk_xmin || key==_pk_xmax) && usedParams.find(_pk_v2) != usedParams.end()) { error("param_conflict", words("param key",key), words("param key",_pk_v2)); } if ((key==_pk_v1 || key==_pk_v2) && usedParams.find(_pk_xmin) != usedParams.end()) { error("param_conflict", words("param key",key), words("param key",_pk_xmin)); } if ((key==_pk_v1 || key==_pk_v2) && usedParams.find(_pk_xmax) != usedParams.end()) { error("param_conflict", words("param key",key), words("param key",_pk_xmax)); } } // if hsteps is not used, nnodes is used instead and there is no default value if (params.find(_pk_hsteps) != params.end()) { params.erase(_pk_hsteps); } // (v1,v2) or (xmin,xmax) has to be set (no default values) if (params.find(_pk_v1) != params.end() && params.find(_pk_v2) != params.end() && params.find(_pk_xmin) != params.end() && params.find(_pk_xmax) != params.end()) { error("param_missing","v1, v2, xmin, xmax"); } if (params.find(_pk_v1) != params.end() && params.find(_pk_v2) == params.end()) { error("param_missing","v1"); } if (params.find(_pk_v2) != params.end() && params.find(_pk_v1) == params.end()) { error("param_missing","v2"); } if (params.find(_pk_xmin) != params.end() && params.find(_pk_xmax) == params.end()) { error("param_missing","xmin"); } if (params.find(_pk_xmax) != params.end() && params.find(_pk_xmin) == params.end()) { error("param_missing","xmax"); } if (params.find(_pk_xmin) != params.end()) { params.erase(_pk_xmin); params.erase(_pk_xmax); } if (params.find(_pk_v1) != params.end()) { params.erase(_pk_v1); params.erase(_pk_v2); } std::set::const_iterator it_p; for (it_p=params.begin(); it_p != params.end(); ++it_p) { buildDefaultParam(*it_p); } boundingBox=BoundingBox(p1_,p2_); computeMB(); trace_p->pop(); } void Segment::buildParam(const Parameter& p) { trace_p->push("Segment::buildParam"); ParameterKey key=p.key(); switch (key) { case _pk_v1: { switch (p.type()) { case _pt: p1_=p.get_pt(); break; case _integer: p1_=Point(real_t(p.get_i())); break; case _real: p1_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_v2: { switch (p.type()) { case _pt: p2_=p.get_pt(); break; case _integer: p2_=Point(real_t(p.get_i())); break; case _real: p2_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_xmin: { switch (p.type()) { case _integer: p1_=Point(real_t(p.get_i())); break; case _real: p1_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_xmax: { switch (p.type()) { case _integer: p2_=Point(real_t(p.get_i())); break; case _real: p2_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_nnodes: { switch (p.type()) { case _integer: { number_t n=p.get_n(); n_=n > 2 ? n : 2; break; } default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_hsteps: { switch (p.type()) { case _integer: h_=std::vector(2,real_t(p.get_n())); break; case _real: h_=std::vector(2,p.get_r()); break; case _realVector: { h_=p.get_rv(); if (h_.size() != 2) { error("bad_size"); } break; } default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } default: Curve::buildParam(p); break; } trace_p->pop(); } void Segment::buildDefaultParam(ParameterKey key) { trace_p->push("Segment::buildDefaultParam"); switch (key) { case _pk_nnodes: n_=2; break; default: Curve::buildDefaultParam(key); break; } trace_p->pop(); } std::set Segment::getParamsKeys() { std::set params=Curve::getParamsKeys(); params.insert(_pk_v1); params.insert(_pk_v2); params.insert(_pk_xmin); params.insert(_pk_xmax); params.insert(_pk_nnodes); params.insert(_pk_hsteps); return params; } Segment::Segment(const Parameter& p1, const Parameter& p2) : Curve() { std::vector ps(2); ps[0]=p1; ps[1]=p2; build(ps); } Segment::Segment(const Parameter& p1, const Parameter& p2, const Parameter& p3) : Curve() { std::vector ps(3); ps[0]=p1; ps[1]=p2; ps[2]=p3; build(ps); } Segment::Segment(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4) : Curve() { std::vector ps(4); ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; build(ps); } Segment::Segment(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4, const Parameter& p5) : Curve() { std::vector ps(5); ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5; build(ps); } string_t Segment::asString() const { string_t s("Segment ("); s += p1_.toString() +", " + p2_.toString() + ")"; return s; } Segment& Segment::reverse() { std::swap(p1_,p2_); if (h_.size()==2) { std::swap(h_[0],h_[1]); } return *this; } Segment operator~(const Segment& s) { Segment s2=s; s2.reverse(); return s2; } std::vector Segment::boundNodes() const { std::vector nodes(2); nodes[0]=&p1_; nodes[1]=&p2_; return nodes; } std::vector Segment::nodes() { std::vector nodes(2); nodes[0]=&p1_; nodes[1]=&p2_; return nodes; } std::vector Segment::nodes() const { std::vector nodes(2); nodes[0]=&p1_; nodes[1]=&p2_; return nodes; } std::vector > > Segment::curves() const { std::vector > > curves(1); curves[0]=std::make_pair(_segment,boundNodes()); return curves; } //! default ellipse arc is quarter of circle of center (0,0,0) and radius 1 EllArc::EllArc() : Curve(), c_(0.,0.), a_(1.,0.), p1_(1.,0.), p2_(0.,1.), n_(2) { shape_=_ellArc; computeMB(); } void EllArc::build(const std::vector& ps) { trace_p->push("EllArc::build"); shape_=_ellArc; std::set params=getParamsKeys(), usedParams; // managing params for (number_t i=0; i < ps.size(); ++i) { ParameterKey key=ps[i].key(); buildParam(ps[i]); if (params.find(key) != params.end()) { params.erase(key); } else { if (usedParams.find(key) == usedParams.end()) { error("geom_unexpected_param_key", words("param key",key), words("shape",_ellArc)); } else { warning("param_already_used", words("param key",key)); } } usedParams.insert(key); // user must use nnodes or hsteps, not both if (key==_pk_hsteps && usedParams.find(_pk_nnodes) != usedParams.end()) { error("param_conflict", words("param key",key), words("param key",_pk_nnodes)); } if (key==_pk_nnodes && usedParams.find(_pk_hsteps) != usedParams.end()) { error("param_conflict", words("param key",key), words("param key",_pk_hsteps)); } } // if hsteps is not used, nnodes is used instead and there is no default value if (params.find(_pk_hsteps) != params.end()) { params.erase(_pk_hsteps); } // center, v1 and v2 have to be set // apogee is optional (default value is v1) if (params.find(_pk_center) != params.end()) { error("param_missing","center"); } if (params.find(_pk_v1) != params.end()) { error("param_missing","v1"); } if (params.find(_pk_v2) != params.end()) { error("param_missing","v2"); } std::set::const_iterator it_p; for (it_p=params.begin(); it_p != params.end(); ++it_p) { buildDefaultParam(*it_p); } computeBB(); computeMB(); trace_p->pop(); } void EllArc::buildParam(const Parameter& p) { trace_p->push("EllArc::buildParam"); ParameterKey key=p.key(); switch (key) { case _pk_center: { switch (p.type()) { case _pt: c_=p.get_pt(); break; case _integer: c_=Point(real_t(p.get_i())); break; case _real: c_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_apogee: { switch (p.type()) { case _pt: a_=p.get_pt(); break; case _integer: a_=Point(real_t(p.get_i())); break; case _real: a_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_v1: { switch (p.type()) { case _pt: p1_=p.get_pt(); break; case _integer: p1_=Point(real_t(p.get_i())); break; case _real: p1_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_v2: { switch (p.type()) { case _pt: p2_=p.get_pt(); break; case _integer: p2_=Point(real_t(p.get_i())); break; case _real: p2_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_nnodes: { switch (p.type()) { case _integer: { number_t n=p.get_n(); n_=n > 2 ? n : 2; break; } default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_hsteps: { switch (p.type()) { case _integer: h_=std::vector(2,real_t(p.get_n())); break; case _real: h_=std::vector(2,p.get_r()); break; case _realVector: { h_=p.get_rv(); if (h_.size() != 2) { error("bad_size"); } break; } default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } default: Curve::buildParam(p); break; } trace_p->pop(); } void EllArc::buildDefaultParam(ParameterKey key) { trace_p->push("EllArc::buildDefaultParam"); switch (key) { case _pk_nnodes: n_=2; break; case _pk_apogee: a_=p1_; break; default: Curve::buildDefaultParam(key); break; } trace_p->pop(); } std::set EllArc::getParamsKeys() { std::set params=Curve::getParamsKeys(); params.insert(_pk_v1); params.insert(_pk_v2); params.insert(_pk_center); params.insert(_pk_apogee); params.insert(_pk_nnodes); params.insert(_pk_hsteps); return params; } EllArc::EllArc(const Parameter& p1, const Parameter& p2, const Parameter& p3) : Curve() { std::vector ps(3); ps[0]=p1; ps[1]=p2; ps[2]=p3; build(ps); } EllArc::EllArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4) : Curve() { std::vector ps(4); ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; build(ps); } EllArc::EllArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4, const Parameter& p5) : Curve() { std::vector ps(5); ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5; build(ps); } EllArc::EllArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4, const Parameter& p5, const Parameter& p6) : Curve() { std::vector ps(6); ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5; ps[5]=p6; build(ps); } EllArc::EllArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4, const Parameter& p5, const Parameter& p6, const Parameter& p7) : Curve() { std::vector ps(7); ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5; ps[5]=p6; ps[6]=p7; build(ps); } string_t EllArc::asString() const { string_t s("Elliptic arc (bounds = {"); s += p1_.toString() +", " + p2_.toString() + "}, center = " + c_.toString() + ", apogee = " + a_.toString() + ")"; return s; } EllArc& EllArc::reverse() { std::swap(p1_,p2_); if (h_.size()==2) { std::swap(h_[0],h_[1]); } return *this; } EllArc operator~(const EllArc& e) { EllArc e2=e; e2.reverse(); return e2; } void EllArc::computeMB() { Point i=(p1_+p2_)/2.; real_t r=c_.distance(a_); Point p=c_+(r/c_.distance(i))*(i-c_); minimalBox= MinimalBox(p1_,p2_,p1_+p-i); } void EllArc::computeBB() { Point cp1=p1_-c_; Point cp2=p2_-c_; real_t r=c_.distance(a_); real_t h; Point ph=projectionOnStraightLine(p2_, c_, p1_, h); Point pp1=ph; Point pp2=c_+(r/c_.distance(p1_))*p1_; Point pp3=p2_; if (dot(ph-c_,cp1) < 0.) { Point pt=c_+p2_-ph; pp3=(r/c_.distance(pt))*pt; } boundingBox=BoundingBox(pp1, pp2, pp3); } std::vector EllArc::boundNodes() const { std::vector nodes(2); nodes[0]=&p1_; nodes[1]=&p2_; return nodes; } std::vector EllArc::nodes() { std::vector nodes(4); nodes[0]=&c_; nodes[1]=&a_; nodes[2]=&p1_; nodes[3]=&p2_; return nodes; } std::vector EllArc::nodes() const { std::vector nodes(4); nodes[0]=&c_; nodes[1]=&a_; nodes[2]=&p1_; nodes[3]=&p2_; return nodes; } std::vector > > EllArc::curves() const { std::vector > > curves(1); curves[0]=std::make_pair(_ellArc,boundNodes()); return curves; } //! default circular arc is quarter of circle of center (0,0,0) and radius 1 CircArc::CircArc() : Curve(), c_(0.,0.), p1_(1.,0.), p2_(0.,1.), n_(2) { shape_=_circArc; computeMB(); } void CircArc::build(const std::vector& ps) { trace_p->push("CircArc::build"); shape_=_circArc; std::set params=getParamsKeys(), usedParams; // managing params for (number_t i=0; i < ps.size(); ++i) { ParameterKey key=ps[i].key(); buildParam(ps[i]); if (params.find(key) != params.end()) { params.erase(key); } else { if (usedParams.find(key) == usedParams.end()) { error("geom_unexpected_param_key", words("param key",key), words("shape",_circArc)); } else { warning("param_already_used", words("param key",key)); } } usedParams.insert(key); // user must use nnodes or hsteps, not both if (key==_pk_hsteps && usedParams.find(_pk_nnodes) != usedParams.end()) { error("param_conflict", words("param key",key), words("param key",_pk_nnodes)); } if (key==_pk_nnodes && usedParams.find(_pk_hsteps) != usedParams.end()) { error("param_conflict", words("param key",key), words("param key",_pk_hsteps)); } } // if hsteps is not used, nnodes is used instead and there is no default value if (params.find(_pk_hsteps) != params.end()) { params.erase(_pk_hsteps); } // center, v1 and v2 have to be set if (params.find(_pk_center) != params.end()) { error("param_missing","center"); } if (params.find(_pk_v1) != params.end()) { error("param_missing","v1"); } if (params.find(_pk_v2) != params.end()) { error("param_missing","v2"); } std::set::const_iterator it_p; for (it_p=params.begin(); it_p != params.end(); ++it_p) { buildDefaultParam(*it_p); } computeBB(); computeMB(); trace_p->pop(); } void CircArc::buildParam(const Parameter& p) { trace_p->push("CircArc::buildParam"); ParameterKey key=p.key(); switch (key) { case _pk_center: { switch (p.type()) { case _pt: c_=p.get_pt(); break; case _integer: c_=Point(real_t(p.get_i())); break; case _real: c_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_v1: { switch (p.type()) { case _pt: p1_=p.get_pt(); break; case _integer: p1_=Point(real_t(p.get_i())); break; case _real: p1_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_v2: { switch (p.type()) { case _pt: p2_=p.get_pt(); break; case _integer: p2_=Point(real_t(p.get_i())); break; case _real: p2_=Point(p.get_r()); break; default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_nnodes: { switch (p.type()) { case _integer: { number_t n=p.get_n(); n_=n > 2 ? n : 2; break; } default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } case _pk_hsteps: { switch (p.type()) { case _integer: h_=std::vector(2,real_t(p.get_n())); break; case _real: h_=std::vector(2,p.get_r()); break; case _realVector: { h_=p.get_rv(); if (h_.size() != 2) { error("bad_size"); } break; } default: error("param_badtype",words("value",p.type()),words("param key",key)); } break; } default: Curve::buildParam(p); break; } trace_p->pop(); } void CircArc::buildDefaultParam(ParameterKey key) { trace_p->push("CircArc::buildDefaultParam"); switch (key) { case _pk_nnodes: n_=2; break; default: Curve::buildDefaultParam(key); break; } trace_p->pop(); } std::set CircArc::getParamsKeys() { std::set params=Curve::getParamsKeys(); params.insert(_pk_v1); params.insert(_pk_v2); params.insert(_pk_center); params.insert(_pk_nnodes); params.insert(_pk_hsteps); return params; } CircArc::CircArc(const Parameter& p1, const Parameter& p2, const Parameter& p3) : Curve() { std::vector ps(3); ps[0]=p1; ps[1]=p2; ps[2]=p3; build(ps); } CircArc::CircArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4) : Curve() { std::vector ps(4); ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; build(ps); } CircArc::CircArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4, const Parameter& p5) : Curve() { std::vector ps(5); ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5; build(ps); } CircArc::CircArc(const Parameter& p1, const Parameter& p2, const Parameter& p3, const Parameter& p4, const Parameter& p5, const Parameter& p6) : Curve() { std::vector ps(6); ps[0]=p1; ps[1]=p2; ps[2]=p3; ps[3]=p4; ps[4]=p5; ps[5]=p6; build(ps); } void CircArc::computeMB() { Point i=(p1_+p2_)/2.; real_t r=c_.distance(p1_); Point p=c_+(r/c_.distance(i))*(i-c_); minimalBox= MinimalBox(p1_,p2_,p1_+p-i); } void CircArc::computeBB() { Point cp1=p1_-c_; Point cp2=p2_-c_; real_t r=c_.distance(p1_); real_t h; Point ph=projectionOnStraightLine(p2_, c_, p1_, h); Point pp1=ph; Point pp2=c_+(r/c_.distance(p1_))*p1_; Point pp3=p2_; if (dot(ph-c_,cp1) < 0.) { Point pt=c_+p2_-ph; pp3=(r/c_.distance(pt))*pt; } boundingBox=BoundingBox(pp1, pp2, pp3); } string_t CircArc::asString() const { string_t s("Circular arc (bounds = {"); s += p1_.toString() +", " + p2_.toString() + "}, center = " + c_.toString() + ")"; return s; } CircArc& CircArc::reverse() { std::swap(p1_,p2_); if (h_.size()==2) { std::swap(h_[0],h_[1]); } return *this; } CircArc operator~(const CircArc& c) { CircArc c2=c; c2.reverse(); return c2; } std::vector CircArc::boundNodes() const { std::vector nodes(2); nodes[0]=&p1_; nodes[1]=&p2_; return nodes; } std::vector CircArc::nodes() { std::vector nodes(3); nodes[0]=&c_; nodes[1]=&p1_; nodes[2]=&p2_; return nodes; } std::vector CircArc::nodes() const { std::vector nodes(3); nodes[0]=&c_; nodes[1]=&p1_; nodes[2]=&p2_; return nodes; } std::vector > > CircArc::curves() const { std::vector > > curves(1); curves[0]=std::make_pair(_circArc,boundNodes()); return curves; } real_t CircArc::measure() const { real_t theta; real_t radius=c_.distance(p1_); real_t scal=dot(p1_-c_,p2_-c_); if (std::abs(scal) < theEpsilon) { return 0.5*pi_*radius; } theta=std::atan(norm2(crossProduct(p1_-c_,p2_-c_))/scal); if (theta < 0) { theta+=pi_; } return theta; } string_t SetOfPoints::asString() const { string_t s("SetOfPoints ("); s += tostring(pts_.size()) + " points)"; return s; } std::vector SetOfPoints::nodes() { std::vector nodes(pts_.size()); for (size_t i=0; i < pts_.size(); i++) { nodes[i]=&pts_[i]; } return nodes; } std::vector SetOfPoints::nodes() const { std::vector nodes(pts_.size()); for (size_t i=0; i < pts_.size(); i++) { nodes[i]=&pts_[i]; } return nodes; } real_t SetOfPoints::measure() const { real_t length=0; for (number_t i=1; i < pts_.size(); ++i) { length += pts_[i-1].distance(pts_[i]); } return length; } } // end of namespace xlifepp