// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_sg_ellipse #define tools_sg_ellipse // same logic as ROOT/TEllipse. #include "node" #include "sf" #include "render_action" #include "pick_action" #include "bbox_action" #include "../mathf" #include "../curve" namespace tools { namespace sg { class ellipse : public node,public curve { TOOLS_NODE_NO_CAST(ellipse,tools::sg::ellipse,node) public: virtual void* cast(const std::string& a_class) const { if(void* p = cmp_cast(this,a_class)) return p; if(void* p = cmp_cast(this,a_class)) return p; return node::cast(a_class); } public: sf rx; sf ry; sf phi_min; //radians sf phi_max; //radians sf steps; public: virtual const desc_fields& node_desc_fields() const { TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::ellipse) static const desc_fields s_v(parent::node_desc_fields(),5, //WARNING : take care of count. TOOLS_ARG_FIELD_DESC(rx), TOOLS_ARG_FIELD_DESC(ry), TOOLS_ARG_FIELD_DESC(phi_min), TOOLS_ARG_FIELD_DESC(phi_max), TOOLS_ARG_FIELD_DESC(steps) ); return s_v; } private: void add_fields(){ add_field(&rx); add_field(&ry); add_field(&phi_min); add_field(&phi_max); add_field(&steps); } public: //curve virtual bool pos_tan_nor(float /*a_s*/, vec3f& a_pos, vec3f& a_tan, vec3f& a_nor) const { float x,y,z; {//x = r*cs;y = r*sn;z = 0; x = 0;y = 0;z = 0; m_model.mul_3f(x,y,z); a_pos.set_value(x,y,z);} {//x = -sn;y = cs;z = 0; x = 0;y = 1;z = 0; m_model.mul_dir_3(x,y,z); a_tan.set_value(x,y,z);} {x = 0;y = 0;z = 1; m_model.mul_dir_3(x,y,z); a_nor.set_value(x,y,z);} return true; } public: virtual void copy(curve*& a_new) const {a_new = new ellipse(*this);} public: virtual void render(render_action& a_action) { if(touched()) { update_sg(); reset_touched(); } //Same logic as Inventor SoLightModel.model = BASE_COLOR. const state& state = a_action.state(); a_action.set_lighting(false); a_action.add_line_strip(m_xyzs); a_action.set_lighting(state.m_GL_LIGHTING); } virtual void pick(pick_action& a_action) { if(touched()) { update_sg(); reset_touched(); } if(a_action.stop_at_first()){ a_action.add_line_strip(m_xyzs); if(a_action.done()) a_action.set_node(this); } else { a_action.set_done(false); a_action.zs().clear(); a_action.ws().clear(); a_action.add_line_strip(m_xyzs); if(a_action.done()) { a_action.add_pick(*this,a_action.zs(),a_action.ws(),a_action.state()); a_action.set_done(false); } } } virtual void bbox(bbox_action& a_action) { if(touched()) { update_sg(); reset_touched(); } a_action.add_line_strip(m_xyzs); } public: ellipse() :parent() ,curve() ,rx(1) ,ry(1) ,phi_min(0) ,phi_max(tools::ftwo_pi()) ,steps(40) { add_fields(); } virtual ~ellipse(){} public: ellipse(const ellipse& a_from) :parent(a_from) ,curve(a_from) ,rx(a_from.rx) ,ry(a_from.ry) ,phi_min(a_from.phi_min) ,phi_max(a_from.phi_max) ,steps(a_from.steps) { add_fields(); } ellipse& operator=(const ellipse& a_from){ parent::operator=(a_from); curve::operator=(a_from); rx = a_from.rx; ry = a_from.ry; phi_min = a_from.phi_min; phi_max = a_from.phi_max; steps = a_from.steps; return *this; } protected: void update_sg() { m_xyzs.clear(); if(!steps.value()) return; unsigned int num = steps.value(); //set number of points approximatively proportional to the ellipse circumference //float circ = kPI*(r1+r2)*(phi2-phi1)/360; //Int_t n = (Int_t)(np*circ/((gPad->GetX2()-gPad->GetX1())+(gPad->GetY2()-gPad->GetY1()))); //if (n < 8) n= 8; //if (n > np) n = np; m_xyzs.resize((num+1)*3); float phimin = phi_min.value(); float phimax = phi_max.value(); float r1 = rx.value(); float r2 = ry.value(); float phi1 = min_of(phimin,phimax); float phi2 = max_of(phimin,phimax); float angle,dx,dy; float dphi = (phi2-phi1)/float(num); size_t pos = 0; for(unsigned int i=0;i<=num;i++) { angle = phi1 + float(i)*dphi; dx = r1*fcos(angle); dy = r2*fsin(angle); m_xyzs[pos] = dx;pos++; m_xyzs[pos] = dy;pos++; m_xyzs[pos] = 0;pos++; } } protected: std::vector m_xyzs; }; }} #endif