Open MAN90 opened 7 years ago
looks like aBoundSurfHandle
is a null object. Can you call aBoundSurfHandle.IsNull()
?
I think you can get the surface from the aGeomSurfHandle
's object.
It would be easier to help when provided with a complete example.
Hi, Thanks for the response.
Yes, aBoundSurfHandle
is NULL.
The function geomlib_ExtendSurfByLength()
requires a Handle_Geom_BoundedSurface
Below is the code of the function. Here, I first find the faces connected to the cylindrical surface forming the fillet and store them into neighbour_faces
. Then i want to extend these faces and find their intersection.
def remove_filet(solid, r_0) :
r_lim = 5
aSolidTopo = Topo(solid, True)
possible_fillet_surfs = get_possible_fillet_surfaces(solid, r_lim)
assert len(possible_fillet_surfs), "This solid has no surfaces which could have fillets"
for fillet_face in possible_fillet_surfs :
if is_simple_fillet(fillet_face, r_lim):
fillet_curves = get_fillet_curves(fillet_face)
aSurfHandle = BRep_Tool.Surface(fillet_face)
print("face is ",fillet_face)
# TODO find the surface connected to each edge of the fillet surface and store them as list of edge,surf pairs
neighbour_faces = list()
neighbour_face_edges = list()
aFaceTopo = Topo(fillet_face, True)
for edge in aFaceTopo.edges():
for face in aSolidTopo.faces_from_edge(edge):
if not(face.IsSame(fillet_face)):
neighbour_faces.append(face)
neighbour_face_edges.append(edge)
print("this face has ", len(neighbour_faces), " faces connected to it")
for n_face in neighbour_faces :
aGeomSurfHandle = BRep_Tool.Surface(n_face)
L = 2 * r_0
aBoundSurfHandle = Handle_Geom_BoundedSurface.DownCast(aGeomSurfHandle)
if aBoundSurfHandle.IsNull():
print ("this bounded surf handle is a null handle")
geomlib_ExtendSurfByLength(aBoundSurfHandle, L, 3, True, False)
color = Quantity_Color(random.random(),
random.random(),
random.random(),
Quantity_TOC_RGB)
display.DisplayColoredShape(n_face, color)
The picture below shows the 4 faces which I want to extend and the one surface missing is the one which forms the fillet.
Thanks and regards Paras
@MAN90 can u please copy/paste (or gist) a full code so that I can easily test your code
Personal note: maybe some relevant code can be found here https://github.com/tpaviot/oce/blob/master/src/ChFi3d/ChFi3d_Builder_C1.cxx
Hi, Here is the complete code with the test geometry. I need to find the intersection of surfaces which do not intersect currently, but would intersect when extended. Thus, I could get the original edge on which the fillet was built.
Has any solution been found for this case?
I tried to use the function geomlib_ExtendSurfByLength with the latest PythonOCC version 7.7.0 but I'm not able to let it work...maybe I'm doing something wrong. I just created a simple Geom_BSplineSurface and then I tried to extend it passing it directly to the function. Does anybody has a small code example that works with one of the latest versions?
Hello, I have problems too. As no working example popped out in the last five years, I was wondering if it is about users not handling the function properly (suggested by the "howto" flag) or if it is a deeper problem?
No progress on that side, here is the code updated to the latest pythonocc version:
# General Python Libraries
import os
import sys
import random
# OpenCASCADE libraries
from OCC.Core.STEPControl import STEPControl_Reader
from OCC.Core.IFSelect import IFSelect_RetDone, IFSelect_ItemsByEntity
from OCC.Core.TopoDS import TopoDS_Solid, TopoDS_Face
from OCC.Core.TopAbs import TopAbs_SOLID
from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_RGB
from OCC.Core.gp import gp_Circ, gp_Pnt
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge
from OCC.Core.BRep import BRep_Tool
from OCC.Core.GeomLib import geomlib
from OCC.Core.Geom import Geom_BoundedSurface
from OCC.Core.PrsDim import PrsDim_RadiusDimension
from OCC.Core.ShapeUpgrade import ShapeUpgrade_ShapeConvertToBezier
# Helper functions
from OCC.Extend.TopologyUtils import TopologyExplorer
# User Interface GUI
from OCC.Display.SimpleGui import init_display
#######################################################################################################################
# fucntion to read a STEP file and returns a list of solid shapes
def read_STEP(filepath):
step_reader = STEPControl_Reader()
status = step_reader.ReadFile(filepath)
if status == IFSelect_RetDone: # check status
failsonly = False
step_reader.PrintCheckLoad(failsonly, IFSelect_ItemsByEntity)
step_reader.PrintCheckTransfer(failsonly, IFSelect_ItemsByEntity)
ok = step_reader.TransferRoot(1)
_nbs = step_reader.NbShapes()
aResShape = step_reader.Shape(1)
else:
print("Error: can't read file.")
sys.exit(0)
solid_list = list()
aTopo = TopologyExplorer(aResShape)
num_solids = aTopo.number_of_solids()
print("number of solids imported form the STEP file : ", num_solids)
for solid in aTopo.solids():
solid_list.append(solid)
return solid_list
# function to check if an edge could be circular arc of a fillet
def could_be_fillet_curve(edge, r_0):
aRadDim = PrsDim_RadiusDimension(edge)
curve = aRadDim.Circle()
curve_radius = curve.Radius()
if curve_radius < r_0:
return curve_radius
else:
return False
# function which returns a list of possible fillet surfaces for a given solid
def get_possible_fillet_surfaces(solid, r_0):
aSolidTopo = TopologyExplorer(solid, True)
possible_surfaces = list()
# iterating over faces of the solid
for face in aSolidTopo.faces():
curve_ctr = 0
aFaceTopo = TopologyExplorer(face, True)
# iterating over edges of a face
for edge in aFaceTopo.edges():
if could_be_fillet_curve(edge, r_0):
curve_ctr += 1
if curve_ctr >= 2:
possible_surfaces.append(face)
return possible_surfaces
# fucntion to check if the face forms a simple fillet
def is_simple_fillet(face, r_0):
curve_radii = list()
aFaceTopo = TopologyExplorer(face, True)
for edge in aFaceTopo.edges():
r = could_be_fillet_curve(edge, r_0)
if r:
curve_radii.append(r)
if curve_radii.count(curve_radii[0]) == len(curve_radii) and len(curve_radii) == 2:
print("This surface forms a simple fillet ")
return True
else:
print("This surface does not form a simple fillet ")
return False
# function to get the curves for simple fillet
def get_fillet_curves(face):
aFaceTopo = TopologyExplorer(face)
curve_list = list()
for edge in aFaceTopo.edges():
aRadDim = PrsDim_RadiusDimension(edge)
curve_list.append(aRadDim.Circle())
return curve_list
# function to remove fillet
def remove_filet(solid, r_0):
r_lim = 5
aSolidTopo = TopologyExplorer(solid, True)
possible_fillet_surfs = get_possible_fillet_surfaces(solid, r_lim)
assert len(
possible_fillet_surfs
), "This solid has no surfaces which could have fillets"
for fillet_face in possible_fillet_surfs:
if is_simple_fillet(fillet_face, r_lim):
fillet_curves = get_fillet_curves(fillet_face)
aSurfHandle = BRep_Tool.Surface(fillet_face)
print("face is ", fillet_face)
# TODO find the surface connected to each edge of the fillet surface and store them as list of edge,surf pairs
neighbour_faces = list()
neighbour_face_edges = list()
aFaceTopo = TopologyExplorer(fillet_face, True)
for edge in aFaceTopo.edges():
for face in aSolidTopo.faces_from_edge(edge):
if not (face.IsSame(fillet_face)):
neighbour_faces.append(face)
neighbour_face_edges.append(edge)
print("this face has ", len(neighbour_faces), " faces connected to it")
for n_face in neighbour_faces:
aGeomSurf = BRep_Tool.Surface(n_face)
L = 2 * r_0
try:
aBoundSurf = Geom_BoundedSurface.DownCast(aGeomSurf)
geomlib.ExtendSurfByLength(aBoundSurf, L, 3, True, False)
except:
print("Surface extension failed")
color = Quantity_Color(
random.random(), random.random(), random.random(), Quantity_TOC_RGB
)
display.DisplayColoredShape(n_face, color)
if __name__ == "__main__":
# input parameters
FILEDIR = "Test_Geoms"
FILENAME = "BoxSingleFillet.STEP"
# reading the file to get the compound
filepath = FILENAME
solids = read_STEP(filepath)
# Initializing the GUI
display, start_display, add_menu, add_fucntion_to_menu = init_display()
# display.DisplayShape(solids[0])
remove_filet(solids[0], 0.01)
display.FitAll()
display.View_Top()
start_display()
The issue deals with the geomlib.ExtendSurfByLength
function, which takes a Geom_BoundedSurface
as a parameter, but the Donwcast fails
Thank you for your quick reply. Indeed arriving from a Geom_Surface
and trying to downcast with Geom_BoundedSurface
does not work. But additionnally, starting from a a Geom_BSplineSurface
which is a Geom_BoundedSurface
by inheritance does seem not work either (see the message above from @numerical2017 ) and in that case no downcast is needed. So maybe two different issues?
I never played with Geom_BoundedSurface
and geomlib.ExtendSurfByLength
, we should first try to have a simple and working example.
If I understand properly the code detailed above and initiated by @MAN90 , Geom_BoundedSurface.DownCast()
returns None
, so geomlib.ExtendSurfByLength
can't work because it receives None
as input. So there is a problem with Geom_BoundedSurface.DownCast()
. I leave this downcast problem on the side to only focus on geomlib.ExtendSurfByLength
In order to test geomlib.ExtendSurfByLength
without Downcast
, I reproduced what I think @numerical2017 did, see the code at the bottom. Instead of coming from a Geom_Curve
(arrow shown below on the left of the chart), the starting point is a Geom_BsplineSurface
(arrow on the right side). No downcast needed thanks to inheritance, right?
The example is basic, it is created based on the available example to generate a Bspline surface, and only one additional line of code is added for geomlib.ExtendSurfByLength
. It is unfortunately a non working example because the output surface is the same than the input. . Thank you for your help.
from OCC.Core.gp import gp_Pnt,gp_Vec
from OCC.Core.Geom import Geom_BezierSurface,Geom_BSplineSurface
from OCC.Core.TColGeom import TColGeom_Array2OfBezierSurface
from OCC.Core.TColgp import TColgp_Array2OfPnt
from OCC.Core.GeomConvert import GeomConvert_CompBezierSurfacesToBSplineSurface
from OCC.Display.SimpleGui import init_display
from OCC.Core.GeomLib import geomlib
#==============================================================================
def create_surface():
# Based on https://github.com/tpaviot/pythonocc-demos/blob/master/examples/core_geometry_bspline.py
array1 = TColgp_Array2OfPnt(1, 4, 1, 4)
array1.SetValue(1, 1, gp_Pnt(1, 1, -1))
array1.SetValue(1, 2, gp_Pnt(2, 1, 0))
array1.SetValue(1, 3, gp_Pnt(3, 1, -1))
array1.SetValue(1, 4, gp_Pnt(4, 1, 0))
array1.SetValue(2, 1, gp_Pnt(1, 2, 3))
array1.SetValue(2, 2, gp_Pnt(2, 2, 5))
array1.SetValue(2, 3, gp_Pnt(3, 2, 2))
array1.SetValue(2, 4, gp_Pnt(4, 2, 3))
array1.SetValue(3, 1, gp_Pnt(1, 3, 2))
array1.SetValue(3, 2, gp_Pnt(2, 3, 1))
array1.SetValue(3, 3, gp_Pnt(3, 3, 0))
array1.SetValue(3, 4, gp_Pnt(4, 3, 1))
array1.SetValue(4, 1, gp_Pnt(1, 4, 0))
array1.SetValue(4, 2, gp_Pnt(2, 4, -1))
array1.SetValue(4, 3, gp_Pnt(3, 4, 0))
array1.SetValue(4, 4, gp_Pnt(4, 4, -1))
a_bezier_surface = Geom_BezierSurface(array1)
a_bezier_array = TColGeom_Array2OfBezierSurface(1, 1, 1, 1)
a_bezier_array.SetValue(1, 1, a_bezier_surface)
a_converted_surface = GeomConvert_CompBezierSurfacesToBSplineSurface(a_bezier_array)
if not a_converted_surface.IsDone(): raise ValueError('GeomConvert failed')
poles = a_converted_surface.Poles()
uknots = a_converted_surface.UKnots()
vknots = a_converted_surface.VKnots()
umult = a_converted_surface.UMultiplicities()
vmult = a_converted_surface.VMultiplicities()
udeg = a_converted_surface.UDegree()
vdeg = a_converted_surface.VDegree()
a_bspline_surf = Geom_BSplineSurface( poles, uknots, vknots, umult, vmult, udeg, vdeg,False,False)
a_bspline_surf.Translate(gp_Vec(0,0,2))
return a_bspline_surf
#==============================================================================
if __name__ == '__main__':
display, start_display, add_menu, add_function_to_menu = init_display()
a_bspline_surf=create_surface()
display.DisplayShape(a_bspline_surf,color='BLUE',update=False)
Lenght=10 ; Cont=1 ; InU=True ; After=True
geomlib.ExtendSurfByLength(a_bspline_surf,Lenght,Cont,InU,After)
display.DisplayShape(a_bspline_surf,color='RED',update=True)
start_display()
Use geomconvert to create a bspline surface, see https://dev.opencascade.org/doc/refman/html/class_geom_convert.html#aec7d0c9e937cc0bcbe97fba8b3c360bf This is safer than downcast,as it will potentially also use some algorithms , if the surface is no bspline yet
BRepOffset_Tool.EnlargeFace
or BRepOffset_Tool.ExtendFace
should also be interesting pointers https://dev.opencascade.org/doc/refman/html/class_b_rep_offset___tool.html#add9d760d50704def44d1a8bb5b70a6cb
BRepOffset_Tool.EnlargeFace
works for my application. Thank you for your help
The meaning of the options is not fully clear to me though. I did not try BRepOffset_Tool.ExtentFace
and I have just seen there is also a BRepLib::ExtendFace
which might be helpful to understand how things work.
I am not affected by the other issue mentionned above, the Downcast
returning None
.
@Squirrel8475 thank you for the feedback, feel free to share any code snippet to explain you use case and how the BRepLib::ExtendFace
method can be used
@tpaviot sure, I just needed a bit more time but please find below the code snippet and the obtained results.
# -*- coding: utf-8 -*-
from OCC.Core.gp import gp_Pnt,gp_Vec
from OCC.Core.Geom import Geom_BezierSurface,Geom_BSplineSurface
from OCC.Core.TColGeom import TColGeom_Array2OfBezierSurface
from OCC.Core.TColgp import TColgp_Array2OfPnt
from OCC.Core.GeomConvert import GeomConvert_CompBezierSurfacesToBSplineSurface
from OCC.Display.SimpleGui import init_display
from OCC.Core.GeomLib import geomlib
from OCC.Core.BRepOffset import BRepOffset_Tool
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace
from OCC.Core.TopoDS import TopoDS_Face
#==============================================================================
def create_surface(event=None):
# Reference:
# https://github.com/tpaviot/pythonocc-demos/blob/master/examples/core_geometry_bspline.py
array1 = TColgp_Array2OfPnt(1, 4, 1, 4)
array1.SetValue(1, 1, gp_Pnt(1, 1, -1))
array1.SetValue(1, 2, gp_Pnt(2, 1, 0))
array1.SetValue(1, 3, gp_Pnt(3, 1, -1))
array1.SetValue(1, 4, gp_Pnt(4, 1, 0))
array1.SetValue(2, 1, gp_Pnt(1, 2, 3))
array1.SetValue(2, 2, gp_Pnt(2, 2, 5))
array1.SetValue(2, 3, gp_Pnt(3, 2, 2))
array1.SetValue(2, 4, gp_Pnt(4, 2, 3))
array1.SetValue(3, 1, gp_Pnt(1, 3, 2))
array1.SetValue(3, 2, gp_Pnt(2, 3, 1))
array1.SetValue(3, 3, gp_Pnt(3, 3, 0))
array1.SetValue(3, 4, gp_Pnt(4, 3, 1))
array1.SetValue(4, 1, gp_Pnt(1, 4, 0))
array1.SetValue(4, 2, gp_Pnt(2, 4, -1))
array1.SetValue(4, 3, gp_Pnt(3, 4, 0))
array1.SetValue(4, 4, gp_Pnt(4, 4, -1))
a_bezier_surface = Geom_BezierSurface(array1)
a_bezier_array = TColGeom_Array2OfBezierSurface(1, 1, 1, 1)
a_bezier_array.SetValue(1, 1, a_bezier_surface)
a_converted_surface = GeomConvert_CompBezierSurfacesToBSplineSurface(a_bezier_array)
if not a_converted_surface.IsDone(): raise ValueError('GeomConvert failed')
poles = a_converted_surface.Poles()
uknots = a_converted_surface.UKnots()
vknots = a_converted_surface.VKnots()
umult = a_converted_surface.UMultiplicities()
vmult = a_converted_surface.VMultiplicities()
udeg = a_converted_surface.UDegree()
vdeg = a_converted_surface.VDegree()
a_bspline_surf = Geom_BSplineSurface( poles, uknots, vknots, umult, vmult, udeg, vdeg,False,False)
a_bspline_surf.Translate(gp_Vec(0,0,2))
return a_bspline_surf
#==============================================================================
if __name__ == '__main__':
# Surface extension - trials and errors
# Warning: using multiple instances of Display is not a valid approach, just for quick & dirty purpose here
# Create a Bspline surface and the corresponging TopoDS Face
# A Bspline surface is chosen as it seems not possible to come
# from a Geom_Surface due to the Downcast returning None as per
# ticket #445 from @Man90. The ticket is still open for this issue.
# https://github.com/tpaviot/pythonocc-core/issues/445
a_bspline_surf=create_surface()
a_face_maker=BRepBuilderAPI_MakeFace(a_bspline_surf,1e-6)
a_face_maker.Build()
the_original_topods_face=a_face_maker.Face()
# First try: geomlib.ExtendSurfByLength
#============================================
# Should be similar to the description of @numerical2017
# in ticket https://github.com/tpaviot/pythonocc-core/issues/445
Lenght=10 ; Cont=1 ; InU=True ; After=True
geomlib.ExtendSurfByLength(a_bspline_surf,Lenght,Cont,InU,After)
display, start_display, add_menu, add_function_to_menu = init_display()
display.DisplayShape(a_bspline_surf,color='red',update=False)
display.DisplayShape(the_original_topods_face,color='cyan',update=True)
start_display()
# This example is not working as the surface is not modified, more work
# needed here to clarify the usage.
# Second try: BRepOffset_Tool.EnLargeFace
#==============================================
#
# * Dev doc:
# https://dev.opencascade.org/doc/refman/html/class_b_rep_offset___tool.html#add9d760d50704def44d1a8bb5b70a6cb
#
ChangeGeom = True
UpDatePCurve = True
enlargeu = True
enlargeVfirst = True
enlargeVlast = True
theExtensionMode =2
lenght =0.5
theLenBeforeUfirst = lenght
theLenAfterUlast = lenght
theLenBeforeVfirst = lenght
theLenAfterVlast = lenght
a_new_topo_ds_face = TopoDS_Face()
BRepOffset_Tool.EnLargeFace(the_original_topods_face,a_new_topo_ds_face,ChangeGeom,
UpDatePCurve,enlargeu,enlargeVfirst,enlargeVlast,theExtensionMode,
theLenBeforeUfirst, theLenAfterUlast, theLenBeforeVfirst, theLenAfterVlast)
display, start_display, add_menu, add_function_to_menu = init_display()
display.DisplayShape(a_new_topo_ds_face,color='red',update=False)
display.DisplayShape(the_original_topods_face,color='cyan',update=True)
start_display()
# This example is producing a modified surface, but it is not simply
# an extension: the "corners" are "joined". It might make sense that
# additionnal algorithms are running behing because the class
# belonging to the "Offset" package, for instance offseting faces from
# a dice required offset + extension + blending the corners, but
# no further digging was done to clarify that.
# BRepOffset_Tool.ExtentFace also not tested.
# Third try: breplib_ExtendFace
#==============================================
#
from OCC.Core.BRepLib import breplib_ExtendFace
theExtVal=0.5
theExtUMin=False
theExtUMax=False
theExtVMin=True
theExtVMax=True
the_modified_topods_face=TopoDS_Face()
breplib_ExtendFace(the_original_topods_face,theExtVal,theExtUMin,theExtUMax,
theExtVMin, theExtVMax, the_modified_topods_face)
display, start_display, add_menu, add_function_to_menu = init_display()
display.DisplayShape(the_modified_topods_face,color='red',update=False)
display.DisplayShape(the_original_topods_face,color='cyan',update=True)
start_display()
# Faces are extended with the behavior expected for my application
# Other classes that might be related to same topic
#==============================================
# BRepOffset_Tool.ExtentFace
I am working on removal of fillets from a solid imported as STEP file. I could determine the surfaces connected to the fillet surface and now need to extend them in order to find their intersection. Here is the relevant code snippet: for n_face in neighbour_faces : aGeomSurfHandle = BRep_Tool.Surface(n_face) aBoundSurfHandle = Handle_Geom_BoundedSurface.DownCast(aGeomSurfHandle) L = 2 * r_0 geomlib_ExtendSurfByLength(aBoundSurfHandle, L, 1, True, False)
Here, neighbour_faces is a list of the faces, r_0 is the fillet radius I get the following error: File "C:\Program Files\Anaconda3\lib\site-packages\OCC\GeomLib.py", line 617, in geomlib_ExtendSurfByLength return _GeomLib.geomlib_ExtendSurfByLength(*args) RuntimeError: Standard_NullObject GeomAdaptor_Surface::Load
Could someone please help me understand where I went wrong. I use the following software config: Anaconda 3; PythonOCC-core 0.17; Python 3.5.2
Thanks and regards Paras