/src/examples/Level2/InteractiveFeatureTree/occ_model.py

http://pythonocc.googlecode.com/ · Python · 408 lines · 259 code · 89 blank · 60 comment · 34 complexity · bbc85ed99282244d3e318c579355283f MD5 · raw file

  1. #!/usr/bin/env python
  2. ##Copyright 2009-2011, Bryan Cole (bryancole.cam@googlemail.com)
  3. ##
  4. ##This file is part of pythonOCC.
  5. ##
  6. ##pythonOCC is free software: you can redistribute it and/or modify
  7. ##it under the terms of the GNU Lesser General Public License as published by
  8. ##the Free Software Foundation, either version 3 of the License, or
  9. ##(at your option) any later version.
  10. ##
  11. ##pythonOCC is distributed in the hope that it will be useful,
  12. ##but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ##GNU Lesser General Public License for more details.
  15. ##
  16. ##You should have received a copy of the GNU Lesser General Public License
  17. ##along with pythonOCC. If not, see <http://www.gnu.org/licenses/>.
  18. from enthought.traits.api import (HasTraits, Property, Bool,
  19. on_trait_change, cached_property, Instance,
  20. List, Str, Enum)
  21. from enthought.traits.ui.api import View, Item
  22. from utils import Tuple, EditorTraits, Int, Float, Range
  23. from OCC import TDF, TopoDS, BRepPrimAPI, BRepAlgoAPI, gp, BRepFilletAPI,\
  24. TNaming, TopTools
  25. from OCC.Utils.Topology import Topo
  26. ###defining an dedicated trait for filter inputs means
  27. ###we can track input changes easily
  28. Input = Instance(klass="ProcessObject", process_input=True)
  29. class ProcessObject(HasTraits):
  30. """
  31. Base class for all model component objects
  32. """
  33. name = Str
  34. #
  35. #This flag indicates if the object parameters have changed
  36. #
  37. modified = Bool(True)
  38. #
  39. #We could link each process-object to a node in an OCAF document
  40. #Not used yet.
  41. #
  42. label = Instance(TDF.TDF_Label)
  43. #
  44. #Parent TDF_label under which this label will be created
  45. #
  46. parent_label = Instance(TDF.TDF_Label)
  47. #
  48. #This is the output of the object. The property calls the execute method
  49. #to evaluate the result (which in turn calls up the tree)
  50. #
  51. shape = Property(Instance(TopoDS.TopoDS_Shape))
  52. #
  53. #Shadow trait which stores the cached shape
  54. #
  55. _shape = Instance(TopoDS.TopoDS_Shape)
  56. #
  57. #A list of all inputs, for the benefit of the TreeEditor
  58. #
  59. _inputs = List
  60. #
  61. #We hook up listeners to each input to listen to changes in their
  62. #modification trait. Hence, modifications propagate down the tree
  63. #
  64. @on_trait_change("+process_input")
  65. def on_input_change(self, obj, name, vold, vnew):
  66. print "ch", vold, vnew
  67. if vold is not None:
  68. vold.on_trait_change(self.on_modify, 'modified', remove=True)
  69. if vold in self._input_set:
  70. del self._inputs[self._inputs.index(vold)]
  71. vnew.on_trait_change(self.on_modify, 'modified')
  72. self._inputs.append(vnew)
  73. def _parent_label_changed(self, old_label, new_label):
  74. ts = TDF.TDF_TagSource()
  75. self.label = ts.NewChild(new_label)
  76. def on_modify(self, vnew):
  77. if vnew:
  78. self.modified = False
  79. self.modified = True
  80. def _get_shape(self):
  81. if self.modified:
  82. shape = self.execute()
  83. self._shape = shape
  84. self.modified = False
  85. return shape
  86. else:
  87. return self._shape
  88. def execute(self):
  89. """return a TopoDS_Shape object"""
  90. raise NotImplementedError
  91. def update_naming(self, make_shape):
  92. """called within the Execute method, to update the Naming
  93. Structure. This is key to getting Topological Naming to work"""
  94. raise NotImplementedError
  95. class TopologySource(ProcessObject):
  96. def update_naming(self, make_shape):
  97. """
  98. Create named shapes for the created primitive and all the
  99. sub-shapes we want to track. It seems sufficient to
  100. track faces. TNaming_Selector automatically identifies
  101. other topology (edges, vertices) based on the faces to
  102. which they belong
  103. """
  104. label = self.label
  105. shape = make_shape.Shape()
  106. builder = TNaming.TNaming_Builder(label)
  107. builder.Generated(shape)
  108. for i, face in enumerate(Topo(shape).faces()):
  109. f_label = label.FindChild(i+1) #creates a new label if it is not found
  110. builder = TNaming.TNaming_Builder(f_label)
  111. builder.Generated(face)
  112. class FilterSource(ProcessObject):
  113. def update_naming(self, make_shape):
  114. label = self.label
  115. shape = make_shape.Shape()
  116. input_shape = make_shape.Shape()
  117. builder = TNaming.TNaming_Builder(label)
  118. builder.Generated(input_shape, shape)
  119. #FindChild creates a new label, if one doesn't exist.
  120. #Label entry numbers are not necessarily incremental.
  121. #They are more like dictionary keys.
  122. gen_label = label.FindChild(1)
  123. mod_label = label.FindChild(2)
  124. del_label = label.FindChild(3)
  125. gen_builder = TNaming.TNaming_Builder(gen_label)
  126. mod_builder = TNaming.TNaming_Builder(mod_label)
  127. del_builder = TNaming.TNaming_Builder(del_label)
  128. topo = Topo(input_shape)
  129. for face in topo.faces():
  130. gen_shapes = make_shape.Generated(face)
  131. itr = TopTools.TopTools_ListIteratorOfListOfShape(gen_shapes)
  132. while itr.More():
  133. this = itr.Value()
  134. gen_builder.Generated(face, this)
  135. print "generated", face, this
  136. itr.Next()
  137. for face in topo.faces():
  138. mod_shapes = make_shape.Modified(face)
  139. itr = TopTools.TopTools_ListIteratorOfListOfShape(mod_shapes)
  140. while itr.More():
  141. this = itr.Value()
  142. mod_builder.Modified(face, this)
  143. print "modified", face, this
  144. itr.Next()
  145. for face in topo.faces():
  146. if make_shape.IsDeleted(face):
  147. del_builder.Delete(face)
  148. class BlockSource(TopologySource):
  149. name = "Block"
  150. dims = Tuple(10.0,20.0,30.0, editor_traits={'cols':3})
  151. position = Tuple(0.,0.,0., editor_traits={'cols':3})
  152. x_axis = Tuple(1.,0.,0., editor_traits={'cols':3})
  153. z_axis = Tuple(0.,0.,1., editor_traits={'cols':3})
  154. traits_view = View('name',
  155. 'dims',
  156. 'position',
  157. 'x_axis',
  158. 'z_axis',
  159. 'modified')
  160. @on_trait_change("dims, position, x_axis, z_axis")
  161. def on_edit(self):
  162. self.modified = False
  163. self.modified = True
  164. def execute(self):
  165. ax = gp.gp_Ax2(gp.gp_Pnt(*self.position),
  166. gp.gp_Dir(*self.z_axis),
  167. gp.gp_Dir(*self.x_axis))
  168. m_box = BRepPrimAPI.BRepPrimAPI_MakeBox(ax, *self.dims)
  169. self.update_naming(m_box)
  170. return m_box.Shape()
  171. class SphereSource(TopologySource):
  172. name="Sphere"
  173. radius = Float(5.0)
  174. position = Tuple(0.,0.,0., editor_traits={'cols':3})
  175. traits_view = View('name',
  176. 'radius',
  177. 'position',
  178. 'modified')
  179. @on_trait_change("radius, position")
  180. def on_edit(self):
  181. self.modified = False
  182. self.modified = True
  183. def execute(self):
  184. pt = gp.gp_Pnt(*self.position)
  185. R = self.radius
  186. sph = BRepPrimAPI.BRepPrimAPI_MakeSphere(pt, R)
  187. self.update_naming(sph)
  188. return sph.Shape()
  189. class BooleanOpFilter(FilterSource):
  190. name = "Boolean Operation"
  191. input = Input
  192. tool = Input
  193. operation = Enum("cut", "fuse", "common")
  194. map = {'cut': BRepAlgoAPI.BRepAlgoAPI_Cut,
  195. 'fuse': BRepAlgoAPI.BRepAlgoAPI_Fuse,
  196. 'common': BRepAlgoAPI.BRepAlgoAPI_Common}
  197. traits_view = View('operation',
  198. 'modified')
  199. def _operation_changed(self, vnew):
  200. self.name = "Boolean Op: %s"%vnew
  201. self.modified = False
  202. self.modified = True
  203. def execute(self):
  204. builder = self.map[self.operation]
  205. s1 = self.input.shape
  206. s2 = self.tool.shape
  207. bld = builder(s1, s2)
  208. self.update_naming(bld)
  209. return bld.Shape()
  210. def update_naming(self, make_shape):
  211. label = self.label
  212. shape = make_shape.Shape()
  213. input_shape = make_shape.Shape1()
  214. tool_shape = make_shape.Shape2()
  215. builder = TNaming.TNaming_Builder(label)
  216. builder.Generated(input_shape, shape)
  217. builder.Generated(tool_shape, shape)
  218. gen_label = label.FindChild(1)
  219. mod_label = label.FindChild(2)
  220. del_label = label.FindChild(3)
  221. gen_builder = TNaming.TNaming_Builder(gen_label)
  222. mod_builder = TNaming.TNaming_Builder(mod_label)
  223. del_builder = TNaming.TNaming_Builder(del_label)
  224. if make_shape.HasGenerated():
  225. for in_shape in [input_shape, tool_shape]:
  226. for face in Topo(in_shape).faces():
  227. gen_shapes = make_shape.Generated(face)
  228. itr = TopTools.TopTools_ListIteratorOfListOfShape(gen_shapes)
  229. while itr.More():
  230. this = itr.Value()
  231. gen_builder.Generated(face, this)
  232. print "generated", face, this
  233. itr.Next()
  234. if make_shape.HasModified():
  235. for face in Topo(input_shape).faces():
  236. mod_shapes = make_shape.Modified(face)
  237. itr = TopTools.TopTools_ListIteratorOfListOfShape(mod_shapes)
  238. while itr.More():
  239. this = itr.Value()
  240. mod_builder.Modify(face, this)
  241. print "modified", face, this
  242. itr.Next()
  243. for face in Topo(tool_shape).faces():
  244. mod_shapes = make_shape.Modified2(face)
  245. itr = TopTools.TopTools_ListIteratorOfListOfShape(mod_shapes)
  246. while itr.More():
  247. this = itr.Value()
  248. mod_builder.Modify(face, this)
  249. print "modified2", face, this
  250. itr.Next()
  251. if make_shape.HasDeleted():
  252. for face in Topo(input_shape).faces():
  253. if make_shape.IsDeleted(face):
  254. del_builder.Delete(face)
  255. for face in Topo(tool_shape).faces():
  256. if make_shape.IsDeleted(face):
  257. del_builder.Delete(face)
  258. class ChamferFilter(FilterSource):
  259. name = "Chamfer Filter"
  260. input = Input
  261. size = Float(1.0)
  262. _n_edges = Int(4)
  263. _low = Int(0)
  264. edge_id = Range(low='_low', high='_n_edges')
  265. selector = Instance(TNaming.TNaming_Selector)
  266. traits_view = View(Item('edge_id'),
  267. 'size',
  268. 'modified')
  269. def _size_changed(self, new_size):
  270. self.modified = False
  271. self.modified = True
  272. @on_trait_change("input, edge_id, label")
  273. def on_change_selection(self):
  274. new_id = self.edge_id
  275. input = self.input
  276. label = self.label
  277. if not all((input, label)): return
  278. input_shape = input.shape
  279. sel_label = self.label.FindChild(4)
  280. selector = TNaming.TNaming_Selector(sel_label)
  281. self.selector = selector
  282. topo = Topo(input_shape)
  283. self._n_edges = topo.number_of_edges()
  284. for i,edge in enumerate(topo.edges()):
  285. if i==new_id:
  286. selector.Select(edge, input_shape)
  287. print "got selection!"
  288. break
  289. else:
  290. print "no selection"
  291. self.modified = False
  292. self.modified = True
  293. def execute(self):
  294. input_shape = self.input.shape
  295. topo = Topo(input_shape)
  296. self._n_edges = topo.number_of_edges()
  297. builder = BRepFilletAPI.BRepFilletAPI_MakeChamfer(input_shape)
  298. Map = TDF.TDF_LabelMap()
  299. itr = TDF.TDF_ChildIterator(self.parent_label, True)
  300. while itr.More():
  301. sub_label = itr.Value()
  302. Map.Add(sub_label)
  303. itr.Next()
  304. selector = self.selector
  305. ret = selector.Solve(Map)
  306. if not ret:
  307. raise Exception("Failed to solve for edge")
  308. #print "Failed to solve for edge"
  309. nt = TNaming.TNaming_Tool()
  310. selected_shape = nt.CurrentShape(selector.NamedShape())
  311. selected_edge = TopoDS.TopoDS().Edge(selected_shape)
  312. try:
  313. face = Topo(input_shape).faces_from_edge(selected_edge).next()
  314. except RuntimeError:
  315. raise #not sure how to handle this
  316. size = self.size
  317. builder.Add(size, size, selected_edge, face)
  318. self.update_naming(builder)
  319. return builder.Shape()