From 81ee60079e0d6a27a8df0d2804082413a4a4e89d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 11 Apr 2016 11:50:43 +0200 Subject: [PATCH] Enable per-item styles in the pythonOCC viewer --- src/ifcgeom/IfcGeomRepresentation.cpp | 17 +++ src/ifcgeom/IfcGeomRepresentation.h | 2 + .../ifcopenshell/geom/occ_utils.py | 138 ++++++++++++++++-- src/ifcwrap/IfcGeomWrapper.i | 1 + 4 files changed, 144 insertions(+), 14 deletions(-) diff --git a/src/ifcgeom/IfcGeomRepresentation.cpp b/src/ifcgeom/IfcGeomRepresentation.cpp index abd17a15d9..06e5266cac 100644 --- a/src/ifcgeom/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/IfcGeomRepresentation.cpp @@ -38,6 +38,23 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep) for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) { const TopoDS_Shape& s = it->Shape(); gp_GTrsf trsf = it->Placement(); + + if (it->hasStyle() && it->Style().Diffuse()) { + const IfcGeom::SurfaceStyle::ColorComponent& clr = *it->Style().Diffuse(); + _surface_styles.push_back(clr.R()); + _surface_styles.push_back(clr.G()); + _surface_styles.push_back(clr.B()); + } else { + _surface_styles.push_back(-1.); + _surface_styles.push_back(-1.); + _surface_styles.push_back(-1.); + } + if (it->hasStyle() && it->Style().Transparency()) { + _surface_styles.push_back(1. - *it->Style().Transparency()); + } else { + _surface_styles.push_back(1.); + } + if (settings().get(IteratorSettings::CONVERT_BACK_UNITS)) { gp_Trsf scale; scale.SetScaleFactor(1.0 / settings().unit_magnitude()); diff --git a/src/ifcgeom/IfcGeomRepresentation.h b/src/ifcgeom/IfcGeomRepresentation.h index d921e80f93..32b8cc856a 100644 --- a/src/ifcgeom/IfcGeomRepresentation.h +++ b/src/ifcgeom/IfcGeomRepresentation.h @@ -76,9 +76,11 @@ namespace IfcGeom { private: int _id; std::string _brep_data; + std::vector _surface_styles; public: int id() const { return _id; } const std::string& brep_data() const { return _brep_data; } + const std::vector& surface_styles() const { return _surface_styles; } Serialization(const BRep& brep); virtual ~Serialization() {} private: diff --git a/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py b/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py index 004151ec1e..e98bad0544 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/occ_utils.py @@ -18,18 +18,35 @@ ############################################################################### import random -from collections import namedtuple +import operator +from collections import namedtuple, Iterable import OCC.gp import OCC.V3d +import OCC.AIS import OCC.Quantity import OCC.BRepTools import OCC.Display.SimpleGui -tuple = namedtuple('shape', ('data', 'geometry')) +shape_tuple = namedtuple('shape_tuple', ('data', 'geometry', 'styles')) handle, main_loop, add_menu, add_function_to_menu = None, None, None, None +DEFAULT_STYLES = { + "DEFAULT" : (.7 , .7, .7 ), + "IfcWall" : (.8 , .8, .8 ), + "IfcSite" : (.75, .8, .65 ), + "IfcSlab" : (.4 , .4, .4 ), + "IfcWallStandardCase": (.9 , .9, .9 ), + "IfcWall" : (.9 , .9, .9 ), + "IfcWindow" : (.75, .8, .75, .3), + "IfcDoor" : (.55, .3, .15 ), + "IfcBeam" : (.75, .7, .7 ), + "IfcRailing" : (.65, .6, .6 ), + "IfcMember" : (.65, .6, .6 ), + "IfcPlate" : (.8 , .8, .8 ) +} + def initialize_display(): global handle, main_loop, add_menu, add_function_to_menu handle, main_loop, add_menu, add_function_to_menu = OCC.Display.SimpleGui.init_display() @@ -37,25 +54,113 @@ def initialize_display(): def setup(): viewer_handle = handle.GetViewer() viewer = viewer_handle.GetObject() - while True: + + def lights(): viewer.InitActiveLights() - try: active_light = viewer.ActiveLight() - except: break - viewer.DelLight(active_light) - viewer.NextActiveLights() - for dir in [(1,2,-3), (-2,-1,1)]: + while True: + try: active_light = viewer.ActiveLight() + except: break + yield active_light + viewer.NextActiveLights() + + lights = list(lights()) + for l in lights: + viewer.DelLight(l) + + for dir in [(3,2,1), (-1,-2,-3)]: light = OCC.V3d.V3d_DirectionalLight(viewer_handle) light.SetDirection(*dir) viewer.SetLightOn(light.GetHandle()) + setup() return handle - +def yield_subshapes(shape): + it = OCC.TopoDS.TopoDS_Iterator(shape) + while it.More(): + yield it.Value() + it.Next() + def display_shape(shape, clr=None): - if not clr: + if isinstance(shape, shape_tuple): + shape, representation = shape.geometry, shape + else: representation is None + + material = OCC.Graphic3d.Graphic3d_MaterialAspect(OCC.Graphic3d.Graphic3d_NOM_PLASTER) + material.SetDiffuse(1) + + if representation and not clr: + if len(set(representation.styles)) == 1: + clr = representation.styles[0] + if min(clr) < 0. or max(clr) > 1.: + clr = DEFAULT_STYLES.get(representation.data.type, DEFAULT_STYLES["DEFAULT"]) + + if clr: + ais = OCC.AIS.AIS_Shape(shape) + ais.SetMaterial(material) + + if isinstance(clr, str): + qclr = getattr(OCC.Quantity, "Quantity_NOC_%s" % clr.upper(), getattr(OCC.Quantity, "Quantity_NOC_%s1" % clr.upper(), None)) + if qclr is None: + raise Exception("No color named '%s'" % clr.upper()) + elif isinstance(clr, Iterable): + clr = tuple(clr) + if len(clr) < 3 and len(clr) > 4: + raise Exception("Need 3 or 4 colour components. Got '%r'." % clr) + qclr = OCC.Quantity.Quantity_Color(clr[0], clr[1], clr[2], OCC.Quantity.Quantity_TOC_RGB) + elif isinstance(clr, OCC.Quantity.Quantity_Color): + qclr = clr + else: + raise Exception("Object of type %r cannot be used as a color." % type(clr)) + + ais.SetColor(qclr) + if isinstance(clr, tuple) and len(clr) == 4 and clr[3] < 1.: + ais.SetTransparency(1. - clr[3]) + + elif representation: + default_style_applied = None + + ais = OCC.AIS.AIS_MultipleConnectedShape(shape) + + subshapes = list(yield_subshapes(shape)) + lens = len(representation.styles), len(subshapes) + if lens[0] != lens[1]: + import warnings + warnings.warn("Unable to assign styles to subshapes. Encountered %d styles for %d shapes." % lens) + else: + for shp, stl in zip(subshapes, representation.styles): + subshape = OCC.AIS.AIS_Shape(shp) + if min(stl) < 0. or max(stl) > 1.: + default_style_applied = stl = DEFAULT_STYLES.get(representation.data.type, DEFAULT_STYLES["DEFAULT"]) + subshape.SetColor(OCC.Quantity.Quantity_Color(stl[0], stl[1], stl[2], OCC.Quantity.Quantity_TOC_RGB)) + subshape.SetMaterial(material) + if len(stl) == 4 and stl[3] < 1.: + subshape.SetTransparency(1. - stl[3]) + ais.Connect(subshape.GetHandle()) + + # For some reason it is necessary to set transparency here again + # in order for transparency to be rendered on the subshape. + applied_styles = representation.styles + if default_style_applied: + if len(default_style_applied) == 3: default_style_applied += (1.,) + applied_styles += (default_style_applied,) + + min_transp = min(map(operator.itemgetter(3), applied_styles)) + if min_transp < 1.: + ais.SetTransparency(1.) + + else: + ais = OCC.AIS.AIS_Shape(shape) + ais.SetMaterial(material) + r = lambda: random.random() * 0.3 + 0.7 clr = OCC.Quantity.Quantity_Color(r(), r(), r(), OCC.Quantity.Quantity_TOC_RGB) - return handle.DisplayShape(shape, color=clr, update=True) + ais.SetColor(clr) + + ais_handle = ais.GetHandle() + handle.Context.Display(ais_handle, False) + + return ais_handle def set_shape_transparency(ais, t): @@ -69,17 +174,22 @@ def get_bounding_box_center(bbox): def create_shape_from_serialization(brep_object): - brep_data, occ_shape = None, None + brep_data, occ_shape, styles = None, None, () is_product_shape = True try: brep_data = brep_object.geometry.brep_data + styles = brep_object.geometry.surface_styles except: try: brep_data = brep_object.brep_data + styles = brep_object.surface_styles is_product_shape = False except: pass - if not brep_data: return tuple(brep_object, None) + + styles = tuple(styles[i:i+4] for i in range(0, len(styles), 4)) + + if not brep_data: return shape_tuple(brep_object, None, styles) try: ss = OCC.BRepTools.BRepTools_ShapeSet() @@ -88,7 +198,7 @@ def create_shape_from_serialization(brep_object): except: pass if is_product_shape: - return tuple(brep_object, occ_shape) + return shape_tuple(brep_object, occ_shape, styles) else: return occ_shape diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index e0db875565..3d40ab9f7d 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -168,6 +168,7 @@ struct ShapeRTTI : public boost::static_visitor # Hide the getters with read-only property implementations id = property(id) brep_data = property(brep_data) + surface_styles = property(surface_styles) %} };