├── icons
├── abcl.gif
├── acl.gif
├── cc3p.gif
├── circ.gif
├── hcl.gif
├── hvcl.gif
├── join.gif
├── lbcl.gif
├── line.gif
├── poly.gif
├── rect.gif
├── sep.gif
├── slot.gif
├── tpcl.gif
├── vcl.gif
├── arc3p.gif
├── arcc2p.gif
├── array.gif
├── cccirc.gif
├── ccirc.gif
├── cctan2.gif
├── cctan3.gif
├── cltan1.gif
├── cltan2.gif
├── del_c.gif
├── del_el.gif
├── del_g.gif
├── fillet.gif
├── parcl.gif
├── perpcl.gif
├── rotate.gif
├── split.gif
├── refangcl.gif
├── stretch.gif
└── translate.gif
├── OCCUtils
├── __init__.py
├── wire.py
├── solid.py
├── Image.py
├── shell.py
├── vertex.py
├── Iteration.py
├── base.py
├── types_lut.py
├── face.py
├── edge.py
└── Topology.py
├── treelib
├── exceptions.py
├── plugins.py
├── __init__.py
└── node.py
├── misc
├── circleexample.py
├── myqtDisplay.py
├── example.py
├── example1.py
├── buildFaceBottomUp.py
├── tkrpncalc.py
├── core_topology_local_ops.py
└── bottle.py
├── waysToMoveShape.txt
├── display.txt
├── README.md
├── sew.py
├── myStepXcafReader.py
├── step
└── tiltedCup.stp
└── unusedDynamic.py
/icons/abcl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/abcl.gif
--------------------------------------------------------------------------------
/icons/acl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/acl.gif
--------------------------------------------------------------------------------
/icons/cc3p.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/cc3p.gif
--------------------------------------------------------------------------------
/icons/circ.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/circ.gif
--------------------------------------------------------------------------------
/icons/hcl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/hcl.gif
--------------------------------------------------------------------------------
/icons/hvcl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/hvcl.gif
--------------------------------------------------------------------------------
/icons/join.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/join.gif
--------------------------------------------------------------------------------
/icons/lbcl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/lbcl.gif
--------------------------------------------------------------------------------
/icons/line.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/line.gif
--------------------------------------------------------------------------------
/icons/poly.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/poly.gif
--------------------------------------------------------------------------------
/icons/rect.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/rect.gif
--------------------------------------------------------------------------------
/icons/sep.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/sep.gif
--------------------------------------------------------------------------------
/icons/slot.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/slot.gif
--------------------------------------------------------------------------------
/icons/tpcl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/tpcl.gif
--------------------------------------------------------------------------------
/icons/vcl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/vcl.gif
--------------------------------------------------------------------------------
/icons/arc3p.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/arc3p.gif
--------------------------------------------------------------------------------
/icons/arcc2p.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/arcc2p.gif
--------------------------------------------------------------------------------
/icons/array.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/array.gif
--------------------------------------------------------------------------------
/icons/cccirc.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/cccirc.gif
--------------------------------------------------------------------------------
/icons/ccirc.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/ccirc.gif
--------------------------------------------------------------------------------
/icons/cctan2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/cctan2.gif
--------------------------------------------------------------------------------
/icons/cctan3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/cctan3.gif
--------------------------------------------------------------------------------
/icons/cltan1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/cltan1.gif
--------------------------------------------------------------------------------
/icons/cltan2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/cltan2.gif
--------------------------------------------------------------------------------
/icons/del_c.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/del_c.gif
--------------------------------------------------------------------------------
/icons/del_el.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/del_el.gif
--------------------------------------------------------------------------------
/icons/del_g.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/del_g.gif
--------------------------------------------------------------------------------
/icons/fillet.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/fillet.gif
--------------------------------------------------------------------------------
/icons/parcl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/parcl.gif
--------------------------------------------------------------------------------
/icons/perpcl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/perpcl.gif
--------------------------------------------------------------------------------
/icons/rotate.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/rotate.gif
--------------------------------------------------------------------------------
/icons/split.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/split.gif
--------------------------------------------------------------------------------
/icons/refangcl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/refangcl.gif
--------------------------------------------------------------------------------
/icons/stretch.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/stretch.gif
--------------------------------------------------------------------------------
/icons/translate.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tpaviot/cadviewer/master/icons/translate.gif
--------------------------------------------------------------------------------
/OCCUtils/__init__.py:
--------------------------------------------------------------------------------
1 | from OCCUtils.Common import get_boundingbox
2 | from OCCUtils.Topology import Topo
3 |
--------------------------------------------------------------------------------
/treelib/exceptions.py:
--------------------------------------------------------------------------------
1 | class NodePropertyError(Exception):
2 | """Basic Node attribute error"""
3 | pass
4 |
5 |
6 | class NodeIDAbsentError(NodePropertyError):
7 | """Exception throwed if a node's identifier is unknown"""
8 | pass
9 |
10 |
11 | class NodePropertyAbsentError(NodePropertyError):
12 | """Exception throwed if a node's data property is not specified"""
13 | pass
14 |
15 |
16 | class MultipleRootError(Exception):
17 | """Exception throwed if more than one root exists in a tree."""
18 | pass
19 |
20 |
21 | class DuplicatedNodeIdError(Exception):
22 | """Exception throwed if an identifier already exists in a tree."""
23 | pass
24 |
25 |
26 | class LinkPastRootNodeError(Exception):
27 | """
28 | Exception throwed in Tree.link_past_node() if one attempts
29 | to "link past" the root node of a tree.
30 | """
31 | pass
32 |
33 |
34 | class InvalidLevelNumber(Exception):
35 | pass
36 |
37 |
38 | class LoopError(Exception):
39 | """
40 | Exception thrown if trying to move node B to node A's position
41 | while A is B's ancestor.
42 | """
43 | pass
44 |
45 |
46 |
--------------------------------------------------------------------------------
/misc/circleexample.py:
--------------------------------------------------------------------------------
1 | from OCC.gp import gp_Pnt, gp_Pnt2d, gp_OX2d
2 | from OCC.Geom2d import Geom2d_Circle
3 | from OCC.Geom2dAdaptor import Geom2dAdaptor_Curve
4 | from OCC.GCPnts import GCPnts_UniformAbscissa
5 |
6 | from OCC.Display.SimpleGui import init_display
7 | display, start_display, add_menu, add_function_to_menu = init_display()
8 |
9 |
10 | def points_from_curve():
11 | radius = 5.
12 | abscissa = 3.
13 | circle = Geom2d_Circle(gp_OX2d(), radius, True)
14 | gac = Geom2dAdaptor_Curve(circle.GetHandle())
15 | ua = GCPnts_UniformAbscissa(gac, abscissa)
16 | a_sequence = []
17 | if ua.IsDone():
18 | n = ua.NbPoints()
19 | for count in range(1, n + 1):
20 | p = gp_Pnt2d()
21 | circle.D0(ua.Parameter(count), p)
22 | a_sequence.append(p)
23 | # convert analytic to bspline
24 | display.DisplayShape(circle, update=True)
25 | i = 0
26 | for p in a_sequence:
27 | i = i + 1
28 | pstring = 'P%i : parameter %f' % (i, ua.Parameter(i))
29 | pnt = gp_Pnt(p.X(), p.Y(), 0)
30 | # display points
31 | display.DisplayShape(pnt, update=True)
32 | display.DisplayMessage(pnt, pstring)
33 |
34 | if __name__ == '__main__':
35 | points_from_curve()
36 | start_display()
37 |
--------------------------------------------------------------------------------
/treelib/plugins.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # Copyright (C) 2011
4 | # Brett Alistair Kromkamp - brettkromkamp@gmail.com
5 | # Copyright (C) 2012-2017
6 | # Xiaming Chen - chenxm35@gmail.com
7 | # and other contributors.
8 | # All rights reserved.
9 | #
10 | # Licensed under the Apache License, Version 2.0 (the "License");
11 | # you may not use this file except in compliance with the License.
12 | # You may obtain a copy of the License at
13 | #
14 | # http://www.apache.org/licenses/LICENSE-2.0
15 | #
16 | # Unless required by applicable law or agreed to in writing, software
17 | # distributed under the License is distributed on an "AS IS" BASIS,
18 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | # See the License for the specific language governing permissions and
20 | # limitations under the License.
21 | """
22 | This is a public location to maintain contributed
23 | utilities to extend the basic Tree class.
24 |
25 | Deprecated! We prefer a unified processing of Tree object.
26 | """
27 | from __future__ import unicode_literals
28 |
29 | import codecs
30 |
31 |
32 | def export_to_dot(tree, filename=None, shape='circle', graph='digraph'):
33 | """Exports the tree in the dot format of the graphviz software"""
34 | print('Deprecated module. Use `tree.to_graphviz()` instead.')
35 | tree.to_graphviz(filename=filename, shape=shape, graph=graph)
36 |
--------------------------------------------------------------------------------
/waysToMoveShape.txt:
--------------------------------------------------------------------------------
1 | Ways to move a TopoDS_shape:
2 |
3 | # TopLoc_Location
4 | # as shown in
5 | tFace = BRepBuilderAPI_MakeFace(mFace).Face()
6 | faceNormal = Construct.face_normal(mFace)
7 | vctr = gp_Vec(faceNormal).Multiplied(value)
8 | trsf = gp_Trsf()
9 | trsf.SetTranslation(vctr)
10 | tFace.Move(TopLoc_Location(trsf))
11 |
12 | # BRepBuilderAPI_Transform
13 | # as shown in core_topology_boolean.py
14 |
15 | def translate_topods_from_vector(brep_or_iterable, vec, copy=False):
16 | '''
17 | translate a brep over a vector
18 | @param brep: the Topo_DS to translate
19 | @param vec: the vector defining the translation
20 | @param copy: copies to brep if True
21 | '''
22 | trns = gp_Trsf()
23 | trns.SetTranslation(vec)
24 | brep_trns = BRepBuilderAPI_Transform(brep_or_iterable, trns, copy)
25 | brep_trns.Build()
26 | return brep_trns.Shape()
27 |
28 |
29 | # as shown in core_classic_occ_bottle.py
30 | # Create a wire out of the edges
31 | aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(), aEdge2.Edge(), aEdge3.Edge())
32 |
33 | # Quick way to specify the X axis
34 | xAxis = gp_OX()
35 |
36 | # Set up the mirror
37 | aTrsf = gp_Trsf()
38 | aTrsf.SetMirror(xAxis)
39 |
40 | # Apply the mirror transformation
41 | aBRespTrsf = BRepBuilderAPI_Transform(aWire.Wire(), aTrsf)
42 |
43 | # Get the mirrored shape back out of the transformation and convert back to a wire
44 | aMirroredShape = aBRespTrsf.Shape()
45 |
46 | # A wire instead of a generic shape now
47 | aMirroredWire = topods.Wire(aMirroredShape)
48 |
49 |
--------------------------------------------------------------------------------
/OCCUtils/wire.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | ##Copyright 2008-2013 Jelle Feringa (jelleferinga@gmail.com)
4 | ##
5 | ##This file is part of pythonOCC.
6 | ##
7 | ##pythonOCC is free software: you can redistribute it and/or modify
8 | ##it under the terms of the GNU Lesser General Public License as published by
9 | ##the Free Software Foundation, either version 3 of the License, or
10 | ##(at your option) any later version.
11 | ##
12 | ##pythonOCC is distributed in the hope that it will be useful,
13 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | ##GNU Lesser General Public License for more details.
16 | ##
17 | ##You should have received a copy of the GNU Lesser General Public License
18 | ##along with pythonOCC. If not, see
19 |
20 | from OCC.Core.TopoDS import TopoDS_Wire
21 |
22 | from OCCUtils.base import BaseObject
23 |
24 |
25 | class Wire(TopoDS_Wire, BaseObject):
26 | def __init__(self, wire):
27 | '''
28 | '''
29 | assert isinstance(wire, TopoDS_Wire), 'need a TopoDS_Wire, got a %s' % wire.__class__
30 | assert not wire.IsNull()
31 | super(Wire, self).__init__()
32 | BaseObject.__init__(self, 'wire')
33 | # we need to copy the base shape using the following three
34 | # lines
35 | assert self.IsNull()
36 | self.TShape(wire.TShape())
37 | self.Location(wire.Location())
38 | self.Orientation(wire.Orientation())
39 | assert not self.IsNull()
40 |
--------------------------------------------------------------------------------
/display.txt:
--------------------------------------------------------------------------------
1 | Context
2 | Context_handle
3 | Create
4 | DisableAntiAliasing
5 | DisplayColoredShape
6 | DisplayMessage
7 | DisplayShape
8 | DisplayVector
9 | DynamicZoom
10 | EnableAntiAliasing
11 | EraseAll
12 | ExportToImage
13 | FitAll
14 | GetContext
15 | GetSelectedShape
16 | GetSelectedShapes
17 | GetView
18 | GetViewer
19 | Init
20 | MoveTo
21 | OnResize
22 | Pan
23 | Repaint
24 | ResetView
25 | Rotation
26 | Select
27 | SelectArea
28 | SetBackgroundImage
29 | SetDoubleBuffer
30 | SetModeHLR
31 | SetModeShaded
32 | SetModeWireFrame
33 | SetOrthographic
34 | SetSelectionMode
35 | SetSelectionModeEdge
36 | SetSelectionModeFace
37 | SetSelectionModeNeutral
38 | SetSelectionModeShape
39 | SetSelectionModeVertex
40 | ShiftSelect
41 | StartRotation
42 | Test
43 | Tumble
44 | View
45 | View_Bottom
46 | View_Front
47 | View_Iso
48 | View_Left
49 | View_Rear
50 | View_Right
51 | View_Top
52 | View_handle
53 | Viewer
54 | Viewer_handle
55 | Zoom
56 | ZoomArea
57 | ZoomFactor
58 | __class__
59 | __delattr__
60 | __dict__
61 | __doc__
62 | __format__
63 | __getattribute__
64 | __hash__
65 | __init__
66 | __module__
67 | __new__
68 | __reduce__
69 | __reduce_ex__
70 | __repr__
71 | __setattr__
72 | __sizeof__
73 | __str__
74 | __subclasshook__
75 | __swig_destroy__
76 | __weakref__
77 | _inited
78 | _local_context_opened
79 | _select_callbacks
80 | _struc_mgr
81 | _window_handle
82 | display_graduated_trihedron
83 | display_trihedron
84 | register_select_callback
85 | selected_shape
86 | selected_shapes
87 | set_bg_gradient_color
88 | set_raytracing_mode
89 | this
90 | thisown
91 | unregister_callback
92 |
--------------------------------------------------------------------------------
/treelib/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2011
2 | # Brett Alistair Kromkamp - brettkromkamp@gmail.com
3 | # Copyright (C) 2012-2017
4 | # Xiaming Chen - chenxm35@gmail.com
5 | # and other contributors.
6 | # All rights reserved.
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 | """
20 | treelib - Python 2/3 Tree Implementation
21 |
22 | `treelib` is a Python module with two primary classes: Node and Tree.
23 | Tree is a self-contained structure with some nodes and connected by branches.
24 | A tree owns merely a root, while a node (except root) has some children and one parent.
25 |
26 | Note: To solve string compatibility between Python 2.x and 3.x, treelib follows
27 | the way of porting Python 3.x to 2/3. That means, all strings are manipulated as
28 | unicode and you do not need u'' prefix anymore. The impacted functions include `str()`,
29 | `show()` and `save2file()` routines.
30 | But if your data contains non-ascii characters and Python 2.x is used,
31 | you have to trigger the compatibility by declaring `unicode_literals` in the code:
32 |
33 | .. code-block:: python
34 |
35 | >>> from __future__ import unicode_literals
36 | """
37 | __version__ = '1.5.5'
38 |
39 | from .tree import Tree
40 | from .node import Node
41 |
--------------------------------------------------------------------------------
/OCCUtils/solid.py:
--------------------------------------------------------------------------------
1 | ##Copyright 2008-2013 Jelle Feringa (jelleferinga@gmail.com)
2 | ##
3 | ##This file is part of pythonOCC.
4 | ##
5 | ##pythonOCC is free software: you can redistribute it and/or modify
6 | ##it under the terms of the GNU Lesser General Public License as published by
7 | ##the Free Software Foundation, either version 3 of the License, or
8 | ##(at your option) any later version.
9 | ##
10 | ##pythonOCC is distributed in the hope that it will be useful,
11 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ##GNU Lesser General Public License for more details.
14 | ##
15 | ##You should have received a copy of the GNU Lesser General Public License
16 | ##along with pythonOCC. If not, see
17 |
18 | from OCC.Core.TopoDS import TopoDS_Solid
19 |
20 | from OCCUtils.Topology import Topo
21 | from OCCUtils.base import GlobalProperties, BaseObject
22 | from OCCUtils.shell import Shell
23 |
24 |
25 | class Solid(TopoDS_Solid, BaseObject):
26 | def __init__(self, solid):
27 | assert isinstance(solid, TopoDS_Solid), 'need a TopoDS_Solid, got a %s' % solid.__class__
28 | assert not solid.IsNull()
29 | super(Solid, self).__init__()
30 | BaseObject.__init__(self, 'solid')
31 | # we need to copy the base shape using the following three
32 | # lines
33 | assert self.IsNull()
34 | self.TShape(solid.TShape())
35 | self.Location(solid.Location())
36 | self.Orientation(solid.Orientation())
37 | assert not self.IsNull()
38 |
39 | self.GlobalProperties = GlobalProperties(self)
40 |
41 | def shells(self):
42 | return (Shell(sh) for sh in Topo(self))
43 |
--------------------------------------------------------------------------------
/misc/myqtDisplay.py:
--------------------------------------------------------------------------------
1 |
2 | from OCC.Display import qtDisplay
3 | from OCC.Display.backend import get_qt_modules
4 |
5 | QtCore, QtGui, QtWidgets, QtOpenGL = get_qt_modules()
6 |
7 | class point(object):
8 | def __init__(self, obj=None):
9 | self.x = 0
10 | self.y = 0
11 | if obj is not None:
12 | self.set(obj)
13 |
14 | def set(self, obj):
15 | self.x = obj.x()
16 | self.y = obj.y()
17 |
18 | class MyqtViewer3d(qtDisplay.qtViewer3d):
19 | " Modify qtViewer3d to emit signals"
20 |
21 | def mousePressEvent(self, event):
22 | self.emit(QtCore.SIGNAL("LMBPressed"))
23 | #print 'LMBPressed signal emitted.'
24 | self.setFocus()
25 | self.dragStartPos = point(event.pos())
26 | self._display.StartRotation(self.dragStartPos.x, self.dragStartPos.y)
27 |
28 | def mouseReleaseEvent(self, event):
29 | self.emit(QtCore.SIGNAL("LMBReleased"))
30 | #print 'LMBReleased signal emitted.'
31 | pt = point(event.pos())
32 | modifiers = event.modifiers()
33 |
34 | if event.button() == QtCore.Qt.LeftButton:
35 | pt = point(event.pos())
36 | if self._select_area:
37 | [Xmin, Ymin, dx, dy] = self._drawbox
38 | self._display.SelectArea(Xmin, Ymin, Xmin + dx, Ymin + dy)
39 | self._select_area = False
40 | else:
41 | # multiple select if shift is pressed
42 | if modifiers == QtCore.Qt.ShiftModifier:
43 | self._display.ShiftSelect(pt.x, pt.y)
44 | else:
45 | # single select otherwise
46 | self._display.Select(pt.x, pt.y)
47 | elif event.button() == QtCore.Qt.RightButton:
48 | if self._zoom_area:
49 | [Xmin, Ymin, dx, dy] = self._drawbox
50 | self._display.ZoomArea(Xmin, Ymin, Xmin + dx, Ymin + dy)
51 | self._zoom_area = False
52 |
--------------------------------------------------------------------------------
/OCCUtils/Image.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | ##Copyright 2008-2015 Thomas Paviot (tpaviot@gmail.com)
4 | ##
5 | ##This file is part of pythonOCC.
6 | ##
7 | ##pythonOCC is free software: you can redistribute it and/or modify
8 | ##it under the terms of the GNU Lesser General Public License as published by
9 | ##the Free Software Foundation, either version 3 of the License, or
10 | ##(at your option) any later version.
11 | ##
12 | ##pythonOCC is distributed in the hope that it will be useful,
13 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | ##GNU Lesser General Public License for more details.
16 | ##
17 | ##You should have received a copy of the GNU Lesser General Public License
18 | ##along with pythonOCC. If not, see .
19 |
20 | import os
21 | import os.path
22 |
23 |
24 | class Texture(object):
25 | """
26 | This class encapsulates the necessary texture properties:
27 | Filename, toScaleU, etc.
28 | """
29 | def __init__(self, filename):
30 | if not os.path.isfile(filename):
31 | raise IOError("File %s not found.\n" % filename)
32 | self._filename = filename
33 | self._toScaleU = 1.0
34 | self._toScaleV = 1.0
35 | self._toRepeatU = 1.0
36 | self._toRepeatV = 1.0
37 | self._originU = 0.0
38 | self._originV = 0.0
39 |
40 | def TextureScale(self, toScaleU, toScaleV):
41 | self._toScaleU = toScaleU
42 | self._toScaleV = toScaleV
43 |
44 | def TextureRepeat(self, toRepeatU, toRepeatV):
45 | self._toRepeatU = toRepeatU
46 | self._toRepeatV = toRepeatV
47 |
48 | def TextureOrigin(self, originU, originV):
49 | self._originU = originU
50 | self._originV = originV
51 |
52 | def GetProperties(self):
53 | return (self._filename,
54 | self._toScaleU, self._toScaleV,
55 | self._toRepeatU, self._toRepeatV,
56 | self._originU, self._originV)
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cadviewer
2 | Simple 3D CAD app using PythonOCC and PyQt5
3 |
4 | This repo is like an old attic in a sense. It contains various code that I have
5 | written as I have experimented with what and how I might go about writing
6 | a CAD application built on PythonOCC. I decided to post it on GitHub.
7 |
8 | I stumbled across some work I did a few years ago, trying to build a simple CAD app
9 | using PythonOCC. Having not looked at it in over 3 years, I wasn't sure it would be
10 | worth the trouble to get it running on the latest version of PyhonOCC and Python 3.
11 | A screenshot from some old code posted online:
12 | https://sites.google.com/site/pythonocc/cadviewer
13 | reminds me that I was using PythonOCC version 0.16.3-dev at the time.
14 | With the recent release of PyOCC version7.4.0-beta, I decided to give it a go.
15 | I asked Thomas Paviot for useful resources to help me understand the changes
16 | in the API from version 0.16 to the current version. His advice was very helpful:
17 |
18 | """
19 | pythonocc-0.16.3 is 4 years old, in the meantime code has changed because of :
20 |
21 | * API changes from opencascade. Have a look at the release notes for each release. Most changes occurred when switching to occt7x series (see https://www.opencascade.com/content/previous-releases for an history of opencascascade releases) ;
22 |
23 | * changes in pythonocc itself. There have been two major changes that you have to know about while porting your old code to the new release :
24 |
25 | 1. The package structure has changed. You have to move all 'from OCC.xxx import xxx' to 'from OCC.Core.xxx import xxx'. That's not a big deal.
26 |
27 | 2. There is not Handle anymore. GetHandle and GetObject methods have disappeared. Just pass the object itself, the wrapper decides wether it has to pass the Handle or the Object to the C++ layer. You can check this commit (https://github.com/tpaviot/pythonocc-demos/commit/e59acdce5720d84ce76134789b48c268e36446d6#diff-68b70730ce65eb74e098809766ab3d0d), where we ported the old 'occ bottle example'.
28 | """
29 |
30 | Here is my progress (so far) on getting it running again:
31 |
32 | cadViewer.py produces the main GUI (but still crashes when the buttons are clicked).
33 |
34 | got import STEP kind of working, but part names are still broken.
35 |
36 |
--------------------------------------------------------------------------------
/OCCUtils/shell.py:
--------------------------------------------------------------------------------
1 | ##Copyright 2008-2015 Jelle Feringa (jelleferinga@gmail.com)
2 | ##
3 | ##This file is part of pythonOCC.
4 | ##
5 | ##pythonOCC is free software: you can redistribute it and/or modify
6 | ##it under the terms of the GNU Lesser General Public License as published by
7 | ##the Free Software Foundation, either version 3 of the License, or
8 | ##(at your option) any later version.
9 | ##
10 | ##pythonOCC is distributed in the hope that it will be useful,
11 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ##GNU Lesser General Public License for more details.
14 | ##
15 | ##You should have received a copy of the GNU Lesser General Public License
16 | ##along with pythonOCC. If not, see
17 |
18 | from OCC.Core.TopoDS import TopoDS_Shell
19 | from OCC.ShapeAnalysis import ShapeAnalysis_Shell
20 |
21 | from OCCUtils.Topology import Topo
22 | from OCCUtils.base import BaseObject, GlobalProperties
23 |
24 |
25 | class Shell(TopoDS_Shell, BaseObject):
26 | _n = 0
27 |
28 | def __init__(self, shell):
29 | assert isinstance(shell, TopoDS_Shell), 'need a TopoDS_Shell, got a %s' % shell.__class__
30 | assert not shell.IsNull()
31 | super(Shell, self).__init__()
32 | BaseObject.__init__(self, 'shell')
33 | # we need to copy the base shape using the following three
34 | # lines
35 | assert self.IsNull()
36 | self.TShape(shell.TShape())
37 | self.Location(shell.Location())
38 | self.Orientation(shell.Orientation())
39 | assert not self.IsNull()
40 |
41 | self.GlobalProperties = GlobalProperties(self)
42 | self._n += 1
43 |
44 | def analyse(self):
45 | """
46 |
47 | :return:
48 | """
49 | ss = ShapeAnalysis_Shell(self)
50 | if ss.HasFreeEdges():
51 | bad_edges = [e for e in Topo(ss.BadEdges()).edges()]
52 | return bad_edges
53 |
54 | def Faces(self):
55 | """
56 |
57 | :return:
58 | """
59 | return Topo(self, True).faces()
60 |
61 | def Wires(self):
62 | """
63 | :return:
64 | """
65 | return Topo(self, True).wires()
66 |
67 | def Edges(self):
68 | return Topo(self, True).edges()
69 |
--------------------------------------------------------------------------------
/OCCUtils/vertex.py:
--------------------------------------------------------------------------------
1 | ##Copyright 2008-2013 Jelle Feringa (jelleferinga@gmail.com)
2 | ##
3 | ##This file is part of pythonOCC.
4 | ##
5 | ##pythonOCC is free software: you can redistribute it and/or modify
6 | ##it under the terms of the GNU Lesser General Public License as published by
7 | ##the Free Software Foundation, either version 3 of the License, or
8 | ##(at your option) any later version.
9 | ##
10 | ##pythonOCC is distributed in the hope that it will be useful,
11 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ##GNU Lesser General Public License for more details.
14 | ##
15 | ##You should have received a copy of the GNU Lesser General Public License
16 | ##along with pythonOCC. If not, see
17 |
18 | from OCC.gp import gp_Pnt, gp_Vec, gp_Dir, gp_XYZ, gp_Pnt2d
19 | from OCC.Core.TopoDS import TopoDS_Vertex
20 | from OCC.ShapeBuild import ShapeBuild_ReShape
21 |
22 | from OCCUtils.base import BaseObject
23 | from OCCUtils.Construct import make_vertex
24 |
25 |
26 | class Vertex(TopoDS_Vertex, BaseObject):
27 | """
28 | wraps gp_Pnt
29 | """
30 | _n = 0
31 |
32 | def __init__(self, x, y, z):
33 | super(Vertex, self).__init__()
34 | """Constructor for KbeVertex"""
35 | BaseObject.__init__(self, name='Vertex #{0}'.format(self._n))
36 |
37 | self._n += 1 # should be a property of KbeObject
38 | self._pnt = gp_Pnt(x, y, z)
39 | self._vertex = make_vertex(self._pnt)
40 | TopoDS_Vertex.__init__(self, self._vertex)
41 |
42 | def _update(self):
43 | """
44 |
45 | """
46 | # TODO: perhaps should take an argument until which topological level
47 | # topological entities bound to the vertex should be updated too...
48 | reshape = ShapeBuild_ReShape()
49 | reshape.Replace(self._vertex, make_vertex(self._pnt))
50 |
51 | @staticmethod
52 | def from_pnt(cls, pnt):
53 | x, y, z = pnt.X(), pnt.Y(), pnt.Z()
54 | return cls(x, y, z)
55 |
56 | @property
57 | def x(self):
58 | return self._pnt.X()
59 |
60 | @x.setter
61 | def x(self, val):
62 | self._pnt.SetX(val)
63 | self._update()
64 |
65 | @property
66 | def y(self):
67 | return self._pnt.Y()
68 |
69 | @y.setter
70 | def y(self, val):
71 | self._pnt.SetY(val)
72 | self._update()
73 |
74 | @property
75 | def z(self):
76 | return self._pnt.Z()
77 |
78 | @z.setter
79 | def z(self, val):
80 | self._pnt.SetZ(val)
81 | self._update()
82 |
83 | @property
84 | def xyz(self):
85 | return self._pnt.Coord()
86 |
87 | @xyz.setter
88 | def xyz(self, *val):
89 | self._pnt.SetXYZ(*val)
90 | self._update()
91 |
92 | def __repr__(self):
93 | return self.name
94 |
95 | @property
96 | def as_vec(self):
97 | '''returns a gp_Vec version of self'''
98 | return gp_Vec(*self._pnt.Coord())
99 |
100 | @property
101 | def as_dir(self):
102 | '''returns a gp_Dir version of self'''
103 | return gp_Dir(*self._pnt.Coord())
104 |
105 | @property
106 | def as_xyz(self):
107 | '''returns a gp_XYZ version of self'''
108 | return gp_XYZ(*self._pnt.Coord())
109 |
110 | @property
111 | def as_pnt(self):
112 | return self._pnt
113 |
114 | @property
115 | def as_2d(self):
116 | '''returns a gp_Pnt2d version of self'''
117 | return gp_Pnt2d(*self._pnt.Coord()[:2])
118 |
--------------------------------------------------------------------------------
/misc/example.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from math import pi
3 |
4 | from OCC.BRepPrimAPI import BRepPrimAPI_MakeBox
5 | from OCC.AIS import *
6 | from OCC.Quantity import *
7 | from OCC.Display.SimpleGui import init_display
8 | from OCC.TopoDS import *
9 | from OCC.gp import *
10 | from OCC.TopLoc import *
11 | from OCC.Geom import *
12 | from OCC.BRep import BRep_Tool_Surface
13 | from OCC.GCE2d import *
14 | from OCC.BRepBuilderAPI import *
15 |
16 | display, start_display, add_menu, add_function_to_menu = init_display()
17 |
18 |
19 | def geom_plane_from_face(aFace):
20 | """
21 | Returns the geometric plane entity from a planar surface
22 | """
23 | return Handle_Geom_Plane.DownCast(OCC.BRep.BRep_Tool_Surface(aFace)).GetObject()
24 |
25 | def redraw(event=None):
26 | # display with crisp edges and transpaarency
27 | context = display.Context
28 | context.RemoveAll()
29 | context.SetAutoActivateSelection(False)
30 | aisShape = AIS_Shape(Box)
31 | h_aisShape = aisShape.GetHandle()
32 | context.Display(h_aisShape)
33 | context.SetTransparency(h_aisShape, .6)
34 | context.HilightWithColor(h_aisShape, OCC.Quantity.Quantity_NOC_BLACK)
35 | display.FitAll()
36 |
37 | def makeBox(event=None):
38 | global Box
39 | # Make a box
40 | Box = BRepPrimAPI_MakeBox(60, 60, 50).Shape()
41 | redraw()
42 |
43 | def rotateBox():
44 | aisShape = AIS_Shape(Box)
45 | ax1 = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(1., 0., 0.))
46 | aRotTrsf = gp_Trsf()
47 | angle = pi/6
48 | aRotTrsf.SetRotation(ax1, angle)
49 | aTopLoc = TopLoc_Location(aRotTrsf)
50 | Box.Move(aTopLoc)
51 | redraw()
52 |
53 | def enableFaceSelect(event=None):
54 | display.selected_shape = None
55 | display.SetSelectionModeFace()
56 |
57 | def makeSqProfile(size, surface):
58 | # points and segments need to be in CW sequence to get W pointing along Z
59 | aPnt1 = gp_Pnt2d(-size, size)
60 | aPnt2 = gp_Pnt2d(size, size)
61 | aPnt3 = gp_Pnt2d(size, -size)
62 | aPnt4 = gp_Pnt2d(-size, -size)
63 | aSegment1 = GCE2d_MakeSegment(aPnt1, aPnt2)
64 | aSegment2 = GCE2d_MakeSegment(aPnt2, aPnt3)
65 | aSegment3 = GCE2d_MakeSegment(aPnt3, aPnt4)
66 | aSegment4 = GCE2d_MakeSegment(aPnt4, aPnt1)
67 | print 'Next is where something crashes'
68 | aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value(),
69 | Handle_Geom_Surface(surface))
70 | aEdge2 = BRepBuilderAPI_MakeEdge(aSegment2.Value(),
71 | Handle_Geom_Surface(surface))
72 | aEdge3 = BRepBuilderAPI_MakeEdge(aSegment3.Value(),
73 | Handle_Geom_Surface(surface))
74 | aEdge4 = BRepBuilderAPI_MakeEdge(aSegment4.Value(),
75 | Handle_Geom_Surface(surface))
76 | print "Doesn't get here (with rotated box)"
77 | aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(),
78 | aEdge2.Edge(),
79 | aEdge3.Edge(),
80 | aEdge4.Edge())
81 |
82 | myWireProfile = aWire.Wire()
83 | return myWireProfile # TopoDS_Wire
84 |
85 | def wireProfileOnFace(event=None):
86 | aShape = display.GetSelectedShape()
87 | shapes = display.GetSelectedShapes()
88 | face = None
89 | if aShape:
90 | face = topods_Face(aShape)
91 | print "A shape found:"
92 | elif shapes:
93 | aShape = shapes[0]
94 | face = topods_Face(aShape)
95 | print len(shapes), "Shapes found"
96 | if face:
97 | surface = geom_plane_from_face(face)
98 | wireProfile = makeSqProfile(50, surface)
99 | display.DisplayShape(wireProfile)
100 | else:
101 | print 'no face'
102 |
103 | def exit(event=None):
104 | sys.exit()
105 |
106 | if __name__ == '__main__':
107 | add_menu('operations')
108 | add_function_to_menu('operations', makeBox)
109 | add_function_to_menu('operations', rotateBox)
110 | add_function_to_menu('operations', enableFaceSelect)
111 | add_function_to_menu('operations', wireProfileOnFace)
112 | add_function_to_menu('operations', exit)
113 | start_display()
114 |
--------------------------------------------------------------------------------
/OCCUtils/Iteration.py:
--------------------------------------------------------------------------------
1 | ##Copyright 2008-2015 Jelle Feringa (jelleferinga@gmail.com)
2 | ##
3 | ##This file is part of pythonOCC.
4 | ##
5 | ##pythonOCC is free software: you can redistribute it and/or modify
6 | ##it under the terms of the GNU Lesser General Public License as published by
7 | ##the Free Software Foundation, either version 3 of the License, or
8 | ##(at your option) any later version.
9 | ##
10 | ##pythonOCC is distributed in the hope that it will be useful,
11 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ##GNU Lesser General Public License for more details.
14 | ##
15 | ##You should have received a copy of the GNU Lesser General Public License
16 | ##along with pythonOCC. If not, see .
17 |
18 | '''
19 | This module helps looping through topology
20 | '''
21 | from OCC.BRep import BRep_Tool
22 |
23 | from OCCUtils.Topology import WireExplorer, Topo
24 | from OCCUtils.edge import Edge
25 |
26 |
27 | class EdgePairsFromWire(object):
28 | '''
29 | helper class to loop through a wire and return ordered pairs of edges
30 | '''
31 | def __init__(self, wire):
32 | self.wire = wire
33 | self.edge_pairs = []
34 | self.prev_edge = None
35 | self.we = WireExplorer(self.wire).ordered_edges()
36 | self.number_of_edges = self.we.__length_hint__()
37 | self.previous_edge = None
38 | self.current_edge = None
39 | self.first_edge = None
40 | self.index = 0
41 |
42 | def next(self):
43 | if self.index == 0:
44 | # first edge, need to set self.previous_edge
45 | self.previous_edge = next(self.we)
46 | self.current_edge = next(self.we)
47 | self.first_edge = self.previous_edge # for the last iteration
48 | self.index += 1
49 | return [self.previous_edge, self.current_edge]
50 | elif self.index == self.number_of_edges-1:
51 | # no next edge
52 | self.index += 1
53 | return [self.current_edge, self.first_edge]
54 | else:
55 | self.previous_edge = self.current_edge
56 | self.current_edge = next(self.we)
57 | self.index += 1
58 | return [self.previous_edge, self.current_edge]
59 |
60 | def __iter__(self):
61 | return self
62 |
63 |
64 | class LoopWirePairs(object):
65 | '''
66 | for looping through consequtive wires
67 | assures that the returned edge pairs are ordered
68 | '''
69 | def __init__(self, wireA, wireB):
70 | self.wireA = wireA
71 | self.wireB = wireB
72 | self.we_A = WireExplorer(self.wireA)
73 | self.we_B = WireExplorer(self.wireB)
74 | self.tp_A = Topo(self.wireA)
75 | self.tp_B = Topo(self.wireB)
76 | self.bt = BRep_Tool()
77 | self.vertsA = [v for v in self.we_A.ordered_vertices()]
78 | self.vertsB = [v for v in self.we_B.ordered_vertices()]
79 |
80 | self.edgesA = [v for v in WireExplorer(wireA).ordered_edges()]
81 | self.edgesB = [v for v in WireExplorer(wireB).ordered_edges()]
82 |
83 | self.pntsB = [self.bt.Pnt(v) for v in self.vertsB]
84 | self.number_of_vertices = len(self.vertsA)
85 | self.index = 0
86 |
87 | def closest_point(self, vertexFromWireA):
88 | pt = self.bt.Pnt(vertexFromWireA)
89 | distances = [pt.Distance(i) for i in self.pntsB]
90 | indx_max_dist = distances.index(min(distances))
91 | return self.vertsB[indx_max_dist]
92 |
93 | def next(self):
94 | if self.index == self.number_of_vertices:
95 | raise StopIteration
96 |
97 | vert = self.vertsA[self.index]
98 | closest = self.closest_point(vert)
99 | edges_a = self.tp_A.edges_from_vertex(vert)
100 | edges_b = self.tp_B.edges_from_vertex(closest)
101 | a1, a2 = Edge(next(edges_a)), Edge(next(edges_a))
102 | b1, b2 = Edge(next(edges_b)), Edge(next(edges_b))
103 | mpA = a1.mid_point()
104 | self.index += 1
105 |
106 | if mpA.Distance(b1.mid_point()) < mpA.Distance(b2.mid_point()):
107 | return iter([a1, a2]), iter([b1, b2])
108 | else:
109 | return iter([a1, a2]), iter([b2, b1])
110 |
111 | def __iter__(self):
112 | return self
113 |
--------------------------------------------------------------------------------
/misc/example1.py:
--------------------------------------------------------------------------------
1 | """
2 | Figured out what the problem was, after studying
3 | pythonocc-core/examples/core_topology_local_ops.py
4 |
5 | BRepBuilderAPI_MakeEdge(aSegment1.Value(), Handle_Geom_Surface(surface))
6 | needs a 'surface' and I was feeding it a Geom_Plane.
7 | """
8 | import sys
9 | from math import pi
10 |
11 | from OCC.BRepPrimAPI import BRepPrimAPI_MakeBox
12 | from OCC.AIS import *
13 | from OCC.Quantity import *
14 | from OCC.Display.SimpleGui import init_display
15 | from OCC.TopoDS import *
16 | from OCC.gp import *
17 | from OCC.TopLoc import *
18 | from OCC.Geom import *
19 | from OCC.BRep import BRep_Tool_Surface
20 | from OCC.GCE2d import *
21 | from OCC.BRepBuilderAPI import *
22 |
23 | display, start_display, add_menu, add_function_to_menu = init_display()
24 | context = display.Context
25 |
26 | def geom_plane_from_face(aFace):
27 | """
28 | Returns the geometric plane entity from a planar surface
29 | """
30 | return Handle_Geom_Plane_DownCast(OCC.BRep.BRep_Tool_Surface(aFace)).GetObject()
31 |
32 | def surface_from_face(aFace):
33 | """
34 | Returns a surface entity from a face
35 | """
36 | return OCC.BRep.BRep_Tool_Surface(aFace)
37 |
38 |
39 | def redraw(event=None):
40 | # display with crisp edges and transparency
41 | context.RemoveAll()
42 | context.SetAutoActivateSelection(False)
43 | aisShape = AIS_Shape(Box)
44 | h_aisShape = aisShape.GetHandle()
45 | context.Display(h_aisShape)
46 | context.SetTransparency(h_aisShape, .6)
47 | context.HilightWithColor(h_aisShape, OCC.Quantity.Quantity_NOC_BLACK)
48 | display.FitAll()
49 |
50 | def makeBox(event=None):
51 | global Box
52 | # Make a box
53 | Box = BRepPrimAPI_MakeBox(60, 60, 50).Shape()
54 | redraw()
55 |
56 | def rotateBox():
57 | aisShape = AIS_Shape(Box)
58 | ax1 = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(1., 0., 0.))
59 | aRotTrsf = gp_Trsf()
60 | angle = pi/6
61 | aRotTrsf.SetRotation(ax1, angle)
62 | aTopLoc = TopLoc_Location(aRotTrsf)
63 | Box.Move(aTopLoc)
64 | redraw()
65 |
66 | def enableFaceSelect(event=None):
67 | display.selected_shape = None
68 | display.SetSelectionModeFace()
69 |
70 | def makeSqProfile(size, surface):
71 | # points and segments need to be in CW sequence to get W pointing along Z
72 | aPnt1 = gp_Pnt2d(-size, size)
73 | aPnt2 = gp_Pnt2d(size, size)
74 | aPnt3 = gp_Pnt2d(size, -size)
75 | aPnt4 = gp_Pnt2d(-size, -size)
76 | aSegment1 = GCE2d_MakeSegment(aPnt1, aPnt2)
77 | aSegment2 = GCE2d_MakeSegment(aPnt2, aPnt3)
78 | aSegment3 = GCE2d_MakeSegment(aPnt3, aPnt4)
79 | aSegment4 = GCE2d_MakeSegment(aPnt4, aPnt1)
80 | print 'Next is where something crashes'
81 | aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value(),
82 | Handle_Geom_Surface(surface))
83 | aEdge2 = BRepBuilderAPI_MakeEdge(aSegment2.Value(),
84 | Handle_Geom_Surface(surface))
85 | aEdge3 = BRepBuilderAPI_MakeEdge(aSegment3.Value(),
86 | Handle_Geom_Surface(surface))
87 | aEdge4 = BRepBuilderAPI_MakeEdge(aSegment4.Value(),
88 | Handle_Geom_Surface(surface))
89 | print "Doesn't get here (with rotated box)"
90 | aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(),
91 | aEdge2.Edge(),
92 | aEdge3.Edge(),
93 | aEdge4.Edge())
94 |
95 | myWireProfile = aWire.Wire()
96 | return myWireProfile # TopoDS_Wire
97 |
98 | def wireProfileOnFace(event=None):
99 | aShape = display.GetSelectedShape()
100 | shapes = display.GetSelectedShapes()
101 | face = None
102 | if aShape:
103 | face = topods_Face(aShape)
104 | print "A shape found:"
105 | elif shapes:
106 | aShape = shapes[0]
107 | face = topods_Face(aShape)
108 | print len(shapes), "Shapes found"
109 | if face:
110 | surface = surface_from_face(face)
111 | wireProfile = makeSqProfile(50, surface)
112 | display.DisplayShape(wireProfile)
113 | else:
114 | print 'no face'
115 |
116 | def exit(event=None):
117 | sys.exit()
118 |
119 | if __name__ == '__main__':
120 | add_menu('operations')
121 | add_function_to_menu('operations', makeBox)
122 | add_function_to_menu('operations', rotateBox)
123 | add_function_to_menu('operations', enableFaceSelect)
124 | add_function_to_menu('operations', wireProfileOnFace)
125 | add_function_to_menu('operations', exit)
126 | start_display()
127 |
--------------------------------------------------------------------------------
/sew.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from math import pi
3 |
4 | from OCC.BRepPrimAPI import BRepPrimAPI_MakeBox
5 | from OCC.AIS import *
6 | from OCC.Quantity import *
7 | from OCC.Display.SimpleGui import init_display
8 | from OCC.TopoDS import *
9 | from OCC.gp import *
10 | from OCC.TopLoc import *
11 | from OCC.Geom import *
12 | from OCC.BRep import BRep_Tool_Surface
13 | from OCC.GCE2d import *
14 | from OCC.BRepBuilderAPI import *
15 | from OCC.GC import *
16 | import aocutils.brep.solid_make
17 |
18 | display, start_display, add_menu, add_function_to_menu = init_display()
19 |
20 |
21 | def geom_plane_from_face(aFace):
22 | """
23 | Returns the geometric plane entity from a planar surface
24 | """
25 | return Handle_Geom_Plane.DownCast(OCC.BRep.BRep_Tool_Surface(aFace)).GetObject()
26 |
27 | def redraw(shape, event=None):
28 | # display with crisp edges and transpaarency
29 | context = display.Context
30 | context.RemoveAll()
31 | context.SetAutoActivateSelection(False)
32 | aisShape = AIS_Shape(shape)
33 | h_aisShape = aisShape.GetHandle()
34 | context.Display(h_aisShape)
35 | context.SetTransparency(h_aisShape, .1)
36 | context.HilightWithColor(h_aisShape, OCC.Quantity.Quantity_NOC_BLACK)
37 | display.FitAll()
38 |
39 | def makeBox(event=None):
40 | # Make a box
41 | Box = BRepPrimAPI_MakeBox(60, 60, 50).Shape()
42 | redraw()
43 |
44 | def rotateBox():
45 | aisShape = AIS_Shape(Box)
46 | ax1 = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(1., 0., 0.))
47 | aRotTrsf = gp_Trsf()
48 | angle = pi/6
49 | aRotTrsf.SetRotation(ax1, angle)
50 | aTopLoc = TopLoc_Location(aRotTrsf)
51 | Box.Move(aTopLoc)
52 | redraw()
53 |
54 | def enableFaceSelect(event=None):
55 | display.selected_shape = None
56 | display.SetSelectionModeFace()
57 |
58 | def makeSqProfile(size, surface):
59 | # points and segments need to be in CW sequence to get W pointing along Z
60 | aPnt1 = gp_Pnt2d(-size, size)
61 | aPnt2 = gp_Pnt2d(size, size)
62 | aPnt3 = gp_Pnt2d(size, -size)
63 | aPnt4 = gp_Pnt2d(-size, -size)
64 | aSegment1 = GCE2d_MakeSegment(aPnt1, aPnt2)
65 | aSegment2 = GCE2d_MakeSegment(aPnt2, aPnt3)
66 | aSegment3 = GCE2d_MakeSegment(aPnt3, aPnt4)
67 | aSegment4 = GCE2d_MakeSegment(aPnt4, aPnt1)
68 | print 'Next is where something crashes'
69 | aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value(),
70 | Handle_Geom_Surface(surface))
71 | aEdge2 = BRepBuilderAPI_MakeEdge(aSegment2.Value(),
72 | Handle_Geom_Surface(surface))
73 | aEdge3 = BRepBuilderAPI_MakeEdge(aSegment3.Value(),
74 | Handle_Geom_Surface(surface))
75 | aEdge4 = BRepBuilderAPI_MakeEdge(aSegment4.Value(),
76 | Handle_Geom_Surface(surface))
77 | print "Doesn't get here (with rotated box)"
78 | aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(),
79 | aEdge2.Edge(),
80 | aEdge3.Edge(),
81 | aEdge4.Edge())
82 |
83 | myWireProfile = aWire.Wire()
84 | return myWireProfile # TopoDS_Wire
85 |
86 | def wireProfileOnFace(event=None):
87 | aShape = display.GetSelectedShape()
88 | shapes = display.GetSelectedShapes()
89 | face = None
90 | if aShape:
91 | face = topods_Face(aShape)
92 | print "A shape found:"
93 | elif shapes:
94 | aShape = shapes[0]
95 | face = topods_Face(aShape)
96 | print len(shapes), "Shapes found"
97 | if face:
98 | surface = geom_plane_from_face(face)
99 | wireProfile = makeSqProfile(50, surface)
100 | display.DisplayShape(wireProfile)
101 | else:
102 | print 'no face'
103 |
104 | def translatePnt(p1, vec):
105 | p2 = gp_Pnt()
106 | p2 = p1.Translated(vec)
107 | return p2
108 |
109 | def pointsToWire(p1, p2, p3, p4):
110 | seg1 = GC_MakeSegment(p1, p2)
111 | seg2 = GC_MakeSegment(p2, p3)
112 | seg3 = GC_MakeSegment(p3, p4)
113 | seg4 = GC_MakeSegment(p4, p1)
114 | edge1 = BRepBuilderAPI_MakeEdge(seg1.Value())
115 | edge2 = BRepBuilderAPI_MakeEdge(seg2.Value())
116 | edge3 = BRepBuilderAPI_MakeEdge(seg3.Value())
117 | edge4 = BRepBuilderAPI_MakeEdge(seg4.Value())
118 | wire = BRepBuilderAPI_MakeWire(edge1.Edge(), edge2.Edge(),
119 | edge3.Edge(), edge4.Edge())
120 | return wire.Wire()
121 |
122 | def sewBox():
123 | # Length of shape (spine)
124 | Vec = gp_Vec(0, 0, 10)
125 | # starting with bot vertices, make bot wire & face
126 | p1 = gp_Pnt(0, 0, 0)
127 | p2 = gp_Pnt(20, 0, 0)
128 | p3 = gp_Pnt(20, 20, 0)
129 | p4 = gp_Pnt(0, 20, 0)
130 | botWire = pointsToWire(p1, p2, p3, p4)
131 | botFace = BRepBuilderAPI_MakeFace(botWire).Face()
132 | # starting with topvertices, make top face
133 | p5 = translatePnt(p1, Vec)
134 | p6 = translatePnt(p2, Vec)
135 | p7 = translatePnt(p3, Vec)
136 | p8 = translatePnt(p4, Vec)
137 | topWire = pointsToWire(p5, p6, p7, p8)
138 | topFace = BRepBuilderAPI_MakeFace(topWire).Face()
139 | # Make spine (wire) to make 'pipe'
140 | spineSeg = GC_MakeSegment(p1, p5)
141 | spineEdge = BRepBuilderAPI_MakeEdge(spineSeg.Value())
142 | spineWire = BRepBuilderAPI_MakeWire(spineEdge.Edge()).Wire()
143 | pipe = OCC.BRepOffsetAPI.BRepOffsetAPI_MakePipe(botWire, spineWire).Shape()
144 | # Sew together botFace, pipe, and topFace to get solid
145 | tolerance = 1e-6
146 | sew = OCC.BRepBuilderAPI.BRepBuilderAPI_Sewing(tolerance)
147 | sew.Add(botFace)
148 | sew.Add(pipe)
149 | sew.Add(topFace)
150 | sew.Perform()
151 | res = sew.SewedShape()
152 | print type(res)
153 | redraw(res)
154 |
155 | def exit(event=None):
156 | sys.exit()
157 |
158 | if __name__ == '__main__':
159 | add_menu('operations')
160 | add_function_to_menu('operations', makeBox)
161 | add_function_to_menu('operations', rotateBox)
162 | add_function_to_menu('operations', enableFaceSelect)
163 | add_function_to_menu('operations', wireProfileOnFace)
164 | add_function_to_menu('operations', exit)
165 | add_menu('Experimental')
166 | add_function_to_menu('Experimental', sewBox)
167 |
168 | start_display()
169 |
--------------------------------------------------------------------------------
/treelib/node.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright (C) 2011
3 | # Brett Alistair Kromkamp - brettkromkamp@gmail.com
4 | # Copyright (C) 2012-2017
5 | # Xiaming Chen - chenxm35@gmail.com
6 | # and other contributors.
7 | # All rights reserved.
8 | #
9 | # Licensed under the Apache License, Version 2.0 (the "License");
10 | # you may not use this file except in compliance with the License.
11 | # You may obtain a copy of the License at
12 | #
13 | # http://www.apache.org/licenses/LICENSE-2.0
14 | #
15 | # Unless required by applicable law or agreed to in writing, software
16 | # distributed under the License is distributed on an "AS IS" BASIS,
17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | # See the License for the specific language governing permissions and
19 | # limitations under the License.
20 | """
21 | Node structure in treelib.
22 |
23 | A :class:`Node` object contains basic properties such as node identifier,
24 | node tag, parent node, children nodes etc., and some operations for a node.
25 | """
26 | import uuid
27 |
28 | from .exceptions import NodePropertyError
29 |
30 |
31 | class Node(object):
32 | """
33 | Nodes are elementary objects that are stored in the `_nodes` dictionary of a Tree.
34 | Use `data` attribute to store node-specific data.
35 | """
36 |
37 | #: Mode constants for routine `update_fpointer()`.
38 | (ADD, DELETE, INSERT, REPLACE) = list(range(4))
39 |
40 | def __init__(self, tag=None, identifier=None, expanded=True, data=None):
41 | """Create a new Node object to be placed inside a Tree object"""
42 |
43 | #: if given as a parameter, must be unique
44 | self._identifier = None
45 | self._set_identifier(identifier)
46 |
47 | #: None or something else
48 | #: if None, self._identifier will be set to the identifier's value.
49 | if tag is None:
50 | self._tag = self._identifier
51 | else:
52 | self._tag = tag
53 |
54 | #: boolean
55 | self.expanded = expanded
56 |
57 | #: identifier of the parent's node :
58 | self._bpointer = None
59 | #: identifier(s) of the soons' node(s) :
60 | self._fpointer = list()
61 |
62 | #: User payload associated with this node.
63 | self.data = data
64 |
65 | def __lt__(self, other):
66 | return self.tag < other.tag
67 |
68 | def _set_identifier(self, nid):
69 | """Initialize self._set_identifier"""
70 | if nid is None:
71 | self._identifier = str(uuid.uuid1())
72 | else:
73 | self._identifier = nid
74 |
75 | @property
76 | def bpointer(self):
77 | """
78 | The parent ID of a node. This attribute can be
79 | accessed and modified with ``.`` and ``=`` operator respectively.
80 | """
81 | return self._bpointer
82 |
83 | @bpointer.setter
84 | def bpointer(self, nid):
85 | """Set the value of `_bpointer`."""
86 | if nid is not None:
87 | self._bpointer = nid
88 | else:
89 | # print("WARNING: the bpointer of node %s " \
90 | # "is set to None" % self._identifier)
91 | self._bpointer = None
92 |
93 | @property
94 | def fpointer(self):
95 | """
96 | With a getting operator, a list of IDs of node's children is obtained. With
97 | a setting operator, the value can be list, set, or dict. For list or set,
98 | it is converted to a list type by the package; for dict, the keys are
99 | treated as the node IDs.
100 | """
101 | return self._fpointer
102 |
103 | @fpointer.setter
104 | def fpointer(self, value):
105 | """Set the value of `_fpointer`."""
106 | if value is None:
107 | self._fpointer = list()
108 | elif isinstance(value, list):
109 | self._fpointer = value
110 | elif isinstance(value, dict):
111 | self._fpointer = list(value.keys())
112 | elif isinstance(value, set):
113 | self._fpointer = list(value)
114 | else: # TODO: add deprecated routine
115 | pass
116 |
117 | @property
118 | def identifier(self):
119 | """
120 | The unique ID of a node within the scope of a tree. This attribute can be
121 | accessed and modified with ``.`` and ``=`` operator respectively.
122 | """
123 | return self._identifier
124 |
125 | @identifier.setter
126 | def identifier(self, value):
127 | """Set the value of `_identifier`."""
128 | if value is None:
129 | print("WARNING: node ID can not be None")
130 | else:
131 | self._set_identifier(value)
132 |
133 | def is_leaf(self):
134 | """Return true if current node has no children."""
135 | if len(self.fpointer) == 0:
136 | return True
137 | else:
138 | return False
139 |
140 | def is_root(self):
141 | """Return true if self has no parent, i.e. as root."""
142 | return self._bpointer is None
143 |
144 | @property
145 | def tag(self):
146 | """
147 | The readable node name for human. This attribute can be accessed and
148 | modified with ``.`` and ``=`` operator respectively.
149 | """
150 | return self._tag
151 |
152 | @tag.setter
153 | def tag(self, value):
154 | """Set the value of `_tag`."""
155 | self._tag = value if value is not None else None
156 |
157 | def update_bpointer(self, nid):
158 | """Set the parent (indicated by the ``nid`` parameter) of a node."""
159 | self.bpointer = nid
160 |
161 | def update_fpointer(self, nid, mode=ADD, replace=None):
162 | """
163 | Update the children list with different modes: addition (Node.ADD or
164 | Node.INSERT) and deletion (Node.DELETE).
165 | """
166 | if nid is None:
167 | return
168 |
169 | if mode is self.ADD:
170 | self._fpointer.append(nid)
171 |
172 | elif mode is self.DELETE:
173 | if nid in self._fpointer:
174 | self._fpointer.remove(nid)
175 |
176 | elif mode is self.INSERT: # deprecate to ADD mode
177 | print("WARNING: INSERT is deprecated to ADD mode")
178 | self.update_fpointer(nid)
179 |
180 | elif mode is self.REPLACE:
181 | if replace is None:
182 | raise NodePropertyError(
183 | 'Argument "repalce" should be provided when mode is {}'.format(mode)
184 | )
185 |
186 | ind = self._fpointer.index(nid)
187 | self._fpointer[ind] = replace
188 |
189 | def __repr__(self):
190 | name = self.__class__.__name__
191 | kwargs = [
192 | "tag={0}".format(self.tag),
193 | "identifier={0}".format(self.identifier),
194 | "data={0}".format(self.data),
195 | ]
196 | return "%s(%s)" % (name, ", ".join(kwargs))
197 |
--------------------------------------------------------------------------------
/OCCUtils/base.py:
--------------------------------------------------------------------------------
1 | ##Copyright 2008-2013 Jelle Feringa (jelleferinga@gmail.com)
2 | ##
3 | ##This file is part of pythonOCC.
4 | ##
5 | ##pythonOCC is free software: you can redistribute it and/or modify
6 | ##it under the terms of the GNU Lesser General Public License as published by
7 | ##the Free Software Foundation, either version 3 of the License, or
8 | ##(at your option) any later version.
9 | ##
10 | ##pythonOCC is distributed in the hope that it will be useful,
11 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ##GNU Lesser General Public License for more details.
14 | ##
15 | ##You should have received a copy of the GNU Lesser General Public License
16 | ##along with pythonOCC. If not, see
17 |
18 | '''
19 | Please note the following;
20 | @readonly
21 | means that the decorated method is a readonly descriptor
22 | @property
23 | means that the decorated method can be set / get using the descriptor
24 | ( irony is that just using @property *would*
25 | result in a readonly descriptor :")
26 |
27 | Sometimes a set of methods should be contained in another module or class,
28 | or simply grouped.
29 | For instance the set of methods after:
30 | #===========================================================================
31 | # Curve.local_properties
32 | #===========================================================================
33 |
34 | Can be a module, class or namespace.
35 |
36 | '''
37 |
38 | import functools
39 |
40 | from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_Copy
41 | from OCC.Core.BRepGProp import (brepgprop_VolumeProperties,
42 | brepgprop_LinearProperties,
43 | brepgprop_SurfaceProperties)
44 | from OCC.Core.BRepCheck import (BRepCheck_Vertex, BRepCheck_Edge, BRepCheck_Wire,
45 | BRepCheck_Face, BRepCheck_Shell, BRepCheck_Analyzer)
46 | from OCC.GProp import GProp_GProps
47 | from OCC.Display.SimpleGui import init_display
48 |
49 | from OCCUtils.Common import get_boundingbox
50 | from OCCUtils.Construct import (make_vertex, TOLERANCE)
51 | from OCCUtils.types_lut import shape_lut, topo_lut, curve_lut, surface_lut
52 |
53 | #===========================================================================
54 | # DISPLAY
55 | #===========================================================================
56 | global display
57 |
58 |
59 | class singleton(object):
60 | def __init__(self, cls):
61 | self.cls = cls
62 | self.instance_container = []
63 |
64 | def __call__(self, *args, **kwargs):
65 | if not len(self.instance_container):
66 | cls = functools.partial(self.cls, *args, **kwargs)
67 | self.instance_container.append(cls())
68 | return self.instance_container[0]
69 |
70 |
71 | @singleton
72 | class Display(object):
73 | def __init__(self):
74 | self.display, self.start_display, self.add_menu, self.add_function_to_menu = init_display()
75 |
76 | def __call__(self, *args, **kwargs):
77 | return self.display.DisplayShape(*args, **kwargs)
78 |
79 | #============
80 | # base class
81 | #============
82 |
83 |
84 | class BaseObject(object):
85 | """base class for all objects"""
86 | def __init__(self, name=None, tolerance=TOLERANCE):
87 | self.GlobalProperties = GlobalProperties(self)
88 | self.name = name
89 | self._dirty = False
90 | self.tolerance = tolerance
91 | self.display_set = False
92 |
93 | @property
94 | def is_dirty(self):
95 | '''when an object is dirty, its topology will be
96 | rebuild when update is called'''
97 | return self._dirty
98 |
99 | @is_dirty.setter
100 | def is_dirty(self, _bool):
101 | self._dirty = bool(_bool)
102 |
103 | @property
104 | def topo_type(self):
105 | return topo_lut[self.ShapeType()]
106 |
107 | @property
108 | def geom_type(self):
109 | if self.topo_type == 'edge':
110 | return curve_lut[self.ShapeType()]
111 | if self.topo_type == 'face':
112 | return surface_lut[self.adaptor.GetType()]
113 | else:
114 | raise ValueError('geom_type works only for edges and faces...')
115 |
116 | def set_display(self, display):
117 | if hasattr(display, 'DisplayShape'):
118 | self.display_set = True
119 | self.display = display
120 | else:
121 | raise ValueError('not a display')
122 |
123 | def check(self):
124 | """
125 | """
126 | _check = dict(vertex=BRepCheck_Vertex, edge=BRepCheck_Edge,
127 | wire=BRepCheck_Wire, face=BRepCheck_Face,
128 | shell=BRepCheck_Shell)
129 | _check[self.topo_type]
130 | # TODO: BRepCheck will be able to inform *what* actually is the matter,
131 | # though implementing this still is a bit of work...
132 | raise NotImplementedError
133 |
134 | def is_valid(self):
135 | analyse = BRepCheck_Analyzer(self)
136 | ok = analyse.IsValid()
137 | if ok:
138 | return True
139 | else:
140 | return False
141 |
142 | def copy(self):
143 | """
144 |
145 | :return:
146 | """
147 | cp = BRepBuilderAPI_Copy(self)
148 | cp.Perform(self)
149 | # get the class, construct a new instance
150 | # cast the cp.Shape() to its specific TopoDS topology
151 | _copy = self.__class__(shape_lut(cp.Shape()))
152 | return _copy
153 |
154 | def distance(self, other):
155 | '''
156 | return the minimum distance
157 |
158 | :return: minimum distance,
159 | minimum distance points on shp1
160 | minimum distance points on shp2
161 | '''
162 | return minimum_distance(self, other)
163 |
164 | def show(self, *args, **kwargs):
165 | """
166 | renders the topological entity in the viewer
167 |
168 | :param update: redraw the scene or not
169 | """
170 | if not self.display_set:
171 | Display()(self, *args, **kwargs)
172 | else:
173 | self.disp.DisplayShape(*args, **kwargs)
174 |
175 | def build(self):
176 | if self.name.startswith('Vertex'):
177 | self = make_vertex(self)
178 |
179 | def __eq__(self, other):
180 | return self.IsEqual(other)
181 |
182 | def __ne__(self, other):
183 | return not self.__eq__(other)
184 |
185 |
186 | class GlobalProperties(object):
187 | '''
188 | global properties for all topologies
189 | '''
190 | def __init__(self, instance):
191 | self.instance = instance
192 |
193 | @property
194 | def system(self):
195 | self._system = GProp_GProps()
196 | # todo, type should be abstracted with TopoDS...
197 | _topo_type = self.instance.topo_type
198 | if _topo_type == 'face' or _topo_type == 'shell':
199 | brepgprop_SurfaceProperties(self.instance, self._system)
200 | elif _topo_type == 'edge':
201 | brepgprop_LinearProperties(self.instance, self._system)
202 | elif _topo_type == 'solid':
203 | brepgprop_VolumeProperties(self.instance, self._system)
204 | return self._system
205 |
206 | def centre(self):
207 | """
208 | :return: centre of the entity
209 | """
210 | return self.system.CentreOfMass()
211 |
212 | def inertia(self):
213 | '''returns the inertia matrix'''
214 | return self.system.MatrixOfInertia(), self.system.MomentOfInertia()
215 |
216 | def area(self):
217 | '''returns the area of the surface'''
218 | return self.system.Mass()
219 |
220 | def bbox(self):
221 | '''
222 | returns the bounding box of the face
223 | '''
224 | return get_boundingbox(self.instance)
225 |
--------------------------------------------------------------------------------
/OCCUtils/types_lut.py:
--------------------------------------------------------------------------------
1 | ##Copyright 2008-2015 Jelle Feringa (jelleferinga@gmail.com)
2 | ##
3 | ##This file is part of pythonOCC.
4 | ##
5 | ##pythonOCC is free software: you can redistribute it and/or modify
6 | ##it under the terms of the GNU Lesser General Public License as published by
7 | ##the Free Software Foundation, either version 3 of the License, or
8 | ##(at your option) any later version.
9 | ##
10 | ##pythonOCC is distributed in the hope that it will be useful,
11 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ##GNU Lesser General Public License for more details.
14 | ##
15 | ##You should have received a copy of the GNU Lesser General Public License
16 | ##along with pythonOCC. If not, see
17 |
18 | from OCC.Core.BRepCheck import *
19 | from OCC.Core.GeomAbs import *
20 | from OCC.Core.TopoDS import topods, TopoDS_Shape
21 | from OCC.Core.BRep import BRep_Tool_Surface
22 | from OCC.Core.TopAbs import *
23 | #from OCC.Core.Geom import Handle_Geom_Plane, Handle_Geom_CylindricalSurface
24 |
25 |
26 | class ShapeToTopology(object):
27 | '''
28 | looks up the topology type and returns the corresponding topological entity
29 | '''
30 | def __init__(self):
31 | self.topoTypes = {TopAbs_VERTEX: topods.Vertex,
32 | TopAbs_EDGE: topods.Edge,
33 | TopAbs_FACE: topods.Face,
34 | TopAbs_WIRE: topods.Wire,
35 | TopAbs_SHELL: topods.Shell,
36 | TopAbs_SOLID: topods.Solid,
37 | TopAbs_COMPOUND: topods.Compound,
38 | TopAbs_COMPSOLID: topods.CompSolid,
39 | }
40 |
41 | def __call__(self, shape):
42 | if isinstance(shape, TopoDS_Shape):
43 | return self.topoTypes[shape.ShapeType()](shape)
44 | else:
45 | raise AttributeError('shape has not method `ShapeType`')
46 |
47 | def __getitem__(self, item):
48 | return self(item)
49 |
50 |
51 | class EnumLookup(object):
52 | """
53 | perform bi-directional lookup of Enums'...
54 | """
55 | def __init__(self, li_in, li_out):
56 | self.d = {}
57 | for a, b in zip(li_in, li_out):
58 | self.d[a] = b
59 | self.d[b] = a
60 |
61 | def __getitem__(self, item):
62 | return self.d[item]
63 |
64 |
65 | _curve_typesA = (GeomAbs_Line, GeomAbs_Circle, GeomAbs_Ellipse,
66 | GeomAbs_Hyperbola, GeomAbs_Parabola,
67 | GeomAbs_BezierCurve, GeomAbs_BSplineCurve, GeomAbs_OtherCurve)
68 | _curve_typesB = ('line', 'circle', 'ellipse', 'hyperbola', 'parabola',
69 | 'bezier', 'spline', 'other')
70 | _surface_typesA = (GeomAbs_Plane, GeomAbs_Cylinder, GeomAbs_Cone,
71 | GeomAbs_Sphere, GeomAbs_Torus, GeomAbs_BezierSurface,
72 | GeomAbs_BSplineSurface, GeomAbs_SurfaceOfRevolution,
73 | GeomAbs_SurfaceOfExtrusion,
74 | GeomAbs_OffsetSurface, GeomAbs_OtherSurface)
75 | _surface_typesB = ('plane', 'cylinder', 'cone', 'sphere', 'torus', 'bezier',
76 | 'spline', 'revolution', 'extrusion', 'offset', 'other')
77 |
78 |
79 | _stateA = ('in', 'out', 'on', 'unknown')
80 | _stateB = (TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN)
81 |
82 |
83 | _orientA = ['TopAbs_FORWARD', 'TopAbs_REVERSED', 'TopAbs_INTERNAL',
84 | 'TopAbs_EXTERNAL']
85 | _orientB = [TopAbs_FORWARD, TopAbs_REVERSED, TopAbs_INTERNAL,
86 | TopAbs_EXTERNAL]
87 |
88 |
89 | _topoTypesA = ['vertex', 'edge', 'wire', 'face', 'shell',
90 | 'solid', 'compsolid', 'compound', 'shape']
91 | _topoTypesB = [TopAbs_VERTEX, TopAbs_EDGE, TopAbs_WIRE, TopAbs_FACE,
92 | TopAbs_SHELL, TopAbs_SOLID,
93 | TopAbs_COMPSOLID, TopAbs_COMPOUND, TopAbs_SHAPE]
94 |
95 |
96 | _geom_types_a = ['line', 'circle', 'ellipse', 'hyperbola', 'parabola',
97 | 'beziercurve', 'bsplinecurve', 'othercurve']
98 | _geom_types_b = [GeomAbs_Line, GeomAbs_Circle, GeomAbs_Ellipse,
99 | GeomAbs_Hyperbola, GeomAbs_Parabola, GeomAbs_BezierCurve,
100 | GeomAbs_BSplineCurve, GeomAbs_OtherCurve]
101 |
102 |
103 | # TODO: make a function that generalizes this, there is absolutely
104 | # no need for 2 lists to define an EnumLookup
105 |
106 | def fix_formatting(_str):
107 | return [i.strip() for i in _str.split(',')]
108 |
109 | _brep_check_a = fix_formatting("NoError, InvalidPointOnCurve,\
110 | InvalidPointOnCurveOnSurface, InvalidPointOnSurface,\
111 | No3DCurve, Multiple3DCurve, Invalid3DCurve, NoCurveOnSurface,\
112 | InvalidCurveOnSurface, InvalidCurveOnClosedSurface, InvalidSameRangeFlag,\
113 | InvalidSameParameterFlag,\
114 | InvalidDegeneratedFlag, FreeEdge, InvalidMultiConnexity, InvalidRange,\
115 | EmptyWire, RedundantEdge, SelfIntersectingWire, NoSurface,\
116 | InvalidWire, RedundantWire, IntersectingWires, InvalidImbricationOfWires,\
117 | EmptyShell, RedundantFace, UnorientableShape, NotClosed,\
118 | NotConnected, SubshapeNotInShape, BadOrientation, BadOrientationOfSubshape,\
119 | InvalidToleranceValue, CheckFail")
120 |
121 | _brep_check_b = [BRepCheck_NoError, BRepCheck_InvalidPointOnCurve,
122 | BRepCheck_InvalidPointOnCurveOnSurface,
123 | BRepCheck_InvalidPointOnSurface,
124 | BRepCheck_No3DCurve, BRepCheck_Multiple3DCurve,
125 | BRepCheck_Invalid3DCurve, BRepCheck_NoCurveOnSurface,
126 | BRepCheck_InvalidCurveOnSurface,
127 | BRepCheck_InvalidCurveOnClosedSurface,
128 | BRepCheck_InvalidSameRangeFlag,
129 | BRepCheck_InvalidSameParameterFlag,
130 | BRepCheck_InvalidDegeneratedFlag, BRepCheck_FreeEdge,
131 | BRepCheck_InvalidMultiConnexity, BRepCheck_InvalidRange,
132 | BRepCheck_EmptyWire, BRepCheck_RedundantEdge,
133 | BRepCheck_SelfIntersectingWire, BRepCheck_NoSurface,
134 | BRepCheck_InvalidWire, BRepCheck_RedundantWire,
135 | BRepCheck_IntersectingWires,
136 | BRepCheck_InvalidImbricationOfWires,
137 | BRepCheck_EmptyShell, BRepCheck_RedundantFace,
138 | BRepCheck_UnorientableShape, BRepCheck_NotClosed,
139 | BRepCheck_NotConnected, BRepCheck_SubshapeNotInShape,
140 | BRepCheck_BadOrientation, BRepCheck_BadOrientationOfSubshape,
141 | BRepCheck_InvalidToleranceValue, BRepCheck_CheckFail]
142 |
143 | brepcheck_lut = EnumLookup(_brep_check_a, _brep_check_b)
144 | curve_lut = EnumLookup(_curve_typesA, _curve_typesB)
145 | surface_lut = EnumLookup(_surface_typesA, _surface_typesB)
146 | state_lut = EnumLookup(_stateA, _stateB)
147 | orient_lut = EnumLookup(_orientA, _orientB)
148 | topo_lut = EnumLookup(_topoTypesA, _topoTypesB)
149 | shape_lut = ShapeToTopology()
150 | geom_lut = EnumLookup(_geom_types_a, _geom_types_b)
151 |
152 | # todo: refactor, these classes have been moved from the "Topology" directory
153 | # which had too many overlapping methods & classes, that are
154 | # now part of the KBE module...
155 | # still need to think what to do with these...
156 | # what_is_face should surely become a lut [ geom_lut? ]
157 | # i'm not sure whether casting to a gp_* is useful...
158 |
159 | classes = dir()
160 | geom_classes = []
161 | for elem in classes:
162 | if elem.startswith('Geom') and not 'swig' in elem:
163 | geom_classes.append(elem)
164 |
165 |
166 | def what_is_face(face):
167 | ''' Returns all class names for which this class can be downcasted
168 | '''
169 | if not face.ShapeType() == TopAbs_FACE:
170 | print('%s is not a TopAbs_FACE. Conversion impossible')
171 | return None
172 | hs = BRep_Tool_Surface(face)
173 | obj = hs.GetObject()
174 | result = []
175 | for elem in classes:
176 | if (elem.startswith('Geom') and not 'swig' in elem):
177 | geom_classes.append(elem)
178 | # Run the test for each class
179 | for geom_class in geom_classes:
180 | if obj.IsKind(geom_class) and not geom_class in result:
181 | result.append(geom_class)
182 | return result
183 |
184 |
185 | def face_is_plane(face):
186 | ''' Returns True if the TopoDS_Shape is a plane, False otherwise
187 | '''
188 | hs = BRep_Tool_Surface(face)
189 | downcast_result = Handle_Geom_Plane().DownCast(hs)
190 | # the handle is null if downcast failed or is not possible,
191 | # that is to say the face is not a plane
192 | if downcast_result.IsNull():
193 | return False
194 | else:
195 | return True
196 |
197 |
198 | def shape_is_cylinder(face):
199 | ''' Returns True is the TopoDS_Shape is a cylinder, False otherwise
200 | '''
201 | hs = BRep_Tool_Surface(face)
202 | downcast_result = Handle_Geom_CylindricalSurface().DownCast(hs)
203 | if downcast_result.IsNull():
204 | return False
205 | else:
206 | return True
207 |
--------------------------------------------------------------------------------
/misc/buildFaceBottomUp.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from math import pi
3 |
4 | from OCC.TopAbs import *
5 | from OCC.TopExp import *
6 | from OCC.BRepPrimAPI import BRepPrimAPI_MakeBox
7 | from OCC.AIS import *
8 | from OCC.Quantity import *
9 | from OCC.Display.SimpleGui import init_display
10 | from OCC.TopoDS import *
11 | from OCC.gp import *
12 | from OCC.TopLoc import *
13 | from OCC.Geom import *
14 | from OCC.BRep import *
15 | from OCC.GCE2d import *
16 | from OCC.BRepBuilderAPI import *
17 | from OCC.GC import *
18 | from OCCUtils import Topology
19 | import aocutils.brep.solid_make
20 |
21 | display, start_display, add_menu, add_function_to_menu = init_display()
22 |
23 |
24 | def geom_plane_from_face(aFace):
25 | """
26 | Returns the geometric plane entity from a planar surface
27 | """
28 | return Handle_Geom_Plane.DownCast(OCC.BRep.BRep_Tool_Surface(aFace)).GetObject()
29 |
30 | def redraw(shape, event=None):
31 | # display with crisp edges and transpaarency
32 | context = display.Context
33 | context.RemoveAll()
34 | context.SetAutoActivateSelection(False)
35 | aisShape = AIS_Shape(shape)
36 | h_aisShape = aisShape.GetHandle()
37 | context.Display(h_aisShape)
38 | context.SetTransparency(h_aisShape, .1)
39 | context.HilightWithColor(h_aisShape, OCC.Quantity.Quantity_NOC_BLACK)
40 | display.FitAll()
41 |
42 | def makeBox(event=None):
43 | # Make a box
44 | Box = BRepPrimAPI_MakeBox(60, 60, 50).Shape()
45 | redraw()
46 |
47 | def rotateBox():
48 | aisShape = AIS_Shape(Box)
49 | ax1 = gp_Ax1(gp_Pnt(0., 0., 0.), gp_Dir(1., 0., 0.))
50 | aRotTrsf = gp_Trsf()
51 | angle = pi/6
52 | aRotTrsf.SetRotation(ax1, angle)
53 | aTopLoc = TopLoc_Location(aRotTrsf)
54 | Box.Move(aTopLoc)
55 | redraw()
56 |
57 | def enableFaceSelect(event=None):
58 | display.selected_shape = None
59 | display.SetSelectionModeFace()
60 |
61 | def makeSqProfile(size, surface):
62 | # points and segments need to be in CW sequence to get W pointing along Z
63 | aPnt1 = gp_Pnt2d(-size, size)
64 | aPnt2 = gp_Pnt2d(size, size)
65 | aPnt3 = gp_Pnt2d(size, -size)
66 | aPnt4 = gp_Pnt2d(-size, -size)
67 | aSegment1 = GCE2d_MakeSegment(aPnt1, aPnt2)
68 | aSegment2 = GCE2d_MakeSegment(aPnt2, aPnt3)
69 | aSegment3 = GCE2d_MakeSegment(aPnt3, aPnt4)
70 | aSegment4 = GCE2d_MakeSegment(aPnt4, aPnt1)
71 | print 'Next is where something crashes'
72 | aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value(),
73 | Handle_Geom_Surface(surface))
74 | aEdge2 = BRepBuilderAPI_MakeEdge(aSegment2.Value(),
75 | Handle_Geom_Surface(surface))
76 | aEdge3 = BRepBuilderAPI_MakeEdge(aSegment3.Value(),
77 | Handle_Geom_Surface(surface))
78 | aEdge4 = BRepBuilderAPI_MakeEdge(aSegment4.Value(),
79 | Handle_Geom_Surface(surface))
80 | print "Doesn't get here (with rotated box)"
81 | aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(),
82 | aEdge2.Edge(),
83 | aEdge3.Edge(),
84 | aEdge4.Edge())
85 |
86 | myWireProfile = aWire.Wire()
87 | return myWireProfile # TopoDS_Wire
88 |
89 | def wireProfileOnFace(event=None):
90 | aShape = display.GetSelectedShape()
91 | shapes = display.GetSelectedShapes()
92 | face = None
93 | if aShape:
94 | face = topods_Face(aShape)
95 | print "A shape found:"
96 | elif shapes:
97 | aShape = shapes[0]
98 | face = topods_Face(aShape)
99 | print len(shapes), "Shapes found"
100 | if face:
101 | surface = geom_plane_from_face(face)
102 | wireProfile = makeSqProfile(50, surface)
103 | display.DisplayShape(wireProfile)
104 | else:
105 | print 'no face'
106 |
107 | def translatePnt(p1, vec):
108 | p2 = gp_Pnt()
109 | p2 = p1.Translated(vec)
110 | return p2
111 |
112 | def pointsToWire(p1, p2, p3, p4):
113 | seg1 = GC_MakeSegment(p1, p2)
114 | seg2 = GC_MakeSegment(p2, p3)
115 | seg3 = GC_MakeSegment(p3, p4)
116 | seg4 = GC_MakeSegment(p4, p1)
117 | edge1 = BRepBuilderAPI_MakeEdge(seg1.Value())
118 | edge2 = BRepBuilderAPI_MakeEdge(seg2.Value())
119 | edge3 = BRepBuilderAPI_MakeEdge(seg3.Value())
120 | edge4 = BRepBuilderAPI_MakeEdge(seg4.Value())
121 | wire = BRepBuilderAPI_MakeWire(edge1.Edge(), edge2.Edge(),
122 | edge3.Edge(), edge4.Edge())
123 | return wire.Wire()
124 |
125 | def sewBox():
126 | # Length of shape (spine)
127 | Vec = gp_Vec(0, 0, 10)
128 | # starting with bot vertices, make bot wire & face
129 | p1 = gp_Pnt(0, 0, 0)
130 | p2 = gp_Pnt(20, 0, 0)
131 | p3 = gp_Pnt(20, 20, 0)
132 | p4 = gp_Pnt(0, 20, 0)
133 | botWire = pointsToWire(p1, p2, p3, p4)
134 | botFace = BRepBuilderAPI_MakeFace(botWire).Face()
135 | # starting with topvertices, make top face
136 | p5 = translatePnt(p1, Vec)
137 | p6 = translatePnt(p2, Vec)
138 | p7 = translatePnt(p3, Vec)
139 | p8 = translatePnt(p4, Vec)
140 | topWire = pointsToWire(p5, p6, p7, p8)
141 | topFace = BRepBuilderAPI_MakeFace(topWire).Face()
142 | # Make spine (wire) to make 'pipe'
143 | spineSeg = GC_MakeSegment(p1, p5)
144 | spineEdge = BRepBuilderAPI_MakeEdge(spineSeg.Value())
145 | spineWire = BRepBuilderAPI_MakeWire(spineEdge.Edge()).Wire()
146 | pipe = OCC.BRepOffsetAPI.BRepOffsetAPI_MakePipe(botWire, spineWire).Shape()
147 | # Sew together botFace, pipe, and topFace to get solid
148 | tolerance = 1e-6
149 | sew = OCC.BRepBuilderAPI.BRepBuilderAPI_Sewing(tolerance)
150 | sew.Add(botFace)
151 | sew.Add(pipe)
152 | sew.Add(topFace)
153 | sew.Perform()
154 | res = sew.SewedShape()
155 | redraw(res)
156 |
157 | def buildFaceBotUp():
158 | """Following procedure in Roman Lygen's blog
159 | """
160 | origin = gp_Pnt(0,0,0)
161 | wDir = gp_Dir(0,0,1)
162 | uDir = gp_Dir(1,0,0)
163 | vDir = gp_Dir(0,1,0)
164 | xyzAx3 = gp_Ax3(origin, wDir, uDir)
165 | gpPlane = gp_Pln(xyzAx3) # type OCC.gp.gp_Pln
166 | # gpPlane = gp_XOY() # type gp_Ax2
167 | plane = Geom_Plane(gpPlane) # type: OCC.Geom.Geom_Plane
168 | aSurf = Handle_Geom_Surface(plane) # type: Handle_Geom_Surface
169 | anExtC = Geom_Circle(gp_XOY(), 10.0) # type: OCC.Geom.Geom_Circle
170 | anIntC = Geom_Circle(gp_XOY(), 5.0) # type: OCC.Geom.Geom_Circle
171 | anExtE = BRepBuilderAPI_MakeEdge(anExtC.GetHandle())
172 | anIntE = BRepBuilderAPI_MakeEdge(anIntC.GetHandle())
173 | anExtWire = BRepBuilderAPI_MakeWire(anExtE.Edge())
174 | anIntWire = BRepBuilderAPI_MakeWire(anIntE.Edge())
175 | aFace = BRepBuilderAPI_MakeFace(anExtWire.Wire())
176 | aFace.Add(anIntWire.Wire()) # adds wire to the face as a hole
177 | display.DisplayShape(aFace.Face())
178 | edgeList = []
179 | anEdgeExplorer = TopExp_Explorer(aFace.Face(), TopAbs_EDGE)
180 | while anEdgeExplorer.More():
181 | anEdge = topods.Edge(anEdgeExplorer.Current())
182 | anEdgeExplorer.Next()
183 | edgeList.append(anEdge)
184 | print 'Number of edges: ', len(edgeList)
185 | Topology.dumpTopology(aFace.Face())
186 | topo = Topology.Topo(aFace.Face())
187 | print 'Number of wires: ', topo.number_of_wires_from_face(aFace.Face())
188 | wires = topo.wires_from_face(aFace.Face())
189 | for wire in wires:
190 | display.DisplayShape(wire)
191 |
192 | def testEdge():
193 | origin = gp_Pnt(0,0,0)
194 | wDir = gp_Dir(0,0,1)
195 | uDir = gp_Dir(1,0,0)
196 | vDir = gp_Dir(0,1,0)
197 | xyzAx3 = gp_Ax3(origin, wDir, uDir)
198 | gpPlane = gp_Pln(xyzAx3) # type OCC.gp.gp_Pln
199 | # gpPlane = gp_XOY() # type gp_Ax2
200 | plane = Geom_Plane(gpPlane) # type: OCC.Geom.Geom_Plane
201 | aSurf = Handle_Geom_Surface(plane) # type: Handle_Geom_Surface
202 | anExtC = Geom_Circle(gp_XOY(), 10.0) # type: OCC.Geom.Geom_Circle
203 | anIntC = Geom_Circle(gp_XOY(), 5.0) # type: OCC.Geom.Geom_Circle
204 | anExtE = BRepBuilderAPI_MakeEdge(anExtC.GetHandle())
205 | anIntE = BRepBuilderAPI_MakeEdge(anIntC.GetHandle())
206 | anExtWire = BRepBuilderAPI_MakeWire(anExtE.Edge())
207 | anIntWire = BRepBuilderAPI_MakeWire(anIntE.Edge())
208 | aFace = BRepBuilderAPI_MakeFace(anExtWire.Wire())
209 | aFace.Add(anIntWire.Wire()) # adds wire to the face as a hole
210 | display.DisplayShape(aFace.Face())
211 | edgeList = []
212 | anEdgeExplorer = TopExp_Explorer(aFace.Face(), TopAbs_EDGE)
213 | while anEdgeExplorer.More():
214 | anEdge = topods.Edge(anEdgeExplorer.Current())
215 |
216 | anEdgeExplorer.Next()
217 | edgeList.append(anEdge)
218 | print 'Number of edges: ', len(edgeList)
219 | for edge in edgeList:
220 | hCurve, umin, umax = BRep_Tool.Curve(edge)
221 | curve = hCurve.GetObject() # type: Geom_Curve
222 | print 'umin = ', umin
223 | print 'umax = ', umax
224 | print 'Is Periodic? ', curve.IsPeriodic()
225 | print 'Shape: ', curve.Continuity()
226 | print 'first: ', curve.FirstParameter()
227 | print 'last: ', curve.LastParameter()
228 | vectr = curve.DN(0.0, 2)
229 | print 'curvature at u=0: ', vectr.Magnitude()
230 |
231 | seg = GC_MakeSegment(gp_Pnt(0,0,0), gp_Pnt(2,2,2))
232 | edg = BRepBuilderAPI_MakeEdge(seg.Value()).Edge()
233 | print type(edg)
234 | hCurve, umin, umax = BRep_Tool.Curve(edg)
235 | curve = hCurve.GetObject()
236 | print type(curve) # type: Geom_Curve
237 | print 'Is Periodic? ', curve.IsPeriodic()
238 | print 'Shape: ', curve.Continuity()
239 | print 'first: ', curve.FirstParameter()
240 | print 'last: ', curve.LastParameter()
241 | vectr = curve.DN(0.0, 2)
242 | print 'curvature at u=0: ', vectr.Magnitude()
243 |
244 |
245 | def exit(event=None):
246 | sys.exit()
247 |
248 | if __name__ == '__main__':
249 | add_menu('operations')
250 | add_function_to_menu('operations', makeBox)
251 | add_function_to_menu('operations', rotateBox)
252 | add_function_to_menu('operations', enableFaceSelect)
253 | add_function_to_menu('operations', wireProfileOnFace)
254 | add_function_to_menu('operations', exit)
255 | add_menu('Experimental')
256 | add_function_to_menu('Experimental', sewBox)
257 | add_function_to_menu('Experimental', buildFaceBotUp)
258 | add_function_to_menu('Experimental', testEdge)
259 |
260 | start_display()
261 |
--------------------------------------------------------------------------------
/misc/tkrpncalc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # CADvas
4 | # A 2D CAD application written in Python and based on the Tkinter canvas.
5 | # The latest version of this file can be found at:
6 | # http://members.localnet.com/~blanding/cadvas
7 | #
8 | # Author: Doug Blanding
9 | #
10 | # CADvas is free software; you can redistribute it and/or modify
11 | # it under the terms of the GNU General Public License as published by
12 | # the Free Software Foundation; either version 2 of the License, or
13 | # (at your option) any later version.
14 | #
15 | # CADvas is distributed in the hope that it will be useful,
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | # GNU General Public License for more details.
19 | #
20 | # You should have received a copy of the GNU General Public License
21 | # along with CADvas; if not, write to the Free Software
22 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 | #
24 |
25 | from __future__ import division
26 | import sys
27 | from Tkinter import *
28 | import math
29 |
30 | def but(root, text, row, col, com=None, span=2, clr='darkslateblue', pad=1):
31 | w = Button(root, text=text, command=com, bg=clr, fg='white', padx=pad)
32 | w.grid(row=row, column=col, columnspan=span, sticky=E+W)
33 |
34 | def ent(root, var, row, col=2, span=10):
35 | e = Entry(root, textvariable=var, relief=SUNKEN)
36 | e.grid(row=row, column=col, columnspan=span)
37 |
38 | def f2s(f):
39 | """Convert float to string with 12 significant figures."""
40 | return '%1.12f' % f
41 |
42 | class Calculator(Toplevel):
43 | """RPN (Reverse Polish Notation) calculator styled after the one
44 | used in CoCreate SolidDesigner CAD."""
45 | mem = ''
46 | keip = False # Flag set when keyboard entry is in progress
47 | needrup = False # Flag signaling need to rotate up with next keyboard entry
48 | def __init__(self, caller=None):
49 | Toplevel.__init__(self)
50 | self.caller = caller # ref to Draw instance
51 | self.title('RPN Calc')
52 | self.protocol("WM_DELETE_WINDOW", self.quit)
53 | #self.resizable(width=0, height=0)
54 | if caller:
55 | self.transient(caller)
56 |
57 | but(self, 't', 0, 0, lambda r='t': self.pr(r), clr='dimgray')
58 | but(self, 'z', 1, 0, lambda r='z': self.pr(r), clr='dimgray')
59 | but(self, 'y', 2, 0, lambda r='y': self.pr(r), clr='dimgray')
60 | but(self, 'x', 3, 0, lambda r='x': self.pr(r), clr='dimgray')
61 |
62 | self.tdisplay = StringVar()
63 | self.zdisplay = StringVar()
64 | self.ydisplay = StringVar()
65 | self.xdisplay = StringVar()
66 | ent(self, self.tdisplay, 0)
67 | ent(self, self.zdisplay, 1)
68 | ent(self, self.ydisplay, 2)
69 | ent(self, self.xdisplay, 3)
70 |
71 | but(self, 'mm->in', 4, 0, self.mm2in, span=4, clr='dimgray')
72 | but(self, 'in->mm', 4, 4, self.in2mm, span=4, clr='dimgray')
73 | but(self, 'Sto', 4, 8, self.storex, clr='darkgreen')
74 | but(self, 'Rcl', 4, 10, self.recallx, clr='darkgreen')
75 | but(self, '7', 5, 0, lambda c='7': self.keyin(c), clr='steelblue')
76 | but(self, '8', 5, 2, lambda c='8': self.keyin(c), clr='steelblue')
77 | but(self, '9', 5, 4, lambda c='9': self.keyin(c), clr='steelblue')
78 | but(self, '+', 5, 6, lambda op='+': self.calc(op))
79 | but(self, 'Rup', 5, 8, self.rotateup, clr='darkgreen')
80 | but(self, 'Rdn', 5, 10, self.rotatedn, clr='darkgreen')
81 | but(self, '4', 6, 0, lambda c='4': self.keyin(c), clr='steelblue')
82 | but(self, '5', 6, 2, lambda c='5': self.keyin(c), clr='steelblue')
83 | but(self, '6', 6, 4, lambda c='6': self.keyin(c), clr='steelblue')
84 | but(self, '-', 6, 6, lambda op='-': self.calc(op))
85 | but(self, '<-', 6, 8, self.trimx, clr='darkred')
86 | but(self, 'x<>y', 6, 10, self.swapxy, clr='darkgreen', pad=0)
87 | but(self, '1', 7, 0, lambda c='1': self.keyin(c), clr='steelblue')
88 | but(self, '2', 7, 2, lambda c='2': self.keyin(c), clr='steelblue')
89 | but(self, '3', 7, 4, lambda c='3': self.keyin(c), clr='steelblue')
90 | but(self, '*', 7, 6, lambda op='*': self.calc(op))
91 | but(self, 'Clx', 7, 8, self.clearx, clr='darkred')
92 | but(self, 'Clr', 7, 10, self.clearall, clr='darkred')
93 | but(self, '0', 8, 0, lambda c='0': self.keyin(c), clr='steelblue', pad=3)
94 | but(self, '.', 8, 2, lambda c='.': self.keyin(c))
95 | but(self, '+/-', 8, 4, lambda op='+/-': self.calc(op))
96 | but(self, ' / ', 8, 6, lambda c='/': self.calc(c), pad=3)
97 | but(self, 'ENTER', 8, 8, self.enter, span=4, clr='darkgoldenrod')
98 | but(self, 'Sin', 9, 0, lambda op='math.sin(x)': self.func(op, in_cnvrt=1),
99 | span=3, clr='darkgoldenrod')
100 | but(self, 'Cos', 9, 3, lambda op='math.cos(x)': self.func(op, in_cnvrt=1),
101 | span=3, clr='darkgoldenrod')
102 | but(self, 'Tan', 9, 6, lambda op='math.tan(x)': self.func(op, in_cnvrt=1),
103 | span=3, clr='darkgoldenrod')
104 | but(self, 'Pi', 9, 9, lambda op='math.pi': self.func(op), span=3, clr='darkgoldenrod')
105 | but(self, 'ASin', 10, 0, lambda op='math.asin(x)': self.func(op, out_cnvrt=1),
106 | span=3, clr='darkgoldenrod')
107 | but(self, 'ACos', 10, 3, lambda op='math.acos(x)': self.func(op, out_cnvrt=1),
108 | span=3, clr='darkgoldenrod')
109 | but(self, 'ATan', 10, 6, lambda op='math.atan(x)': self.func(op, out_cnvrt=1),
110 | span=3, clr='darkgoldenrod')
111 | but(self, '', 10, 9, span=3, clr='darkgoldenrod')
112 | but(self, 'x^2', 11, 0, lambda op='x**2': self.func(op), span=3, clr='darkgreen')
113 | but(self, '1/x', 11, 3, lambda op='1/x': self.func(op), span=3, clr='darkgreen')
114 | but(self, 'e^x', 11, 6, lambda op='math.e**x': self.func(op), span=3, clr='darkgreen')
115 | but(self, '10^x', 11, 9, lambda op='10**x': self.func(op), span=3, clr='darkgreen')
116 | but(self, 'Sqrt', 12, 0, lambda op='math.sqrt(x)': self.func(op), span=3, clr='darkgreen')
117 | but(self, 'y^x', 12, 3, lambda op='y**x': self.func(op), span=3, clr='darkgreen')
118 | but(self, 'ln', 12, 6, lambda op='math.log(x)': self.func(op), span=3, clr='darkgreen')
119 | but(self, 'log', 12, 9, lambda op='math.log10(x)': self.func(op), span=3, clr='darkgreen')
120 |
121 |
122 | def quit(self):
123 | if self.caller:
124 | self.caller.calculator = None
125 | self.destroy()
126 |
127 | def pr(self, val):
128 | """Send value in register to caller."""
129 | # There must be a better way to get this value
130 | str_value = `eval('self.'+val+'display.get()')`.strip("'")
131 | self.caller.enterfloat(str_value)
132 | self.keip = False
133 | self.needrup = True
134 |
135 | def keyin(self, c):
136 | if self.keip:
137 | self.xdisplay.set(self.xdisplay.get()+c)
138 | else:
139 | self.keip = True
140 | if self.needrup:
141 | self.rotateup(loop=0)
142 | self.clearx()
143 | self.keyin(c)
144 |
145 | def enter(self):
146 | self.tdisplay.set(self.zdisplay.get())
147 | self.zdisplay.set(self.ydisplay.get())
148 | self.ydisplay.set(self.xdisplay.get())
149 | self.keip = False
150 | self.needrup = False
151 |
152 | def calc(self, op):
153 | """Arithmetic calculations between x and y registers, then rotate down."""
154 | try:
155 | if op == '+/-':
156 | self.xdisplay.set(`eval('-'+self.xdisplay.get())`)
157 | else:
158 | x = `eval(self.ydisplay.get()+op+self.xdisplay.get())`
159 | self.xdisplay.set(x)
160 | self.ydisplay.set(self.zdisplay.get())
161 | self.zdisplay.set(self.tdisplay.get())
162 | self.keip = False
163 | self.needrup = True
164 | except:
165 | self.xdisplay.set("ERROR")
166 |
167 |
168 | def func(self, op, in_cnvrt=0, out_cnvrt=0):
169 | """Evaluate function op then put result in x-register, don't rotate stack.
170 | if in_cnvrt: convert input value of x-register from degrees to radians.
171 | if out_cnvrt: convert output value of x-register from radians to degrees."""
172 | try:
173 | x = float(self.xdisplay.get())
174 | except:
175 | x = 0
176 | try:
177 | y = float(self.ydisplay.get())
178 | except:
179 | y = 0
180 | if in_cnvrt:
181 | x = x * math.pi / 180
182 | result = eval(op)
183 | if out_cnvrt:
184 | result = result * 180 / math.pi
185 | self.xdisplay.set(f2s(result))
186 | self.keip = False
187 | self.needrup = True
188 |
189 | def mm2in(self):
190 | if self.xdisplay.get():
191 | self.xdisplay.set(`eval(self.xdisplay.get()+'/25.4')`)
192 | self.keip = False
193 | self.needrup = True
194 |
195 | def in2mm(self):
196 | if self.xdisplay.get():
197 | self.xdisplay.set(`eval(self.xdisplay.get()+'*25.4')`)
198 | self.keip = False
199 | self.needrup = True
200 |
201 | def storex(self):
202 | self.mem = self.xdisplay.get()
203 | self.keip = False
204 | self.needrup = True
205 |
206 | def recallx(self):
207 | self.rotateup()
208 | self.xdisplay.set(self.mem)
209 | self.keip = False
210 | self.needrup = True
211 |
212 | def rotateup(self, loop=1):
213 | x = self.tdisplay.get()
214 | self.tdisplay.set(self.zdisplay.get())
215 | self.zdisplay.set(self.ydisplay.get())
216 | self.ydisplay.set(self.xdisplay.get())
217 | if loop:
218 | self.xdisplay.set(x)
219 |
220 | def rotatedn(self):
221 | x = self.xdisplay.get()
222 | self.xdisplay.set(self.ydisplay.get())
223 | self.ydisplay.set(self.zdisplay.get())
224 | self.zdisplay.set(self.tdisplay.get())
225 | self.tdisplay.set(x)
226 |
227 | def trimx(self):
228 | self.xdisplay.set(self.xdisplay.get()[:-1])
229 |
230 | def swapxy(self):
231 | x = self.xdisplay.get()
232 | y = self.ydisplay.get()
233 | self.xdisplay.set(y)
234 | self.ydisplay.set(x)
235 |
236 | def clearx(self):
237 | self.xdisplay.set('')
238 |
239 | def clearall(self):
240 | self.xdisplay.set('')
241 | self.ydisplay.set('')
242 | self.zdisplay.set('')
243 | self.tdisplay.set('')
244 |
245 | def putx(self, value):
246 | if self.needrup:
247 | self.rotateup(loop=0)
248 | self.xdisplay.set(`value`)
249 | self.keip = False
250 | self.needrup = True
251 |
252 | if __name__ == '__main__':
253 | Calculator().mainloop()
254 |
--------------------------------------------------------------------------------
/misc/core_topology_local_ops.py:
--------------------------------------------------------------------------------
1 | ##Copyright 2009-2016 Thomas Paviot (tpaviot@gmail.com)
2 | ##
3 | ##This file is part of pythonOCC.
4 | ##
5 | ##pythonOCC is free software: you can redistribute it and/or modify
6 | ##it under the terms of the GNU Lesser General Public License as published by
7 | ##the Free Software Foundation, either version 3 of the License, or
8 | ##(at your option) any later version.
9 | ##
10 | ##pythonOCC is distributed in the hope that it will be useful,
11 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ##GNU Lesser General Public License for more details.
14 | ##
15 | ##You should have received a copy of the GNU Lesser General Public License
16 | ##along with pythonOCC. If not, see .
17 | import sys
18 | from math import pi
19 |
20 | from OCC.BRep import BRep_Tool_Surface
21 | from OCC.BRepAlgoAPI import BRepAlgoAPI_Section, BRepAlgoAPI_Fuse
22 | from OCC.BRepBuilderAPI import BRepBuilderAPI_MakeWire, BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeFace, \
23 | BRepBuilderAPI_GTransform
24 | from OCC.BRepFeat import BRepFeat_MakePrism, BRepFeat_MakeDPrism, BRepFeat_SplitShape, \
25 | BRepFeat_MakeLinearForm, BRepFeat_MakeRevol
26 | from OCC.BRepLib import breplib_BuildCurves3d
27 | from OCC.BRepOffset import BRepOffset_Skin
28 | from OCC.BRepOffsetAPI import BRepOffsetAPI_MakeThickSolid, BRepOffsetAPI_MakeOffsetShape
29 | from OCC.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakePrism
30 | from OCC.Display.SimpleGui import init_display
31 | from OCC.GCE2d import GCE2d_MakeLine
32 | from OCC.Geom import Handle_Geom_Plane_DownCast, Geom_Plane
33 | from OCC.Geom2d import Geom2d_Circle
34 | from OCC.GeomAbs import GeomAbs_Arc
35 | from OCC.TopTools import TopTools_ListOfShape
36 | from OCC.TopoDS import TopoDS_Face
37 | from OCC.gp import gp_Pnt2d, gp_Circ2d, gp_Ax2d, gp_Dir2d, gp_Pnt, gp_Pln, gp_Vec, gp_OX, gp_Trsf, gp_GTrsf
38 |
39 | from core_topology_traverse import Topo
40 |
41 | display, start_display, add_menu, add_function_to_menu = init_display()
42 |
43 |
44 | def extrusion(event=None):
45 | # Make a box
46 | Box = BRepPrimAPI_MakeBox(400., 250., 300.)
47 | S = Box.Shape()
48 |
49 | # Choose the first Face of the box
50 | F = next(Topo(S).faces())
51 | surf = BRep_Tool_Surface(F)
52 |
53 | # Make a plane from this face
54 | Pl = Handle_Geom_Plane_DownCast(surf)
55 | Pln = Pl.GetObject()
56 |
57 | # Get the normal of this plane. This will be the direction of extrusion.
58 | D = Pln.Axis().Direction()
59 |
60 | # Inverse normal
61 | #D.Reverse()
62 |
63 | # Create the 2D planar sketch
64 | MW = BRepBuilderAPI_MakeWire()
65 | p1 = gp_Pnt2d(200., -100.)
66 | p2 = gp_Pnt2d(100., -100.)
67 | aline = GCE2d_MakeLine(p1, p2).Value()
68 | Edge1 = BRepBuilderAPI_MakeEdge(aline, surf, 0., p1.Distance(p2))
69 | MW.Add(Edge1.Edge())
70 | p1 = p2
71 | p2 = gp_Pnt2d(100., -200.)
72 | aline = GCE2d_MakeLine(p1, p2).Value()
73 | Edge2 = BRepBuilderAPI_MakeEdge(aline, surf, 0., p1.Distance(p2))
74 | MW.Add(Edge2.Edge())
75 | p1 = p2
76 | p2 = gp_Pnt2d(200., -200.)
77 | aline = GCE2d_MakeLine(p1, p2).Value()
78 | Edge3 = BRepBuilderAPI_MakeEdge(aline, surf, 0., p1.Distance(p2))
79 | MW.Add(Edge3.Edge())
80 | p1 = p2
81 | p2 = gp_Pnt2d(200., -100.)
82 | aline = GCE2d_MakeLine(p1, p2).Value()
83 | Edge4 = BRepBuilderAPI_MakeEdge(aline, surf, 0., p1.Distance(p2))
84 | MW.Add(Edge4.Edge())
85 |
86 | # Build Face from Wire. NB: a face is required to generate a solid.
87 | MKF = BRepBuilderAPI_MakeFace()
88 | MKF.Init(surf, False, 1e-6)
89 | MKF.Add(MW.Wire())
90 | FP = MKF.Face()
91 | breplib_BuildCurves3d(FP)
92 |
93 | MKP = BRepFeat_MakePrism(S, FP, F, D, False, True)
94 | MKP.Perform(200.)
95 | # TODO MKP completes, seeing a split operation but no extrusion
96 | assert MKP.IsDone()
97 | res1 = MKP.Shape()
98 |
99 | display.EraseAll()
100 | display.DisplayColoredShape(res1, 'BLUE')
101 | display.DisplayColoredShape(FP, 'YELLOW')
102 | display.FitAll()
103 |
104 |
105 | def brepfeat_prism(event=None):
106 | box = BRepPrimAPI_MakeBox(400, 250, 300).Shape()
107 | faces = Topo(box).faces()
108 |
109 | for i in range(3):
110 | face = next(faces)
111 |
112 | srf = BRep_Tool_Surface(face)
113 |
114 | c = gp_Circ2d(gp_Ax2d(gp_Pnt2d(200, 130),
115 | gp_Dir2d(1, 0)), 75)
116 |
117 | circle = Geom2d_Circle(c).GetHandle()
118 |
119 | wire = BRepBuilderAPI_MakeWire()
120 | wire.Add(BRepBuilderAPI_MakeEdge(circle, srf, 0., pi).Edge())
121 | wire.Add(BRepBuilderAPI_MakeEdge(circle, srf, pi, 2. * pi).Edge())
122 | wire.Build()
123 |
124 | display.DisplayShape(wire.Wire())
125 |
126 | mkf = BRepBuilderAPI_MakeFace()
127 | mkf.Init(srf, False, 1e-6)
128 | mkf.Add(wire.Wire())
129 | mkf.Build()
130 |
131 | new_face = mkf.Face()
132 | breplib_BuildCurves3d(new_face)
133 |
134 | display.DisplayColoredShape(box, 'GREEN')
135 | display.DisplayShape(new_face)
136 | """
137 | prism = BRepFeat_MakeDPrism(box, mkf.Face(), face, 100, True, True)
138 |
139 | prism.Perform(400)
140 | assert prism.IsDone()
141 | display.EraseAll()
142 | display.DisplayShape(prism.Shape())
143 | """
144 | #display.DisplayColoredShape(wire.Wire(), 'RED')
145 | display.FitAll()
146 |
147 |
148 | def thick_solid(event=None):
149 | S = BRepPrimAPI_MakeBox(150, 200, 110).Shape()
150 |
151 | topo = Topo(S)
152 | vert = next(topo.vertices())
153 |
154 | shapes = TopTools_ListOfShape()
155 | for f in topo.faces_from_vertex(vert):
156 | shapes.Append(f)
157 |
158 | _thick_solid = BRepOffsetAPI_MakeThickSolid(S, shapes, 15, 0.01)
159 | display.EraseAll()
160 | display.DisplayShape(_thick_solid.Shape())
161 | display.FitAll()
162 |
163 |
164 | def offset_cube(event=None):
165 | S2 = BRepPrimAPI_MakeBox(gp_Pnt(300, 0, 0), 220, 140, 180).Shape()
166 | offsetB = BRepOffsetAPI_MakeOffsetShape(S2, -20, 0.01, BRepOffset_Skin, False, False, GeomAbs_Arc)
167 | offB = display.DisplayColoredShape(S2, 'BLUE')
168 | display.Context.SetTransparency(offB, 0.3)
169 | display.DisplayColoredShape(offsetB.Shape(), 'GREEN')
170 | display.FitAll()
171 |
172 |
173 | def split_shape(event=None):
174 | S = BRepPrimAPI_MakeBox(gp_Pnt(-100, -60, -80), 150, 200, 170).Shape()
175 | asect = BRepAlgoAPI_Section(S, gp_Pln(1, 2, 1, -15), False)
176 | asect.ComputePCurveOn1(True)
177 | asect.Approximation(True)
178 | asect.Build()
179 | R = asect.Shape()
180 |
181 | asplit = BRepFeat_SplitShape(S)
182 |
183 | for edg in Topo(R).edges():
184 | face = TopoDS_Face()
185 | if asect.HasAncestorFaceOn1(edg, face):
186 | asplit.Add(edg, face)
187 |
188 | asplit.Build()
189 | display.EraseAll()
190 | display.DisplayShape(asplit.Shape())
191 | display.FitAll()
192 |
193 |
194 | def brep_feat_rib(event=None):
195 | mkw = BRepBuilderAPI_MakeWire()
196 |
197 | mkw.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(0., 0., 0.), gp_Pnt(200., 0., 0.)).Edge())
198 | mkw.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(200., 0., 0.), gp_Pnt(200., 0., 50.)).Edge())
199 | mkw.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(200., 0., 50.), gp_Pnt(50., 0., 50.)).Edge())
200 | mkw.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(50., 0., 50.), gp_Pnt(50., 0., 200.)).Edge())
201 | mkw.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(50., 0., 200.), gp_Pnt(0., 0., 200.)).Edge())
202 | mkw.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(0., 0., 200.), gp_Pnt(0., 0., 0.)).Edge())
203 |
204 | S = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(mkw.Wire()).Face(),
205 | gp_Vec(gp_Pnt(0., 0., 0.),
206 | gp_Pnt(0., 100., 0.)))
207 | display.EraseAll()
208 | # display.DisplayShape(S.Shape())
209 |
210 | W = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(gp_Pnt(50., 45., 100.),
211 | gp_Pnt(100., 45., 50.)).Edge())
212 |
213 | aplane = Geom_Plane(0., 1., 0., -45.)
214 |
215 | aform = BRepFeat_MakeLinearForm(S.Shape(), W.Wire(), aplane.GetHandle(),
216 | gp_Vec(0., 10., 0.), gp_Vec(0., 0., 0.),
217 | 1, True)
218 | aform.Perform()
219 | display.DisplayShape(aform.Shape())
220 | display.FitAll()
221 |
222 |
223 | def brep_feat_local_revolution(event=None):
224 | S = BRepPrimAPI_MakeBox(400., 250., 300.).Shape()
225 | faces = list(Topo(S).faces())
226 | F1 = faces[2]
227 | surf = BRep_Tool_Surface(F1)
228 |
229 | D = gp_OX()
230 |
231 | MW1 = BRepBuilderAPI_MakeWire()
232 | p1 = gp_Pnt2d(100., 100.)
233 | p2 = gp_Pnt2d(200., 100.)
234 | aline = GCE2d_MakeLine(p1, p2).Value()
235 | MW1.Add(BRepBuilderAPI_MakeEdge(aline, surf, 0., p1.Distance(p2)).Edge())
236 |
237 | p1 = gp_Pnt2d(200., 100.)
238 | p2 = gp_Pnt2d(150., 200.)
239 | aline = GCE2d_MakeLine(p1, p2).Value()
240 | MW1.Add(BRepBuilderAPI_MakeEdge(aline, surf, 0., p1.Distance(p2)).Edge())
241 |
242 | p1 = gp_Pnt2d(150., 200.)
243 | p2 = gp_Pnt2d(100., 100.)
244 | aline = GCE2d_MakeLine(p1, p2).Value()
245 | MW1.Add(BRepBuilderAPI_MakeEdge(aline, surf, 0., p1.Distance(p2)).Edge())
246 |
247 | MKF1 = BRepBuilderAPI_MakeFace()
248 | MKF1.Init(surf, False, 1e-6)
249 | MKF1.Add(MW1.Wire())
250 | FP = MKF1.Face()
251 | breplib_BuildCurves3d(FP)
252 | MKrev = BRepFeat_MakeRevol(S, FP, F1, D, 1, True)
253 | F2 = faces[4]
254 | MKrev.Perform(F2)
255 | display.EraseAll()
256 | display.DisplayShape(MKrev.Shape())
257 | display.FitAll()
258 |
259 |
260 | def brep_feat_extrusion_protrusion(event=None):
261 | # Extrusion
262 | S = BRepPrimAPI_MakeBox(400., 250., 300.).Shape()
263 | faces = Topo(S).faces()
264 | F = next(faces)
265 | surf1 = BRep_Tool_Surface(F)
266 |
267 | Pl1 = Handle_Geom_Plane_DownCast(surf1).GetObject()
268 |
269 | D1 = Pl1.Pln().Axis().Direction().Reversed()
270 | MW = BRepBuilderAPI_MakeWire()
271 | p1, p2 = gp_Pnt2d(200., -100.), gp_Pnt2d(100., -100.)
272 | aline = GCE2d_MakeLine(p1, p2).Value()
273 | MW.Add(BRepBuilderAPI_MakeEdge(aline, surf1, 0., p1.Distance(p2)).Edge())
274 |
275 | p1, p2 = gp_Pnt2d(100., -100.), gp_Pnt2d(100., -200.)
276 | aline = GCE2d_MakeLine(p1, p2).Value()
277 | MW.Add(BRepBuilderAPI_MakeEdge(aline, surf1, 0., p1.Distance(p2)).Edge())
278 |
279 | p1, p2 = gp_Pnt2d(100., -200.), gp_Pnt2d(200., -200.)
280 | aline = GCE2d_MakeLine(p1, p2).Value()
281 | MW.Add(BRepBuilderAPI_MakeEdge(aline, surf1, 0., p1.Distance(p2)).Edge())
282 |
283 | p1, p2 = gp_Pnt2d(200., -200.), gp_Pnt2d(200., -100.)
284 | aline = GCE2d_MakeLine(p1, p2).Value()
285 | MW.Add(BRepBuilderAPI_MakeEdge(aline, surf1, 0., p1.Distance(p2)).Edge())
286 |
287 | MKF = BRepBuilderAPI_MakeFace()
288 | MKF.Init(surf1, False, 1e-6)
289 | MKF.Add(MW.Wire())
290 | FP = MKF.Face()
291 | breplib_BuildCurves3d(FP)
292 |
293 | display.EraseAll()
294 | MKP = BRepFeat_MakePrism(S, FP, F, D1, 0, True)
295 | MKP.PerformThruAll()
296 |
297 | res1 = MKP.Shape()
298 | display.DisplayShape(res1)
299 |
300 | # Protrusion
301 | next(faces)
302 | F2 = next(faces)
303 | surf2 = BRep_Tool_Surface(F2)
304 | Pl2 = Handle_Geom_Plane_DownCast(surf2).GetObject()
305 | D2 = Pl2.Pln().Axis().Direction().Reversed()
306 | MW2 = BRepBuilderAPI_MakeWire()
307 | p1, p2 = gp_Pnt2d(100., 100.), gp_Pnt2d(200., 100.)
308 | aline = GCE2d_MakeLine(p1, p2).Value()
309 | MW2.Add(BRepBuilderAPI_MakeEdge(aline, surf2, 0., p1.Distance(p2)).Edge())
310 |
311 | p1, p2 = gp_Pnt2d(200., 100.), gp_Pnt2d(150., 200.)
312 | aline = GCE2d_MakeLine(p1, p2).Value()
313 | MW2.Add(BRepBuilderAPI_MakeEdge(aline, surf2, 0., p1.Distance(p2)).Edge())
314 |
315 | p1, p2 = gp_Pnt2d(150., 200.), gp_Pnt2d(100., 100.)
316 | aline = GCE2d_MakeLine(p1, p2).Value()
317 | MW2.Add(BRepBuilderAPI_MakeEdge(aline, surf2, 0., p1.Distance(p2)).Edge())
318 |
319 | MKF2 = BRepBuilderAPI_MakeFace()
320 | MKF2.Init(surf2, False, 1e-6)
321 | MKF2.Add(MW2.Wire())
322 | MKF2.Build()
323 |
324 | FP = MKF2.Face()
325 | breplib_BuildCurves3d(FP)
326 | MKP2 = BRepFeat_MakePrism(res1, FP, F2, D2, 0, True)
327 | MKP2.PerformThruAll()
328 | display.EraseAll()
329 |
330 | trf = gp_Trsf()
331 | trf.SetTranslation(gp_Vec(0, 0, 300))
332 | gtrf = gp_GTrsf()
333 | gtrf.SetTrsf(trf)
334 | tr = BRepBuilderAPI_GTransform(MKP2.Shape(), gtrf, True)
335 |
336 | fused = BRepAlgoAPI_Fuse(tr.Shape(), MKP2.Shape())
337 | fused.RefineEdges()
338 | fused.Build()
339 | print('Boolean operation error status:', fused.ErrorStatus())
340 | display.DisplayShape(fused.Shape())
341 | display.FitAll()
342 |
343 | def exit(event=None):
344 | sys.exit()
345 |
346 |
347 | if __name__ == '__main__':
348 | add_menu('topology local operations')
349 | add_function_to_menu('topology local operations', brepfeat_prism)
350 | add_function_to_menu('topology local operations', extrusion)
351 | add_function_to_menu('topology local operations', thick_solid)
352 | add_function_to_menu('topology local operations', offset_cube)
353 | add_function_to_menu('topology local operations', split_shape)
354 | add_function_to_menu('topology local operations', brep_feat_rib)
355 | add_function_to_menu('topology local operations', brep_feat_local_revolution)
356 | add_function_to_menu('topology local operations', brep_feat_extrusion_protrusion)
357 | add_function_to_menu('topology local operations', exit)
358 | start_display()
359 |
--------------------------------------------------------------------------------
/myStepXcafReader.py:
--------------------------------------------------------------------------------
1 | #
2 | # myStepXcafReader.py
3 | # The goal of this module is to be able to read (and write) step files with complete
4 | # Assembly / Part structure, including the names of parts and assemblies, colors
5 | # of parts, and with all components shown in their correct positions.
6 | # The latest version of this file can be found at:
7 | # //https://github.com/dblanding/cadviewer
8 | #
9 | # Author: Doug Blanding
10 | #
11 | # myStepXcafReader is free software; you can redistribute it and/or modify
12 | # it under the terms of the GNU General Public License as published by
13 | # the Free Software Foundation; either version 2 of the License, or
14 | # (at your option) any later version.
15 | #
16 | # myStepXcafReader is distributed in the hope that it will be useful,
17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | # GNU General Public License for more details.
20 | #
21 | # You should have received a copy of the GNU General Public License
22 | # if not, write to the Free Software Foundation, Inc.
23 | # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 | #
25 |
26 |
27 | from __future__ import print_function
28 |
29 | import logging
30 | import os.path
31 | import OCC.Core.BRep
32 | from OCC.Core.IFSelect import IFSelect_RetDone
33 | import OCC.Core.Interface
34 | import OCC.Core.Quantity
35 | from OCC.Core.STEPCAFControl import STEPCAFControl_Reader
36 | import OCC.Core.STEPControl
37 | from OCC.Core.TDataStd import TDataStd_Name, TDataStd_Name_GetID
38 | from OCC.Core.TCollection import TCollection_ExtendedString
39 | import OCC.Core.TColStd
40 | from OCC.Core.TDF import TDF_LabelSequence
41 | from OCC.Core.TDocStd import TDocStd_Document
42 | import OCC.Core.TopAbs
43 | import OCC.Core.TopoDS
44 | from OCC.Core.XCAFApp import XCAFApp_Application_GetApplication
45 | from OCC.Core.XCAFDoc import (XCAFDoc_DocumentTool_ShapeTool,
46 | XCAFDoc_DocumentTool_ColorTool,
47 | XCAFDoc_DocumentTool_LayerTool,
48 | XCAFDoc_DocumentTool_MaterialTool)
49 |
50 | import OCC.Core.XSControl
51 | #import aocutils.topology
52 | import treelib
53 |
54 | logger = logging.getLogger(__name__)
55 | logger.setLevel(10) # 10 = debug; 20 = info; 40 = error
56 |
57 | class StepXcafImporter(object):
58 | """
59 | Read a step file with the goal of collecting a complete and accurate
60 | Assembly/Part structure, including the names of parts and assemblies,
61 | part color, and with all components shown in their correct positions.
62 | Data stored in self.tree
63 | """
64 | def __init__(self, filename, nextUID=0):
65 |
66 | self.filename = filename
67 | print(filename)
68 | self.tree = treelib.tree.Tree() # to hold assembly structure
69 | self._currentUID = nextUID
70 | self.assyUidStack = [0]
71 | self.assyLocStack = []
72 |
73 | self.read_file()
74 |
75 | def getNewUID(self):
76 | uid = self._currentUID + 1
77 | self._currentUID = uid
78 | return uid
79 |
80 | def getName(self, label):
81 | '''Get the part name from its label.'''
82 | N = TDataStd_Name()
83 | label.FindAttribute(TDataStd_Name_GetID(), N)
84 | strdump = N.DumpToString()
85 | #name = strdump.split('|')[-2]
86 | return strdump
87 |
88 | def getColor(self, shape):
89 | # Get the part color
90 | #string_seq = self.layer_tool.GetObject().GetLayers(shape)
91 | color = OCC.Core.Quantity.Quantity_Color()
92 | self.color_tool.GetColor(shape,
93 | OCC.Core.XCAFDoc.XCAFDoc_ColorSurf, color)
94 | logger.debug("color: {0}, {1}, {2}".format(color.Red(),
95 | color.Green(),
96 | color.Blue()))
97 | return color
98 |
99 | def findComponents(self, label, comps): # Discover Components of an Assembly
100 | logger.debug("")
101 | logger.debug("Finding components of label (entry = %s)" % label.EntryDumpToString())
102 | for j in range(comps.Length()):
103 | logger.debug("loop %i of %i" % (j+1, comps.Length()))
104 | cLabel = comps.Value(j+1)
105 | cShape = self.shape_tool.GetShape(cLabel)
106 | logger.debug("Label %i - type : %s" % (j+1, type(cLabel)))
107 | logger.debug("Entry: %s" % cLabel.EntryDumpToString())
108 | name = self.getName(cLabel)
109 | logger.debug("Part name: %s" % name)
110 | logger.debug("Is Assembly? %s" % self.shape_tool.IsAssembly(cLabel))
111 | logger.debug("Is Component? %s" % self.shape_tool.IsComponent(cLabel))
112 | logger.debug("Is Simple Shape? %s" % self.shape_tool.IsSimpleShape(cLabel))
113 | logger.debug("Is Reference? %s" % self.shape_tool.IsReference(cLabel))
114 | refLabel = OCC.Core.TDF.TDF_Label()
115 | isRef = self.shape_tool.GetReferredShape(cLabel, refLabel)
116 | if isRef:
117 | refShape = self.shape_tool.GetShape(refLabel)
118 | refLabelEntry = refLabel.EntryDumpToString()
119 | logger.debug("Entry of referred shape: %s" % refLabelEntry)
120 | refName = self.getName(refLabel)
121 | logger.debug("Name of referred shape: %s" % refName)
122 | logger.debug("Is Assembly? %s" % self.shape_tool.IsAssembly(refLabel))
123 | logger.debug("Is Component? %s" % self.shape_tool.IsComponent(refLabel))
124 | logger.debug("Is Simple Shape? %s" % self.shape_tool.IsSimpleShape(refLabel))
125 | logger.debug("Is Reference? %s" % self.shape_tool.IsReference(refLabel))
126 | if self.shape_tool.IsSimpleShape(refLabel):
127 | tempAssyLocStack = list(self.assyLocStack)
128 | tempAssyLocStack.reverse()
129 |
130 | for loc in tempAssyLocStack:
131 | cShape.Move(loc)
132 |
133 | color = self.getColor(refShape)
134 | self.tree.create_node(name,
135 | self.getNewUID(),
136 | self.assyUidStack[-1],
137 | {'a': False, 'l': None, 'c': color, 's': cShape})
138 | elif self.shape_tool.IsAssembly(refLabel):
139 | name = self.getName(cLabel) # Instance name
140 | aLoc = OCC.Core.TopLoc.TopLoc_Location()
141 | aLoc = self.shape_tool.GetLocation(cLabel)
142 | self.assyLocStack.append(aLoc)
143 | newAssyUID = self.getNewUID()
144 | self.tree.create_node(name,
145 | newAssyUID,
146 | self.assyUidStack[-1],
147 | {'a': True, 'l': aLoc, 'c': None, 's': None})
148 | self.assyUidStack.append(newAssyUID)
149 | rComps = OCC.Core.TDF.TDF_LabelSequence() # Components of Assy
150 | subchilds = False
151 | isAssy = self.shape_tool.GetComponents(refLabel, rComps, subchilds)
152 | logger.debug("Assy name: %s" % name)
153 | logger.debug("Is Assembly? %s" % isAssy)
154 | logger.debug("Number of components: %s" % rComps.Length())
155 | if rComps.Length():
156 | self.findComponents(refLabel, rComps)
157 | self.assyUidStack.pop()
158 | self.assyLocStack.pop()
159 | return
160 |
161 | def read_file(self):
162 | """
163 | Build self.tree (treelib.Tree()) containing the CAD data read from a step file.
164 | Each node of self.tree contains the following:
165 | (Name, UID, ParentUID, {Data}) where the Data keys are:
166 | 'a' (isAssy?), 'l' (TopLoc_Location), 'c' (Quantity_Color), 's' (TopoDS_Shape)
167 | """
168 | logger.info("Reading STEP file")
169 | doc = TDocStd_Document(TCollection_ExtendedString("STEP"))
170 |
171 | # Create the application
172 | app = XCAFApp_Application_GetApplication()
173 | app.NewDocument(TCollection_ExtendedString("MDTV-CAF"), doc)
174 |
175 | # Get root shapes
176 | shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main())
177 | shape_tool.SetAutoNaming(True)
178 | self.color_tool = XCAFDoc_DocumentTool_ColorTool(doc.Main())
179 | layer_tool = XCAFDoc_DocumentTool_LayerTool(doc.Main())
180 | l_materials = XCAFDoc_DocumentTool_MaterialTool(doc.Main())
181 |
182 | step_reader = STEPCAFControl_Reader()
183 | step_reader.SetColorMode(True)
184 | step_reader.SetLayerMode(True)
185 | step_reader.SetNameMode(True)
186 | step_reader.SetMatMode(True)
187 |
188 | status = step_reader.ReadFile(self.filename)
189 | if status == IFSelect_RetDone:
190 | logger.info("Transfer doc to STEPCAFControl_Reader")
191 | step_reader.Transfer(doc)
192 |
193 | labels = TDF_LabelSequence()
194 | color_labels = TDF_LabelSequence()
195 |
196 | shape_tool.GetShapes(labels)
197 | self.shape_tool = shape_tool
198 | #self.shape_tool = shape_tool
199 | logger.info('Number of labels at root : %i' % labels.Length())
200 | label = labels.Value(1) # First label at root
201 | name = self.getName(label)
202 | logger.info('Name of root label: %s' % name)
203 | isAssy = shape_tool.IsAssembly(label)
204 | logger.info("First label at root holds an assembly? %s" % isAssy)
205 | if isAssy:
206 | # If first label at root holds an assembly, it is the Top Assembly.
207 | # Through this label, the entire assembly is accessible.
208 | # No need to examine other labels at root explicitly.
209 | topLoc = OCC.Core.TopLoc.TopLoc_Location()
210 | topLoc = shape_tool.GetLocation(label)
211 | self.assyLocStack.append(topLoc)
212 | entry = label.EntryDumpToString()
213 | logger.debug("Entry: %s" % entry)
214 | logger.debug("Top assy name: %s" % name)
215 | # Create root node for top assy
216 | newAssyUID = self.getNewUID()
217 | self.tree.create_node(name,
218 | newAssyUID,
219 | None,
220 | {'a': True, 'l': None, 'c': None, 's': None})
221 | self.assyUidStack.append(newAssyUID)
222 | topComps = OCC.Core.TDF.TDF_LabelSequence() # Components of Top Assy
223 | subchilds = False
224 | isAssy = shape_tool.GetComponents(label, topComps, subchilds)
225 | logger.debug("Is Assembly? %s" % isAssy)
226 | logger.debug("Number of components: %s" % topComps.Length())
227 | logger.debug("Is Reference? %s" % shape_tool.IsReference(label))
228 | if topComps.Length():
229 | self.findComponents(label, topComps)
230 | else:
231 | # Labels at root can hold solids or compounds (which are 'crude' assemblies)
232 | # Either way, we will need to create a root node in self.tree
233 | newAssyUID = self.getNewUID()
234 | self.tree.create_node(os.path.basename(self.filename),
235 | newAssyUID,
236 | None,
237 | {'a': True, 'l': None, 'c': None, 's': None})
238 | self.assyUidStack = [newAssyUID]
239 | for j in range(labels.Length()):
240 | label = labels.Value(j+1)
241 | name = self.getName(label)
242 | isAssy = shape_tool.IsAssembly(label)
243 | logger.debug("Label %i is assembly?: %s" % (j+1, isAssy))
244 | shape = shape_tool.GetShape(label)
245 | color = self.getColor(shape)
246 | isSimpleShape = self.shape_tool.IsSimpleShape(label)
247 | logger.debug("Is Simple Shape? %s" % isSimpleShape)
248 | shapeType = shape.ShapeType()
249 | logger.debug("The shape type is: %i" % shapeType)
250 | if shapeType == 0:
251 | logger.debug("The shape type is OCC.Core.TopAbs.TopAbs_COMPOUND")
252 | topo = aocutils.topology.Topo(shape)
253 | logger.debug("Nb of compounds : %i" % topo.number_of_compounds)
254 | logger.debug("Nb of solids : %i" % topo.number_of_solids)
255 | logger.debug("Nb of shells : %i" % topo.number_of_shells)
256 | newAssyUID = self.getNewUID()
257 | for i, solid in enumerate(topo.solids):
258 | name = "P%s" % str(i+1)
259 | self.tree.create_node(name,
260 | self.getNewUID(),
261 | self.assyUidStack[-1],
262 | {'a': False, 'l': None, 'c': color, 's': solid})
263 | elif shapeType == 2:
264 | logger.debug("The shape type is OCC.Core.TopAbs.TopAbs_SOLID")
265 | self.tree.create_node(name,
266 | self.getNewUID(),
267 | self.assyUidStack[-1],
268 | {'a': False, 'l': None, 'c': color, 's': shape})
269 | elif shapeType == 3:
270 | logger.debug("The shape type is OCC.Core.TopAbs.TopAbs_SHELL")
271 | self.tree.create_node(name,
272 | self.getNewUID(),
273 | self.assyUidStack[-1],
274 | {'a': False, 'l': None, 'c': color, 's': shape})
275 |
276 | return True
277 |
278 |
--------------------------------------------------------------------------------
/OCCUtils/face.py:
--------------------------------------------------------------------------------
1 | ##Copyright 2008-2013 Jelle Feringa (jelleferinga@gmail.com)
2 | ##
3 | ##This file is part of pythonOCC.
4 | ##
5 | ##pythonOCC is free software: you can redistribute it and/or modify
6 | ##it under the terms of the GNU Lesser General Public License as published by
7 | ##the Free Software Foundation, either version 3 of the License, or
8 | ##(at your option) any later version.
9 | ##
10 | ##pythonOCC is distributed in the hope that it will be useful,
11 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ##GNU Lesser General Public License for more details.
14 | ##
15 | ##You should have received a copy of the GNU Lesser General Public License
16 | ##along with pythonOCC. If not, see
17 |
18 | from OCC.Core.BRep import BRep_Tool_Surface, BRep_Tool
19 | from OCC.Core.BRepTopAdaptor import BRepTopAdaptor_FClass2d
20 | from OCC.Geom import Geom_Curve
21 | from OCC.GeomAPI import GeomAPI_ProjectPointOnSurf
22 | from OCC.GeomLib import GeomLib_IsPlanarSurface
23 | from OCC.Core.TopAbs import TopAbs_IN
24 | from OCC.Core.TopExp import topexp
25 | from OCC.Core.TopoDS import TopoDS_Vertex, TopoDS_Face, TopoDS_Edge
26 | from OCC.GeomLProp import GeomLProp_SLProps
27 | from OCC.Core.BRepTools import breptools_UVBounds
28 | from OCC.Core.BRepAdaptor import BRepAdaptor_Surface, BRepAdaptor_HSurface
29 | from OCC.ShapeAnalysis import ShapeAnalysis_Surface
30 | from OCC.GeomProjLib import geomprojlib
31 | from OCC.Adaptor3d import Adaptor3d_IsoCurve
32 | from OCC.gp import gp_Pnt2d, gp_Dir
33 |
34 | from OCCUtils.base import BaseObject
35 | from OCCUtils.edge import Edge
36 | from OCCUtils.Construct import TOLERANCE, to_adaptor_3d
37 | from OCCUtils.Topology import Topo, WireExplorer
38 |
39 |
40 | class DiffGeomSurface(object):
41 | def __init__(self, instance):
42 | self.instance = instance
43 | self._curvature = None
44 | self._curvature_initiated = False
45 |
46 | def curvature(self, u, v):
47 | '''returns the curvature at the u parameter
48 | the curvature object can be returned too using
49 | curvatureType == curvatureType
50 | curvatureTypes are:
51 | gaussian
52 | minimum
53 | maximum
54 | mean
55 | curvatureType
56 | '''
57 | if not self._curvature_initiated:
58 | self._curvature = GeomLProp_SLProps(self.instance.surface_handle, u, v, 2, 1e-7)
59 |
60 | _domain = self.instance.domain()
61 | if u in _domain or v in _domain:
62 | print('<<>>')
63 | div = 1000
64 | delta_u, delta_v = (_domain[0] - _domain[1])/div, (_domain[2] - _domain[3])/div
65 |
66 | if u in _domain:
67 | low, hi = u-_domain[0], u-_domain[1]
68 | if low < hi:
69 | u = u - delta_u
70 | else:
71 | u = u + delta_u
72 |
73 | if v in _domain:
74 | low, hi = v-_domain[2], v-_domain[3]
75 | if low < hi:
76 | v = v - delta_v
77 | else:
78 | v = v + delta_v
79 |
80 | self._curvature.SetParameters(u, v)
81 | self._curvature_initiated = True
82 |
83 | return self._curvature
84 |
85 | def gaussian_curvature(self, u, v):
86 | return self.curvature(u, v).GaussianCurvature()
87 |
88 | def min_curvature(self, u, v):
89 | return self.curvature(u, v).MinCurvature()
90 |
91 | def mean_curvature(self, u, v):
92 | return self.curvature(u, v).MeanCurvature()
93 |
94 | def max_curvature(self, u, v):
95 | return self.curvature(u, v).MaxCurvature()
96 |
97 | def normal(self, u, v):
98 | # TODO: should make this return a gp_Vec
99 | curv = self.curvature(u, v)
100 | if curv.IsNormalDefined():
101 | return curv.Normal()
102 | else:
103 | raise ValueError('normal is not defined at u,v: {0}, {1}'.format(u, v))
104 |
105 | def tangent(self, u, v):
106 | dU, dV = gp_Dir(), gp_Dir()
107 | curv = self.curvature(u, v)
108 | if curv.IsTangentUDefined() and curv.IsTangentVDefined():
109 | curv.TangentU(dU), curv.TangentV(dV)
110 | return dU, dV
111 | else:
112 | return None, None
113 |
114 | def radius(self, u, v):
115 | '''returns the radius at u
116 | '''
117 | # TODO: SHOULD WE RETURN A SIGNED RADIUS? ( get rid of abs() )?
118 | try:
119 | _crv_min = 1./self.min_curvature(u, v)
120 | except ZeroDivisionError:
121 | _crv_min = 0.
122 |
123 | try:
124 | _crv_max = 1./self.max_curvature(u, v)
125 | except ZeroDivisionError:
126 | _crv_max = 0.
127 | return abs((_crv_min+_crv_max)/2.)
128 |
129 |
130 | class Face(TopoDS_Face, BaseObject):
131 | """high level surface API
132 | object is a Face if part of a Solid
133 | otherwise the same methods do apply, apart from the topology obviously
134 | """
135 | def __init__(self, face):
136 | '''
137 | '''
138 | assert isinstance(face, TopoDS_Face), 'need a TopoDS_Face, got a %s' % face.__class__
139 | assert not face.IsNull()
140 | super(Face, self).__init__()
141 | BaseObject.__init__(self, 'face')
142 | # we need to copy the base shape using the following three
143 | # lines
144 | assert self.IsNull()
145 | self.TShape(face.TShape())
146 | self.Location(face.Location())
147 | self.Orientation(face.Orientation())
148 | assert not self.IsNull()
149 |
150 | # cooperative classes
151 | self.DiffGeom = DiffGeomSurface(self)
152 |
153 | # STATE; whether cooperative classes are yet initialized
154 | self._curvature_initiated = False
155 | self._geometry_lookup_init = False
156 |
157 | #===================================================================
158 | # properties
159 | #===================================================================
160 | self._h_srf = None
161 | self._srf = None
162 | self._adaptor = None
163 | self._adaptor_handle = None
164 | self._classify_uv = None # cache the u,v classifier, no need to rebuild for every sample
165 | self._topo = None
166 |
167 | # aliasing of useful methods
168 | def is_u_periodic(self):
169 | return self.adaptor.IsUPeriodic()
170 |
171 | def is_v_periodic(self):
172 | return self.adaptor.IsVPeriodic()
173 |
174 | def is_u_closed(self):
175 | return self.adaptor.IsUClosed()
176 |
177 | def is_v_closed(self):
178 | return self.adaptor.IsVClosed()
179 |
180 | def is_u_rational(self):
181 | return self.adaptor.IsURational()
182 |
183 | def is_v_rational(self):
184 | return self.adaptor.IsVRational()
185 |
186 | def u_degree(self):
187 | return self.adaptor.UDegree()
188 |
189 | def v_degree(self):
190 | return self.adaptor.VDegree()
191 |
192 | def u_continuity(self):
193 | return self.adaptor.UContinuity()
194 |
195 | def v_continuity(self):
196 | return self.adaptor.VContinuity()
197 |
198 | def domain(self):
199 | '''the u,v domain of the curve
200 | :return: UMin, UMax, VMin, VMax
201 | '''
202 | return breptools_UVBounds(self)
203 |
204 | def mid_point(self):
205 | """
206 | :return: the parameter at the mid point of the face,
207 | and its corresponding gp_Pnt
208 | """
209 | u_min, u_max, v_min, v_max = self.domain()
210 | u_mid = (u_min + u_max) / 2.
211 | v_mid = (v_min + v_max) / 2.
212 | return ((u_mid, v_mid), self.adaptor.Value(u_mid, v_mid))
213 |
214 | @property
215 | def topo(self):
216 | if self._topo is not None:
217 | return self._topo
218 | else:
219 | self._topo = Topo(self)
220 | return self._topo
221 |
222 | @property
223 | def surface(self):
224 | if self._srf is None or self.is_dirty:
225 | self._h_srf = BRep_Tool_Surface(self)
226 | self._srf = self._h_srf.GetObject()
227 | return self._srf
228 |
229 | @property
230 | def surface_handle(self):
231 | if self._h_srf is None or self.is_dirty:
232 | self.surface # force building handle
233 | return self._h_srf
234 |
235 | @property
236 | def adaptor(self):
237 | if self._adaptor is not None and not self.is_dirty:
238 | pass
239 | else:
240 | self._adaptor = BRepAdaptor_Surface(self)
241 | self._adaptor_handle = BRepAdaptor_HSurface()
242 | self._adaptor_handle.Set(self._adaptor)
243 | return self._adaptor
244 |
245 | @property
246 | def adaptor_handle(self):
247 | if self._adaptor_handle is not None and not self.is_dirty:
248 | pass
249 | else:
250 | self.adaptor
251 | return self._adaptor_handle
252 |
253 | def is_closed(self):
254 | sa = ShapeAnalysis_Surface(self.surface_handle)
255 | # sa.GetBoxUF()
256 | return sa.IsUClosed(), sa.IsVClosed()
257 |
258 | def is_planar(self, tol=TOLERANCE):
259 | '''checks if the surface is planar within a tolerance
260 | :return: bool, gp_Pln
261 | '''
262 | print(self.surface_handle)
263 | is_planar_surface = GeomLib_IsPlanarSurface(self.surface_handle, tol)
264 | return is_planar_surface.IsPlanar()
265 |
266 | def is_trimmed(self):
267 | """
268 | :return: True if the Wire delimiting the Face lies on the bounds
269 | of the surface
270 | if this is not the case, the wire represents a contour that delimits
271 | the face [ think cookie cutter ]
272 | and implies that the surface is trimmed
273 | """
274 | _round = lambda x: round(x, 3)
275 | a = map(_round, breptools_UVBounds(self))
276 | b = map(_round, self.adaptor.Surface().Surface().GetObject().Bounds())
277 | if a != b:
278 | print('a,b', a, b)
279 | return True
280 | return False
281 |
282 | def on_trimmed(self, u, v):
283 | '''tests whether the surface at the u,v parameter has been trimmed
284 | '''
285 | if self._classify_uv is None:
286 | self._classify_uv = BRepTopAdaptor_FClass2d(self, 1e-9)
287 | uv = gp_Pnt2d(u, v)
288 | if self._classify_uv.Perform(uv) == TopAbs_IN:
289 | return True
290 | else:
291 | return False
292 |
293 | def parameter_to_point(self, u, v):
294 | '''returns the coordinate at u,v
295 | '''
296 | return self.surface.Value(u, v)
297 |
298 | def point_to_parameter(self, pt):
299 | '''
300 | returns the uv value of a point on a surface
301 | @param pt:
302 | '''
303 | sas = ShapeAnalysis_Surface(self.surface_handle)
304 | uv = sas.ValueOfUV(pt, self.tolerance)
305 | return uv.Coord()
306 |
307 | def continuity_edge_face(self, edge, face):
308 | """
309 | compute the continuity between two faces at :edge:
310 |
311 | :param edge: an Edge or TopoDS_Edge from :face:
312 | :param face: a Face or TopoDS_Face
313 | :return: bool, GeomAbs_Shape if it has continuity, otherwise
314 | False, None
315 | """
316 | bt = BRep_Tool()
317 | if bt.HasContinuity(edge, self, face):
318 | continuity = bt.Continuity(edge, self, face)
319 | return True, continuity
320 | else:
321 | return False, None
322 |
323 | #===========================================================================
324 | # Surface.project
325 | # project curve, point on face
326 | #===========================================================================
327 |
328 | def project_vertex(self, pnt, tol=TOLERANCE):
329 | '''projects self with a point, curve, edge, face, solid
330 | method wraps dealing with the various topologies
331 |
332 | if other is a point:
333 | returns uv, point
334 |
335 | '''
336 | if isinstance(pnt, TopoDS_Vertex):
337 | pnt = BRep_Tool.Pnt(pnt)
338 |
339 | proj = GeomAPI_ProjectPointOnSurf(pnt, self.surface_handle, tol)
340 | uv = proj.LowerDistanceParameters()
341 | proj_pnt = proj.NearestPoint()
342 |
343 | return uv, proj_pnt
344 |
345 | def project_curve(self, other):
346 | # this way Geom_Circle and alike are valid too
347 | if (isinstance(other, TopoDS_Edge) or
348 | isinstance(other, Geom_Curve) or
349 | issubclass(other, Geom_Curve)):
350 | # convert edge to curve
351 | first, last = topexp.FirstVertex(other), topexp.LastVertex(other)
352 | lbound, ubound = BRep_Tool().Parameter(first, other), BRep_Tool().Parameter(last, other)
353 | other = BRep_Tool.Curve(other, lbound, ubound).GetObject()
354 | return geomprojlib.Project(other, self.surface_handle)
355 |
356 | def project_edge(self, edg):
357 | if hasattr(edg, 'adaptor'):
358 | return self.project_curve(self, self.adaptor)
359 | return self.project_curve(self, to_adaptor_3d(edg))
360 |
361 | def iso_curve(self, u_or_v, param):
362 | """
363 | get the iso curve from a u,v + parameter
364 | :param u_or_v:
365 | :param param:
366 | :return:
367 | """
368 | uv = 0 if u_or_v == 'u' else 1
369 | iso = Adaptor3d_IsoCurve(self.adaptor_handle.GetHandle(), uv, param)
370 | return iso
371 |
372 | def edges(self):
373 | return [Edge(i) for i in WireExplorer(next(self.topo.wires())).ordered_edges()]
374 |
375 | def __repr__(self):
376 | return self.name
377 |
378 | def __str__(self):
379 | return self.__repr__()
380 |
381 | if __name__ == "__main__":
382 | from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeSphere
383 | sph = BRepPrimAPI_MakeSphere(1, 1).Face()
384 | fc = Face(sph)
385 | print(fc.is_trimmed())
386 | print(fc.is_planar())
387 |
--------------------------------------------------------------------------------
/misc/bottle.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # cadViewer.py
4 | # An embryonic python 3D CAD application with very little functionality.
5 | # Perhaps it could be a starting point for a more elaborate program.
6 | # It may be only useful to facilitate the exploration of pythonOCC syntax.
7 | # The latest version of this file can be found at:
8 | # https://sites.google.com/site/pythonocc/
9 | #
10 | # Author: Doug Blanding
11 | #
12 | # cadViewer is free software; you can redistribute it and/or modify
13 | # it under the terms of the GNU General Public License as published by
14 | # the Free Software Foundation; either version 2 of the License, or
15 | # (at your option) any later version.
16 | #
17 | # cadViewer is distributed in the hope that it will be useful,
18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | # GNU General Public License for more details.
21 | #
22 | # You should have received a copy of the GNU General Public License
23 | # if not, write to the Free Software Foundation, Inc.
24 | # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 | #
26 |
27 |
28 | from __future__ import absolute_import
29 |
30 | from PyQt4.QtGui import QApplication
31 | from guiApp import MainWindow
32 | import sys
33 | import math
34 | from OCC.gp import *
35 | from OCC.GC import *
36 | from OCC.BRepBuilderAPI import *
37 | from OCC.TopoDS import *
38 | from OCC.TopExp import *
39 | from OCC.TopAbs import *
40 | from OCC.BRepAlgoAPI import *
41 | from OCC.BRepFilletAPI import *
42 | from OCC.BRepPrimAPI import *
43 | from OCC.Geom import *
44 | from OCC.Geom2d import *
45 | from OCC.GCE2d import *
46 | from OCC.BRepOffsetAPI import *
47 | from OCC.IGESControl import *
48 | from OCC.TopTools import *
49 | from OCC.Standard import *
50 | from OCC.TopLoc import *
51 | from OCC.Quantity import *
52 | from OCC.AIS import AIS_Shape
53 | import OCC.BRepLib as BRepLib
54 | import OCC.BRep as BRep
55 | import workplane
56 |
57 | # Make Bottle Stuff...
58 |
59 | def face_is_plane(face):
60 | """
61 | Returns True if the TopoDS_Shape is a plane, False otherwise
62 | """
63 | hs = OCC.BRep.BRep_Tool_Surface(face)
64 | downcast_result = Handle_Geom_Plane.DownCast(hs)
65 | # The handle is null if downcast failed or is not possible, that is to say the face is not a plane
66 | if downcast_result.IsNull():
67 | return False
68 | else:
69 | return True
70 |
71 | def geom_plane_from_face(aFace):
72 | """
73 | Returns the geometric plane entity from a planar surface
74 | """
75 | return Handle_Geom_Plane.DownCast(OCC.BRep.BRep_Tool_Surface(aFace)).GetObject()
76 |
77 | # Bottle Dimensions...
78 | width = 50
79 | height = 70
80 | thickness = 30
81 |
82 | def makeBottle(): # complete bottle
83 | startBottle(startOnly=False)
84 |
85 | def startBottle(startOnly=True): # minus the neck fillet, shelling & threads
86 | partName = "Bottle-start"
87 | # The points we'll use to create the profile of the bottle's body
88 | aPnt1 = gp_Pnt(-width / 2.0, 0, 0)
89 | aPnt2 = gp_Pnt(-width / 2.0, -thickness / 4.0, 0)
90 | aPnt3 = gp_Pnt(0, -thickness / 2.0, 0)
91 | aPnt4 = gp_Pnt(width / 2.0, -thickness / 4.0, 0)
92 | aPnt5 = gp_Pnt(width / 2.0, 0, 0)
93 |
94 | aArcOfCircle = GC_MakeArcOfCircle(aPnt2, aPnt3, aPnt4)
95 | aSegment1 = GC_MakeSegment(aPnt1, aPnt2)
96 | aSegment2 = GC_MakeSegment(aPnt4, aPnt5)
97 |
98 | # Could also construct the line edges directly using the points instead of the resulting line
99 | aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value())
100 | aEdge2 = BRepBuilderAPI_MakeEdge(aArcOfCircle.Value())
101 | aEdge3 = BRepBuilderAPI_MakeEdge(aSegment2.Value())
102 |
103 | # Create a wire out of the edges
104 | aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(), aEdge2.Edge(), aEdge3.Edge())
105 |
106 | # Quick way to specify the X axis
107 | xAxis = gp_OX()
108 |
109 | # Set up the mirror
110 | aTrsf = gp_Trsf()
111 | aTrsf.SetMirror(xAxis)
112 |
113 | # Apply the mirror transformation
114 | aBRespTrsf = BRepBuilderAPI_Transform(aWire.Wire(), aTrsf)
115 |
116 | # Get the mirrored shape back out of the transformation and convert back to a wire
117 | aMirroredShape = aBRespTrsf.Shape()
118 |
119 | # A wire instead of a generic shape now
120 | aMirroredWire = topods.Wire(aMirroredShape)
121 |
122 | # Combine the two constituent wires
123 | mkWire = BRepBuilderAPI_MakeWire()
124 | mkWire.Add(aWire.Wire())
125 | mkWire.Add(aMirroredWire)
126 | myWireProfile = mkWire.Wire()
127 |
128 | # The face that we'll sweep to make the prism
129 | myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile)
130 |
131 | # We want to sweep the face along the Z axis to the height
132 | aPrismVec = gp_Vec(0, 0, height)
133 | myBody = BRepPrimAPI_MakePrism(myFaceProfile.Face(), aPrismVec)
134 |
135 | # Add fillets to all edges through the explorer
136 | mkFillet = BRepFilletAPI_MakeFillet(myBody.Shape())
137 | anEdgeExplorer = TopExp_Explorer(myBody.Shape(), TopAbs_EDGE)
138 |
139 | while anEdgeExplorer.More():
140 | anEdge = topods.Edge(anEdgeExplorer.Current())
141 | mkFillet.Add(thickness / 12.0, anEdge)
142 |
143 | anEdgeExplorer.Next()
144 |
145 | myBody = mkFillet.Shape()
146 |
147 |
148 | # Create the neck of the bottle
149 | neckLocation = gp_Pnt(0, 0, height)
150 | neckAxis = gp_DZ()
151 | neckAx2 = gp_Ax2(neckLocation, neckAxis)
152 |
153 | myNeckRadius = thickness / 4.0
154 | myNeckHeight = height / 10.0
155 |
156 | mkCylinder = BRepPrimAPI_MakeCylinder(neckAx2, myNeckRadius, myNeckHeight)
157 | myBody = BRepAlgoAPI_Fuse(myBody , mkCylinder.Shape())
158 | if startOnly: # quit here
159 | uid = win.getNewPartUID(myBody.Shape(), name=partName)
160 | win.redraw()
161 | return
162 |
163 | partName = "Bottle-complete"
164 | # Our goal is to find the highest Z face and remove it
165 | faceToRemove = None
166 | zMax = -1
167 |
168 | # We have to work our way through all the faces to find the highest Z face
169 | aFaceExplorer = TopExp_Explorer(myBody.Shape(), TopAbs_FACE)
170 | while aFaceExplorer.More():
171 | aFace = topods.Face(aFaceExplorer.Current())
172 |
173 | if face_is_plane(aFace):
174 | aPlane = geom_plane_from_face(aFace)
175 |
176 | # We want the highest Z face, so compare this to the previous faces
177 | aPnt = aPlane.Location()
178 | aZ = aPnt.Z()
179 | if aZ > zMax:
180 | zMax = aZ
181 | faceToRemove = aFace
182 |
183 | aFaceExplorer.Next()
184 |
185 | facesToRemove = TopTools_ListOfShape()
186 | facesToRemove.Append(faceToRemove)
187 |
188 | myBody = BRepOffsetAPI_MakeThickSolid(myBody.Shape(), facesToRemove, -thickness / 50.0, 0.001)
189 |
190 | # Set up our surfaces for the threading on the neck
191 | neckAx2_Ax3 = gp_Ax3(neckLocation, gp_DZ())
192 | aCyl1 = Geom_CylindricalSurface(neckAx2_Ax3, myNeckRadius * 0.99)
193 | aCyl2 = Geom_CylindricalSurface(neckAx2_Ax3, myNeckRadius * 1.05)
194 |
195 | # Set up the curves for the threads on the bottle's neck
196 | aPnt = gp_Pnt2d(2.0 * math.pi, myNeckHeight / 2.0)
197 | aDir = gp_Dir2d(2.0 * math.pi, myNeckHeight / 4.0)
198 | anAx2d = gp_Ax2d(aPnt, aDir)
199 |
200 | aMajor = 2.0 * math.pi
201 | aMinor = myNeckHeight / 10.0
202 |
203 | anEllipse1 = Geom2d_Ellipse(anAx2d, aMajor, aMinor)
204 | anEllipse2 = Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4.0)
205 |
206 | anArc1 = Geom2d_TrimmedCurve(Handle_Geom2d_Ellipse(anEllipse1), 0, math.pi)
207 | anArc2 = Geom2d_TrimmedCurve(Handle_Geom2d_Ellipse(anEllipse2), 0, math.pi)
208 | anEllipsePnt1 = anEllipse1.Value(0)
209 | anEllipsePnt2 = anEllipse1.Value(math.pi)
210 |
211 | aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2)
212 |
213 | # Build edges and wires for threading
214 | anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(Handle_Geom2d_Curve(anArc1), Handle_Geom_Surface(aCyl1))
215 | anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment.Value(), Handle_Geom_Surface(aCyl1))
216 | anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(Handle_Geom2d_Curve(anArc2), Handle_Geom_Surface(aCyl2))
217 | anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment.Value(), Handle_Geom_Surface(aCyl2))
218 |
219 | threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1.Edge(), anEdge2OnSurf1.Edge())
220 | threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2.Edge(), anEdge2OnSurf2.Edge())
221 |
222 | # Compute the 3D representations of the edges/wires
223 | BRepLib.breplib.BuildCurves3d(threadingWire1.Shape())
224 | BRepLib.breplib.BuildCurves3d(threadingWire2.Shape())
225 |
226 | # Create the surfaces of the threading
227 | aTool = BRepOffsetAPI_ThruSections(True)
228 | aTool.AddWire(threadingWire1.Wire())
229 | aTool.AddWire(threadingWire2.Wire())
230 | aTool.CheckCompatibility(False)
231 | myThreading = aTool.Shape()
232 |
233 | # Build the resulting compound
234 | aRes = TopoDS_Compound()
235 | aBuilder = BRep.BRep_Builder()
236 | aBuilder.MakeCompound(aRes)
237 | aBuilder.Add(aRes, myBody.Shape())
238 | aBuilder.Add(aRes, myThreading)
239 | uid = win.getNewPartUID(aRes, name=partName)
240 | win.redraw()
241 |
242 | # Make Bottle step by step...
243 | def makePoints(event=None):
244 | global aPnt1, aPnt2, aPnt3, aPnt4, aPnt5
245 | aPnt1 = gp_Pnt(-width / 2. , 0 , 0)
246 | aPnt2 = gp_Pnt(-width / 2. , -thickness / 4. , 0)
247 | aPnt3 = gp_Pnt(0 , -thickness / 2. , 0)
248 | aPnt4 = gp_Pnt(width / 2. , -thickness / 4. , 0)
249 | aPnt5 = gp_Pnt(width / 2. , 0 , 0)
250 | V1 = BRepBuilderAPI_MakeVertex(aPnt1)
251 | V2 = BRepBuilderAPI_MakeVertex(aPnt2)
252 | V3 = BRepBuilderAPI_MakeVertex(aPnt3)
253 | V4 = BRepBuilderAPI_MakeVertex(aPnt4)
254 | V5 = BRepBuilderAPI_MakeVertex(aPnt5)
255 | # add dummy point above bottle just to set view size
256 | V6 = BRepBuilderAPI_MakeVertex(gp_Pnt(0,0,height*1.1))
257 | display.DisplayShape(V1.Vertex())
258 | display.DisplayShape(V2.Vertex())
259 | display.DisplayShape(V3.Vertex())
260 | display.DisplayShape(V4.Vertex())
261 | display.DisplayShape(V5.Vertex())
262 | display.DisplayShape(V6.Vertex())
263 | display.FitAll()
264 | display.EraseAll()
265 | display.DisplayShape(V1.Vertex())
266 | display.DisplayShape(V2.Vertex())
267 | display.DisplayShape(V3.Vertex())
268 | display.DisplayShape(V4.Vertex())
269 | display.DisplayShape(V5.Vertex())
270 | display.Repaint()
271 | win.statusBar().showMessage('Make Points complete')
272 |
273 | def makeLines(event=None):
274 | global aEdge1, aEdge2, aEdge3
275 | aArcOfCircle = GC_MakeArcOfCircle(aPnt2,aPnt3 ,aPnt4)
276 | aSegment1 = GC_MakeSegment(aPnt1 , aPnt2)
277 | aSegment2 = GC_MakeSegment(aPnt4 , aPnt5)
278 | # Display lines
279 | aEdge1 = BRepBuilderAPI_MakeEdge(aSegment1.Value())
280 | aEdge2 = BRepBuilderAPI_MakeEdge(aArcOfCircle.Value())
281 | aEdge3 = BRepBuilderAPI_MakeEdge(aSegment2.Value())
282 | display.DisplayColoredShape(aEdge1.Edge(),'RED')
283 | display.DisplayColoredShape(aEdge2.Edge(),'RED')
284 | display.DisplayColoredShape(aEdge3.Edge(),'RED')
285 | display.Repaint()
286 | win.statusBar().showMessage('Make lines complete')
287 |
288 | def makeHalfWire(event=None):
289 | global aWire
290 | aWire = BRepBuilderAPI_MakeWire(aEdge1.Edge(),
291 | aEdge2.Edge(),
292 | aEdge3.Edge()).Wire()
293 | display.EraseAll()
294 | display.DisplayColoredShape(aWire, 'BLUE')
295 | display.Repaint()
296 | win.statusBar().showMessage('Make Half Wire complete')
297 |
298 | def makeWholeWire(event=None):
299 | global myWireProfile
300 | xAxis = gp_OX()
301 | # Set up the mirror
302 | aTrsf = gp_Trsf()
303 | aTrsf.SetMirror(xAxis)
304 | # Apply the mirror transform
305 | aBRepTrsf = BRepBuilderAPI_Transform(aWire, aTrsf)
306 | # Convert mirrored shape to a wire
307 | aMirroredShape = aBRepTrsf.Shape()
308 | aMirroredWire = topods_Wire(aMirroredShape)
309 | # Combine the two wires
310 | mkWire = BRepBuilderAPI_MakeWire()
311 | mkWire.Add(aWire)
312 | mkWire.Add(aMirroredWire)
313 | myWireProfile = mkWire.Wire()
314 | display.DisplayColoredShape(myWireProfile, 'BLUE')
315 | display.Repaint()
316 | win.statusBar().showMessage('Make whole wire complete')
317 |
318 | def makeFace(event=None):
319 | global myFaceProfile
320 | myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile)
321 | if myFaceProfile.IsDone():
322 | bottomFace = myFaceProfile.Face()
323 | display.DisplayShape(bottomFace, color='YELLOW', transparency=0.6)
324 | display.Repaint()
325 | win.statusBar().showMessage('Make face complete')
326 |
327 | def makeBody(event=None):
328 | partName = 'body'
329 | aPrismVec = gp_Vec(0 , 0 , height)
330 | myBody = BRepPrimAPI_MakePrism(myFaceProfile.Shape(),
331 | aPrismVec).Shape()
332 | win.getNewPartUID(myBody, name=partName)
333 | win.statusBar().showMessage('Bottle body complete')
334 | win.redraw()
335 |
336 | def makeFillets(event=None):
337 | newPrtName = 'bodyWithFillets'
338 | workPart = win.activePart
339 | wrkPrtUID = win.activePartUID
340 | mkFillet = BRepFilletAPI_MakeFillet(workPart)
341 | aEdgeExplorer = TopExp_Explorer(workPart,
342 | TopAbs_EDGE)
343 | while aEdgeExplorer.More():
344 | aEdge = topods_Edge(aEdgeExplorer.Current())
345 | mkFillet.Add(thickness / 12. , aEdge)
346 | aEdgeExplorer.Next()
347 | myBody = mkFillet.Shape()
348 | win.getNewPartUID(myBody, name=newPrtName, ancestor=wrkPrtUID)
349 | win.statusBar().showMessage('Bottle with fillets complete')
350 | win.redraw()
351 |
352 | def addNeck(event=None):
353 | newPrtName = 'bodyWithNeck'
354 | workPart = win.activePart
355 | wrkPrtUID = win.activePartUID
356 | neckLocation = gp_Pnt(0 , 0 , height)
357 | neckNormal = gp_DZ()
358 | neckAx2 = gp_Ax2(neckLocation , neckNormal)
359 | myNeckRadius = thickness / 4.
360 | myNeckHeight = height / 10.
361 | MKCylinder = BRepPrimAPI_MakeCylinder(neckAx2,
362 | myNeckRadius,
363 | myNeckHeight)
364 | myNeck = MKCylinder.Shape()
365 | myBody = BRepAlgoAPI_Fuse(workPart, myNeck).Shape()
366 | win.getNewPartUID(myBody, name=newPrtName, ancestor=wrkPrtUID)
367 | win.statusBar().showMessage('Add neck complete')
368 | win.redraw()
369 |
370 |
--------------------------------------------------------------------------------
/OCCUtils/edge.py:
--------------------------------------------------------------------------------
1 | ##Copyright 2008-2015 Jelle Feringa (jelleferinga@gmail.com)
2 | ##
3 | ##This file is part of pythonOCC.
4 | ##
5 | ##pythonOCC is free software: you can redistribute it and/or modify
6 | ##it under the terms of the GNU Lesser General Public License as published by
7 | ##the Free Software Foundation, either version 3 of the License, or
8 | ##(at your option) any later version.
9 | ##
10 | ##pythonOCC is distributed in the hope that it will be useful,
11 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ##GNU Lesser General Public License for more details.
14 | ##
15 | ##You should have received a copy of the GNU Lesser General Public License
16 | ##along with pythonOCC. If not, see
17 |
18 | from OCC.Core.BRepAdaptor import BRepAdaptor_Curve, BRepAdaptor_HCurve
19 | from OCC.GCPnts import GCPnts_UniformAbscissa
20 | from OCC.Geom import Geom_OffsetCurve, Geom_TrimmedCurve
21 | from OCC.Core.TopExp import topexp
22 | from OCC.Core.TopoDS import TopoDS_Edge, TopoDS_Vertex, TopoDS_Face
23 | from OCC.gp import gp_Vec, gp_Dir, gp_Pnt
24 | from OCC.GeomLProp import GeomLProp_CurveTool
25 | from OCC.Core.BRepLProp import BRepLProp_CLProps
26 | from OCC.GeomLib import geomlib
27 | from OCC.GCPnts import GCPnts_AbscissaPoint
28 | from OCC.GeomAPI import GeomAPI_ProjectPointOnCurve
29 | from OCC.ShapeAnalysis import ShapeAnalysis_Edge
30 | from OCC.Core.BRep import BRep_Tool, BRep_Tool_Continuity
31 | from OCC.Core.BRepIntCurveSurface import BRepIntCurveSurface_Inter
32 |
33 | # high-level
34 | from OCCUtils.Common import vertex2pnt, minimum_distance, assert_isdone, fix_continuity
35 | from OCCUtils.Construct import make_edge
36 | from OCCUtils.types_lut import geom_lut
37 | from OCCUtils.base import BaseObject
38 |
39 |
40 | class IntersectCurve(object):
41 | def __init__(self, instance):
42 | self.instance = instance
43 |
44 | def intersect(self, other, tolerance=1e-2):
45 | '''Intersect self with a point, curve, edge, face, solid
46 | method wraps dealing with the various topologies
47 | '''
48 | if isinstance(other, TopoDS_Face):
49 | face_curve_intersect = BRepIntCurveSurface_Inter()
50 | face_curve_intersect.Init(other, self.instance.adaptor.Curve(), tolerance)
51 | pnts = []
52 | while face_curve_intersect.More():
53 | next(face_curve_intersect)
54 | pnts.append(face_curve_intersect.Pnt())
55 | return pnts
56 |
57 |
58 | class DiffGeomCurve(object):
59 | def __init__(self, instance):
60 | self.instance = instance
61 | self._local_props = BRepLProp_CLProps(self.instance.adaptor, 2, self.instance.tolerance)
62 |
63 | @property
64 | def _curvature(self):
65 | return self._local_props
66 |
67 | def radius(self, u):
68 | '''returns the radius at u
69 | '''
70 | # NOT SO SURE IF THIS IS THE SAME THING!!!
71 | self._curvature.SetParameter(u)
72 | pnt = gp_Pnt()
73 | self._curvature.CentreOfCurvature(pnt)
74 | return pnt
75 |
76 | def curvature(self, u):
77 | # ugly
78 | self._curvature.SetParameter(u)
79 | return self._curvature.Curvature()
80 |
81 | def tangent(self, u):
82 | '''sets or gets ( iff vector ) the tangency at the u parameter
83 | tangency can be constrained so when setting the tangency,
84 | you're constrainting it in fact
85 | '''
86 | self._curvature.SetParameter(u)
87 | if self._curvature.IsTangentDefined():
88 | ddd = gp_Dir()
89 | self._curvature.Tangent(ddd)
90 | return ddd
91 | else:
92 | raise ValueError('no tangent defined')
93 |
94 | def normal(self, u):
95 | '''returns the normal at u
96 |
97 | computes the main normal if no normal is found
98 | see:
99 | www.opencascade.org/org/forum/thread_645+&cd=10&hl=nl&ct=clnk&gl=nl
100 | '''
101 | try:
102 | self._curvature.SetParameter(u)
103 | a_dir = gp_Dir()
104 | self._curvature.Normal(a_dir)
105 | return a_dir
106 | except:
107 | raise ValueError('no normal was found')
108 |
109 | def derivative(self, u, n):
110 | '''
111 | returns n derivatives at parameter b
112 | '''
113 | self._curvature.SetParameter(u)
114 | deriv = {1: self._curvature.D1,
115 | 2: self._curvature.D2,
116 | 3: self._curvature.D3,
117 | }
118 | try:
119 | return deriv[n]
120 | except KeyError:
121 | raise AssertionError('n of derivative is one of [1,2,3]')
122 |
123 | def points_from_tangential_deflection(self):
124 | pass
125 |
126 | #===========================================================================
127 | # Curve.Construct
128 | #===========================================================================
129 |
130 |
131 | class ConstructFromCurve():
132 | def __init__(self, instance):
133 | self.instance = instance
134 |
135 | def make_offset(self, offset, vec):
136 | '''
137 | returns an offsetted curve
138 | @param offset: the distance between self.crv and the curve to offset
139 | @param vec: offset direction
140 | '''
141 | return Geom_OffsetCurve(self.instance.h_crv, offset, vec)
142 |
143 |
144 | class Edge(TopoDS_Edge, BaseObject):
145 | def __init__(self, edge):
146 | assert isinstance(edge, TopoDS_Edge), 'need a TopoDS_Edge, got a %s' % edge.__class__
147 | assert not edge.IsNull()
148 | super(Edge, self).__init__()
149 | BaseObject.__init__(self, 'edge')
150 | # we need to copy the base shape using the following three
151 | # lines
152 | assert self.IsNull()
153 | self.TShape(edge.TShape())
154 | self.Location(edge.Location())
155 | self.Orientation(edge.Orientation())
156 | assert not self.IsNull()
157 |
158 | # tracking state
159 | self._local_properties_init = False
160 | self._curvature_init = False
161 | self._geometry_lookup_init = False
162 | self._curve_handle = None
163 | self._curve = None
164 | self._adaptor = None
165 | self._adaptor_handle = None
166 |
167 | # instantiating cooperative classes
168 | # cooperative classes are distinct through CamelCaps from
169 | # normal method -> pep8
170 | self.DiffGeom = DiffGeomCurve(self)
171 | self.Intersect = IntersectCurve(self)
172 | self.Construct = ConstructFromCurve(self)
173 |
174 | # GeomLProp object
175 | self._curvature = None
176 |
177 | def is_closed(self):
178 | return self.adaptor.IsClosed()
179 |
180 | def is_periodic(self):
181 | return self.adaptor.IsPeriodic()
182 |
183 | def is_rational(self):
184 | return self.adaptor.IsRational()
185 |
186 | def continuity(self):
187 | return self.adaptor.Continuity
188 |
189 | def degree(self):
190 | if 'line' in self.type:
191 | return 1
192 | elif 'curve' in self.type:
193 | return self.adaptor.Degree()
194 | else:
195 | # hyperbola, parabola, circle
196 | return 2
197 |
198 | def nb_knots(self):
199 | return self.adaptor.NbKnots()
200 |
201 | def nb_poles(self):
202 | return self.adaptor.NbPoles()
203 |
204 | @property
205 | def curve(self):
206 | if self._curve is not None and not self.is_dirty:
207 | pass
208 | else:
209 | self._curve_handle = BRep_Tool().Curve(self)[0]
210 | self._curve = self._curve_handle.GetObject()
211 | return self._curve
212 |
213 | @property
214 | def curve_handle(self):
215 | if self._curve_handle is not None and not self.is_dirty:
216 | return self._curve_handle
217 | else:
218 | return None
219 |
220 | @property
221 | def adaptor(self):
222 | if self._adaptor is not None and not self.is_dirty:
223 | pass
224 | else:
225 | self._adaptor = BRepAdaptor_Curve(self)
226 | self._adaptor_handle = BRepAdaptor_HCurve(self._adaptor)
227 | return self._adaptor
228 |
229 | @property
230 | def adaptor_handle(self):
231 | if self._adaptor_handle is not None and not self.is_dirty:
232 | pass
233 | else:
234 | self.adaptor
235 | return self._adaptor_handle
236 |
237 | @property
238 | def geom_curve_handle(self):
239 | """
240 | :return: Handle_Geom_Curve adapted from `self`
241 | """
242 | if self._adaptor_handle is not None and not self.is_dirty:
243 | return self._adaptor.Curve().Curve()
244 | else:
245 | return None
246 |
247 | @property
248 | def type(self):
249 | return geom_lut[self.adaptor.Curve().GetType()]
250 |
251 | def pcurve(self, face):
252 | """
253 | computes the 2d parametric spline that lies on the surface of the face
254 | :return: Geom2d_Curve, u, v
255 | """
256 | crv, u, v = BRep_Tool().CurveOnSurface(self, face)
257 | return crv.GetObject(), u, v
258 |
259 | def _local_properties(self):
260 | self._lprops_curve_tool = GeomLProp_CurveTool()
261 | self._local_properties_init = True
262 |
263 | def domain(self):
264 | '''returns the u,v domain of the curve'''
265 | return self.adaptor.FirstParameter(), self.adaptor.LastParameter()
266 |
267 | #===========================================================================
268 | # Curve.GlobalProperties
269 | #===========================================================================
270 |
271 | def length(self, lbound=None, ubound=None, tolerance=1e-5):
272 | '''returns the curve length
273 | if either lbound | ubound | both are given, than the length
274 | of the curve will be measured over that interval
275 | '''
276 | _min, _max = self.domain()
277 | if _min < self.adaptor.FirstParameter():
278 | raise ValueError('the lbound argument is lower than the first parameter of the curve: %s ' % (self.adaptor.FirstParameter()))
279 | if _max > self.adaptor.LastParameter():
280 | raise ValueError('the ubound argument is greater than the last parameter of the curve: %s ' % (self.adaptor.LastParameter()))
281 |
282 | lbound = _min if lbound is None else lbound
283 | ubound = _max if ubound is None else ubound
284 | return GCPnts_AbscissaPoint().Length(self.adaptor, lbound, ubound, tolerance)
285 |
286 | #===========================================================================
287 | # Curve.modify
288 | #===========================================================================
289 |
290 | def trim(self, lbound, ubound):
291 | '''
292 | trim the curve
293 | @param lbound:
294 | @param ubound:
295 | '''
296 | a, b = sorted([lbound, ubound])
297 | tr = Geom_TrimmedCurve(self.adaptor.Curve().Curve(), a, b).GetHandle()
298 | return Edge(make_edge(tr))
299 |
300 | def extend_by_point(self, pnt, degree=3, beginning=True):
301 | '''extends the curve to point
302 |
303 | does not extend if the degree of self.curve > 3
304 | @param pnt:
305 | @param degree:
306 | @param beginning:
307 | '''
308 | if self.degree > 3:
309 | raise ValueError('to extend you self.curve should be <= 3, is %s' % (self.degree))
310 | return geomlib.ExtendCurveToPoint(self.curve, pnt, degree, beginning)
311 |
312 | #===========================================================================
313 | # Curve.
314 | #===========================================================================
315 | def closest(self, other):
316 | return minimum_distance(self, other)
317 |
318 | def project_vertex(self, pnt_or_vertex):
319 | ''' returns the closest orthogonal project on `pnt` on edge
320 | '''
321 | if isinstance(pnt_or_vertex, TopoDS_Vertex):
322 | pnt_or_vertex = vertex2pnt(pnt_or_vertex)
323 |
324 | poc = GeomAPI_ProjectPointOnCurve(pnt_or_vertex, self.curve_handle)
325 | return poc.LowerDistanceParameter(), poc.NearestPoint()
326 |
327 | def distance_on_curve(self, distance, close_parameter, estimate_parameter):
328 | '''returns the parameter if there is a parameter
329 | on the curve with a distance length from u
330 | raises OutOfBoundary if no such parameter exists
331 | '''
332 | gcpa = GCPnts_AbscissaPoint(self.adaptor, distance, close_parameter, estimate_parameter, 1e-5)
333 | with assert_isdone(gcpa, 'couldnt compute distance on curve'):
334 | return gcpa.Parameter()
335 |
336 | def mid_point(self):
337 | """
338 | :return: the parameter at the mid point of the curve, and
339 | its corresponding gp_Pnt
340 | """
341 | _min, _max = self.domain()
342 | _mid = (_min+_max) / 2.
343 | return _mid, self.adaptor.Value(_mid)
344 |
345 | def divide_by_number_of_points(self, n_pts, lbound=None, ubound=None):
346 | '''returns a nested list of parameters and points on the edge
347 | at the requested interval [(param, gp_Pnt),...]
348 | '''
349 | _lbound, _ubound = self.domain()
350 | if lbound:
351 | _lbound = lbound
352 | elif ubound:
353 | _ubound = ubound
354 |
355 | # minimally two points or a Standard_ConstructionError is raised
356 | if n_pts <= 1:
357 | n_pts = 2
358 |
359 | try:
360 | npts = GCPnts_UniformAbscissa(self.adaptor, n_pts, _lbound, _ubound)
361 | except:
362 | print("Warning : GCPnts_UniformAbscissa failed")
363 | if npts.IsDone():
364 | tmp = []
365 | for i in xrange(1, npts.NbPoints()+1):
366 | param = npts.Parameter(i)
367 | pnt = self.adaptor.Value(param)
368 | tmp.append((param, pnt))
369 | return tmp
370 | else:
371 | return None
372 |
373 | def __eq__(self, other):
374 | if hasattr(other, 'topo'):
375 | return self.IsEqual(other)
376 | else:
377 | return self.IsEqual(other)
378 |
379 | def __ne__(self, other):
380 | return not self.__eq__(other)
381 |
382 | def first_vertex(self):
383 | return topexp.FirstVertex(self)
384 |
385 | def last_vertex(self):
386 | return topexp.LastVertex(self)
387 |
388 | def common_vertex(self, edge):
389 | vert = TopoDS_Vertex()
390 | if topexp.CommonVertex(self, edge, vert):
391 | return vert
392 | else:
393 | return False
394 |
395 | def as_vec(self):
396 | if self.is_line():
397 | first, last = map(vertex2pnt, [self.first_vertex(), self.last_vertex()])
398 | return gp_Vec(first, last)
399 | else:
400 | raise ValueError("edge is not a line, hence no meaningful vector can be returned")
401 |
402 | #===========================================================================
403 | # Curve.
404 | #===========================================================================
405 |
406 | def parameter_to_point(self, u):
407 | '''returns the coordinate at parameter u
408 | '''
409 | return self.adaptor.Value(u)
410 |
411 | def fix_continuity(self, continuity):
412 | """
413 | splits an edge to achieve a level of continuity
414 | :param continuity: GeomAbs_C*
415 | """
416 | return fix_continuity(self, continuity)
417 |
418 | def continuity_from_faces(self, f1, f2):
419 | return BRep_Tool_Continuity(self, f1, f2)
420 |
421 | #===========================================================================
422 | # Curve.
423 | #===========================================================================
424 |
425 | def is_line(self):
426 | '''checks if the curve is planar
427 | '''
428 | if self.nb_knots() == 2 and self.nb_poles() == 2:
429 | return True
430 | else:
431 | return False
432 |
433 | def is_seam(self, face):
434 | """
435 | :return: True if the edge has two pcurves on one surface
436 | ( in the case of a sphere for example... )
437 | """
438 | sae = ShapeAnalysis_Edge()
439 | return sae.IsSeam(self, face)
440 |
441 | def is_edge_on_face(self, face):
442 | '''checks whether curve lies on a surface or a face
443 | '''
444 | return ShapeAnalysis_Edge().HasPCurve(self, face)
445 |
446 | #===========================================================================
447 | # Curve.graphic
448 | #===========================================================================
449 | def show(self):
450 | '''
451 | poles, knots, should render all slightly different.
452 | here's how...
453 |
454 | http://www.opencascade.org/org/forum/thread_1125/
455 | '''
456 | super(Edge, self).show()
457 |
458 |
459 | if __name__ == '__main__':
460 | from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox
461 | from OCCUtils.Topology import Topo
462 | b = BRepPrimAPI_MakeBox(10, 20, 30).Shape()
463 | t = Topo(b)
464 | ed = next(t.edges())
465 | my_e = Edge(ed)
466 | print(my_e.tolerance)
467 |
--------------------------------------------------------------------------------
/step/tiltedCup.stp:
--------------------------------------------------------------------------------
1 | ISO-10303-21;
2 | HEADER;
3 | FILE_DESCRIPTION(('Open CASCADE Model'),'2;1');
4 | FILE_NAME('Open CASCADE Shape Model','2016-08-04T20:07:36',('Author'),(
5 | 'Open CASCADE'),'Open CASCADE STEP processor 6.7','Open CASCADE 6.7'
6 | ,'Unknown');
7 | FILE_SCHEMA(('AUTOMOTIVE_DESIGN_CC2 { 1 2 10303 214 -1 1 5 4 }'));
8 | ENDSEC;
9 | DATA;
10 | #1 = APPLICATION_PROTOCOL_DEFINITION('international standard',
11 | 'config_control_design',1994,#2);
12 | #2 = APPLICATION_CONTEXT(
13 | 'configuration controlled 3D designs of mechanical parts and assemblies'
14 | );
15 | #3 = SHAPE_DEFINITION_REPRESENTATION(#4,#10);
16 | #4 = PRODUCT_DEFINITION_SHAPE('','',#5);
17 | #5 = PRODUCT_DEFINITION('design','',#6,#9);
18 | #6 = PRODUCT_DEFINITION_FORMATION_WITH_SPECIFIED_SOURCE('','',#7,
19 | .NOT_KNOWN.);
20 | #7 = PRODUCT('Open CASCADE STEP translator 6.7 1',
21 | 'Open CASCADE STEP translator 6.7 1','',(#8));
22 | #8 = MECHANICAL_CONTEXT('',#2,'mechanical');
23 | #9 = DESIGN_CONTEXT('',#2,'design');
24 | #10 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#15),#313);
25 | #11 = AXIS2_PLACEMENT_3D('',#12,#13,#14);
26 | #12 = CARTESIAN_POINT('',(0.E+000,0.E+000,0.E+000));
27 | #13 = DIRECTION('',(0.E+000,0.E+000,1.));
28 | #14 = DIRECTION('',(1.,0.E+000,-0.E+000));
29 | #15 = MANIFOLD_SOLID_BREP('',#16);
30 | #16 = CLOSED_SHELL('',(#17,#105,#159,#163,#198,#253,#309));
31 | #17 = ADVANCED_FACE('',(#18),#32,.T.);
32 | #18 = FACE_BOUND('',#19,.T.);
33 | #19 = EDGE_LOOP('',(#20,#50,#77,#78));
34 | #20 = ORIENTED_EDGE('',*,*,#21,.T.);
35 | #21 = EDGE_CURVE('',#22,#24,#26,.T.);
36 | #22 = VERTEX_POINT('',#23);
37 | #23 = CARTESIAN_POINT('',(40.,-8.660254037844,5.));
38 | #24 = VERTEX_POINT('',#25);
39 | #25 = CARTESIAN_POINT('',(40.,-69.28203230275,40.));
40 | #26 = SEAM_CURVE('',#27,(#31,#43),.PCURVE_S1.);
41 | #27 = LINE('',#28,#29);
42 | #28 = CARTESIAN_POINT('',(40.,-4.898587196589E-015,-8.484601909799E-015)
43 | );
44 | #29 = VECTOR('',#30,1.);
45 | #30 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
46 | #31 = PCURVE('',#32,#37);
47 | #32 = CYLINDRICAL_SURFACE('',#33,40.);
48 | #33 = AXIS2_PLACEMENT_3D('',#34,#35,#36);
49 | #34 = CARTESIAN_POINT('',(0.E+000,0.E+000,0.E+000));
50 | #35 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
51 | #36 = DIRECTION('',(1.,0.E+000,0.E+000));
52 | #37 = DEFINITIONAL_REPRESENTATION('',(#38),#42);
53 | #38 = LINE('',#39,#40);
54 | #39 = CARTESIAN_POINT('',(6.28318530718,-0.E+000));
55 | #40 = VECTOR('',#41,1.);
56 | #41 = DIRECTION('',(0.E+000,1.));
57 | #42 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
58 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
59 | ) );
60 | #43 = PCURVE('',#32,#44);
61 | #44 = DEFINITIONAL_REPRESENTATION('',(#45),#49);
62 | #45 = LINE('',#46,#47);
63 | #46 = CARTESIAN_POINT('',(0.E+000,-0.E+000));
64 | #47 = VECTOR('',#48,1.);
65 | #48 = DIRECTION('',(0.E+000,1.));
66 | #49 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
67 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
68 | ) );
69 | #50 = ORIENTED_EDGE('',*,*,#51,.F.);
70 | #51 = EDGE_CURVE('',#24,#24,#52,.T.);
71 | #52 = SURFACE_CURVE('',#53,(#58,#65),.PCURVE_S1.);
72 | #53 = CIRCLE('',#54,40.);
73 | #54 = AXIS2_PLACEMENT_3D('',#55,#56,#57);
74 | #55 = CARTESIAN_POINT('',(0.E+000,-69.28203230275,40.));
75 | #56 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
76 | #57 = DIRECTION('',(1.,0.E+000,0.E+000));
77 | #58 = PCURVE('',#32,#59);
78 | #59 = DEFINITIONAL_REPRESENTATION('',(#60),#64);
79 | #60 = LINE('',#61,#62);
80 | #61 = CARTESIAN_POINT('',(0.E+000,80.));
81 | #62 = VECTOR('',#63,1.);
82 | #63 = DIRECTION('',(1.,0.E+000));
83 | #64 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
84 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
85 | ) );
86 | #65 = PCURVE('',#66,#71);
87 | #66 = PLANE('',#67);
88 | #67 = AXIS2_PLACEMENT_3D('',#68,#69,#70);
89 | #68 = CARTESIAN_POINT('',(0.E+000,-69.28203230275,40.));
90 | #69 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
91 | #70 = DIRECTION('',(1.,0.E+000,0.E+000));
92 | #71 = DEFINITIONAL_REPRESENTATION('',(#72),#76);
93 | #72 = CIRCLE('',#73,40.);
94 | #73 = AXIS2_PLACEMENT_2D('',#74,#75);
95 | #74 = CARTESIAN_POINT('',(0.E+000,0.E+000));
96 | #75 = DIRECTION('',(1.,0.E+000));
97 | #76 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
98 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
99 | ) );
100 | #77 = ORIENTED_EDGE('',*,*,#21,.F.);
101 | #78 = ORIENTED_EDGE('',*,*,#79,.T.);
102 | #79 = EDGE_CURVE('',#22,#22,#80,.T.);
103 | #80 = SURFACE_CURVE('',#81,(#86,#93),.PCURVE_S1.);
104 | #81 = CIRCLE('',#82,40.);
105 | #82 = AXIS2_PLACEMENT_3D('',#83,#84,#85);
106 | #83 = CARTESIAN_POINT('',(0.E+000,-8.660254037844,5.));
107 | #84 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
108 | #85 = DIRECTION('',(1.,0.E+000,0.E+000));
109 | #86 = PCURVE('',#32,#87);
110 | #87 = DEFINITIONAL_REPRESENTATION('',(#88),#92);
111 | #88 = LINE('',#89,#90);
112 | #89 = CARTESIAN_POINT('',(0.E+000,10.));
113 | #90 = VECTOR('',#91,1.);
114 | #91 = DIRECTION('',(1.,0.E+000));
115 | #92 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
116 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
117 | ) );
118 | #93 = PCURVE('',#94,#99);
119 | #94 = TOROIDAL_SURFACE('',#95,30.,10.);
120 | #95 = AXIS2_PLACEMENT_3D('',#96,#97,#98);
121 | #96 = CARTESIAN_POINT('',(0.E+000,-8.660254037844,5.));
122 | #97 = DIRECTION('',(0.E+000,0.866025403784,-0.5));
123 | #98 = DIRECTION('',(1.,0.E+000,0.E+000));
124 | #99 = DEFINITIONAL_REPRESENTATION('',(#100),#104);
125 | #100 = LINE('',#101,#102);
126 | #101 = CARTESIAN_POINT('',(-0.E+000,0.E+000));
127 | #102 = VECTOR('',#103,1.);
128 | #103 = DIRECTION('',(-1.,0.E+000));
129 | #104 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
130 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
131 | ) );
132 | #105 = ADVANCED_FACE('',(#106),#94,.T.);
133 | #106 = FACE_BOUND('',#107,.F.);
134 | #107 = EDGE_LOOP('',(#108,#130,#131,#132));
135 | #108 = ORIENTED_EDGE('',*,*,#109,.F.);
136 | #109 = EDGE_CURVE('',#22,#110,#112,.T.);
137 | #110 = VERTEX_POINT('',#111);
138 | #111 = CARTESIAN_POINT('',(30.,0.E+000,0.E+000));
139 | #112 = SEAM_CURVE('',#113,(#118,#124),.PCURVE_S1.);
140 | #113 = CIRCLE('',#114,10.);
141 | #114 = AXIS2_PLACEMENT_3D('',#115,#116,#117);
142 | #115 = CARTESIAN_POINT('',(30.,-8.660254037844,5.));
143 | #116 = DIRECTION('',(-0.E+000,0.5,0.866025403784));
144 | #117 = DIRECTION('',(1.,0.E+000,0.E+000));
145 | #118 = PCURVE('',#94,#119);
146 | #119 = DEFINITIONAL_REPRESENTATION('',(#120),#123);
147 | #120 = B_SPLINE_CURVE_WITH_KNOTS('',1,(#121,#122),.UNSPECIFIED.,.F.,.F.,
148 | (2,2),(0.E+000,1.570796326795),.PIECEWISE_BEZIER_KNOTS.);
149 | #121 = CARTESIAN_POINT('',(0.E+000,0.E+000));
150 | #122 = CARTESIAN_POINT('',(0.E+000,1.570796326795));
151 | #123 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
152 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
153 | ) );
154 | #124 = PCURVE('',#94,#125);
155 | #125 = DEFINITIONAL_REPRESENTATION('',(#126),#129);
156 | #126 = B_SPLINE_CURVE_WITH_KNOTS('',1,(#127,#128),.UNSPECIFIED.,.F.,.F.,
157 | (2,2),(0.E+000,1.570796326795),.PIECEWISE_BEZIER_KNOTS.);
158 | #127 = CARTESIAN_POINT('',(-6.28318530718,0.E+000));
159 | #128 = CARTESIAN_POINT('',(-6.28318530718,1.570796326795));
160 | #129 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
161 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
162 | ) );
163 | #130 = ORIENTED_EDGE('',*,*,#79,.T.);
164 | #131 = ORIENTED_EDGE('',*,*,#109,.T.);
165 | #132 = ORIENTED_EDGE('',*,*,#133,.F.);
166 | #133 = EDGE_CURVE('',#110,#110,#134,.T.);
167 | #134 = SURFACE_CURVE('',#135,(#140,#147),.PCURVE_S1.);
168 | #135 = CIRCLE('',#136,30.);
169 | #136 = AXIS2_PLACEMENT_3D('',#137,#138,#139);
170 | #137 = CARTESIAN_POINT('',(0.E+000,0.E+000,0.E+000));
171 | #138 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
172 | #139 = DIRECTION('',(1.,0.E+000,0.E+000));
173 | #140 = PCURVE('',#94,#141);
174 | #141 = DEFINITIONAL_REPRESENTATION('',(#142),#146);
175 | #142 = LINE('',#143,#144);
176 | #143 = CARTESIAN_POINT('',(-0.E+000,1.570796326795));
177 | #144 = VECTOR('',#145,1.);
178 | #145 = DIRECTION('',(-1.,0.E+000));
179 | #146 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
180 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
181 | ) );
182 | #147 = PCURVE('',#148,#153);
183 | #148 = PLANE('',#149);
184 | #149 = AXIS2_PLACEMENT_3D('',#150,#151,#152);
185 | #150 = CARTESIAN_POINT('',(0.E+000,0.E+000,0.E+000));
186 | #151 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
187 | #152 = DIRECTION('',(1.,0.E+000,0.E+000));
188 | #153 = DEFINITIONAL_REPRESENTATION('',(#154),#158);
189 | #154 = CIRCLE('',#155,30.);
190 | #155 = AXIS2_PLACEMENT_2D('',#156,#157);
191 | #156 = CARTESIAN_POINT('',(0.E+000,0.E+000));
192 | #157 = DIRECTION('',(1.,0.E+000));
193 | #158 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
194 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
195 | ) );
196 | #159 = ADVANCED_FACE('',(#160),#148,.F.);
197 | #160 = FACE_BOUND('',#161,.F.);
198 | #161 = EDGE_LOOP('',(#162));
199 | #162 = ORIENTED_EDGE('',*,*,#133,.T.);
200 | #163 = ADVANCED_FACE('',(#164,#167),#66,.T.);
201 | #164 = FACE_BOUND('',#165,.T.);
202 | #165 = EDGE_LOOP('',(#166));
203 | #166 = ORIENTED_EDGE('',*,*,#51,.T.);
204 | #167 = FACE_BOUND('',#168,.T.);
205 | #168 = EDGE_LOOP('',(#169));
206 | #169 = ORIENTED_EDGE('',*,*,#170,.F.);
207 | #170 = EDGE_CURVE('',#171,#171,#173,.T.);
208 | #171 = VERTEX_POINT('',#172);
209 | #172 = CARTESIAN_POINT('',(35.,-69.28203230275,40.));
210 | #173 = SURFACE_CURVE('',#174,(#179,#186),.PCURVE_S1.);
211 | #174 = CIRCLE('',#175,35.);
212 | #175 = AXIS2_PLACEMENT_3D('',#176,#177,#178);
213 | #176 = CARTESIAN_POINT('',(0.E+000,-69.28203230275,40.));
214 | #177 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
215 | #178 = DIRECTION('',(1.,0.E+000,0.E+000));
216 | #179 = PCURVE('',#66,#180);
217 | #180 = DEFINITIONAL_REPRESENTATION('',(#181),#185);
218 | #181 = CIRCLE('',#182,35.);
219 | #182 = AXIS2_PLACEMENT_2D('',#183,#184);
220 | #183 = CARTESIAN_POINT('',(0.E+000,0.E+000));
221 | #184 = DIRECTION('',(1.,0.E+000));
222 | #185 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
223 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
224 | ) );
225 | #186 = PCURVE('',#187,#192);
226 | #187 = CYLINDRICAL_SURFACE('',#188,35.);
227 | #188 = AXIS2_PLACEMENT_3D('',#189,#190,#191);
228 | #189 = CARTESIAN_POINT('',(0.E+000,0.E+000,0.E+000));
229 | #190 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
230 | #191 = DIRECTION('',(1.,0.E+000,0.E+000));
231 | #192 = DEFINITIONAL_REPRESENTATION('',(#193),#197);
232 | #193 = LINE('',#194,#195);
233 | #194 = CARTESIAN_POINT('',(0.E+000,80.));
234 | #195 = VECTOR('',#196,1.);
235 | #196 = DIRECTION('',(1.,0.E+000));
236 | #197 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
237 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
238 | ) );
239 | #198 = ADVANCED_FACE('',(#199),#187,.F.);
240 | #199 = FACE_BOUND('',#200,.F.);
241 | #200 = EDGE_LOOP('',(#201,#202,#225,#252));
242 | #201 = ORIENTED_EDGE('',*,*,#170,.F.);
243 | #202 = ORIENTED_EDGE('',*,*,#203,.F.);
244 | #203 = EDGE_CURVE('',#204,#171,#206,.T.);
245 | #204 = VERTEX_POINT('',#205);
246 | #205 = CARTESIAN_POINT('',(35.,-8.660254037844,5.));
247 | #206 = SEAM_CURVE('',#207,(#211,#218),.PCURVE_S1.);
248 | #207 = LINE('',#208,#209);
249 | #208 = CARTESIAN_POINT('',(35.,-4.286263797016E-015,-7.424026671074E-015
250 | ));
251 | #209 = VECTOR('',#210,1.);
252 | #210 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
253 | #211 = PCURVE('',#187,#212);
254 | #212 = DEFINITIONAL_REPRESENTATION('',(#213),#217);
255 | #213 = LINE('',#214,#215);
256 | #214 = CARTESIAN_POINT('',(0.E+000,-0.E+000));
257 | #215 = VECTOR('',#216,1.);
258 | #216 = DIRECTION('',(0.E+000,1.));
259 | #217 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
260 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
261 | ) );
262 | #218 = PCURVE('',#187,#219);
263 | #219 = DEFINITIONAL_REPRESENTATION('',(#220),#224);
264 | #220 = LINE('',#221,#222);
265 | #221 = CARTESIAN_POINT('',(6.28318530718,-0.E+000));
266 | #222 = VECTOR('',#223,1.);
267 | #223 = DIRECTION('',(0.E+000,1.));
268 | #224 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
269 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
270 | ) );
271 | #225 = ORIENTED_EDGE('',*,*,#226,.T.);
272 | #226 = EDGE_CURVE('',#204,#204,#227,.T.);
273 | #227 = SURFACE_CURVE('',#228,(#233,#240),.PCURVE_S1.);
274 | #228 = CIRCLE('',#229,35.);
275 | #229 = AXIS2_PLACEMENT_3D('',#230,#231,#232);
276 | #230 = CARTESIAN_POINT('',(0.E+000,-8.660254037844,5.));
277 | #231 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
278 | #232 = DIRECTION('',(1.,0.E+000,0.E+000));
279 | #233 = PCURVE('',#187,#234);
280 | #234 = DEFINITIONAL_REPRESENTATION('',(#235),#239);
281 | #235 = LINE('',#236,#237);
282 | #236 = CARTESIAN_POINT('',(0.E+000,10.));
283 | #237 = VECTOR('',#238,1.);
284 | #238 = DIRECTION('',(1.,0.E+000));
285 | #239 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
286 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
287 | ) );
288 | #240 = PCURVE('',#241,#246);
289 | #241 = TOROIDAL_SURFACE('',#242,30.,5.);
290 | #242 = AXIS2_PLACEMENT_3D('',#243,#244,#245);
291 | #243 = CARTESIAN_POINT('',(0.E+000,-8.660254037844,5.));
292 | #244 = DIRECTION('',(0.E+000,0.866025403784,-0.5));
293 | #245 = DIRECTION('',(1.,0.E+000,0.E+000));
294 | #246 = DEFINITIONAL_REPRESENTATION('',(#247),#251);
295 | #247 = LINE('',#248,#249);
296 | #248 = CARTESIAN_POINT('',(-0.E+000,0.E+000));
297 | #249 = VECTOR('',#250,1.);
298 | #250 = DIRECTION('',(-1.,0.E+000));
299 | #251 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
300 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
301 | ) );
302 | #252 = ORIENTED_EDGE('',*,*,#203,.T.);
303 | #253 = ADVANCED_FACE('',(#254),#241,.F.);
304 | #254 = FACE_BOUND('',#255,.T.);
305 | #255 = EDGE_LOOP('',(#256,#280,#281,#282));
306 | #256 = ORIENTED_EDGE('',*,*,#257,.F.);
307 | #257 = EDGE_CURVE('',#204,#258,#260,.T.);
308 | #258 = VERTEX_POINT('',#259);
309 | #259 = CARTESIAN_POINT('',(30.,-4.330127018922,2.5));
310 | #260 = SEAM_CURVE('',#261,(#266,#273),.PCURVE_S1.);
311 | #261 = CIRCLE('',#262,5.);
312 | #262 = AXIS2_PLACEMENT_3D('',#263,#264,#265);
313 | #263 = CARTESIAN_POINT('',(30.,-8.660254037844,5.));
314 | #264 = DIRECTION('',(-0.E+000,0.5,0.866025403784));
315 | #265 = DIRECTION('',(1.,0.E+000,0.E+000));
316 | #266 = PCURVE('',#241,#267);
317 | #267 = DEFINITIONAL_REPRESENTATION('',(#268),#272);
318 | #268 = LINE('',#269,#270);
319 | #269 = CARTESIAN_POINT('',(-0.E+000,0.E+000));
320 | #270 = VECTOR('',#271,1.);
321 | #271 = DIRECTION('',(-0.E+000,1.));
322 | #272 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
323 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
324 | ) );
325 | #273 = PCURVE('',#241,#274);
326 | #274 = DEFINITIONAL_REPRESENTATION('',(#275),#279);
327 | #275 = LINE('',#276,#277);
328 | #276 = CARTESIAN_POINT('',(-6.28318530718,0.E+000));
329 | #277 = VECTOR('',#278,1.);
330 | #278 = DIRECTION('',(-0.E+000,1.));
331 | #279 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
332 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
333 | ) );
334 | #280 = ORIENTED_EDGE('',*,*,#226,.T.);
335 | #281 = ORIENTED_EDGE('',*,*,#257,.T.);
336 | #282 = ORIENTED_EDGE('',*,*,#283,.F.);
337 | #283 = EDGE_CURVE('',#258,#258,#284,.T.);
338 | #284 = SURFACE_CURVE('',#285,(#290,#297),.PCURVE_S1.);
339 | #285 = CIRCLE('',#286,30.);
340 | #286 = AXIS2_PLACEMENT_3D('',#287,#288,#289);
341 | #287 = CARTESIAN_POINT('',(0.E+000,-4.330127018922,2.5));
342 | #288 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
343 | #289 = DIRECTION('',(1.,0.E+000,0.E+000));
344 | #290 = PCURVE('',#241,#291);
345 | #291 = DEFINITIONAL_REPRESENTATION('',(#292),#296);
346 | #292 = LINE('',#293,#294);
347 | #293 = CARTESIAN_POINT('',(-0.E+000,1.570796326795));
348 | #294 = VECTOR('',#295,1.);
349 | #295 = DIRECTION('',(-1.,0.E+000));
350 | #296 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
351 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
352 | ) );
353 | #297 = PCURVE('',#298,#303);
354 | #298 = PLANE('',#299);
355 | #299 = AXIS2_PLACEMENT_3D('',#300,#301,#302);
356 | #300 = CARTESIAN_POINT('',(0.E+000,-4.330127018922,2.5));
357 | #301 = DIRECTION('',(0.E+000,-0.866025403784,0.5));
358 | #302 = DIRECTION('',(1.,0.E+000,0.E+000));
359 | #303 = DEFINITIONAL_REPRESENTATION('',(#304),#308);
360 | #304 = CIRCLE('',#305,30.);
361 | #305 = AXIS2_PLACEMENT_2D('',#306,#307);
362 | #306 = CARTESIAN_POINT('',(0.E+000,0.E+000));
363 | #307 = DIRECTION('',(1.,0.E+000));
364 | #308 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
365 | PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
366 | ) );
367 | #309 = ADVANCED_FACE('',(#310),#298,.T.);
368 | #310 = FACE_BOUND('',#311,.T.);
369 | #311 = EDGE_LOOP('',(#312));
370 | #312 = ORIENTED_EDGE('',*,*,#283,.T.);
371 | #313 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3)
372 | GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#317)) GLOBAL_UNIT_ASSIGNED_CONTEXT
373 | ((#314,#315,#316)) REPRESENTATION_CONTEXT('Context #1',
374 | '3D Context with UNIT and UNCERTAINTY') );
375 | #314 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
376 | #315 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) );
377 | #316 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() );
378 | #317 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(5.E-004),#314,
379 | 'distance_accuracy_value','confusion accuracy');
380 | #318 = PRODUCT_RELATED_PRODUCT_CATEGORY('detail',$,(#7));
381 | #319 = PRODUCT_CATEGORY_RELATIONSHIP('','',#320,#318);
382 | #320 = PRODUCT_CATEGORY('part',$);
383 | #321 = CC_DESIGN_PERSON_AND_ORGANIZATION_ASSIGNMENT(#322,#325,(#6,#5));
384 | #322 = PERSON_AND_ORGANIZATION(#323,#324);
385 | #323 = PERSON('IP192.168.001.000,410210336','','',$,$,$);
386 | #324 = ORGANIZATION('IP192.168.001.000','Unspecified','');
387 | #325 = PERSON_AND_ORGANIZATION_ROLE('creator');
388 | #326 = CC_DESIGN_PERSON_AND_ORGANIZATION_ASSIGNMENT(#322,#327,(#7));
389 | #327 = PERSON_AND_ORGANIZATION_ROLE('design_owner');
390 | #328 = CC_DESIGN_PERSON_AND_ORGANIZATION_ASSIGNMENT(#322,#329,(#6));
391 | #329 = PERSON_AND_ORGANIZATION_ROLE('design_supplier');
392 | #330 = CC_DESIGN_PERSON_AND_ORGANIZATION_ASSIGNMENT(#322,#331,(#332));
393 | #331 = PERSON_AND_ORGANIZATION_ROLE('classification_officer');
394 | #332 = SECURITY_CLASSIFICATION('','',#333);
395 | #333 = SECURITY_CLASSIFICATION_LEVEL('unclassified');
396 | #334 = CC_DESIGN_SECURITY_CLASSIFICATION(#332,(#6));
397 | #335 = CC_DESIGN_DATE_AND_TIME_ASSIGNMENT(#336,#340,(#5));
398 | #336 = DATE_AND_TIME(#337,#338);
399 | #337 = CALENDAR_DATE(2016,4,8);
400 | #338 = LOCAL_TIME(20,7,$,#339);
401 | #339 = COORDINATED_UNIVERSAL_TIME_OFFSET(5,$,.BEHIND.);
402 | #340 = DATE_TIME_ROLE('creation_date');
403 | #341 = CC_DESIGN_DATE_AND_TIME_ASSIGNMENT(#336,#342,(#332));
404 | #342 = DATE_TIME_ROLE('classification_date');
405 | #343 = CC_DESIGN_APPROVAL(#344,(#6,#5,#332));
406 | #344 = APPROVAL(#345,'');
407 | #345 = APPROVAL_STATUS('not_yet_approved');
408 | #346 = APPROVAL_PERSON_ORGANIZATION(#322,#344,#347);
409 | #347 = APPROVAL_ROLE('approver');
410 | #348 = APPROVAL_DATE_TIME(#336,#344);
411 | ENDSEC;
412 | END-ISO-10303-21;
413 |
--------------------------------------------------------------------------------
/OCCUtils/Topology.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | ##Copyright 2008-2015 Jelle Feringa (jelleferinga@gmail.com)
4 | ##
5 | ##This file is part of pythonOCC.
6 | ##
7 | ##pythonOCC is free software: you can redistribute it and/or modify
8 | ##it under the terms of the GNU Lesser General Public License as published by
9 | ##the Free Software Foundation, either version 3 of the License, or
10 | ##(at your option) any later version.
11 | ##
12 | ##pythonOCC is distributed in the hope that it will be useful,
13 | ##but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | ##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | ##GNU Lesser General Public License for more details.
16 | ##
17 | ##You should have received a copy of the GNU Lesser General Public License
18 | ##along with pythonOCC. If not, see .
19 |
20 | from __future__ import print_function
21 |
22 | __all__ = ['Topo', 'WireExplorer', 'dumpTopology']
23 |
24 | from OCC.Core.BRep import BRep_Tool
25 |
26 | from OCC.Core.BRepTools import BRepTools_WireExplorer
27 | from OCC.Core.TopAbs import (TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE, TopAbs_WIRE,
28 | TopAbs_SHELL, TopAbs_SOLID, TopAbs_COMPOUND,
29 | TopAbs_COMPSOLID)
30 | from OCC.Core.TopExp import TopExp_Explorer, topexp_MapShapesAndAncestors
31 | from OCC.Core.TopTools import (TopTools_ListOfShape,
32 | TopTools_ListIteratorOfListOfShape,
33 | TopTools_IndexedDataMapOfShapeListOfShape)
34 | from OCC.Core.TopoDS import (topods, TopoDS_Wire, TopoDS_Vertex, TopoDS_Edge,
35 | TopoDS_Face, TopoDS_Shell, TopoDS_Solid,
36 | TopoDS_Compound, TopoDS_CompSolid, topods_Edge,
37 | topods_Vertex, TopoDS_Iterator)
38 |
39 |
40 | class WireExplorer(object):
41 | '''
42 | Wire traversal
43 | '''
44 | def __init__(self, wire):
45 | assert isinstance(wire, TopoDS_Wire), 'not a TopoDS_Wire'
46 | self.wire = wire
47 | self.wire_explorer = BRepTools_WireExplorer(self.wire)
48 | self.done = False
49 |
50 | def _reinitialize(self):
51 | self.wire_explorer = BRepTools_WireExplorer(self.wire)
52 | self.done = False
53 |
54 | def _loop_topo(self, edges=True):
55 | if self.done:
56 | self._reinitialize()
57 | topologyType = topods_Edge if edges else topods_Vertex
58 | seq = []
59 | hashes = [] # list that stores hashes to avoid redundancy
60 | occ_seq = TopTools_ListOfShape()
61 | while self.wire_explorer.More():
62 | # loop edges
63 | if edges:
64 | current_item = self.wire_explorer.Current()
65 | # loop vertices
66 | else:
67 | current_item = self.wire_explorer.CurrentVertex()
68 | current_item_hash = current_item.__hash__()
69 | if not current_item_hash in hashes:
70 | hashes.append(current_item_hash)
71 | occ_seq.Append(current_item)
72 | self.wire_explorer.Next()
73 |
74 | # Convert occ_seq to python list
75 | occ_iterator = TopTools_ListIteratorOfListOfShape(occ_seq)
76 | while occ_iterator.More():
77 | topo_to_add = topologyType(occ_iterator.Value())
78 | seq.append(topo_to_add)
79 | occ_iterator.Next()
80 | self.done = True
81 | return iter(seq)
82 |
83 | def ordered_edges(self):
84 | return self._loop_topo(edges=True)
85 |
86 | def ordered_vertices(self):
87 | return self._loop_topo(edges=False)
88 |
89 |
90 | class Topo(object):
91 | '''
92 | Topology traversal
93 | '''
94 |
95 | def __init__(self, myShape, ignore_orientation=False):
96 | """
97 |
98 | implements topology traversal from any TopoDS_Shape
99 | this class lets you find how various topological entities are connected from one to another
100 | find the faces connected to an edge, find the vertices this edge is made from, get all faces connected to
101 | a vertex, and find out how many topological elements are connected from a source
102 |
103 | *note* when traversing TopoDS_Wire entities, its advised to use the specialized
104 | ``WireExplorer`` class, which will return the vertices / edges in the expected order
105 |
106 | :param myShape: the shape which topology will be traversed
107 |
108 | :param ignore_orientation: filter out TopoDS_* entities of similar TShape but different Orientation
109 |
110 | for instance, a cube has 24 edges, 4 edges for each of 6 faces
111 |
112 | that results in 48 vertices, while there are only 8 vertices that have a unique
113 | geometric coordinate
114 |
115 | in certain cases ( computing a graph from the topology ) its preferable to return
116 | topological entities that share similar geometry, though differ in orientation
117 | by setting the ``ignore_orientation`` variable
118 | to True, in case of a cube, just 12 edges and only 8 vertices will be returned
119 |
120 | for further reference see TopoDS_Shape IsEqual / IsSame methods
121 |
122 | """
123 | self.myShape = myShape
124 | self.ignore_orientation = ignore_orientation
125 |
126 | # the topoFactory dicts maps topology types and functions that can
127 | # create this topology
128 | self.topoFactory = {
129 | TopAbs_VERTEX: topods.Vertex,
130 | TopAbs_EDGE: topods.Edge,
131 | TopAbs_FACE: topods.Face,
132 | TopAbs_WIRE: topods.Wire,
133 | TopAbs_SHELL: topods.Shell,
134 | TopAbs_SOLID: topods.Solid,
135 | TopAbs_COMPOUND: topods.Compound,
136 | TopAbs_COMPSOLID: topods.CompSolid
137 | }
138 |
139 | def _loop_topo(self, topologyType, topologicalEntity=None, topologyTypeToAvoid=None):
140 | '''
141 | this could be a faces generator for a python TopoShape class
142 | that way you can just do:
143 | for face in srf.faces:
144 | processFace(face)
145 | '''
146 | topoTypes = {TopAbs_VERTEX: TopoDS_Vertex,
147 | TopAbs_EDGE: TopoDS_Edge,
148 | TopAbs_FACE: TopoDS_Face,
149 | TopAbs_WIRE: TopoDS_Wire,
150 | TopAbs_SHELL: TopoDS_Shell,
151 | TopAbs_SOLID: TopoDS_Solid,
152 | TopAbs_COMPOUND: TopoDS_Compound,
153 | TopAbs_COMPSOLID: TopoDS_CompSolid}
154 |
155 | assert topologyType in topoTypes.keys(), '%s not one of %s' % (topologyType, topoTypes.keys())
156 | self.topExp = TopExp_Explorer()
157 | # use self.myShape if nothing is specified
158 | if topologicalEntity is None and topologyTypeToAvoid is None:
159 | self.topExp.Init(self.myShape, topologyType)
160 | elif topologicalEntity is None and topologyTypeToAvoid is not None:
161 | self.topExp.Init(self.myShape, topologyType, topologyTypeToAvoid)
162 | elif topologyTypeToAvoid is None:
163 | self.topExp.Init(topologicalEntity, topologyType)
164 | elif topologyTypeToAvoid:
165 | self.topExp.Init(topologicalEntity,
166 | topologyType,
167 | topologyTypeToAvoid)
168 | seq = []
169 | hashes = [] # list that stores hashes to avoid redundancy
170 | occ_seq = TopTools_ListOfShape()
171 | while self.topExp.More():
172 | current_item = self.topExp.Current()
173 | current_item_hash = current_item.__hash__()
174 |
175 | if not current_item_hash in hashes:
176 | hashes.append(current_item_hash)
177 | occ_seq.Append(current_item)
178 |
179 | self.topExp.Next()
180 | # Convert occ_seq to python list
181 | occ_iterator = TopTools_ListIteratorOfListOfShape(occ_seq)
182 | while occ_iterator.More():
183 | topo_to_add = self.topoFactory[topologyType](occ_iterator.Value())
184 | seq.append(topo_to_add)
185 | occ_iterator.Next()
186 |
187 | if self.ignore_orientation:
188 | # filter out those entities that share the same TShape
189 | # but do *not* share the same orientation
190 | filter_orientation_seq = []
191 | for i in seq:
192 | _present = False
193 | for j in filter_orientation_seq:
194 | if i.IsSame(j):
195 | _present = True
196 | break
197 | if _present is False:
198 | filter_orientation_seq.append(i)
199 | return filter_orientation_seq
200 | else:
201 | return iter(seq)
202 |
203 | def faces(self):
204 | '''
205 | loops over all faces
206 | '''
207 | return self._loop_topo(TopAbs_FACE)
208 |
209 | def _number_of_topo(self, iterable):
210 | n = 0
211 | for i in iterable:
212 | n += 1
213 | return n
214 |
215 | def number_of_faces(self):
216 | return self._number_of_topo(self.faces())
217 |
218 | def vertices(self):
219 | '''
220 | loops over all vertices
221 | '''
222 | return self._loop_topo(TopAbs_VERTEX)
223 |
224 | def number_of_vertices(self):
225 | return self._number_of_topo(self.vertices())
226 |
227 | def edges(self):
228 | '''
229 | loops over all edges
230 | '''
231 | return self._loop_topo(TopAbs_EDGE)
232 |
233 | def number_of_edges(self):
234 | return self._number_of_topo(self.edges())
235 |
236 | def wires(self):
237 | '''
238 | loops over all wires
239 | '''
240 | return self._loop_topo(TopAbs_WIRE)
241 |
242 | def number_of_wires(self):
243 | return self._number_of_topo(self.wires())
244 |
245 | def shells(self):
246 | '''
247 | loops over all shells
248 | '''
249 | return self._loop_topo(TopAbs_SHELL, None)
250 |
251 | def number_of_shells(self):
252 | return self._number_of_topo(self.shells())
253 |
254 | def solids(self):
255 | '''
256 | loops over all solids
257 | '''
258 | return self._loop_topo(TopAbs_SOLID, None)
259 |
260 | def number_of_solids(self):
261 | return self._number_of_topo(self.solids())
262 |
263 | def comp_solids(self):
264 | '''
265 | loops over all compound solids
266 | '''
267 | return self._loop_topo(TopAbs_COMPSOLID)
268 |
269 | def number_of_comp_solids(self):
270 | return self._number_of_topo(self.comp_solids())
271 |
272 | def compounds(self):
273 | '''
274 | loops over all compounds
275 | '''
276 | return self._loop_topo(TopAbs_COMPOUND)
277 |
278 | def number_of_compounds(self):
279 | return self._number_of_topo(self.compounds())
280 |
281 | def ordered_vertices_from_wire(self, wire):
282 | '''
283 | @param wire: TopoDS_Wire
284 | '''
285 | we = WireExplorer(wire)
286 | return we.ordered_vertices()
287 |
288 | def number_of_ordered_vertices_from_wire(self, wire):
289 | return self._number_of_topo(self.ordered_vertices_from_wire(wire))
290 |
291 | def ordered_edges_from_wire(self, wire):
292 | '''
293 | @param wire: TopoDS_Wire
294 | '''
295 | we = WireExplorer(wire)
296 | return we.ordered_edges()
297 |
298 | def number_of_ordered_edges_from_wire(self, wire):
299 | return self._number_of_topo(self.ordered_edges_from_wire(wire))
300 |
301 | def _map_shapes_and_ancestors(self, topoTypeA, topoTypeB, topologicalEntity):
302 | '''
303 | using the same method
304 | @param topoTypeA:
305 | @param topoTypeB:
306 | @param topologicalEntity:
307 | '''
308 | topo_set = set()
309 | _map = TopTools_IndexedDataMapOfShapeListOfShape()
310 | topexp_MapShapesAndAncestors(self.myShape, topoTypeA, topoTypeB, _map)
311 | results = _map.FindFromKey(topologicalEntity)
312 | if results.IsEmpty():
313 | yield None
314 |
315 | topology_iterator = TopTools_ListIteratorOfListOfShape(results)
316 | while topology_iterator.More():
317 |
318 | topo_entity = self.topoFactory[topoTypeB](topology_iterator.Value())
319 |
320 | # return the entity if not in set
321 | # to assure we're not returning entities several times
322 | if not topo_entity in topo_set:
323 | if self.ignore_orientation:
324 | unique = True
325 | for i in topo_set:
326 | if i.IsSame(topo_entity):
327 | unique = False
328 | break
329 | if unique:
330 | yield topo_entity
331 | else:
332 | yield topo_entity
333 |
334 | topo_set.add(topo_entity)
335 | topology_iterator.Next()
336 |
337 | def _number_shapes_ancestors(self, topoTypeA, topoTypeB, topologicalEntity):
338 | '''returns the number of shape ancestors
339 | If you want to know how many edges a faces has:
340 | _number_shapes_ancestors(self, TopAbs_EDGE, TopAbs_FACE, edg)
341 | will return the number of edges a faces has
342 | @param topoTypeA:
343 | @param topoTypeB:
344 | @param topologicalEntity:
345 | '''
346 | topo_set = set()
347 | _map = TopTools_IndexedDataMapOfShapeListOfShape()
348 | topexp_MapShapesAndAncestors(self.myShape, topoTypeA, topoTypeB, _map)
349 | results = _map.FindFromKey(topologicalEntity)
350 | if results.IsEmpty():
351 | return None
352 | topology_iterator = TopTools_ListIteratorOfListOfShape(results)
353 | while topology_iterator.More():
354 | topo_set.add(topology_iterator.Value())
355 | topology_iterator.Next()
356 | return len(topo_set)
357 |
358 | # ======================================================================
359 | # EDGE <-> FACE
360 | # ======================================================================
361 | def faces_from_edge(self, edge):
362 | """
363 |
364 | :param edge:
365 | :return:
366 | """
367 | return self._map_shapes_and_ancestors(TopAbs_EDGE, TopAbs_FACE, edge)
368 |
369 | def number_of_faces_from_edge(self, edge):
370 | """
371 |
372 | :param edge:
373 | :return:
374 | """
375 | return self._number_shapes_ancestors(TopAbs_EDGE, TopAbs_FACE, edge)
376 |
377 | def edges_from_face(self, face):
378 | """
379 |
380 | :param face:
381 | :return:
382 | """
383 | return self._loop_topo(TopAbs_EDGE, face)
384 |
385 | def number_of_edges_from_face(self, face):
386 | cnt = 0
387 | for i in self._loop_topo(TopAbs_EDGE, face):
388 | cnt += 1
389 | return cnt
390 |
391 | # ======================================================================
392 | # VERTEX <-> EDGE
393 | # ======================================================================
394 | def vertices_from_edge(self, edg):
395 | return self._loop_topo(TopAbs_VERTEX, edg)
396 |
397 | def number_of_vertices_from_edge(self, edg):
398 | cnt = 0
399 | for i in self._loop_topo(TopAbs_VERTEX, edg):
400 | cnt += 1
401 | return cnt
402 |
403 | def edges_from_vertex(self, vertex):
404 | return self._map_shapes_and_ancestors(TopAbs_VERTEX, TopAbs_EDGE, vertex)
405 |
406 | def number_of_edges_from_vertex(self, vertex):
407 | return self._number_shapes_ancestors(TopAbs_VERTEX, TopAbs_EDGE, vertex)
408 |
409 | # ======================================================================
410 | # WIRE <-> EDGE
411 | # ======================================================================
412 | def edges_from_wire(self, wire):
413 | return self._loop_topo(TopAbs_EDGE, wire)
414 |
415 | def number_of_edges_from_wire(self, wire):
416 | cnt = 0
417 | for i in self._loop_topo(TopAbs_EDGE, wire):
418 | cnt += 1
419 | return cnt
420 |
421 | def wires_from_edge(self, edg):
422 | return self._map_shapes_and_ancestors(TopAbs_EDGE, TopAbs_WIRE, edg)
423 |
424 | def wires_from_vertex(self, edg):
425 | return self._map_shapes_and_ancestors(TopAbs_VERTEX, TopAbs_WIRE, edg)
426 |
427 | def number_of_wires_from_edge(self, edg):
428 | return self._number_shapes_ancestors(TopAbs_EDGE, TopAbs_WIRE, edg)
429 |
430 | # ======================================================================
431 | # WIRE <-> FACE
432 | # ======================================================================
433 | def wires_from_face(self, face):
434 | return self._loop_topo(TopAbs_WIRE, face)
435 |
436 | def number_of_wires_from_face(self, face):
437 | cnt = 0
438 | for i in self._loop_topo(TopAbs_WIRE, face):
439 | cnt += 1
440 | return cnt
441 |
442 | def faces_from_wire(self, wire):
443 | return self._map_shapes_and_ancestors(TopAbs_WIRE, TopAbs_FACE, wire)
444 |
445 | def number_of_faces_from_wires(self, wire):
446 | return self._number_shapes_ancestors(TopAbs_WIRE, TopAbs_FACE, wire)
447 |
448 | # ======================================================================
449 | # VERTEX <-> FACE
450 | # ======================================================================
451 | def faces_from_vertex(self, vertex):
452 | return self._map_shapes_and_ancestors(TopAbs_VERTEX, TopAbs_FACE, vertex)
453 |
454 | def number_of_faces_from_vertex(self, vertex):
455 | return self._number_shapes_ancestors(TopAbs_VERTEX, TopAbs_FACE, vertex)
456 |
457 | def vertices_from_face(self, face):
458 | return self._loop_topo(TopAbs_VERTEX, face)
459 |
460 | def number_of_vertices_from_face(self, face):
461 | cnt = 0
462 | for i in self._loop_topo(TopAbs_VERTEX, face):
463 | cnt += 1
464 | return cnt
465 |
466 | # ======================================================================
467 | # FACE <-> SOLID
468 | # ======================================================================
469 | def solids_from_face(self, face):
470 | return self._map_shapes_and_ancestors(TopAbs_FACE, TopAbs_SOLID, face)
471 |
472 | def number_of_solids_from_face(self, face):
473 | return self._number_shapes_ancestors(TopAbs_FACE, TopAbs_SOLID, face)
474 |
475 | def faces_from_solids(self, solid):
476 | return self._loop_topo(TopAbs_FACE, solid)
477 |
478 | def number_of_faces_from_solids(self, solid):
479 | cnt = 0
480 | for i in self._loop_topo(TopAbs_FACE, solid):
481 | cnt += 1
482 | return cnt
483 |
484 |
485 | def dumpTopology(shape, level=0):
486 | """
487 | Print the details of an object from the top down
488 | """
489 | brt = BRep_Tool()
490 | s = shape.ShapeType()
491 | if s == TopAbs_VERTEX:
492 | pnt = brt.Pnt(topods_Vertex(shape))
493 | print(".." * level + "" % (hash(shape), pnt.X(), pnt.Y(), pnt.Z()))
494 | else:
495 | print(".." * level, end="")
496 | print(shapeTypeString(shape))
497 | it = TopoDS_Iterator(shape)
498 | while it.More():
499 | shp = it.Value()
500 | it.Next()
501 | dumpTopology(shp, level + 1)
502 |
503 |
504 | def shapeTypeString(shape):
505 | st = shape.ShapeType()
506 | s = "?"
507 | if st == TopAbs_VERTEX:
508 | s = "Vertex"
509 | if st == TopAbs_SOLID:
510 | s = "Solid"
511 | if st == TopAbs_EDGE:
512 | s = "Edge"
513 | if st == TopAbs_FACE:
514 | s = "Face"
515 | if st == TopAbs_SHELL:
516 | s = "Shell"
517 | if st == TopAbs_WIRE:
518 | s = "Wire"
519 | if st == TopAbs_COMPOUND:
520 | s = "Compound."
521 | if st == TopAbs_COMPSOLID:
522 | s = "Compsolid."
523 | return "%s: %i" % (s, hash(shape))
524 |
--------------------------------------------------------------------------------
/unusedDynamic.py:
--------------------------------------------------------------------------------
1 | def tweakFace(mFace, workPart, tPlane):
2 | # Move mFace (on workPart) to target plane
3 | # All other faces remain in their original planes.
4 | # Only works if all adjacent faces are planar.
5 | """
6 | The algorithm is to first find the four vertices of mFace (to be moved) then
7 | at each vertex, identify the edge that is *not* contained in mFace. The
8 | intersection of each of these edges with the target plane is a new vertex.
9 | The mFace is replaced by a new face defined by the four new vertices.
10 | The adjacent faces are stretched to the new vertices, remaining in their
11 | initial planes. The part is then sewn back together.
12 | """
13 | topo = Topology.Topo(workPart)
14 | edgeList = [] # edges of face to be moved
15 | for edge in topo.edges_from_face(mFace):
16 | edgeList.append(edge)
17 | wires = topo.wires_from_face(mFace)
18 | for wire in wires: # assuming there is only one wire
19 | oldVertices = topo.ordered_vertices_from_wire(wire)
20 | oldVrtxList = [] # ordered list of vertices of mFace
21 | for vrtx in oldVertices:
22 | oldVrtxList.append(vrtx)
23 |
24 | # Find new points (which will become the vertices of moved mFace)
25 | newPntList = [] # also ordered to corespond with oldVrtxList
26 | for vrtx in oldVrtxList: # for each vertex of mFace
27 | edgs = topo.edges_from_vertex(vrtx)
28 | for edg in edgs: # for each edge connected to vertex
29 | edgeInFace = False # assume edge is not in face
30 | for e in edgeList:
31 | if (hash(edg) == hash(e)): # until discovered that it is
32 | edgeInFace = True
33 | if not edgeInFace: # edge between 2 adjacent faces
34 | pList = [] # end points of edge
35 | for vrtx in topo.vertices_from_edge(edg):
36 | pList.append(BRep_Tool().Pnt(vrtx))
37 | gpvec = gp_Vec(pList[0], pList[1])
38 | gpdir = gp_Dir(gpvec)
39 | line = gp_Lin(pList[0], gpdir)
40 | newPntList.append(intersectPnt(line, tPlane))
41 | break
42 |
43 | print 'number of new points = ', len(newPntList)
44 |
45 | for i in range(len(newPntList)):
46 | P = newPntList[i]
47 | display.DisplayShape(P)
48 | pstring = "P%i" % i
49 | display.DisplayMessage(P, pstring)
50 |
51 |
52 | # sort through all the part's faces and stretch the adjacent ones
53 | faces = topo.faces_from_solids(workPart) # all faces
54 | adjFaces = [] # Adjacent faces (stretched)
55 | otherFaces = [] # Other faces (to be reused unchanged)
56 | for face in faces:
57 | edges = topo.edges_from_face(face)
58 | if face == mFace:
59 | pass # This is the face to be moved
60 | else:
61 | adjacentFace = False # assume face is not adjacent...
62 | for e in edges:
63 | for f in edgeList:
64 | if (hash(e) == hash(f)): # common edge
65 | adjacentFace = True # until discovered that it is
66 | if adjacentFace:
67 | wires = topo.wires_from_face(face)
68 | wireList = []
69 | for wire in wires:
70 | wireList.append(wire)
71 | outerWire = wireList.pop(0)
72 | orderedVertices = topo.ordered_vertices_from_wire(outerWire)
73 | orderedPtList = []
74 | for vrtx in orderedVertices:
75 | pnt = BRep_Tool().Pnt(vrtx)
76 | for i in range(len(oldVrtxList)):
77 | if (hash(vrtx) == hash(oldVrtxList[i])): # common vertex
78 | pnt = newPntList[i]
79 | orderedPtList.append(pnt)
80 | orderedPtList.reverse() # need to do this for faces with holes
81 | stretchedWire = pointsToWire(orderedPtList)
82 | makeFace = BRepBuilderAPI_MakeFace(stretchedWire)
83 | for wire in wireList:
84 | makeFace.Add(wire)
85 | if makeFace.IsDone():
86 | stretchedFace = makeFace.Face()
87 | adjFaces.append(stretchedFace)
88 | else:
89 | otherFaces.append(face)
90 |
91 | # make newFace to replace mFace
92 | newWire = pointsToWire(newPntList)
93 | makeFace = BRepBuilderAPI_MakeFace(newWire)
94 | if makeFace.IsDone():
95 | newFace = makeFace.Face()
96 |
97 | # sew all the faces together
98 | tolerance = 1e-7
99 | sew = BRepBuilderAPI_Sewing(tolerance)
100 |
101 | print 'Number of other faces: ', len(otherFaces)
102 | for f in otherFaces:
103 | sew.Add(f)
104 |
105 | for f in adjFaces:
106 | sew.Add(f)
107 | sew.Add(newFace)
108 | sew.Perform()
109 | res = sew.SewedShape()
110 | return res
111 |
112 | def makeToolBody(mFace, tPlane):
113 | # Make toolBody on mFace (of active part) to target surface.
114 | # (target surface is ignored for now) Far face is parallel to mFace.
115 | # All other faces remain in their original planes.
116 | """
117 | This algorithm follows the procedure of the 'intelligent local operation'
118 | used by HP SolidDesigner, in which a toolbody is constructed so that its
119 | 'near' face mates against mFace and its 'far' face is aligned to the target
120 | surface. The toolbody's 'side faces' align with the faces adjacent to mFace
121 | on the workpart. The toolbody can then be fused to the workpart so mFace
122 | gets effectively 'moved' out to the target surface. If the target surface is
123 | 'inside' the workpart, then the toolbody is subtracted from the workpart.
124 |
125 | Here it is in detail, assuming mFace is planar and has only one wire (no
126 | holes.) Target surface is assumed to be completely outside the workpart.
127 |
128 | Use the underlying wire of mFace to create an identical tool face which can
129 | then be extruded into a prism. The side faces of the prism will corespond
130 | exactly with the edges of mFace. This prism becomes the toolbody.
131 | One by one, tweak the adjacent faces of the toolbody into alignment with the
132 | adjacent faces of the workpart, and align the 'far' face of the prism to the
133 | target surface. To correlate the toolbody side faces with the sidefaces of
134 | the workPart to which they will become aligned, keep track of their common
135 | edge.
136 | """
137 | workPart = win.activePart
138 | wrkPrtUID = win.activePartUID
139 | topo = Topology.Topo(workPart)
140 | mF_wires = topo.wires_from_face(mFace)
141 | if topo.number_of_wires_from_face(mFace) > 1:
142 | print 'Not yet implemented for faces with holes.'
143 | return
144 | else: # Only one wire in mFace
145 | pass
146 | mF_wire = next(mF_wires)
147 | mF_vrtxList = [] # ordered list of vertices of mFace
148 | for vrtx in topo.ordered_vertices_from_wire(mF_wire):
149 | mF_vrtxList.append(vrtx)
150 |
151 | mF_edgeList = [] # ordered list of edges of mFace
152 | nEdges = 0
153 | for edge in topo.ordered_edges_from_wire(mF_wire):
154 | mF_edgeList.append(edge)
155 | nEdges += 1
156 |
157 | # make an ordered list of faces adjacent to mFace
158 | faces = topo.faces_from_solids(win.activePart) # all faces
159 | adjFacesDict = {} # key=seq : value=face
160 | for face in faces:
161 | edges = topo.edges_from_face(face)
162 | if face.IsSame(mFace):
163 | pass # This is mFace
164 | else:
165 | adjacentFace = False # assume face is not adjacent...
166 | for e in edges:
167 | seq = 0 # keep track of which edge in ordered list is matched
168 | for f in mF_edgeList:
169 | seq += 1
170 | if (hash(e) == hash(f)): # common edge
171 | adjacentFace = True # until discovered that it is
172 | break
173 | if adjacentFace:
174 | break
175 | if adjacentFace:
176 | adjFacesDict[seq] = face
177 | mF_adjFaceList = adjFacesDict.values() # ordered list of adjacent faces
178 |
179 | # create a toolBody that mates against mFace
180 | faceNormal = Construct.face_normal(mFace) # type: gp_Dir
181 | vctr = gp_Vec(faceNormal).Multiplied(10)
182 | toolBody = BRepPrimAPI_MakePrism(mFace, vctr).Shape()
183 |
184 | # find toolBody face sharing an edge with workpart adjacent face
185 | # compare face normals to see if toolBody face needs to be tweaked
186 | # keep track by index of wp ordered list
187 | facesToTweak = {} # key = edge index ; value = toolBody faceNormal
188 | tb_topo = Topology.Topo(toolBody)
189 | tb_faces = tb_topo.faces_from_solids(toolBody) # all faces of toolBody
190 | for i in range(len(mF_edgeList)):
191 | print i
192 | we = mF_edgeList[i] # workpart edge
193 | for tb_face in tb_faces:
194 | adjacentFace = False # assume face is not adjacent...
195 | if tb_face.IsSame(mFace):
196 | print 'found mated face'
197 | else:
198 | tb_edges = tb_topo.edges_from_face(tb_face)
199 | for tb_e in tb_edges:
200 | if tb_e.IsSame(we): # common edge
201 | adjacentFace = True # until discovered that it is
202 | #break
203 | if adjacentFace:
204 | print 'found TB face matching workPart adjFace %i:' % i
205 | # check coplanarity between tb_face and wp_face
206 | wp_face = mF_adjFaceList[i]
207 | wpFaceNormal = Construct.face_normal(wp_face) # type: gp_Dir
208 | tbFaceNormal = Construct.face_normal(tb_face) # type: gp_Dir
209 | angle = wpFaceNormal.Angle(tbFaceNormal)
210 | if angle > 1e-10:
211 | print 'face needs to be tweaked'
212 | facesToTweak[i] = tbFaceNormal
213 | else:
214 | print 'no need to tweak face'
215 | break
216 | else:
217 | print 'found other face'
218 |
219 | # Tweak toolBody faces that need to be aligned to workPart faces
220 | for k,v in facesToTweak.items():
221 | print 'Tweaking face ', k
222 | tb_topo = Topology.Topo(toolBody)
223 | tb_faces = tb_topo.faces_from_solids(toolBody) # all faces of toolBody
224 | targetFace = mF_adjFaceList[k]
225 | targetPlane = planeOfFace(targetFace)
226 | for tb_face in tb_faces:
227 | tbFaceNormal = Construct.face_normal(tb_face)
228 | angle = tbFaceNormal.Angle(v)
229 | if angle < 1e-10:
230 | sharedEdge = edgeOnFaceP(mF_edgeList[k], tb_face)
231 | if sharedEdge:
232 | print 'Common edge test: ', sharedEdge
233 | toolBody = tweakFace(tb_face, toolBody, targetPlane)
234 | win.getNewPartUID(toolBody)
235 |
236 | def alignFace(initial=True):
237 | """
238 | Align a selected face on the active part to some other face.
239 | This involves 'stretching' adjacent faces to reach the new aligned face.
240 | All the faces (of the active part) are then sewn back together.
241 | """
242 | # This only works if all adjacent faces are planar.
243 |
244 | if initial:
245 | win.registerCallback(alignFaceC)
246 | display.SetSelectionModeFace()
247 | statusText = "Select face to move (on active part)."
248 | win.statusBar().showMessage(statusText)
249 | elif len(win.faceStack) == 2:
250 | workPart = win.activePart
251 | wrkPrtUID = win.activePartUID
252 | tFace = win.faceStack.pop() # target face (to be aligned to)
253 | tPlane = planeOfFace(tFace)
254 | mFace = win.faceStack.pop() # face to be moved
255 | res = tweakFace(mFace, workPart, tPlane)
256 | win.getNewPartUID(res, ancestor=wrkPrtUID)
257 |
258 | win.statusBar().showMessage('Align Face operation complete')
259 | win.clearCallback()
260 |
261 | def offsetEndFace(initial=True):
262 | """
263 | Offset one end face of a simple cylinder (the active part) by a dist value.
264 | This involves 'stretching' the cylindrical face to reach the new end face.
265 | The faces are then sewn back together.
266 | """
267 | if initial:
268 | win.registerCallback(offsetEndFaceC)
269 | display.SetSelectionModeFace()
270 | statusText = "Select face to move (on active part)."
271 | win.statusBar().showMessage(statusText)
272 | elif (win.lineEditStack and win.faceStack):
273 | text = win.lineEditStack.pop()
274 | value = float(text) * win.unitscale
275 | mFace = win.faceStack.pop() # face to be moved
276 | workPart = win.activePart
277 | wrkPrtUID = win.activePartUID
278 | topo = Topology.Topo(workPart)
279 | faces = topo.faces_from_solids(workPart) # all faces
280 | for face in faces:
281 | '''
282 | This is tricky.
283 | Below, I decide a face is cylindrical if it has three edges.
284 | But that is only true if the cylinder is one 360-deg face.
285 | As I discovered in the 'plate' part of the step file,
286 | those cylindrical holes were comprised of two 180-deg faces,
287 | each with 4 edges. So this is not going to be reliable.
288 |
289 | Maybe it would be smarter to first decide whether a face
290 | is the end face of a cylinder, then look for adjacent faces.
291 |
292 | That gives me two problems that need reliable solutions:
293 | 1- How to test whether a face is the end face of a cylinder
294 | 2- How to find adjacent cylinder faces
295 |
296 | I recall a short utility function for testing 'IsPlanar'...
297 | '''
298 | nbrEdges = topo.number_of_edges_from_face(face)
299 | print nbrEdges
300 | edges = topo.edges_from_face(face)
301 | if face == mFace: # This is the face to be moved
302 | pass
303 | elif nbrEdges == 3:
304 | cylFace = face
305 | else:
306 | othrEndFace = face
307 | print '\n'
308 | print 'Topology Info for mFace:'
309 | face = mFace
310 | print 'Number of Edges of mFace = ', topo.number_of_edges_from_face(face)
311 | print '\n'
312 | faceEdges = topo.edges_from_face(face)
313 | for faceEdge in faceEdges:
314 | hCurve, umin, umax = BRep_Tool.Curve(faceEdge)
315 | curve = hCurve.GetObject()
316 | vectr = curve.DN(0.0, 2)
317 | print 'curvature at u=0: ', vectr.Magnitude()
318 | print 'first: ', curve.FirstParameter()
319 | print 'last: ', curve.LastParameter()
320 | print '\n'
321 | print 'Number of Vertices of mFace = ', topo.number_of_vertices_from_face(face)
322 |
323 | print '\n'
324 | print 'Topology Info for cylFace:'
325 | face = cylFace
326 | print 'Number of Edges of cylFace = ', topo.number_of_edges_from_face(face)
327 | print '\n'
328 | faceEdges = topo.edges_from_face(face)
329 | for faceEdge in faceEdges:
330 | hCurve, umin, umax = BRep_Tool.Curve(faceEdge)
331 | curve = hCurve.GetObject()
332 | vectr = curve.DN(0.0, 2)
333 | print 'curvature at u=0: ', vectr.Magnitude()
334 | print 'first: ', curve.FirstParameter()
335 | print 'last: ', curve.LastParameter()
336 | print '\n'
337 | print 'Number of Vertices of cylFace = ', topo.number_of_vertices_from_face(face)
338 | brlSurf = BRepLib_FindSurface(face) # type: BRepLib_FindSurface
339 | print type(brlSurf)
340 | isPlanarSurf = GeomLib_IsPlanarSurface(brlSurf.Surface(), TOLERANCE).IsPlanar()
341 | print 'Planar: ', isPlanarSurf
342 | mFaceVertices = topo.vertices_from_face(mFace)
343 |
344 | win.statusBar().showMessage('Offset Face operation complete')
345 | win.clearCallback()
346 |
347 | def offsetEndFaceC(shapeList, *kwargs): # callback (collector) for offsetEndFace
348 | print shapeList
349 | print kwargs
350 | win.lineEdit.setFocus()
351 | for shape in shapeList:
352 | face = topods_Face(shape)
353 | win.faceStack.append(face)
354 | if (win.faceStack and win.lineEditStack):
355 | offsetEndFace(initial=False)
356 | elif len(win.faceStack) == 1:
357 | statusText = "Enter distance value."
358 | win.statusBar().showMessage(statusText)
359 |
360 | def alignEndFace(initial=True):
361 | """
362 | Align one end face of a simple cylinder (the active part) to a target face.
363 | This involves 'stretching' the cylindrical face to reach the new end face.
364 | The faces are then sewn back together.
365 | """
366 | if initial:
367 | win.registerCallback(alignEndFaceC)
368 | display.SetSelectionModeFace()
369 | statusText = "Select face to move (on active part)."
370 | win.statusBar().showMessage(statusText)
371 | elif len(win.faceStack) == 2:
372 | tFace = win.faceStack.pop() # target face
373 | tSurf = BRep_Tool_Surface(tFace)
374 | mFace = win.faceStack.pop() # face to be moved
375 | workPart = win.activePart
376 | wrkPrtUID = win.activePartUID
377 | topo = Topology.Topo(workPart)
378 | faces = topo.faces_from_solids(workPart) # all faces
379 | for face in faces:
380 | isPlanar = face_is_plane(face)
381 | print 'Planar: ', isPlanar
382 | if face == mFace:
383 | print 'found mFace'
384 | elif isPlanar:
385 | otherEndFace = face
386 | print 'found other end face'
387 | else:
388 | cylFace = face
389 | print 'found cylFace'
390 | cylSurf = BRep_Tool_Surface(cylFace)
391 | cylEdges = [] # edges of new cylindrical face
392 | for face in (tFace, otherEndFace):
393 | planeSurf = BRep_Tool_Surface(face)
394 | inters = GeomAPI_IntSS()
395 | inters.Perform(cylSurf, planeSurf, 1.0e-7)
396 | if inters.IsDone():
397 | nbLines = inters.NbLines()
398 | print nbLines
399 | curve = inters.Line(nbLines) # type: Handle_Geom_curve
400 | edge = BRepBuilderAPI_MakeEdge(curve).Edge()
401 | cylEdges.append(edge)
402 | newCylFace = brepfill.Face(cylEdges[0], cylEdges[1])
403 | newWire = BRepBuilderAPI_MakeWire(cylEdges[0]).Wire()
404 | newFace = BRepBuilderAPI_MakeFace(newWire).Face()
405 | # sew all the faces together
406 | tolerance = 1e-7
407 | sew = BRepBuilderAPI_Sewing(tolerance)
408 | sew.Add(otherEndFace)
409 | sew.Add(newCylFace)
410 | sew.Add(newFace)
411 | sew.Perform()
412 | res = sew.SewedShape()
413 | win.getNewPartUID(res, ancestor=wrkPrtUID)
414 | win.statusBar().showMessage('Offset Face operation complete')
415 | win.clearCallback()
416 |
417 | def alignEndFaceC(shapeList, *kwargs): # callback (collector) for alignEndFace
418 | print shapeList
419 | print kwargs
420 | win.lineEdit.setFocus()
421 | for shape in shapeList:
422 | face = topods_Face(shape)
423 | win.faceStack.append(face)
424 | if len(win.faceStack) == 1:
425 | statusText = "Select target face."
426 | win.statusBar().showMessage(statusText)
427 | elif len(win.faceStack) == 2:
428 | alignEndFace(initial=False)
429 |
430 | def testFace(initial=True):
431 | """
432 | Test makeToolBody
433 | """
434 |
435 | if initial:
436 | win.registerCallback(testFaceC)
437 | display.SetSelectionModeFace()
438 | statusText = "Select face to move (on active part)."
439 | win.statusBar().showMessage(statusText)
440 | elif len(win.faceStack) == 2:
441 | tFace = win.faceStack.pop() # target face (to be aligned to)
442 | tPlane = planeOfFace(tFace)
443 | mFace = win.faceStack.pop() # face to be moved
444 | makeToolBody(mFace, tPlane)
445 | win.statusBar().showMessage('Align Face operation complete')
446 | win.clearCallback()
447 |
448 | def testFaceC(shapeList, *kwargs): # callback (collector) for testFace
449 | print shapeList
450 | print kwargs
451 | for shape in shapeList:
452 | face = topods_Face(shape)
453 | win.faceStack.append(face)
454 | if len(win.faceStack) == 1:
455 | statusText = "Select face to align to."
456 | win.statusBar().showMessage(statusText)
457 | if len(win.faceStack) == 2:
458 | testFace(initial=False)
459 |
460 |
--------------------------------------------------------------------------------