Files
geant4/source/externals/g4tools/include/tools/sg/polyhedron
T
2021-06-25 16:12:29 +02:00

500 lines
13 KiB
Plaintext

// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_sg_polyhedron
#define tools_sg_polyhedron
#include "node"
#include "sf"
#include "render_action"
#include "pick_action"
#include "bbox_action"
#include "state"
#include "render_manager"
#include "gstos"
#include "../hep/sf_polyhedron"
#include "../vmanip"
#include "tessellate"
namespace tools {
namespace sg {
class polyhedron : public node, public gstos {
TOOLS_NODE(polyhedron,tools::sg::polyhedron,node)
public:
hep::sf_polyhedron ph;
sf<bool> solid;
sf<bool> reduced_wire_frame;
sf<bool> enforce_edges;
public:
virtual const desc_fields& node_desc_fields() const {
TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::polyhedron)
static const desc_fields s_v(parent::node_desc_fields(),4, //WARNING : take care of count.
TOOLS_ARG_FIELD_DESC(ph),
TOOLS_ARG_FIELD_DESC(solid),
TOOLS_ARG_FIELD_DESC(reduced_wire_frame),
TOOLS_ARG_FIELD_DESC(enforce_edges)
);
return s_v;
}
private:
void add_fields(){
add_field(&ph);
add_field(&solid);
add_field(&reduced_wire_frame);
add_field(&enforce_edges);
}
public: //node
typedef tessellate::prims_t prims_t;
protected: //gstos
virtual unsigned int create_gsto(std::ostream& a_out,render_manager& a_mgr) {
m_size = 0;
if(solid.value()) {
size_t sz = 0;
if(m_draw_edges) sz += m_xyzs.size();
{tools_vforcit(prims_t,m_primss,itt) {
const prims_t& prims = *itt;
tools_vforcit(tess_prim*,prims,it) {
const tess_prim& item = *(*it);
const std::vector<float>& coords = item.m_coords;
const std::vector<float>& norms = item.m_norms;
if(coords.empty()) continue;
if(norms.size()!=coords.size()) {
a_out << "tools::sg::polyhedron::create_gsto :"
<< " bad number of normals."
<< std::endl;
continue;
}
sz += coords.size()+norms.size();
}
}}
if(sz) {
float* buffer = new float[sz];
char* pos = (char*)buffer;
size_t psz = 0;
if(m_draw_edges) {
if(m_xyzs.size()) {
size_t _sz = m_xyzs.size()*sizeof(float);
::memcpy(pos,vec_data<float>(m_xyzs),_sz);
pos += _sz;
psz += _sz;
m_size = m_xyzs.size();
//m_xyzs.clear(); //we need them for pick,write,...
}
}
{tools_vforcit(prims_t,m_primss,itt) {
const prims_t& prims = *itt;
tools_vforcit(tess_prim*,prims,it) {
tess_prim& item = *(*it);
const std::vector<float>& coords = item.m_coords;
const std::vector<float>& norms = item.m_norms;
if(coords.empty()) continue;
if(norms.size()!=coords.size()) continue;
item.m_size = coords.size();
{item.m_pos_coords = psz;
size_t _sz = coords.size()*sizeof(float);
::memcpy(pos,vec_data<float>(coords),_sz);
pos += _sz;
psz += _sz;}
{item.m_pos_norms = psz;
size_t _sz = norms.size()*sizeof(float);
::memcpy(pos,vec_data<float>(norms),_sz);
pos += _sz;
psz += _sz;}
// we don't need coords, norms for rendering
// but needed for pick,write...
//coords.clear();
//norms.clear();
//we still need m_prims.
}
}}
unsigned int id = a_mgr.create_gsto_from_data(sz,buffer);
delete [] buffer;
return id;
}
} else {
m_size = m_xyzs.size();
return a_mgr.create_gsto_from_data(m_xyzs);
}
return 0;
}
public:
virtual void render(render_action& a_action) {
const state& state = a_action.state();
bool draw_edges = false;
if(solid.value()) {
draw_edges = state.m_GL_LIGHTING?false:true;
if(enforce_edges.value()) draw_edges = true;
}
if( touched() ||
(draw_edges && m_xyzs.empty()) ||
(solid.value() && m_primss.empty()) ){
update_what what = lines;
if(solid.value()) what = draw_edges?faces_and_lines:faces;
update_sg(a_action.out(),what);
reset_touched();
}
unsigned int _id = 0;
if(state.m_use_gsto) {
m_draw_edges = draw_edges;
_id = get_gsto_id(a_action.out(),a_action.render_manager());
} else {
clean_gstos(&a_action.render_manager());
}
//a_action.out() << "debug : tools::sg::polyhedron::render_action :"
// << " m_xyzs.size() " << m_xyzs.size()
// << " m_primss.size() " << m_primss.size()
// << std::endl;
if(solid.value()) {
if(_id) {
a_action.begin_gsto(_id);
if(draw_edges && m_size) {
//Same logic as Inventor SoLightModel.model = BASE_COLOR.
a_action.set_lighting(false);
a_action.color4f(0,0,0,1);
a_action.draw_gsto_v(gl::lines(),m_size/3,0);
//pushes back the filled polygons to avoid z-fighting with lines
a_action.set_polygon_offset(true);
a_action.color4f(state.m_color);
a_action.set_lighting(state.m_GL_LIGHTING);
}
{tools_vforcit(prims_t,m_primss,itt) {
const prims_t& prims = *itt;
tools_vforcit(tess_prim*,prims,it) {
const tess_prim& item = *(*it);
a_action.draw_gsto_vn(item.m_mode,item.m_size/3,item.m_pos_coords,item.m_pos_norms);
}
}}
a_action.set_polygon_offset(state.m_GL_POLYGON_OFFSET_FILL);
a_action.end_gsto();
} else {
if(draw_edges){
if(m_xyzs.size()) {
//Same logic as Inventor SoLightModel.model = BASE_COLOR.
a_action.set_lighting(false);
a_action.color4f(0,0,0,1);
a_action.draw_vertex_array(gl::lines(),m_xyzs);
//pushes back the filled polygons to avoid z-fighting with lines
a_action.set_polygon_offset(true);
a_action.color4f(state.m_color);
a_action.set_lighting(state.m_GL_LIGHTING);
}
}
{tools_vforcit(prims_t,m_primss,itt) {
const prims_t& prims = *itt;
tools_vforcit(tess_prim*,prims,it) {
const tess_prim& item = *(*it);
const std::vector<float>& coords = item.m_coords;
if(coords.empty()) continue;
const std::vector<float>& norms = item.m_norms;
if(norms.size()!=coords.size()) {
a_action.out() << "tools::sg::polyhedron::render :"
<< " bad number of normals."
<< std::endl;
continue;
}
a_action.draw_vertex_normal_array(item.m_mode,coords,norms);
}
}}
a_action.set_polygon_offset(state.m_GL_POLYGON_OFFSET_FILL);
}
} else { //not solid
//Same logic as Inventor SoLightModel.model = BASE_COLOR.
a_action.set_lighting(false); // do we want that ?
if(_id) {
a_action.begin_gsto(_id);
a_action.draw_gsto_v(gl::lines(),m_size/3,0);
a_action.end_gsto();
} else {
a_action.draw_vertex_array(gl::lines(),m_xyzs);
}
a_action.set_lighting(state.m_GL_LIGHTING);
}
}
virtual void bbox(bbox_action& a_action) {
if(touched()) {
update_sg(a_action.out(),lines);
reset_touched();
}
if(solid.value()) {
tools_vforcit(prims_t,m_primss,itt) {
const prims_t& prims = *itt;
tools_vforcit(tess_prim*,prims,it) {
const tess_prim& item = *(*it);
const std::vector<float>& coords = item.m_coords;
a_action.add_points(coords);
}
}
} else {
a_action.add_points(m_xyzs);
}
}
virtual void pick(pick_action& a_action) {
if(touched()) {
update_what what = solid.value()?faces:lines;
update_sg(a_action.out(),what);
reset_touched();
}
if(solid.value()) {
tools_vforcit(prims_t,m_primss,itt) {
const prims_t& prims = *itt;
tools_vforcit(tess_prim*,prims,it) {
const tess_prim& item = *(*it);
const std::vector<float>& coords = item.m_coords;
if(a_action.add__primitive(*this,item.m_mode,coords,true)) return;
}
}
} else {
a_action.add__lines(*this,m_xyzs,true);
}
}
public:
polyhedron()
:parent()
,ph(hep::polyhedron())
,solid(true)
,reduced_wire_frame(true)
,enforce_edges(false)
,m_tess(0)
{
add_fields();
}
virtual ~polyhedron(){
_clear();
delete m_tess;
}
public:
polyhedron(const polyhedron& a_from)
:parent(a_from)
,gstos(a_from)
,ph(a_from.ph)
,solid(a_from.solid)
,reduced_wire_frame(a_from.reduced_wire_frame)
,enforce_edges(a_from.enforce_edges)
,m_xyzs(a_from.m_xyzs)
,m_tess(0)
{
add_fields();
}
polyhedron& operator=(const polyhedron& a_from){
parent::operator=(a_from);
gstos::operator=(a_from);
ph = a_from.ph;
solid = a_from.solid;
reduced_wire_frame = a_from.reduced_wire_frame;
enforce_edges = a_from.enforce_edges;
m_xyzs = a_from.m_xyzs;
return *this;
}
public:
enum update_what {
faces = 0,
lines = 1,
faces_and_lines
};
void update_sg(std::ostream& a_out,const update_what& a_what) {
//a_out << "debug : tools::sg::polyhedron::update_sg" << std::endl;
clean_gstos(); //must reset for all render_manager.
_clear();
const hep::polyhedron& sbPolyhedron = ph.value();
if(sbPolyhedron.GetNoFacets()<=0) {
//a_out << "tools::sg::polyhedron::update_sg : abnormal polyhedron." << std::endl;
return; // Abnormal polyhedron.
}
if((a_what==faces)||(a_what==faces_and_lines)) {
std::vector<double> doubles;
vec3d unitNormal;
vec3d* pV = sbPolyhedron.GetPV();
// Assume all facets are convex quadrilaterals :
bool notLastFace;
do {
notLastFace = sbPolyhedron.GetNextUnitNormal(unitNormal);
doubles.clear(); //begin POLYGON
bool notLastEdge;
int edgeFlag = 1;
do {
// optimize to avoid copying vec3f.
//notLastEdge = sbPolyhedron.GetNextVertex(vertex,edgeFlag);
int index;
notLastEdge = sbPolyhedron.GetNextVertexIndex(index,edgeFlag);
vec3d* vertex = pV+index; //WARNING : must not be modified !
doubles.push_back((*vertex)[0]);
doubles.push_back((*vertex)[1]);
doubles.push_back((*vertex)[2]);
} while (notLastEdge);
if(!m_tess) m_tess = new tessellate(a_out);
m_primss.push_back(prims_t());
prims_t& prims = m_primss.back();
m_tess->do_it(doubles.size()/3,vec_data(doubles),prims);
m_tess->clear();
} while (notLastFace);
}
if((a_what==lines)||(a_what==faces_and_lines)) {
float pvbx = 0;
float pvby = 0;
float pvbz = 0;
float pvex,pvey,pvez;
vec3d unitNormal;
vec3d* pV = sbPolyhedron.GetPV();
bool notLastFace;
do {
notLastFace = sbPolyhedron.GetNextUnitNormal(unitNormal);
// Treat edges :
int edgeFlag = 1;
int prevEdgeFlag = edgeFlag;
bool notLastEdge;
bool firstEdge = true;
do {
int index;
notLastEdge = sbPolyhedron.GetNextVertexIndex(index,edgeFlag);
vec3d* vertex = pV+index; //WARNING : must not be modified !
if(!reduced_wire_frame) edgeFlag = 1;
if(firstEdge) {
if(edgeFlag) {
pvbx = (float)(*vertex)[0];
pvby = (float)(*vertex)[1];
pvbz = (float)(*vertex)[2];
} else {
}
firstEdge = false;
prevEdgeFlag = edgeFlag;
} else {
if(edgeFlag!=prevEdgeFlag) {
if(edgeFlag) { // Pass to a visible edge :
pvbx = (float)(*vertex)[0];
pvby = (float)(*vertex)[1];
pvbz = (float)(*vertex)[2];
} else { // Pass to an invisible edge :
pvex = (float)(*vertex)[0];
pvey = (float)(*vertex)[1];
pvez = (float)(*vertex)[2];
m_xyzs.push_back(pvbx);
m_xyzs.push_back(pvby);
m_xyzs.push_back(pvbz);
m_xyzs.push_back(pvex);
m_xyzs.push_back(pvey);
m_xyzs.push_back(pvez);
}
prevEdgeFlag = edgeFlag;
} else {
if(edgeFlag) {
pvex = (float)(*vertex)[0];
pvey = (float)(*vertex)[1];
pvez = (float)(*vertex)[2];
m_xyzs.push_back(pvbx);
m_xyzs.push_back(pvby);
m_xyzs.push_back(pvbz);
m_xyzs.push_back(pvex);
m_xyzs.push_back(pvey);
m_xyzs.push_back(pvez);
pvbx = pvex;
pvby = pvey;
pvbz = pvez;
} else {
}
}
}
} while (notLastEdge);
} while (notLastFace);
}
}
const std::vector<float>& xyzs() const {return m_xyzs;}
protected:
void _clear(){
tools_vforit(prims_t,m_primss,it) raw_clear(*it);
m_primss.clear();
m_xyzs.clear();
}
protected:
std::vector<float> m_xyzs;
//gluTess
tessellate* m_tess;
std::vector<prims_t> m_primss;
size_t m_size;
bool m_draw_edges;
};
}}
#endif