mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
Extend IfcGeomServer with calculated quantities
This commit is contained in:
@@ -655,6 +655,13 @@ namespace IfcGeom {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Gets the native (Open Cascade) representation of the current geometrical entity.
|
||||
BRepElement<P>* get_native()
|
||||
{
|
||||
// TODO: Test settings and throw
|
||||
return current_shape_model;
|
||||
}
|
||||
|
||||
const Element<P>* getObject(int id) {
|
||||
|
||||
gp_Trsf trsf;
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
#include <vld.h>
|
||||
#endif
|
||||
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
template <typename T>
|
||||
@@ -71,6 +75,17 @@ std::string sread(std::istream& s) {
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string format_json(const T& t) {
|
||||
return boost::lexical_cast<std::string>(t);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string format_json(const std::string& s) {
|
||||
// NB: No escaping whatsoever. Only use alphanumeric values.
|
||||
return "\"" + s + "\"";
|
||||
}
|
||||
|
||||
static std::streambuf *stdout_orig, *stdout_redir;
|
||||
|
||||
template <typename T>
|
||||
@@ -199,10 +214,16 @@ public:
|
||||
WriteLog(const std::string& str) : Command(LOG), str(str) {};
|
||||
};
|
||||
|
||||
class EntityExtension {
|
||||
public:
|
||||
virtual void write_contents(std::ostream& s) = 0;
|
||||
};
|
||||
|
||||
class Entity : public Command {
|
||||
private:
|
||||
const IfcGeom::TriangulationElement<float>* geom;
|
||||
bool append_line_data;
|
||||
EntityExtension* eext_;
|
||||
protected:
|
||||
void read_content(std::istream& /*s*/) {}
|
||||
void write_content(std::ostream& s) {
|
||||
@@ -276,9 +297,12 @@ protected:
|
||||
material_indices.push_back(*it);
|
||||
}
|
||||
swrite(s, std::string((char*) material_indices.data(), material_indices.size() * sizeof(int32_t))); }
|
||||
if (eext_) {
|
||||
eext_->write_contents(s);
|
||||
}
|
||||
}
|
||||
public:
|
||||
Entity(const IfcGeom::TriangulationElement<float>* geom) : Command(ENTITY), geom(geom), append_line_data(false) {};
|
||||
Entity(const IfcGeom::TriangulationElement<float>* geom, EntityExtension* eext = 0) : Command(ENTITY), geom(geom), append_line_data(false), eext_(eext) {};
|
||||
};
|
||||
|
||||
class Next : public Command {
|
||||
@@ -331,6 +355,102 @@ public:
|
||||
uint32_t value() const { return value_; }
|
||||
};
|
||||
|
||||
static const std::string TOTAL_SURFACE_AREA = "TOTAL_SURFACE_AREA";
|
||||
static const std::string TOTAL_SHAPE_VOLUME = "TOTAL_SHAPE_VOLUME";
|
||||
static const std::string WALKABLE_SURFACE_AREA = "WALKABLE_SURFACE_AREA";
|
||||
static const double MAX_WALKABLE_SURFACE_ANGLE_DEGREES = 15.;
|
||||
|
||||
class QuantityWriter : public EntityExtension {
|
||||
private:
|
||||
const IfcGeom::BRepElement<float>* elem_;
|
||||
public:
|
||||
QuantityWriter(const IfcGeom::BRepElement<float>* elem) :
|
||||
elem_(elem)
|
||||
{}
|
||||
void write_contents(std::ostream& s) {
|
||||
|
||||
double total_surface_area = 0.;
|
||||
double total_shape_volume = 0.;
|
||||
double walkable_surface_area = 0.;
|
||||
|
||||
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = elem_->geometry().begin(); it != elem_->geometry().end(); ++it) {
|
||||
gp_GTrsf gtrsf = it->Placement();
|
||||
const gp_Trsf& o_trsf = elem_->transformation().data();
|
||||
gtrsf.PreMultiply(o_trsf);
|
||||
const TopoDS_Shape& shp = it->Shape();
|
||||
const TopoDS_Shape moved_shape = IfcGeom::Kernel::apply_transformation(shp, gtrsf);
|
||||
|
||||
{
|
||||
GProp_GProps prop_area;
|
||||
BRepGProp::SurfaceProperties(moved_shape, prop_area);
|
||||
total_surface_area += prop_area.Mass();
|
||||
}
|
||||
|
||||
{
|
||||
GProp_GProps prop_volume;
|
||||
BRepGProp::VolumeProperties(moved_shape, prop_volume);
|
||||
total_shape_volume += prop_volume.Mass();
|
||||
}
|
||||
|
||||
if (elem_->type() == "IfcSpace") {
|
||||
TopExp_Explorer exp(moved_shape, TopAbs_FACE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
const TopoDS_Face& face = TopoDS::Face(exp.Current());
|
||||
Handle(Geom_Surface) surf = BRep_Tool::Surface(face);
|
||||
|
||||
// Assume we can only walk on planar surfaces
|
||||
if (surf->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BRepGProp_Face prop(face);
|
||||
double u0, u1, v0, v1;
|
||||
BRepTools::UVBounds(face, u0, u1, v0, v1);
|
||||
gp_Pnt p;
|
||||
gp_Vec normal_direction;
|
||||
prop.Normal((u0 + u1) / 2., (v0 + v1) / 2., p, normal_direction);
|
||||
|
||||
gp_Vec normal(0., 0., 0.);
|
||||
if (normal_direction.Magnitude() > ALMOST_ZERO) {
|
||||
normal = gp_Dir(normal_direction.XYZ());
|
||||
}
|
||||
|
||||
if (normal.Angle(gp::DZ()) < (MAX_WALKABLE_SURFACE_ANGLE_DEGREES * M_PI / 180.0)) {
|
||||
GProp_GProps prop_face;
|
||||
BRepGProp::SurfaceProperties(face, prop_face);
|
||||
walkable_surface_area += prop_face.Mass();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Manual JSON formatting is always a bad idea
|
||||
std::ostringstream ss;
|
||||
ss.write("{", 1);
|
||||
ss << format_json(TOTAL_SURFACE_AREA);
|
||||
ss.write(":", 1);
|
||||
ss << format_json(total_surface_area);
|
||||
ss.write(",", 1);
|
||||
ss << format_json(TOTAL_SHAPE_VOLUME);
|
||||
ss.write(":", 1);
|
||||
ss << format_json(total_shape_volume);
|
||||
if (elem_->type() == "IfcSpace") {
|
||||
ss.write(",", 1);
|
||||
ss << format_json(WALKABLE_SURFACE_AREA);
|
||||
ss.write(":", 1);
|
||||
ss << format_json(walkable_surface_area);
|
||||
}
|
||||
ss.write("}", 1);
|
||||
|
||||
// We do a 4-byte manual alignment
|
||||
std::string payload = ss.str();
|
||||
s << payload;
|
||||
if (payload.size() % 4) {
|
||||
s << std::string(4 - (payload.size() % 4), ' ');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main () {
|
||||
// Redirect stdout to this stream, so that involuntary
|
||||
// writes to stdout do not interfere with our protocol.
|
||||
@@ -390,7 +510,8 @@ int main () {
|
||||
break;
|
||||
}
|
||||
const IfcGeom::TriangulationElement<float>* geom = static_cast<const IfcGeom::TriangulationElement<float>*>(iterator->get());
|
||||
Entity(geom).write(std::cout);
|
||||
QuantityWriter eext(iterator->get_native());
|
||||
Entity(geom, &eext).write(std::cout);
|
||||
continue;
|
||||
}
|
||||
case NEXT: {
|
||||
|
||||
Reference in New Issue
Block a user