Files
2025-12-05 08:54:02 +01:00

198 lines
4.6 KiB
Plaintext

// 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<ellipse>(this,a_class)) return p;
if(void* p = cmp_cast<curve>(this,a_class)) return p;
return node::cast(a_class);
}
public:
sf<float> rx;
sf<float> ry;
sf<float> phi_min; //radians
sf<float> phi_max; //radians
sf<unsigned int> 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<float>(phimin,phimax);
float phi2 = max_of<float>(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<float> m_xyzs;
};
}}
#endif