From d8b1ea33f89a9693f61f69f6e12d16c343f37126 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Mon, 9 Aug 2021 10:59:24 +0200 Subject: [PATCH 1/8] remove internal edges in 2D fuse --- libsrc/occ/python_occ_shapes.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libsrc/occ/python_occ_shapes.cpp b/libsrc/occ/python_occ_shapes.cpp index ab3ac396..c62cb841 100644 --- a/libsrc/occ/python_occ_shapes.cpp +++ b/libsrc/occ/python_occ_shapes.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=4 #define OCC_HAVE_DUMP_JSON @@ -367,7 +368,13 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) { return shape.Located(loc); }) .def("__add__", [] (const TopoDS_Shape & shape1, const TopoDS_Shape & shape2) { - return BRepAlgoAPI_Fuse(shape1, shape2).Shape(); + auto fused = BRepAlgoAPI_Fuse(shape1, shape2).Shape(); + + // make one face when fusing in 2D + // from https://gitlab.onelab.info/gmsh/gmsh/-/issues/627 + ShapeUpgrade_UnifySameDomain unify(fused, true, true, true); + unify.Build(); + return unify.Shape(); }) .def("__mul__", [] (const TopoDS_Shape & shape1, const TopoDS_Shape & shape2) { From 0de8254ea2d47523b99f121cb721d26c7876cc7a Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Tue, 10 Aug 2021 20:28:49 +0200 Subject: [PATCH 2/8] spline-curves, curve tangents --- libsrc/occ/python_occ_shapes.cpp | 100 ++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/libsrc/occ/python_occ_shapes.cpp b/libsrc/occ/python_occ_shapes.cpp index c62cb841..1629edcc 100644 --- a/libsrc/occ/python_occ_shapes.cpp +++ b/libsrc/occ/python_occ_shapes.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -566,6 +568,22 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) auto curve = BRep_Tool::Curve(e, s0, s1); return curve->Value(s1); }) + .def_property_readonly("start_tangent", + [](const TopoDS_Edge & e) { + double s0, s1; + auto curve = BRep_Tool::Curve(e, s0, s1); + gp_Pnt p; gp_Vec v; + curve->D1(s0, p, v); + return v; + }) + .def_property_readonly("end_tangent", + [](const TopoDS_Edge & e) { + double s0, s1; + auto curve = BRep_Tool::Curve(e, s0, s1); + gp_Pnt p; gp_Vec v; + curve->D1(s1, p, v); + return v; + }) ; py::class_ (m, "TopoDS_Wire"); py::class_ (m, "TopoDS_Face") @@ -841,6 +859,55 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) }, py::arg("p1"), py::arg("v"), py::arg("p2")); + m.def("BSplineCurve", [](std::vector vpoles, int degree) { + // not yet working ???? + TColgp_Array1OfPnt poles(0, vpoles.size()-1); + TColStd_Array1OfReal knots(0, vpoles.size()+degree); + TColStd_Array1OfInteger mult(0, vpoles.size()+degree); + int cnt = 0; + try + { + for (int i = 0; i < vpoles.size(); i++) + { + poles.SetValue(i, vpoles[i]); + knots.SetValue(i, i); + mult.SetValue(i,1); + } + for (int i = vpoles.size(); i < vpoles.size()+degree+1; i++) + { + knots.SetValue(i, i); + mult.SetValue(i, 1); + } + + Handle(Geom_Curve) curve = new Geom_BSplineCurve(poles, knots, mult, degree); + return BRepBuilderAPI_MakeEdge(curve).Edge(); + } + catch (Standard_Failure & e) + { + stringstream errstr; + e.Print(errstr); + throw NgException("cannot create spline: "+errstr.str()); + } + }); + + m.def("BezierCurve", [](std::vector vpoles) { + TColgp_Array1OfPnt poles(0, vpoles.size()-1); + try + { + for (int i = 0; i < vpoles.size(); i++) + poles.SetValue(i, vpoles[i]); + + Handle(Geom_Curve) curve = new Geom_BezierCurve(poles); + return BRepBuilderAPI_MakeEdge(curve).Edge(); + } + catch (Standard_Failure & e) + { + stringstream errstr; + e.Print(errstr); + throw NgException("cannot create Bezier-spline: "+errstr.str()); + } + }); + m.def("Edge", [](Handle(Geom2d_Curve) curve2d, TopoDS_Face face) { auto edge = BRepBuilderAPI_MakeEdge(curve2d, BRep_Tool::Surface (face)).Edge(); BRepLib::BuildCurves3d(edge); @@ -849,32 +916,25 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) m.def("Wire", [](std::vector edges) { BRepBuilderAPI_MakeWire builder; - for (auto s : edges) - switch (s.ShapeType()) - { - case TopAbs_EDGE: - try - { - builder.Add(TopoDS::Edge(s)); break; - } - catch (Standard_Failure & e) - { - e.Print(cout); - throw NgException("cannot add to wire"); - } - case TopAbs_WIRE: - builder.Add(TopoDS::Wire(s)); break; - default: - throw Exception("can make wire only from edges and wires"); - } try { + for (auto s : edges) + switch (s.ShapeType()) + { + case TopAbs_EDGE: + builder.Add(TopoDS::Edge(s)); break; + case TopAbs_WIRE: + builder.Add(TopoDS::Wire(s)); break; + default: + throw Exception("can make wire only from edges and wires"); + } return builder.Wire(); } catch (Standard_Failure & e) { - e.Print(cout); - throw NgException("error in wire builder"); + stringstream errstr; + e.Print(errstr); + throw NgException("error in wire builder: "+errstr.str()); } }); From 73f387a7ed158ab969dc1a934e8d46eeecaee8a0 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Wed, 11 Aug 2021 11:00:05 +0200 Subject: [PATCH 3/8] UnifySameDomain is good for 2D, needs some more exploration --- libsrc/occ/python_occ_shapes.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libsrc/occ/python_occ_shapes.cpp b/libsrc/occ/python_occ_shapes.cpp index 1629edcc..5377876e 100644 --- a/libsrc/occ/python_occ_shapes.cpp +++ b/libsrc/occ/python_occ_shapes.cpp @@ -371,12 +371,12 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) .def("__add__", [] (const TopoDS_Shape & shape1, const TopoDS_Shape & shape2) { auto fused = BRepAlgoAPI_Fuse(shape1, shape2).Shape(); - + return fused; // make one face when fusing in 2D // from https://gitlab.onelab.info/gmsh/gmsh/-/issues/627 - ShapeUpgrade_UnifySameDomain unify(fused, true, true, true); - unify.Build(); - return unify.Shape(); + // ShapeUpgrade_UnifySameDomain unify(fused, true, true, true); + // unify.Build(); + // return unify.Shape(); }) .def("__mul__", [] (const TopoDS_Shape & shape1, const TopoDS_Shape & shape2) { From 56c59353bbd7f8535efc707822ac074d7b64e052 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Wed, 11 Aug 2021 21:54:45 +0200 Subject: [PATCH 4/8] surface normal --- libsrc/occ/python_occ_shapes.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libsrc/occ/python_occ_shapes.cpp b/libsrc/occ/python_occ_shapes.cpp index 5377876e..abd08a04 100644 --- a/libsrc/occ/python_occ_shapes.cpp +++ b/libsrc/occ/python_occ_shapes.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=4 #define OCC_HAVE_DUMP_JSON @@ -617,6 +618,13 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) surf->D1 (u,v,p,du,dv); return tuple(p,du,dv); }) + + .def("Normal", [] (const Handle(Geom_Surface) & surf, double u, double v) { + GeomLProp_SLProps lprop(surf,u,v,1,1e-8); + if (lprop.IsNormalDefined()) + return lprop.Normal(); + throw Exception("normal not defined"); + }) ; From d658985e69361cfef56266a70e908ba035f45085 Mon Sep 17 00:00:00 2001 From: Joachim Schoeberl Date: Wed, 11 Aug 2021 21:57:22 +0200 Subject: [PATCH 5/8] don't do own Newton for finding OCC u/v parameters (e.g. a problem for parameter domain for a sphere --- libsrc/occ/occmeshsurf.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libsrc/occ/occmeshsurf.cpp b/libsrc/occ/occmeshsurf.cpp index ff3d1ae3..8f815b5c 100644 --- a/libsrc/occ/occmeshsurf.cpp +++ b/libsrc/occ/occmeshsurf.cpp @@ -369,6 +369,9 @@ namespace netgen double u = gi.u; double v = gi.v; +#ifdef OLD + // was a problem for pheres: got u-v paramters outside range of definition + gp_Pnt x = occface->Value (u,v); if (p.SquareDistance(x) <= sqr(PROJECTION_TOLERANCE)) return; @@ -418,7 +421,7 @@ namespace netgen } } while (count < 20); - +#endif // Newton did not converge, use OCC projection From a7f836cb9ab3feaf531dab63f823c0efbb485ba2 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 12 Aug 2021 08:31:06 +0200 Subject: [PATCH 6/8] comment out debug output --- libsrc/occ/python_occ.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsrc/occ/python_occ.cpp b/libsrc/occ/python_occ.cpp index 7d120721..40ffb31d 100644 --- a/libsrc/occ/python_occ.cpp +++ b/libsrc/occ/python_occ.cpp @@ -322,9 +322,9 @@ DLL_HEADER void ExportNgOCC(py::module &m) cout << "handle(shape) = " << *(void**)(void*)(&(shape.TShape())) << endl; - TDF_LabelSequence doc_shapes; - shape_tool->GetShapes(doc_shapes); - cout << "shape tool nbentities: " << doc_shapes.Size() << endl; + // TDF_LabelSequence doc_shapes; + // shape_tool->GetShapes(doc_shapes); + // cout << "shape tool nbentities: " << doc_shapes.Size() << endl; TDF_Label label = shape_tool -> FindShape(shape); cout << "shape label = " << endl << label << endl; if (label.IsNull()) return; From ae6b23fffc149551b8e5a343a0ac4aa1e1ff8f4e Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 12 Aug 2021 11:20:07 +0200 Subject: [PATCH 7/8] add functionality to draw occ shapes with webgui --- libsrc/occ/python_occ_shapes.cpp | 97 ++++++++++++ python/CMakeLists.txt | 1 + python/webgui.py | 247 +++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 python/webgui.py diff --git a/libsrc/occ/python_occ_shapes.cpp b/libsrc/occ/python_occ_shapes.cpp index abd08a04..ea661ccb 100644 --- a/libsrc/occ/python_occ_shapes.cpp +++ b/libsrc/occ/python_occ_shapes.cpp @@ -56,6 +56,35 @@ using namespace netgen; +void ExtractFaceData( const TopoDS_Face & face, int index, std::vector * p, Box<3> & box ) +{ + Handle(Geom_Surface) surf = BRep_Tool::Surface (face); + + TopLoc_Location loc; + Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc); + + bool flip = TopAbs_REVERSED == face.Orientation(); + + int ntriangles = triangulation -> NbTriangles(); + for (int j = 1; j <= ntriangles; j++) + { + Poly_Triangle triangle = (triangulation -> Triangles())(j); + std::array,3> pts; + for (int k = 0; k < 3; k++) + pts[k] = occ2ng( (triangulation -> Nodes())(triangle(k+1)).Transformed(loc) ); + + if(flip) + Swap(pts[1], pts[2]); + + for (int k = 0; k < 3; k++) + { + box.Add(pts[k]); + for (int d = 0; d < 3; d++) + p[k].push_back( pts[k][d] ); + p[k].push_back( index ); + } + } +} py::object CastShape(const TopoDS_Shape & s) { @@ -543,6 +572,74 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) // return MoveToNumpyArray(triangles); return triangles; }) + .def("_webgui_data", [](const TopoDS_Shape & shape) + { + BRepTools::Clean (shape); + double deflection = 0.01; + BRepMesh_IncrementalMesh (shape, deflection, true); + // triangulation = BRep_Tool::Triangulation (face, loc); + + std::vector p[3]; + py::list names, colors; + + int index = 0; + + Box<3> box(Box<3>::EMPTY_BOX); + for (TopExp_Explorer e(shape, TopAbs_FACE); e.More(); e.Next()) + { + TopoDS_Face face = TopoDS::Face(e.Current()); + // Handle(TopoDS_Face) face = e.Current(); + ExtractFaceData(face, index, p, box); + auto & props = OCCGeometry::global_shape_properties[face.TShape()]; + if(props.col) + { + auto & c = *props.col; + colors.append(py::make_tuple(c[0], c[1], c[2])); + } + else + colors.append(py::make_tuple(0.0, 1.0, 0.0)); + if(props.name) + { + names.append(*props.name); + } + else + names.append(""); + index++; + } + + auto center = box.Center(); + + py::list mesh_center; + mesh_center.append(center[0]); + mesh_center.append(center[1]); + mesh_center.append(center[2]); + py::dict data; + data["ngsolve_version"] = "Netgen x.x"; // TODO + data["mesh_dim"] = 3; // TODO + data["mesh_center"] = mesh_center; + data["mesh_radius"] = box.Diam()/2; + data["order2d"] = 1; + data["order3d"] = 0; + data["draw_vol"] = false; + data["draw_surf"] = true; + data["funcdim"] = 0; + data["show_wireframe"] = false; + data["show_mesh"] = true; + data["edges"] = py::list{}; + data["Bezier_points"] = py::list{}; + py::list points; + points.append(p[0]); + points.append(p[1]); + points.append(p[2]); + data["Bezier_trig_points"] = points; + data["funcmin"] = 0; + data["funcmax"] = 1; + data["mesh_regions_2d"] = index; + data["autoscale"] = false; + data["colors"] = colors; + data["names"] = names; + return data; + }) ; py::class_ (m, "TopoDS_Vertex") diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 47910190..c3dc982b 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -3,6 +3,7 @@ configure_file(__init__.py ${CMAKE_CURRENT_BINARY_DIR}/__init__.py @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/__init__.py meshing.py csg.py geom2d.py stl.py gui.py NgOCC.py occ.py read_gmsh.py + webgui.py DESTINATION ${NG_INSTALL_DIR_PYTHON}/${NG_INSTALL_SUFFIX} COMPONENT netgen ) diff --git a/python/webgui.py b/python/webgui.py new file mode 100644 index 00000000..48f65811 --- /dev/null +++ b/python/webgui.py @@ -0,0 +1,247 @@ +import math +import numpy as np +from time import time +import os + +from webgui_jupyter_widgets import BaseWebGuiScene, encodeData, WebGuiDocuWidget +import webgui_jupyter_widgets.widget as wg + +class WebGLScene(BaseWebGuiScene): + def __init__(self, mesh, clipping, on_init): + from IPython.display import display, Javascript + import threading + self.mesh = mesh + self.clipping = clipping + self.on_init = on_init + + def GetData(self, set_minmax=True): + import json + # d = BuildRenderData(self.mesh, self.cf, self.order, draw_surf=self.draw_surf, draw_vol=self.draw_vol, deformation=self.deformation, region=self.region) + d = self.mesh._webgui_data() + bp = d['Bezier_trig_points'] + for i in range(len(bp)): + bp[i] = encodeData(np.array(bp[i])) + + + if self.clipping is not None: + d['clipping'] = True + if isinstance(self.clipping, dict): + allowed_args = ("x", "y", "z", "dist", "function", "pnt", "vec") + if "vec" in self.clipping: + vec = self.clipping["vec"] + self.clipping["x"] = vec[0] + self.clipping["y"] = vec[1] + self.clipping["z"] = vec[2] + if "pnt" in self.clipping: + d['mesh_center'] = list(self.clipping["pnt"]) + for name, val in self.clipping.items(): + if not (name in allowed_args): + raise Exception('Only {} allowed as arguments for clipping!'.format(", ".join(allowed_args))) + d['clipping_' + name] = val + + if self.on_init: + d['on_init'] = self.on_init + + return d + + +bezier_trig_trafos = { } # cache trafos for different orders + +def BuildRenderData(mesh, func, order=2, draw_surf=True, draw_vol=True, deformation=None, region=True): + d = {} + d['ngsolve_version'] = "Netgen" + d['mesh_dim'] = 3 # mesh.dim TODO + + d['order2d'] = 1 + d['order3d'] = 0 + + d['draw_vol'] = False + d['draw_surf'] = True + d['funcdim'] = 1 + + func2 = None + if func and func.is_complex: + d['is_complex'] = True + func1 = func[0].real + func2 = ngs.CoefficientFunction( (func[0].imag, 0.0) ) + elif func and func.dim>1: + func1 = func[0] + func2 = ngs.CoefficientFunction( tuple(func[i] if i we are just drawing a mesh, eval mesh element index instead + mats = mesh.GetMaterials() + bnds = mesh.GetBoundaries() + nmats = len(mesh.GetMaterials()) + nbnds = len(mesh.GetBoundaries()) + n = max(nmats, nbnds) + func1 = ngs.CoefficientFunction(list(range(n))) + n_regions = [0, 0, nmats, nbnds] + d['mesh_regions_2d'] = n_regions[mesh.dim] + d['mesh_regions_3d'] = nmats if mesh.dim==3 else 0 + d['funcdim'] = 0 + func1 = ngs.CoefficientFunction( (ngs.x, ngs.y, ngs.z, func1 ) ) + func0 = ngs.CoefficientFunction( (ngs.x, ngs.y, ngs.z, 0.0 ) ) + if deformation is not None: + func1 += ngs.CoefficientFunction((deformation, 0.0)) + func0 += ngs.CoefficientFunction((deformation, 0.0)) + + d['show_wireframe'] = False + d['show_mesh'] = True + if order2d>0: + og = order2d + d['show_wireframe'] = True + d['show_mesh'] = True + timer2.Start() + + timer3Bvals.Start() + + # transform point-values to Bernsteinbasis + def Binomial(n,i): return math.factorial(n) / math.factorial(i) / math.factorial(n-i) + def Bernstein(x, i, n): return Binomial(n,i) * x**i*(1-x)**(n-i) + Bvals = ngs.Matrix(og+1,og+1) + for i in range(og+1): + for j in range(og+1): + Bvals[i,j] = Bernstein(i/og, j, og) + iBvals = Bvals.I + timer3Bvals.Stop() + # print (Bvals) + # print (iBvals) + + + Bezier_points = [] + + ipts = [(i/og,0) for i in range(og+1)] + [(0, i/og) for i in range(og+1)] + [(i/og,1.0-i/og) for i in range(og+1)] + ir_trig = ngs.IntegrationRule(ipts, [0,]*len(ipts)) + ipts = [(i/og,0) for i in range(og+1)] + [(0, i/og) for i in range(og+1)] + [(i/og,1.0) for i in range(og+1)] + [(1.0, i/og) for i in range(og+1)] + ir_quad = ngs.IntegrationRule(ipts, [0,]*len(ipts)) + + vb = [ngs.VOL, ngs.BND][mesh.dim-2] + if region and region.VB() == vb: + vb = region + cf = func1 if draw_surf else func0 + timer2map.Start() + pts = mesh.MapToAllElements({ngs.ET.TRIG: ir_trig, ngs.ET.QUAD: ir_quad}, vb) + timer2map.Stop() + pmat = cf(pts) + + timermult.Start() + pmat = pmat.reshape(-1, og+1, 4) + if False: + BezierPnts = np.tensordot(iBvals.NumPy(), pmat, axes=(1,1)) + else: + BezierPnts = np.zeros( (og+1, pmat.shape[0], 4) ) + for i in range(4): + ngsmat = ngs.Matrix(pmat[:,:,i].transpose()) + BezierPnts[:,:,i] = iBvals * ngsmat + timermult.Stop() + + timer2list.Start() + for i in range(og+1): + Bezier_points.append(encodeData(BezierPnts[i])) + timer2list.Stop() + + d['Bezier_points'] = Bezier_points + + ipts = [(i/og,0) for i in range(og+1)] + ir_seg = ngs.IntegrationRule(ipts, [0,]*len(ipts)) + vb = [ngs.VOL, ngs.BND, ngs.BBND][mesh.dim-1] + if region and region.VB() == vb: + vb = region + pts = mesh.MapToAllElements(ir_seg, vb) + pmat = func0(pts) + pmat = pmat.reshape(-1, og+1, 4) + edge_data = np.tensordot(iBvals.NumPy(), pmat, axes=(1,1)) + edges = [] + for i in range(og+1): + edges.append(encodeData(edge_data[i])) + d['edges'] = edges + + ndtrig = int((og+1)*(og+2)/2) + + if og in bezier_trig_trafos.keys(): + iBvals_trig = bezier_trig_trafos[og] + else: + def BernsteinTrig(x, y, i, j, n): + return math.factorial(n)/math.factorial(i)/math.factorial(j)/math.factorial(n-i-j) \ + * x**i*y**j*(1-x-y)**(n-i-j) + Bvals = ngs.Matrix(ndtrig, ndtrig) + ii = 0 + for ix in range(og+1): + for iy in range(og+1-ix): + jj = 0 + for jx in range(og+1): + for jy in range(og+1-jx): + Bvals[ii,jj] = BernsteinTrig(ix/og, iy/og, jx, jy, og) + jj += 1 + ii += 1 + iBvals_trig = Bvals.I + bezier_trig_trafos[og] = iBvals_trig + + + # Bezier_points = [ [] for i in range(ndtrig) ] + Bezier_points = [] + + ipts = [(i/og,j/og) for j in range(og+1) for i in range(og+1-j)] + ir_trig = ngs.IntegrationRule(ipts, [0,]*len(ipts)) + ipts = ([(i/og,j/og) for j in range(og+1) for i in range(og+1-j)] + + [(1-i/og,1-j/og) for j in range(og+1) for i in range(og+1-j)]) + ir_quad = ngs.IntegrationRule(ipts, [0,]*len(ipts)) + + vb = [ngs.VOL, ngs.BND][mesh.dim-2] + if region and region.VB() == vb: + vb = region + pts = mesh.MapToAllElements({ngs.ET.TRIG: ir_trig, ngs.ET.QUAD: ir_quad}, vb) + + pmat = ngs.CoefficientFunction( func1 if draw_surf else func0 ) (pts) + + + funcmin = np.min(pmat[:,3]) + funcmax = np.max(pmat[:,3]) + pmin = np.min(pmat[:,0:3], axis=0) + pmax = np.max(pmat[:,0:3], axis=0) + + mesh_center = 0.5*(pmin+pmax) + mesh_radius = np.linalg.norm(pmax-pmin)/2 + + pmat = pmat.reshape(-1, len(ir_trig), 4) + + BezierPnts = np.tensordot(iBvals_trig.NumPy(), pmat, axes=(1,1)) + + for i in range(ndtrig): + Bezier_points.append(encodeData(BezierPnts[i])) + + + d['Bezier_trig_points'] = Bezier_points + d['mesh_center'] = list(mesh_center) + d['mesh_radius'] = mesh_radius + + + + if func: + d['funcmin'] = funcmin + d['funcmax'] = funcmax + return d + +def Draw(shape, clipping=None, js_code=None, filename=""): + # todo: also handle occ geometry, list of shapes, etc. + + scene = WebGLScene(shape, clipping=clipping, on_init=js_code) + + if wg._IN_IPYTHON: + if wg._IN_GOOGLE_COLAB: + from IPython.display import display, HTML + html = scene.GenerateHTML() + display(HTML(html)) + else: + # render scene using widgets.DOMWidget + scene.Draw() + return scene + else: + if filename: + scene.GenerateHTML(filename=filename) + return scene + From fb64f0d8736c869de3454e5cf284308135f3bf58 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Fri, 13 Aug 2021 16:46:49 +0200 Subject: [PATCH 8/8] geometry edges in webgui --- libsrc/occ/python_occ_shapes.cpp | 63 ++++++++++++++++++++++++++++++-- python/webgui.py | 3 ++ 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/libsrc/occ/python_occ_shapes.cpp b/libsrc/occ/python_occ_shapes.cpp index ea661ccb..e9bd6477 100644 --- a/libsrc/occ/python_occ_shapes.cpp +++ b/libsrc/occ/python_occ_shapes.cpp @@ -56,10 +56,34 @@ using namespace netgen; +void ExtractEdgeData( const TopoDS_Edge & edge, int index, std::vector * p, Box<3> & box ) +{ + if (BRep_Tool::Degenerated(edge)) return; + + Handle(Poly_PolygonOnTriangulation) poly; + Handle(Poly_Triangulation) T; + TopLoc_Location loc; + BRep_Tool::PolygonOnTriangulation(edge, poly, T, loc); + + int nbnodes = poly -> NbNodes(); + for (int j = 1; j < nbnodes; j++) + { + auto p0 = occ2ng((T -> Nodes())(poly->Nodes()(j)).Transformed(loc)); + auto p1 = occ2ng((T -> Nodes())(poly->Nodes()(j+1)).Transformed(loc)); + for(auto k : Range(3)) + { + p[0].push_back(p0[k]); + p[1].push_back(p1[k]); + } + p[0].push_back(index); + p[1].push_back(index); + box.Add(p0); + box.Add(p1); + } +} + void ExtractFaceData( const TopoDS_Face & face, int index, std::vector * p, Box<3> & box ) { - Handle(Geom_Surface) surf = BRep_Tool::Surface (face); - TopLoc_Location loc; Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc); @@ -606,6 +630,31 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) names.append(""); index++; } + + std::vector edge_p[2]; + py::list edge_names, edge_colors; + index = 0; + for (TopExp_Explorer e(shape, TopAbs_EDGE); e.More(); e.Next()) + { + TopoDS_Edge edge = TopoDS::Edge(e.Current()); + ExtractEdgeData(edge, index, edge_p, box); + auto & props = OCCGeometry::global_shape_properties[edge.TShape()]; + if(props.col) + { + auto & c = *props.col; + edge_colors.append(py::make_tuple(c[0], c[1], c[2])); + } + else + edge_colors.append(py::make_tuple(0.0, 0.0, 0.0)); + if(props.name) + { + edge_names.append(*props.name); + } + else + edge_names.append(""); + index++; + } + auto center = box.Center(); @@ -623,9 +672,8 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) data["draw_vol"] = false; data["draw_surf"] = true; data["funcdim"] = 0; - data["show_wireframe"] = false; + data["show_wireframe"] = true; data["show_mesh"] = true; - data["edges"] = py::list{}; data["Bezier_points"] = py::list{}; py::list points; points.append(p[0]); @@ -638,6 +686,13 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) data["autoscale"] = false; data["colors"] = colors; data["names"] = names; + + py::list edges; + edges.append(edge_p[0]); + edges.append(edge_p[1]); + data["edges"] = edges; + data["edge_names"] = edge_names; + data["edge_colors"] = edge_colors; return data; }) ; diff --git a/python/webgui.py b/python/webgui.py index 48f65811..b3a17ff4 100644 --- a/python/webgui.py +++ b/python/webgui.py @@ -22,6 +22,9 @@ class WebGLScene(BaseWebGuiScene): for i in range(len(bp)): bp[i] = encodeData(np.array(bp[i])) + ep = d['edges'] + for i in range(len(ep)): + ep[i] = encodeData(np.array(ep[i])) if self.clipping is not None: d['clipping'] = True