Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
P
pyMKcam
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
machinery
pyMKcam
Commits
9b939792
Commit
9b939792
authored
Mar 30, 2012
by
Lars Kruse
Browse files
Options
Browse Files
Download
Plain Diff
Merge
https://github.com/wdreeveii/pycam-fast-points
parents
df4e35e1
f9a45628
Changes
44
Hide whitespace changes
Inline
Side-by-side
Showing
44 changed files
with
1141 additions
and
1127 deletions
+1141
-1127
BaseCutter.py
pycam/Cutters/BaseCutter.py
+18
-18
CylindricalCutter.py
pycam/Cutters/CylindricalCutter.py
+26
-46
SphericalCutter.py
pycam/Cutters/SphericalCutter.py
+26
-26
ToroidalCutter.py
pycam/Cutters/ToroidalCutter.py
+24
-23
Letters.py
pycam/Geometry/Letters.py
+7
-10
Line.py
pycam/Geometry/Line.py
+45
-44
Matrix.py
pycam/Geometry/Matrix.py
+14
-34
Model.py
pycam/Geometry/Model.py
+35
-36
Plane.py
pycam/Geometry/Plane.py
+17
-16
Point.py
pycam/Geometry/Point.py
+0
-170
PointKdtree.py
pycam/Geometry/PointKdtree.py
+2
-4
PointUtils.py
pycam/Geometry/PointUtils.py
+101
-0
Polygon.py
pycam/Geometry/Polygon.py
+84
-114
PolygonExtractor.py
pycam/Geometry/PolygonExtractor.py
+85
-85
Triangle.py
pycam/Geometry/Triangle.py
+64
-73
TriangleKdtree.py
pycam/Geometry/TriangleKdtree.py
+4
-4
__init__.py
pycam/Geometry/__init__.py
+45
-37
intersection.py
pycam/Geometry/intersection.py
+85
-85
OpenGLTools.py
pycam/Gui/OpenGLTools.py
+12
-17
CXFImporter.py
pycam/Importers/CXFImporter.py
+5
-5
DXFImporter.py
pycam/Importers/DXFImporter.py
+16
-15
STLImporter.py
pycam/Importers/STLImporter.py
+11
-12
TestModel.py
pycam/Importers/TestModel.py
+10
-11
ContourFollow.py
pycam/PathGenerators/ContourFollow.py
+18
-21
DropCutter.py
pycam/PathGenerators/DropCutter.py
+8
-10
EngraveCutter.py
pycam/PathGenerators/EngraveCutter.py
+0
-1
PushCutter.py
pycam/PathGenerators/PushCutter.py
+2
-1
__init__.py
pycam/PathGenerators/__init__.py
+27
-27
ContourCutter.py
pycam/PathProcessors/ContourCutter.py
+3
-3
__init__.py
pycam/PathProcessors/__init__.py
+2
-2
Fonts.py
pycam/Plugins/Fonts.py
+2
-2
ModelProjection.py
pycam/Plugins/ModelProjection.py
+3
-3
OpenGLViewModel.py
pycam/Plugins/OpenGLViewModel.py
+11
-14
OpenGLViewToolpath.py
pycam/Plugins/OpenGLViewToolpath.py
+34
-6
OpenGLWindow.py
pycam/Plugins/OpenGLWindow.py
+6
-8
ToolpathCrop.py
pycam/Plugins/ToolpathCrop.py
+2
-2
ToolpathExport.py
pycam/Plugins/ToolpathExport.py
+2
-2
ToolpathGrid.py
pycam/Plugins/ToolpathGrid.py
+3
-4
ODEBlocks.py
pycam/Simulation/ODEBlocks.py
+31
-31
ZBuffer.py
pycam/Simulation/ZBuffer.py
+18
-16
Generator.py
pycam/Toolpath/Generator.py
+1
-1
MotionGrid.py
pycam/Toolpath/MotionGrid.py
+24
-22
SupportGrid.py
pycam/Toolpath/SupportGrid.py
+33
-37
__init__.py
pycam/Toolpath/__init__.py
+175
-29
No files found.
pycam/Cutters/BaseCutter.py
View file @
9b939792
...
@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from
pycam.Geometry
import
IDGenerator
from
pycam.Geometry
import
IDGenerator
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.utils
import
number
,
INFINITE
,
epsilon
from
pycam.Geometry.utils
import
number
,
INFINITE
,
epsilon
from
pycam.Geometry.intersection
import
intersect_cylinder_point
,
\
from
pycam.Geometry.intersection
import
intersect_cylinder_point
,
\
intersect_cylinder_line
intersect_cylinder_line
...
@@ -32,12 +32,12 @@ import uuid
...
@@ -32,12 +32,12 @@ import uuid
class
BaseCutter
(
IDGenerator
):
class
BaseCutter
(
IDGenerator
):
vertical
=
Point
(
0
,
0
,
-
1
)
vertical
=
(
0
,
0
,
-
1
)
def
__init__
(
self
,
radius
,
location
=
None
,
height
=
None
):
def
__init__
(
self
,
radius
,
location
=
None
,
height
=
None
):
super
(
BaseCutter
,
self
)
.
__init__
()
super
(
BaseCutter
,
self
)
.
__init__
()
if
location
is
None
:
if
location
is
None
:
location
=
Point
(
0
,
0
,
0
)
location
=
(
0
,
0
,
0
)
if
height
is
None
:
if
height
is
None
:
height
=
10
height
=
10
radius
=
number
(
radius
)
radius
=
number
(
radius
)
...
@@ -56,22 +56,22 @@ class BaseCutter(IDGenerator):
...
@@ -56,22 +56,22 @@ class BaseCutter(IDGenerator):
def
get_minx
(
self
,
start
=
None
):
def
get_minx
(
self
,
start
=
None
):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
return
start
.
x
-
self
.
distance_radius
return
start
[
0
]
-
self
.
distance_radius
def
get_maxx
(
self
,
start
=
None
):
def
get_maxx
(
self
,
start
=
None
):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
return
start
.
x
+
self
.
distance_radius
return
start
[
0
]
+
self
.
distance_radius
def
get_miny
(
self
,
start
=
None
):
def
get_miny
(
self
,
start
=
None
):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
return
start
.
y
-
self
.
distance_radius
return
start
[
1
]
-
self
.
distance_radius
def
get_maxy
(
self
,
start
=
None
):
def
get_maxy
(
self
,
start
=
None
):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
return
start
.
y
+
self
.
distance_radius
return
start
[
1
]
+
self
.
distance_radius
def
update_uuid
(
self
):
def
update_uuid
(
self
):
self
.
uuid
=
uuid
.
uuid4
()
self
.
uuid
=
uuid
.
uuid4
()
...
@@ -105,7 +105,7 @@ class BaseCutter(IDGenerator):
...
@@ -105,7 +105,7 @@ class BaseCutter(IDGenerator):
# "moveto" is used for collision detection calculation.
# "moveto" is used for collision detection calculation.
self
.
location
=
location
self
.
location
=
location
for
shape
,
set_pos_func
in
self
.
shape
.
values
():
for
shape
,
set_pos_func
in
self
.
shape
.
values
():
set_pos_func
(
location
.
x
,
location
.
y
,
location
.
z
)
set_pos_func
(
location
[
0
],
location
[
1
],
location
[
2
]
)
def
intersect
(
self
,
direction
,
triangle
,
start
=
None
):
def
intersect
(
self
,
direction
,
triangle
,
start
=
None
):
raise
NotImplementedError
(
"Inherited class of BaseCutter does not "
\
raise
NotImplementedError
(
"Inherited class of BaseCutter does not "
\
...
@@ -126,7 +126,7 @@ class BaseCutter(IDGenerator):
...
@@ -126,7 +126,7 @@ class BaseCutter(IDGenerator):
# check bounding circle collision
# check bounding circle collision
c
=
triangle
.
middle
c
=
triangle
.
middle
if
(
c
.
x
-
start
.
x
)
**
2
+
(
c
.
y
-
start
.
y
)
**
2
\
if
(
c
[
0
]
-
start
[
0
])
**
2
+
(
c
[
1
]
-
start
[
1
]
)
**
2
\
>
(
self
.
distance_radiussq
+
2
*
self
.
distance_radius
\
>
(
self
.
distance_radiussq
+
2
*
self
.
distance_radius
\
*
triangle
.
radius
+
triangle
.
radiussq
)
+
epsilon
:
*
triangle
.
radius
+
triangle
.
radiussq
)
+
epsilon
:
return
None
return
None
...
@@ -150,7 +150,7 @@ class BaseCutter(IDGenerator):
...
@@ -150,7 +150,7 @@ class BaseCutter(IDGenerator):
start
=
start
)
start
=
start
)
if
cp
:
if
cp
:
# check if the contact point is between the endpoints
# check if the contact point is between the endpoints
m
=
cp
.
sub
(
edge
.
p1
)
.
dot
(
edge
.
dir
)
m
=
pdot
(
psub
(
cp
,
edge
.
p1
),
edge
.
dir
)
if
(
m
<
-
epsilon
)
or
(
m
>
edge
.
len
+
epsilon
):
if
(
m
<
-
epsilon
)
or
(
m
>
edge
.
len
+
epsilon
):
return
(
None
,
INFINITE
,
cp
)
return
(
None
,
INFINITE
,
cp
)
return
(
cl
,
l
,
cp
)
return
(
cl
,
l
,
cp
)
...
@@ -159,8 +159,8 @@ class BaseCutter(IDGenerator):
...
@@ -159,8 +159,8 @@ class BaseCutter(IDGenerator):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
l
)
=
intersect_cylinder_point
(
(
ccp
,
cp
,
l
)
=
intersect_cylinder_point
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
axis
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
)
,
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
point
)
self
.
axis
,
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
point
)
# offset intersection
# offset intersection
if
ccp
:
if
ccp
:
cl
=
cp
.
add
(
start
.
sub
(
ccp
))
cl
=
cp
.
add
(
start
.
sub
(
ccp
))
...
@@ -172,7 +172,7 @@ class BaseCutter(IDGenerator):
...
@@ -172,7 +172,7 @@ class BaseCutter(IDGenerator):
start
=
self
.
location
start
=
self
.
location
(
cl
,
ccp
,
cp
,
l
)
=
self
.
intersect_cylinder_point
(
direction
,
point
,
(
cl
,
ccp
,
cp
,
l
)
=
self
.
intersect_cylinder_point
(
direction
,
point
,
start
=
start
)
start
=
start
)
if
ccp
and
ccp
.
z
<
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
)
.
z
:
if
ccp
and
ccp
[
2
]
<
padd
(
psub
(
start
,
self
.
location
),
self
.
center
)[
2
]
:
return
(
None
,
INFINITE
,
None
)
return
(
None
,
INFINITE
,
None
)
return
(
cl
,
l
,
cp
)
return
(
cl
,
l
,
cp
)
...
@@ -180,11 +180,11 @@ class BaseCutter(IDGenerator):
...
@@ -180,11 +180,11 @@ class BaseCutter(IDGenerator):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
l
)
=
intersect_cylinder_line
(
(
ccp
,
cp
,
l
)
=
intersect_cylinder_line
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
axis
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
)
,
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
edge
)
self
.
axis
,
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
edge
)
# offset intersection
# offset intersection
if
ccp
:
if
ccp
:
cl
=
start
.
add
(
cp
.
sub
(
ccp
))
cl
=
padd
(
start
,
psub
(
cp
,
ccp
))
return
(
cl
,
ccp
,
cp
,
l
)
return
(
cl
,
ccp
,
cp
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -195,10 +195,10 @@ class BaseCutter(IDGenerator):
...
@@ -195,10 +195,10 @@ class BaseCutter(IDGenerator):
start
=
start
)
start
=
start
)
if
not
ccp
:
if
not
ccp
:
return
(
None
,
INFINITE
,
None
)
return
(
None
,
INFINITE
,
None
)
m
=
cp
.
sub
(
edge
.
p1
)
.
dot
(
edge
.
dir
)
m
=
pdot
(
psub
(
cp
,
edge
.
p1
),
edge
.
dir
)
if
(
m
<
-
epsilon
)
or
(
m
>
edge
.
len
+
epsilon
):
if
(
m
<
-
epsilon
)
or
(
m
>
edge
.
len
+
epsilon
):
return
(
None
,
INFINITE
,
None
)
return
(
None
,
INFINITE
,
None
)
if
ccp
.
z
<
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
)
.
z
:
if
ccp
[
2
]
<
padd
(
psub
(
start
,
self
.
location
),
self
.
center
)[
2
]
:
return
(
None
,
INFINITE
,
None
)
return
(
None
,
INFINITE
,
None
)
return
(
cl
,
l
,
cp
)
return
(
cl
,
l
,
cp
)
pycam/Cutters/CylindricalCutter.py
View file @
9b939792
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.utils
import
INFINITE
,
sqrt
from
pycam.Geometry.utils
import
INFINITE
,
sqrt
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.intersection
import
intersect_circle_plane
,
\
from
pycam.Geometry.intersection
import
intersect_circle_plane
,
\
intersect_circle_point
,
intersect_circle_line
intersect_circle_point
,
intersect_circle_line
from
pycam.Cutters.BaseCutter
import
BaseCutter
from
pycam.Cutters.BaseCutter
import
BaseCutter
...
@@ -40,7 +40,7 @@ class CylindricalCutter(BaseCutter):
...
@@ -40,7 +40,7 @@ class CylindricalCutter(BaseCutter):
def
__init__
(
self
,
radius
,
**
kwargs
):
def
__init__
(
self
,
radius
,
**
kwargs
):
BaseCutter
.
__init__
(
self
,
radius
,
**
kwargs
)
BaseCutter
.
__init__
(
self
,
radius
,
**
kwargs
)
self
.
axis
=
Vector
(
0
,
0
,
1
)
self
.
axis
=
(
0
,
0
,
1
,
'v'
)
def
__repr__
(
self
):
def
__repr__
(
self
):
return
"CylindricalCutter<
%
s,
%
s>"
%
(
self
.
location
,
self
.
radius
)
return
"CylindricalCutter<
%
s,
%
s>"
%
(
self
.
location
,
self
.
radius
)
...
@@ -92,17 +92,17 @@ class CylindricalCutter(BaseCutter):
...
@@ -92,17 +92,17 @@ class CylindricalCutter(BaseCutter):
geom_connect_transform
=
ode
.
GeomTransform
(
geom
.
space
)
geom_connect_transform
=
ode
.
GeomTransform
(
geom
.
space
)
geom_connect_transform
.
setBody
(
geom
.
getBody
())
geom_connect_transform
.
setBody
(
geom
.
getBody
())
geom_connect
=
ode_physics
.
get_parallelepiped_geom
(
geom_connect
=
ode_physics
.
get_parallelepiped_geom
(
(
Point
(
-
hypotenuse
/
2
,
radius
,
-
diff_z
/
2
),
((
-
hypotenuse
/
2
,
radius
,
-
diff_z
/
2
),
Point
(
hypotenuse
/
2
,
radius
,
diff_z
/
2
),
(
hypotenuse
/
2
,
radius
,
diff_z
/
2
),
Point
(
hypotenuse
/
2
,
-
radius
,
diff_z
/
2
),
(
hypotenuse
/
2
,
-
radius
,
diff_z
/
2
),
Point
(
-
hypotenuse
/
2
,
-
radius
,
-
diff_z
/
2
)),
(
-
hypotenuse
/
2
,
-
radius
,
-
diff_z
/
2
)),
(
Point
(
-
hypotenuse
/
2
,
radius
,
((
-
hypotenuse
/
2
,
radius
,
self
.
height
-
diff_z
/
2
),
self
.
height
-
diff_z
/
2
),
Point
(
hypotenuse
/
2
,
(
hypotenuse
/
2
,
radius
,
self
.
height
+
diff_z
/
2
),
radius
,
self
.
height
+
diff_z
/
2
),
Point
(
hypotenuse
/
2
,
-
radius
,
(
hypotenuse
/
2
,
-
radius
,
self
.
height
+
diff_z
/
2
),
self
.
height
+
diff_z
/
2
),
Point
(
-
hypotenuse
/
2
,
-
radius
,
(
-
hypotenuse
/
2
,
-
radius
,
self
.
height
-
diff_z
/
2
)))
self
.
height
-
diff_z
/
2
)))
geom_connect
.
setRotation
(
rot_matrix_box
)
geom_connect
.
setRotation
(
rot_matrix_box
)
geom_connect
.
setPosition
((
hypotenuse
/
2
,
0
,
radius
))
geom_connect
.
setPosition
((
hypotenuse
/
2
,
0
,
radius
))
...
@@ -119,7 +119,7 @@ class CylindricalCutter(BaseCutter):
...
@@ -119,7 +119,7 @@ class CylindricalCutter(BaseCutter):
if
not
GL_enabled
:
if
not
GL_enabled
:
return
return
GL
.
glPushMatrix
()
GL
.
glPushMatrix
()
GL
.
glTranslate
(
self
.
center
.
x
,
self
.
center
.
y
,
self
.
center
.
z
)
GL
.
glTranslate
(
self
.
center
[
0
],
self
.
center
[
1
],
self
.
center
[
2
]
)
if
not
hasattr
(
self
,
"_cylinder"
):
if
not
hasattr
(
self
,
"_cylinder"
):
self
.
_cylinder
=
GLU
.
gluNewQuadric
()
self
.
_cylinder
=
GLU
.
gluNewQuadric
()
GLU
.
gluCylinder
(
self
.
_cylinder
,
self
.
radius
,
self
.
radius
,
self
.
height
,
GLU
.
gluCylinder
(
self
.
_cylinder
,
self
.
radius
,
self
.
radius
,
self
.
height
,
...
@@ -131,17 +131,17 @@ class CylindricalCutter(BaseCutter):
...
@@ -131,17 +131,17 @@ class CylindricalCutter(BaseCutter):
def
moveto
(
self
,
location
,
**
kwargs
):
def
moveto
(
self
,
location
,
**
kwargs
):
BaseCutter
.
moveto
(
self
,
location
,
**
kwargs
)
BaseCutter
.
moveto
(
self
,
location
,
**
kwargs
)
self
.
center
=
Point
(
location
.
x
,
location
.
y
,
self
.
center
=
(
location
[
0
],
location
[
1
]
,
location
.
z
-
self
.
get_required_distance
())
location
[
2
]
-
self
.
get_required_distance
())
def
intersect_circle_plane
(
self
,
direction
,
triangle
,
start
=
None
):
def
intersect_circle_plane
(
self
,
direction
,
triangle
,
start
=
None
):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
d
)
=
intersect_circle_plane
(
(
ccp
,
cp
,
d
)
=
intersect_circle_plane
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
distance_radius
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
),
direction
,
triangle
)
self
.
distance_radius
,
direction
,
triangle
)
if
ccp
and
cp
:
if
ccp
and
cp
:
cl
=
cp
.
add
(
start
.
sub
(
ccp
))
cl
=
padd
(
cp
,
psub
(
start
,
ccp
))
return
(
cl
,
ccp
,
cp
,
d
)
return
(
cl
,
ccp
,
cp
,
d
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -149,10 +149,10 @@ class CylindricalCutter(BaseCutter):
...
@@ -149,10 +149,10 @@ class CylindricalCutter(BaseCutter):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
l
)
=
intersect_circle_point
(
(
ccp
,
cp
,
l
)
=
intersect_circle_point
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
axis
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
)
,
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
point
)
self
.
axis
,
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
point
)
if
ccp
:
if
ccp
:
cl
=
cp
.
add
(
start
.
sub
(
ccp
))
cl
=
padd
(
cp
,
psub
(
start
,
ccp
))
return
(
cl
,
ccp
,
cp
,
l
)
return
(
cl
,
ccp
,
cp
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -160,10 +160,10 @@ class CylindricalCutter(BaseCutter):
...
@@ -160,10 +160,10 @@ class CylindricalCutter(BaseCutter):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
l
)
=
intersect_circle_line
(
(
ccp
,
cp
,
l
)
=
intersect_circle_line
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
axis
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
)
,
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
edge
)
self
.
axis
,
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
edge
)
if
ccp
:
if
ccp
:
cl
=
cp
.
add
(
start
.
sub
(
ccp
))
cl
=
padd
(
cp
,
psub
(
start
,
ccp
))
return
(
cl
,
ccp
,
cp
,
l
)
return
(
cl
,
ccp
,
cp
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -177,9 +177,7 @@ class CylindricalCutter(BaseCutter):
...
@@ -177,9 +177,7 @@ class CylindricalCutter(BaseCutter):
d
=
d_t
d
=
d_t
cl
=
cl_t
cl
=
cl_t
cp
=
cp_t
cp
=
cp_t
if
cl
and
(
direction
.
x
==
0
)
and
(
direction
.
y
==
0
):
if
cl
and
(
direction
[
0
]
==
0
)
and
(
direction
[
1
]
==
0
):
#print 'circle_triangle:'
#print 'cl is:', cl, 'd is:', d, 'cp is:', cp
return
(
cl
,
d
,
cp
)
return
(
cl
,
d
,
cp
)
(
cl_e1
,
d_e1
,
cp_e1
)
=
self
.
intersect_circle_edge
(
direction
,
(
cl_e1
,
d_e1
,
cp_e1
)
=
self
.
intersect_circle_edge
(
direction
,
triangle
.
e1
,
start
=
start
)
triangle
.
e1
,
start
=
start
)
...
@@ -191,20 +189,15 @@ class CylindricalCutter(BaseCutter):
...
@@ -191,20 +189,15 @@ class CylindricalCutter(BaseCutter):
d
=
d_e1
d
=
d_e1
cl
=
cl_e1
cl
=
cl_e1
cp
=
cp_e1
cp
=
cp_e1
#print 'circle_edge e1:'
if
d_e2
<
d
:
if
d_e2
<
d
:
d
=
d_e2
d
=
d_e2
cl
=
cl_e2
cl
=
cl_e2
cp
=
cp_e2
cp
=
cp_e2
#print 'circle_edge e2:'
if
d_e3
<
d
:
if
d_e3
<
d
:
d
=
d_e3
d
=
d_e3
cl
=
cl_e3
cl
=
cl_e3
cp
=
cp_e3
cp
=
cp_e3
#print 'circle_edge e3:'
if
cl
and
(
direction
[
0
]
==
0
)
and
(
direction
[
1
]
==
0
):
if
cl
and
(
direction
.
x
==
0
)
and
(
direction
.
y
==
0
):
#print 'circle_edge:'
#print 'cl is:', cl, 'd is:', d, 'cp is:', cp
return
(
cl
,
d
,
cp
)
return
(
cl
,
d
,
cp
)
(
cl_p1
,
d_p1
,
cp_p1
)
=
self
.
intersect_circle_vertex
(
direction
,
(
cl_p1
,
d_p1
,
cp_p1
)
=
self
.
intersect_circle_vertex
(
direction
,
triangle
.
p1
,
start
=
start
)
triangle
.
p1
,
start
=
start
)
...
@@ -216,22 +209,17 @@ class CylindricalCutter(BaseCutter):
...
@@ -216,22 +209,17 @@ class CylindricalCutter(BaseCutter):
d
=
d_p1
d
=
d_p1
cl
=
cl_p1
cl
=
cl_p1
cp
=
cp_p1
cp
=
cp_p1
#print 'circle vertex p1:'
if
d_p2
<
d
:
if
d_p2
<
d
:
d
=
d_p2
d
=
d_p2
cl
=
cl_p2
cl
=
cl_p2
cp
=
cp_p2
cp
=
cp_p2
#print 'circle vertex p2:'
if
d_p3
<
d
:
if
d_p3
<
d
:
d
=
d_p3
d
=
d_p3
cl
=
cl_p3
cl
=
cl_p3
cp
=
cp_p3
cp
=
cp_p3
#print 'circle vertex p3:'
if
cl
and
(
direction
[
0
]
==
0
)
and
(
direction
[
1
]
==
0
):
if
cl
and
(
direction
.
x
==
0
)
and
(
direction
.
y
==
0
):
#print 'circle vertex:'
#print 'cl is:', cl, 'd is:', d, 'cp is:', cp
return
(
cl
,
d
,
cp
)
return
(
cl
,
d
,
cp
)
if
(
direction
.
x
!=
0
)
or
(
direction
.
y
!=
0
):
if
(
direction
[
0
]
!=
0
)
or
(
direction
[
1
]
!=
0
):
(
cl_p1
,
d_p1
,
cp_p1
)
=
self
.
intersect_cylinder_vertex
(
direction
,
(
cl_p1
,
d_p1
,
cp_p1
)
=
self
.
intersect_cylinder_vertex
(
direction
,
triangle
.
p1
,
start
=
start
)
triangle
.
p1
,
start
=
start
)
(
cl_p2
,
d_p2
,
cp_p2
)
=
self
.
intersect_cylinder_vertex
(
direction
,
(
cl_p2
,
d_p2
,
cp_p2
)
=
self
.
intersect_cylinder_vertex
(
direction
,
...
@@ -242,17 +230,14 @@ class CylindricalCutter(BaseCutter):
...
@@ -242,17 +230,14 @@ class CylindricalCutter(BaseCutter):
d
=
d_p1
d
=
d_p1
cl
=
cl_p1
cl
=
cl_p1
cp
=
cp_p1
cp
=
cp_p1
#print 'cyl vertex p1:'
if
d_p2
<
d
:
if
d_p2
<
d
:
d
=
d_p2
d
=
d_p2
cl
=
cl_p2
cl
=
cl_p2
cp
=
cp_p2
cp
=
cp_p2
#print 'cyl vertex p2:'
if
d_p3
<
d
:
if
d_p3
<
d
:
d
=
d_p3
d
=
d_p3
cl
=
cl_p3
cl
=
cl_p3
cp
=
cp_p3
cp
=
cp_p3
#print 'cyl vertex p3:'
(
cl_e1
,
d_e1
,
cp_e1
)
=
self
.
intersect_cylinder_edge
(
direction
,
(
cl_e1
,
d_e1
,
cp_e1
)
=
self
.
intersect_cylinder_edge
(
direction
,
triangle
.
e1
,
start
=
start
)
triangle
.
e1
,
start
=
start
)
(
cl_e2
,
d_e2
,
cp_e2
)
=
self
.
intersect_cylinder_edge
(
direction
,
(
cl_e2
,
d_e2
,
cp_e2
)
=
self
.
intersect_cylinder_edge
(
direction
,
...
@@ -263,18 +248,13 @@ class CylindricalCutter(BaseCutter):
...
@@ -263,18 +248,13 @@ class CylindricalCutter(BaseCutter):
d
=
d_e1
d
=
d_e1
cl
=
cl_e1
cl
=
cl_e1
cp
=
cp_e1
cp
=
cp_e1
#print 'cyl edge e1:'
if
d_e2
<
d
:
if
d_e2
<
d
:
d
=
d_e2
d
=
d_e2
cl
=
cl_e2
cl
=
cl_e2
cp
=
cp_e2
cp
=
cp_e2
#print 'cyl edge e2:'
if
d_e3
<
d
:
if
d_e3
<
d
:
d
=
d_e3
d
=
d_e3
cl
=
cl_e3
cl
=
cl_e3
cp
=
cp_e3
cp
=
cp_e3
#print 'cyl edge e3:'
#print 'cyl:'
#print 'cl is:', cl, 'd is:', d, 'cp is:', cp
return
(
cl
,
d
,
cp
)
return
(
cl
,
d
,
cp
)
pycam/Cutters/SphericalCutter.py
View file @
9b939792
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry
import
Matrix
from
pycam.Geometry
import
Matrix
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.utils
import
INFINITE
,
epsilon
,
sqrt
from
pycam.Geometry.utils
import
INFINITE
,
epsilon
,
sqrt
from
pycam.Geometry.intersection
import
intersect_sphere_plane
,
\
from
pycam.Geometry.intersection
import
intersect_sphere_plane
,
\
intersect_sphere_point
,
intersect_sphere_line
intersect_sphere_point
,
intersect_sphere_line
...
@@ -41,7 +41,7 @@ class SphericalCutter(BaseCutter):
...
@@ -41,7 +41,7 @@ class SphericalCutter(BaseCutter):
def
__init__
(
self
,
radius
,
**
kwargs
):
def
__init__
(
self
,
radius
,
**
kwargs
):
BaseCutter
.
__init__
(
self
,
radius
,
**
kwargs
)
BaseCutter
.
__init__
(
self
,
radius
,
**
kwargs
)
self
.
axis
=
Vector
(
0
,
0
,
1
)
self
.
axis
=
(
0
,
0
,
1
,
'v'
)
def
__repr__
(
self
):
def
__repr__
(
self
):
return
"SphericalCutter<
%
s,
%
s>"
%
(
self
.
location
,
self
.
radius
)
return
"SphericalCutter<
%
s,
%
s>"
%
(
self
.
location
,
self
.
radius
)
...
@@ -84,17 +84,17 @@ class SphericalCutter(BaseCutter):
...
@@ -84,17 +84,17 @@ class SphericalCutter(BaseCutter):
geom_connect_transform
=
ode
.
GeomTransform
(
geom
.
space
)
geom_connect_transform
=
ode
.
GeomTransform
(
geom
.
space
)
geom_connect_transform
.
setBody
(
geom
.
getBody
())
geom_connect_transform
.
setBody
(
geom
.
getBody
())
geom_connect
=
ode_physics
.
get_parallelepiped_geom
((
geom_connect
=
ode_physics
.
get_parallelepiped_geom
((
Point
(
-
hypotenuse
/
2
,
radius
,
-
diff_z
/
2
),
(
-
hypotenuse
/
2
,
radius
,
-
diff_z
/
2
),
Point
(
hypotenuse
/
2
,
radius
,
diff_z
/
2
),
(
hypotenuse
/
2
,
radius
,
diff_z
/
2
),
Point
(
hypotenuse
/
2
,
-
radius
,
diff_z
/
2
),
(
hypotenuse
/
2
,
-
radius
,
diff_z
/
2
),
Point
(
-
hypotenuse
/
2
,
-
radius
,
-
diff_z
/
2
)),
(
-
hypotenuse
/
2
,
-
radius
,
-
diff_z
/
2
)),
(
Point
(
-
hypotenuse
/
2
,
radius
,
((
-
hypotenuse
/
2
,
radius
,
self
.
height
-
diff_z
/
2
),
self
.
height
-
diff_z
/
2
),
Point
(
hypotenuse
/
2
,
radius
,
(
hypotenuse
/
2
,
radius
,
self
.
height
+
diff_z
/
2
),
self
.
height
+
diff_z
/
2
),
Point
(
hypotenuse
/
2
,
-
radius
,
(
hypotenuse
/
2
,
-
radius
,
self
.
height
+
diff_z
/
2
),
self
.
height
+
diff_z
/
2
),
Point
(
-
hypotenuse
/
2
,
-
radius
,
(
-
hypotenuse
/
2
,
-
radius
,
self
.
height
-
diff_z
/
2
)))
self
.
height
-
diff_z
/
2
)))
geom_connect
.
setRotation
(
rot_matrix_box
)
geom_connect
.
setRotation
(
rot_matrix_box
)
geom_connect
.
setPosition
((
hypotenuse
/
2
,
0
,
radius
))
geom_connect
.
setPosition
((
hypotenuse
/
2
,
0
,
radius
))
...
@@ -129,7 +129,7 @@ class SphericalCutter(BaseCutter):
...
@@ -129,7 +129,7 @@ class SphericalCutter(BaseCutter):
if
not
GL_enabled
:
if
not
GL_enabled
:
return
return
GL
.
glPushMatrix
()
GL
.
glPushMatrix
()
GL
.
glTranslate
(
self
.
center
.
x
,
self
.
center
.
y
,
self
.
center
.
z
)
GL
.
glTranslate
(
self
.
center
[
0
],
self
.
center
[
1
],
self
.
center
[
2
]
)
if
not
hasattr
(
self
,
"_sphere"
):
if
not
hasattr
(
self
,
"_sphere"
):
self
.
_sphere
=
GLU
.
gluNewQuadric
()
self
.
_sphere
=
GLU
.
gluNewQuadric
()
GLU
.
gluSphere
(
self
.
_sphere
,
self
.
radius
,
10
,
10
)
GLU
.
gluSphere
(
self
.
_sphere
,
self
.
radius
,
10
,
10
)
...
@@ -141,17 +141,17 @@ class SphericalCutter(BaseCutter):
...
@@ -141,17 +141,17 @@ class SphericalCutter(BaseCutter):
def
moveto
(
self
,
location
,
**
kwargs
):
def
moveto
(
self
,
location
,
**
kwargs
):
BaseCutter
.
moveto
(
self
,
location
,
**
kwargs
)
BaseCutter
.
moveto
(
self
,
location
,
**
kwargs
)
self
.
center
=
Point
(
location
.
x
,
location
.
y
,
location
.
z
+
self
.
radius
)
self
.
center
=
(
location
[
0
],
location
[
1
],
location
[
2
]
+
self
.
radius
)
def
intersect_sphere_plane
(
self
,
direction
,
triangle
,
start
=
None
):
def
intersect_sphere_plane
(
self
,
direction
,
triangle
,
start
=
None
):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
d
)
=
intersect_sphere_plane
(
(
ccp
,
cp
,
d
)
=
intersect_sphere_plane
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
distance_radius
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
),
direction
,
triangle
)
self
.
distance_radius
,
direction
,
triangle
)
# offset intersection
# offset intersection
if
ccp
:
if
ccp
:
cl
=
cp
.
add
(
start
.
sub
(
ccp
))
cl
=
padd
(
cp
,
psub
(
start
,
ccp
))
return
(
cl
,
ccp
,
cp
,
d
)
return
(
cl
,
ccp
,
cp
,
d
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -166,8 +166,8 @@ class SphericalCutter(BaseCutter):
...
@@ -166,8 +166,8 @@ class SphericalCutter(BaseCutter):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
l
)
=
intersect_sphere_point
(
(
ccp
,
cp
,
l
)
=
intersect_sphere_point
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
distance_radius
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
)
,
self
.
distance_radiussq
,
direction
,
point
)
self
.
distance_radius
,
self
.
distance_radius
sq
,
direction
,
point
)
# offset intersection
# offset intersection
cl
=
None
cl
=
None
if
cp
:
if
cp
:
...
@@ -183,11 +183,11 @@ class SphericalCutter(BaseCutter):
...
@@ -183,11 +183,11 @@ class SphericalCutter(BaseCutter):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
l
)
=
intersect_sphere_line
(
(
ccp
,
cp
,
l
)
=
intersect_sphere_line
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
distance_radius
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
)
,
self
.
distance_radiussq
,
direction
,
edge
)
self
.
distance_radius
,
self
.
distance_radius
sq
,
direction
,
edge
)
# offset intersection
# offset intersection
if
ccp
:
if
ccp
:
cl
=
cp
.
sub
(
ccp
.
sub
(
start
))
cl
=
psub
(
cp
,
psub
(
ccp
,
start
))
return
(
cl
,
ccp
,
cp
,
l
)
return
(
cl
,
ccp
,
cp
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -196,9 +196,9 @@ class SphericalCutter(BaseCutter):
...
@@ -196,9 +196,9 @@ class SphericalCutter(BaseCutter):
start
=
start
)
start
=
start
)
if
cp
:
if
cp
:
# check if the contact point is between the endpoints
# check if the contact point is between the endpoints
d
=
edge
.
p2
.
sub
(
edge
.
p1
)
d
=
psub
(
edge
.
p2
,
edge
.
p1
)
m
=
cp
.
sub
(
edge
.
p1
)
.
dot
(
d
)
m
=
pdot
(
psub
(
cp
,
edge
.
p1
),
d
)
if
(
m
<
-
epsilon
)
or
(
m
>
d
.
normsq
+
epsilon
):
if
(
m
<
-
epsilon
)
or
(
m
>
pnormsq
(
d
)
+
epsilon
):
return
(
None
,
INFINITE
,
None
)
return
(
None
,
INFINITE
,
None
)
return
(
cl
,
l
,
cp
)
return
(
cl
,
l
,
cp
)
...
@@ -216,7 +216,7 @@ class SphericalCutter(BaseCutter):
...
@@ -216,7 +216,7 @@ class SphericalCutter(BaseCutter):
d
=
d_t
d
=
d_t
cl
=
cl_t
cl
=
cl_t
cp
=
cp_t
cp
=
cp_t
if
cl
and
(
direction
.
x
==
0
)
and
(
direction
.
y
==
0
):
if
cl
and
(
direction
[
0
]
==
0
)
and
(
direction
[
1
]
==
0
):
return
(
cl
,
d
,
cp
)
return
(
cl
,
d
,
cp
)
(
cl_e1
,
d_e1
,
cp_e1
)
=
self
.
intersect_sphere_edge
(
direction
,
(
cl_e1
,
d_e1
,
cp_e1
)
=
self
.
intersect_sphere_edge
(
direction
,
triangle
.
e1
,
start
=
start
)
triangle
.
e1
,
start
=
start
)
...
@@ -254,9 +254,9 @@ class SphericalCutter(BaseCutter):
...
@@ -254,9 +254,9 @@ class SphericalCutter(BaseCutter):
d
=
d_p3
d
=
d_p3
cl
=
cl_p3
cl
=
cl_p3
cp
=
cp_p3
cp
=
cp_p3
if
cl
and
(
direction
.
x
==
0
)
and
(
direction
.
y
==
0
):
if
cl
and
(
direction
[
0
]
==
0
)
and
(
direction
[
1
]
==
0
):
return
(
cl
,
d
,
cp
)
return
(
cl
,
d
,
cp
)
if
(
direction
.
x
!=
0
)
or
(
direction
.
y
!=
0
):
if
(
direction
[
0
]
!=
0
)
or
(
direction
[
1
]
!=
0
):
(
cl_p1
,
d_p1
,
cp_p1
)
=
self
.
intersect_cylinder_vertex
(
direction
,
(
cl_p1
,
d_p1
,
cp_p1
)
=
self
.
intersect_cylinder_vertex
(
direction
,
triangle
.
p1
,
start
=
start
)
triangle
.
p1
,
start
=
start
)
(
cl_p2
,
d_p2
,
cp_p2
)
=
self
.
intersect_cylinder_vertex
(
direction
,
(
cl_p2
,
d_p2
,
cp_p2
)
=
self
.
intersect_cylinder_vertex
(
direction
,
...
...
pycam/Cutters/ToroidalCutter.py
View file @
9b939792
...
@@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License
...
@@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.utils
import
INFINITE
,
number
,
epsilon
from
pycam.Geometry.utils
import
INFINITE
,
number
,
epsilon
from
pycam.Geometry.intersection
import
intersect_torus_plane
,
\
from
pycam.Geometry.intersection
import
intersect_torus_plane
,
\
intersect_torus_point
,
intersect_circle_plane
,
intersect_circle_point
,
\
intersect_torus_point
,
intersect_circle_plane
,
intersect_circle_point
,
\
...
@@ -46,7 +46,7 @@ class ToroidalCutter(BaseCutter):
...
@@ -46,7 +46,7 @@ class ToroidalCutter(BaseCutter):
# we need "minorradius" for "moveto" - thus set it before parent's init
# we need "minorradius" for "moveto" - thus set it before parent's init
BaseCutter
.
__init__
(
self
,
radius
,
**
kwargs
)
BaseCutter
.
__init__
(
self
,
radius
,
**
kwargs
)
self
.
majorradius
=
self
.
radius
-
minorradius
self
.
majorradius
=
self
.
radius
-
minorradius
self
.
axis
=
Point
(
0
,
0
,
1
)
self
.
axis
=
(
0
,
0
,
1
)
self
.
majorradiussq
=
self
.
majorradius
**
2
self
.
majorradiussq
=
self
.
majorradius
**
2
self
.
minorradiussq
=
self
.
minorradius
**
2
self
.
minorradiussq
=
self
.
minorradius
**
2
self
.
distance_majorradius
=
self
.
majorradius
\
self
.
distance_majorradius
=
self
.
majorradius
\
...
@@ -97,7 +97,7 @@ class ToroidalCutter(BaseCutter):
...
@@ -97,7 +97,7 @@ class ToroidalCutter(BaseCutter):
if
not
GL_enabled
:
if
not
GL_enabled
:
return
return
GL
.
glPushMatrix
()
GL
.
glPushMatrix
()
GL
.
glTranslate
(
self
.
center
.
x
,
self
.
center
.
y
,
self
.
center
.
z
)
GL
.
glTranslate
(
self
.
center
[
0
],
self
.
center
[
1
],
self
.
center
[
2
]
)
GLUT
.
glutSolidTorus
(
self
.
minorradius
,
self
.
majorradius
,
10
,
20
)
GLUT
.
glutSolidTorus
(
self
.
minorradius
,
self
.
majorradius
,
10
,
20
)
if
not
hasattr
(
self
,
"_cylinder"
):
if
not
hasattr
(
self
,
"_cylinder"
):
self
.
_cylinder
=
GLU
.
gluNewQuadric
()
self
.
_cylinder
=
GLU
.
gluNewQuadric
()
...
@@ -105,7 +105,7 @@ class ToroidalCutter(BaseCutter):
...
@@ -105,7 +105,7 @@ class ToroidalCutter(BaseCutter):
10
,
20
)
10
,
20
)
GL
.
glPopMatrix
()
GL
.
glPopMatrix
()
GL
.
glPushMatrix
()
GL
.
glPushMatrix
()
GL
.
glTranslate
(
self
.
location
.
x
,
self
.
location
.
y
,
self
.
location
.
z
)
GL
.
glTranslate
(
self
.
location
[
0
],
self
.
location
[
1
],
self
.
location
[
2
]
)
if
not
hasattr
(
self
,
"_disk"
):
if
not
hasattr
(
self
,
"_disk"
):
self
.
_disk
=
GLU
.
gluNewQuadric
()
self
.
_disk
=
GLU
.
gluNewQuadric
()
GLU
.
gluDisk
(
self
.
_disk
,
0
,
self
.
majorradius
,
20
,
10
)
GLU
.
gluDisk
(
self
.
_disk
,
0
,
self
.
majorradius
,
20
,
10
)
...
@@ -113,17 +113,17 @@ class ToroidalCutter(BaseCutter):
...
@@ -113,17 +113,17 @@ class ToroidalCutter(BaseCutter):
def
moveto
(
self
,
location
,
**
kwargs
):
def
moveto
(
self
,
location
,
**
kwargs
):
BaseCutter
.
moveto
(
self
,
location
,
**
kwargs
)
BaseCutter
.
moveto
(
self
,
location
,
**
kwargs
)
self
.
center
=
Point
(
location
.
x
,
location
.
y
,
location
.
z
+
self
.
minorradius
)
self
.
center
=
(
location
[
0
],
location
[
1
],
location
[
2
]
+
self
.
minorradius
)
def
intersect_torus_plane
(
self
,
direction
,
triangle
,
start
=
None
):
def
intersect_torus_plane
(
self
,
direction
,
triangle
,
start
=
None
):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
l
)
=
intersect_torus_plane
(
(
ccp
,
cp
,
l
)
=
intersect_torus_plane
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
axis
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
)
,
self
.
distance_majorradius
,
self
.
distance_minorradius
,
direction
,
self
.
axis
,
self
.
distance_majorradius
,
self
.
distance_minorradius
,
direction
,
triangle
)
triangle
)
if
cp
:
if
cp
:
cl
=
cp
.
add
(
start
.
sub
(
ccp
))
cl
=
padd
(
cp
,
psub
(
start
,
ccp
))
return
(
cl
,
ccp
,
cp
,
l
)
return
(
cl
,
ccp
,
cp
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -138,12 +138,12 @@ class ToroidalCutter(BaseCutter):
...
@@ -138,12 +138,12 @@ class ToroidalCutter(BaseCutter):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
l
)
=
intersect_torus_point
(
(
ccp
,
cp
,
l
)
=
intersect_torus_point
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
axis
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
)
,
self
.
distance_majorradius
,
self
.
distance_minorradius
,
self
.
axis
,
self
.
distance_majorradius
,
self
.
distance_minorradius
,
self
.
distance_majorradiussq
,
self
.
distance_minorradiussq
,
self
.
distance_majorradiussq
,
self
.
distance_minorradiussq
,
direction
,
point
)
direction
,
point
)
if
ccp
:
if
ccp
:
cl
=
p
oint
.
add
(
start
.
sub
(
ccp
))
cl
=
p
add
(
point
,
psub
(
start
,
ccp
))
return
(
cl
,
ccp
,
point
,
l
)
return
(
cl
,
ccp
,
point
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -195,11 +195,11 @@ class ToroidalCutter(BaseCutter):
...
@@ -195,11 +195,11 @@ class ToroidalCutter(BaseCutter):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
l
)
=
intersect_cylinder_point
(
(
ccp
,
cp
,
l
)
=
intersect_cylinder_point
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
axis
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
),
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
point
)
self
.
axis
,
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
point
)
# offset intersection
# offset intersection
if
ccp
:
if
ccp
:
cl
=
start
.
add
(
direction
.
mul
(
l
))
cl
=
padd
(
start
,
pmul
(
direction
,
l
))
return
(
cl
,
ccp
,
cp
,
l
)
return
(
cl
,
ccp
,
cp
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -207,21 +207,22 @@ class ToroidalCutter(BaseCutter):
...
@@ -207,21 +207,22 @@ class ToroidalCutter(BaseCutter):
if
start
is
None
:
if
start
is
None
:
start
=
self
.
location
start
=
self
.
location
(
ccp
,
cp
,
l
)
=
intersect_cylinder_line
(
(
ccp
,
cp
,
l
)
=
intersect_cylinder_line
(
start
.
sub
(
self
.
location
)
.
add
(
self
.
center
),
self
.
axis
,
padd
(
psub
(
start
,
self
.
location
),
self
.
center
),
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
edge
)
self
.
axis
,
self
.
distance_radius
,
self
.
distance_radiussq
,
direction
,
edge
)
# offset intersection
# offset intersection
if
ccp
:
if
ccp
:
cl
=
start
.
add
(
cp
.
sub
(
ccp
))
cl
=
padd
(
start
,
psub
(
cp
,
ccp
))
#cl = start.add(cp.sub(ccp))
return
(
cl
,
ccp
,
cp
,
l
)
return
(
cl
,
ccp
,
cp
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
def
intersect_cylinder_edge
(
self
,
direction
,
edge
,
start
=
None
):
def
intersect_cylinder_edge
(
self
,
direction
,
edge
,
start
=
None
):
(
cl
,
ccp
,
cp
,
l
)
=
self
.
intersect_cylinder_line
(
direction
,
edge
,
(
cl
,
ccp
,
cp
,
l
)
=
self
.
intersect_cylinder_line
(
direction
,
edge
,
start
=
start
)
start
=
start
)
if
ccp
and
ccp
.
z
<
self
.
center
.
z
:
if
ccp
and
ccp
[
2
]
<
self
.
center
[
2
]
:
return
(
None
,
INFINITE
,
None
)
return
(
None
,
INFINITE
,
None
)
if
ccp
:
if
ccp
:
m
=
cp
.
sub
(
edge
.
p1
)
.
dot
(
edge
.
dir
)
m
=
pdot
(
psub
(
cp
,
edge
.
p1
),
edge
.
dir
)
if
(
m
<
-
epsilon
)
or
(
m
>
edge
.
len
+
epsilon
):
if
(
m
<
-
epsilon
)
or
(
m
>
edge
.
len
+
epsilon
):
return
(
None
,
INFINITE
,
None
)
return
(
None
,
INFINITE
,
None
)
return
(
cl
,
l
,
cp
)
return
(
cl
,
l
,
cp
)
...
@@ -233,7 +234,7 @@ class ToroidalCutter(BaseCutter):
...
@@ -233,7 +234,7 @@ class ToroidalCutter(BaseCutter):
self
.
distance_majorradius
,
direction
,
triangle
)
self
.
distance_majorradius
,
direction
,
triangle
)
# offset intersection
# offset intersection
if
ccp
:
if
ccp
:
cl
=
cp
.
sub
(
ccp
.
sub
(
start
))
cl
=
psub
(
cp
,
psub
(
ccp
,
start
))
return
(
cl
,
ccp
,
cp
,
l
)
return
(
cl
,
ccp
,
cp
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -244,7 +245,7 @@ class ToroidalCutter(BaseCutter):
...
@@ -244,7 +245,7 @@ class ToroidalCutter(BaseCutter):
self
.
distance_majorradius
,
self
.
distance_majorradiussq
,
self
.
distance_majorradius
,
self
.
distance_majorradiussq
,
direction
,
point
)
direction
,
point
)
if
ccp
:
if
ccp
:
cl
=
cp
.
sub
(
ccp
.
sub
(
start
))
cl
=
psub
(
cp
,
psub
(
ccp
,
start
))
return
(
cl
,
ccp
,
point
,
l
)
return
(
cl
,
ccp
,
point
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -255,7 +256,7 @@ class ToroidalCutter(BaseCutter):
...
@@ -255,7 +256,7 @@ class ToroidalCutter(BaseCutter):
self
.
distance_majorradius
,
self
.
distance_majorradiussq
,
self
.
distance_majorradius
,
self
.
distance_majorradiussq
,
direction
,
edge
)
direction
,
edge
)
if
ccp
:
if
ccp
:
cl
=
cp
.
sub
(
ccp
.
sub
(
start
))
cl
=
psub
(
cp
,
psub
(
ccp
,
start
))
return
(
cl
,
ccp
,
cp
,
l
)
return
(
cl
,
ccp
,
cp
,
l
)
return
(
None
,
None
,
None
,
INFINITE
)
return
(
None
,
None
,
None
,
INFINITE
)
...
@@ -347,7 +348,7 @@ class ToroidalCutter(BaseCutter):
...
@@ -347,7 +348,7 @@ class ToroidalCutter(BaseCutter):
d
=
d_e3
d
=
d_e3
cl
=
cl_e3
cl
=
cl_e3
cp
=
cp_e3
cp
=
cp_e3
if
direction
.
x
!=
0
or
direction
.
y
!=
0
:
if
direction
[
0
]
!=
0
or
direction
[
1
]
!=
0
:
(
cl_p1
,
d_p1
,
cp_p1
)
=
self
.
intersect_cylinder_vertex
(
direction
,
(
cl_p1
,
d_p1
,
cp_p1
)
=
self
.
intersect_cylinder_vertex
(
direction
,
triangle
.
p1
,
start
=
start
)
triangle
.
p1
,
start
=
start
)
(
cl_p2
,
d_p2
,
cp_p2
)
=
self
.
intersect_cylinder_vertex
(
direction
,
(
cl_p2
,
d_p2
,
cp_p2
)
=
self
.
intersect_cylinder_vertex
(
direction
,
...
...
pycam/Geometry/Letters.py
View file @
9b939792
...
@@ -24,7 +24,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -24,7 +24,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from
pycam.Geometry
import
TransformableContainer
from
pycam.Geometry
import
TransformableContainer
from
pycam.Geometry.Model
import
ContourModel
from
pycam.Geometry.Model
import
ContourModel
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
TEXT_ALIGN_LEFT
=
0
TEXT_ALIGN_LEFT
=
0
TEXT_ALIGN_CENTER
=
1
TEXT_ALIGN_CENTER
=
1
...
@@ -50,9 +50,7 @@ class Letter(TransformableContainer):
...
@@ -50,9 +50,7 @@ class Letter(TransformableContainer):
def
get_positioned_lines
(
self
,
base_point
,
skew
=
None
):
def
get_positioned_lines
(
self
,
base_point
,
skew
=
None
):
result
=
[]
result
=
[]
get_skewed_point
=
lambda
p
:
\
get_skewed_point
=
lambda
p
:
(
base_point
[
0
]
+
p
[
0
]
+
(
p
[
1
]
*
skew
/
100.0
),
base_point
[
1
]
+
p
[
1
],
base_point
[
2
])
Point
(
base_point
.
x
+
p
.
x
+
(
p
.
y
*
skew
/
100.0
),
base_point
.
y
+
p
.
y
,
base_point
.
z
)
for
line
in
self
.
lines
:
for
line
in
self
.
lines
:
skewed_p1
=
get_skewed_point
(
line
.
p1
)
skewed_p1
=
get_skewed_point
(
line
.
p1
)
skewed_p2
=
get_skewed_point
(
line
.
p2
)
skewed_p2
=
get_skewed_point
(
line
.
p2
)
...
@@ -107,7 +105,7 @@ class Charset(object):
...
@@ -107,7 +105,7 @@ class Charset(object):
align
=
None
):
align
=
None
):
result
=
ContourModel
()
result
=
ContourModel
()
if
origin
is
None
:
if
origin
is
None
:
origin
=
Point
(
0
,
0
,
0
)
origin
=
(
0
,
0
,
0
)
if
align
is
None
:
if
align
is
None
:
align
=
TEXT_ALIGN_LEFT
align
=
TEXT_ALIGN_LEFT
base
=
origin
base
=
origin
...
@@ -120,7 +118,7 @@ class Charset(object):
...
@@ -120,7 +118,7 @@ class Charset(object):
line_height
=
self
.
default_height
line_height
=
self
.
default_height
for
character
in
line
:
for
character
in
line
:
if
character
==
" "
:
if
character
==
" "
:
base
=
base
.
add
(
Point
(
word_spacing
,
0
,
0
))
base
=
padd
(
base
,
(
word_spacing
,
0
,
0
))
elif
character
in
self
.
letters
.
keys
():
elif
character
in
self
.
letters
.
keys
():
charset_letter
=
self
.
letters
[
character
]
charset_letter
=
self
.
letters
[
character
]
new_model
=
ContourModel
()
new_model
=
ContourModel
()
...
@@ -133,13 +131,12 @@ class Charset(object):
...
@@ -133,13 +131,12 @@ class Charset(object):
# update line height
# update line height
line_height
=
max
(
line_height
,
charset_letter
.
maxy
())
line_height
=
max
(
line_height
,
charset_letter
.
maxy
())
# shift the base position
# shift the base position
base
=
base
.
add
(
Point
(
base
=
padd
(
base
,
(
charset_letter
.
maxx
()
+
letter_spacing
,
0
,
0
))
charset_letter
.
maxx
()
+
letter_spacing
,
0
,
0
))
else
:
else
:
# unknown character - add a small whitespace
# unknown character - add a small whitespace
base
=
base
.
add
(
Point
(
letter_spacing
,
0
,
0
))
base
=
padd
(
base
,
(
letter_spacing
,
0
,
0
))
# go to the next line
# go to the next line
base
=
Point
(
origin
.
x
,
base
.
y
-
line_height
*
line_factor
,
origin
.
z
)
base
=
(
origin
[
0
],
base
[
1
]
-
line_height
*
line_factor
,
origin
[
2
]
)
if
not
current_line
.
maxx
is
None
:
if
not
current_line
.
maxx
is
None
:
if
align
==
TEXT_ALIGN_CENTER
:
if
align
==
TEXT_ALIGN_CENTER
:
current_line
.
shift
(
-
current_line
.
maxx
/
2
,
0
,
0
)
current_line
.
shift
(
-
current_line
.
maxx
/
2
,
0
,
0
)
...
...
pycam/Geometry/Line.py
View file @
9b939792
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry
import
TransformableContainer
,
IDGenerator
from
pycam.Geometry
import
TransformableContainer
,
IDGenerator
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.utils
import
epsilon
,
sqrt
from
pycam.Geometry.utils
import
epsilon
,
sqrt
# OpenGLTools will be imported later, if necessary
# OpenGLTools will be imported later, if necessary
...
@@ -48,61 +48,61 @@ class Line(IDGenerator, TransformableContainer):
...
@@ -48,61 +48,61 @@ class Line(IDGenerator, TransformableContainer):
self
.
reset_cache
()
self
.
reset_cache
()
def
copy
(
self
):
def
copy
(
self
):
return
self
.
__class__
(
self
.
p1
.
copy
(),
self
.
p2
.
copy
()
)
return
self
.
__class__
(
self
.
p1
,
self
.
p2
)
@
property
@
property
def
vector
(
self
):
def
vector
(
self
):
if
self
.
_vector
is
None
:
if
self
.
_vector
is
None
:
self
.
_vector
=
self
.
p2
.
sub
(
self
.
p1
)
self
.
_vector
=
psub
(
self
.
p2
,
self
.
p1
)
return
self
.
_vector
return
self
.
_vector
@
property
@
property
def
dir
(
self
):
def
dir
(
self
):
return
self
.
vector
.
normalized
(
)
return
pnormalized
(
self
.
vector
)
@
property
@
property
def
len
(
self
):
def
len
(
self
):
return
self
.
vector
.
norm
return
pnorm
(
self
.
vector
)
@
property
@
property
def
minx
(
self
):
def
minx
(
self
):
if
self
.
_minx
is
None
:
if
self
.
_minx
is
None
:
self
.
_minx
=
min
(
self
.
p1
.
x
,
self
.
p2
.
x
)
self
.
_minx
=
min
(
self
.
p1
[
0
],
self
.
p2
[
0
]
)
return
self
.
_minx
return
self
.
_minx
@
property
@
property
def
maxx
(
self
):
def
maxx
(
self
):
if
self
.
_maxx
is
None
:
if
self
.
_maxx
is
None
:
self
.
_maxx
=
max
(
self
.
p1
.
x
,
self
.
p2
.
x
)
self
.
_maxx
=
max
(
self
.
p1
[
0
],
self
.
p2
[
0
]
)
return
self
.
_maxx
return
self
.
_maxx
@
property
@
property
def
miny
(
self
):
def
miny
(
self
):
if
self
.
_miny
is
None
:
if
self
.
_miny
is
None
:
self
.
_miny
=
min
(
self
.
p1
.
y
,
self
.
p2
.
y
)
self
.
_miny
=
min
(
self
.
p1
[
1
],
self
.
p2
[
1
]
)
return
self
.
_miny
return
self
.
_miny
@
property
@
property
def
maxy
(
self
):
def
maxy
(
self
):
if
self
.
_maxy
is
None
:
if
self
.
_maxy
is
None
:
self
.
_maxy
=
max
(
self
.
p1
.
y
,
self
.
p2
.
y
)
self
.
_maxy
=
max
(
self
.
p1
[
1
],
self
.
p2
[
1
]
)
return
self
.
_maxy
return
self
.
_maxy
@
property
@
property
def
minz
(
self
):
def
minz
(
self
):
if
self
.
_minz
is
None
:
if
self
.
_minz
is
None
:
self
.
_minz
=
min
(
self
.
p1
.
z
,
self
.
p2
.
z
)
self
.
_minz
=
min
(
self
.
p1
[
2
],
self
.
p2
[
2
]
)
return
self
.
_minz
return
self
.
_minz
@
property
@
property
def
maxz
(
self
):
def
maxz
(
self
):
if
self
.
_maxz
is
None
:
if
self
.
_maxz
is
None
:
self
.
_maxz
=
max
(
self
.
p1
.
z
,
self
.
p2
.
z
)
self
.
_maxz
=
max
(
self
.
p1
[
2
],
self
.
p2
[
2
]
)
return
self
.
_maxz
return
self
.
_maxz
def
__repr__
(
self
):
def
__repr__
(
self
):
return
"Line<
%
g,
%
g,
%
g>-<
%
g,
%
g,
%
g>"
%
(
self
.
p1
.
x
,
self
.
p1
.
y
,
self
.
p1
.
z
,
return
"Line<
%
g,
%
g,
%
g>-<
%
g,
%
g,
%
g>"
%
(
self
.
p1
[
0
],
self
.
p1
[
1
],
self
.
p1
[
2
]
,
self
.
p2
.
x
,
self
.
p2
.
y
,
self
.
p2
.
z
)
self
.
p2
[
0
],
self
.
p2
[
1
],
self
.
p2
[
2
]
)
def
__cmp__
(
self
,
other
):
def
__cmp__
(
self
,
other
):
""" Two lines are equal if both pairs of points are at the same
""" Two lines are equal if both pairs of points are at the same
...
@@ -119,10 +119,10 @@ class Line(IDGenerator, TransformableContainer):
...
@@ -119,10 +119,10 @@ class Line(IDGenerator, TransformableContainer):
return
cmp
(
self
.
p2
,
other
.
p2
)
return
cmp
(
self
.
p2
,
other
.
p2
)
else
:
else
:
return
cmp
(
str
(
self
),
str
(
other
))
return
cmp
(
str
(
self
),
str
(
other
))
def
next
(
self
):
def
next
(
self
):
yield
self
.
p1
yield
"p1"
yield
self
.
p2
yield
"p2"
def
get_children_count
(
self
):
def
get_children_count
(
self
):
# a line always contains two points
# a line always contains two points
...
@@ -141,23 +141,23 @@ class Line(IDGenerator, TransformableContainer):
...
@@ -141,23 +141,23 @@ class Line(IDGenerator, TransformableContainer):
return
(
self
.
p1
,
self
.
p2
)
return
(
self
.
p1
,
self
.
p2
)
def
point_with_length_multiply
(
self
,
l
):
def
point_with_length_multiply
(
self
,
l
):
return
self
.
p1
.
add
(
self
.
dir
.
mul
(
l
*
self
.
len
))
return
padd
(
self
.
p1
,
pmul
(
self
.
dir
,
l
*
self
.
len
))
def
get_length_line
(
self
,
length
):
def
get_length_line
(
self
,
length
):
""" return a line with the same direction and the specified length
""" return a line with the same direction and the specified length
"""
"""
return
Line
(
self
.
p1
,
self
.
p1
.
add
(
self
.
dir
.
mul
(
length
)))
return
Line
(
self
.
p1
,
padd
(
self
.
p1
,
pmul
(
self
.
dir
,
length
)))
def
closest_point
(
self
,
p
):
def
closest_point
(
self
,
p
):
v
=
self
.
dir
v
=
self
.
dir
if
v
is
None
:
if
v
is
None
:
# for zero-length lines
# for zero-length lines
return
self
.
p1
return
self
.
p1
l
=
self
.
p1
.
dot
(
v
)
-
p
.
dot
(
v
)
l
=
pdot
(
self
.
p1
,
v
)
-
pdot
(
p
,
v
)
return
self
.
p1
.
sub
(
v
.
mul
(
l
))
return
psub
(
self
.
p1
,
pmul
(
v
,
l
))
def
dist_to_point_sq
(
self
,
p
):
def
dist_to_point_sq
(
self
,
p
):
return
p
.
sub
(
self
.
closest_point
(
p
))
.
normsq
return
p
normsq
(
psub
(
p
,
self
.
closes_point
(
p
)))
def
dist_to_point
(
self
,
p
):
def
dist_to_point
(
self
,
p
):
return
sqrt
(
self
.
dist_to_point_sq
(
p
))
return
sqrt
(
self
.
dist_to_point_sq
(
p
))
...
@@ -166,8 +166,9 @@ class Line(IDGenerator, TransformableContainer):
...
@@ -166,8 +166,9 @@ class Line(IDGenerator, TransformableContainer):
if
(
p
==
self
.
p1
)
or
(
p
==
self
.
p2
):
if
(
p
==
self
.
p1
)
or
(
p
==
self
.
p2
):
# these conditions are not covered by the code below
# these conditions are not covered by the code below
return
True
return
True
dir1
=
p
.
sub
(
self
.
p1
)
.
normalized
()
dir2
=
self
.
p2
.
sub
(
p
)
.
normalized
()
dir1
=
pnormalized
(
psub
(
p
,
self
.
p1
))
dir2
=
pnormalized
(
psub
(
self
.
p2
,
p
))
# True if the two parts of the line have the same direction or if the
# True if the two parts of the line have the same direction or if the
# point is self.p1 or self.p2.
# point is self.p1 or self.p2.
return
(
dir1
==
dir2
==
self
.
dir
)
or
(
dir1
is
None
)
or
(
dir2
is
None
)
return
(
dir1
==
dir2
==
self
.
dir
)
or
(
dir1
is
None
)
or
(
dir2
is
None
)
...
@@ -178,8 +179,8 @@ class Line(IDGenerator, TransformableContainer):
...
@@ -178,8 +179,8 @@ class Line(IDGenerator, TransformableContainer):
if
not
color
is
None
:
if
not
color
is
None
:
GL
.
glColor4f
(
*
color
)
GL
.
glColor4f
(
*
color
)
GL
.
glBegin
(
GL
.
GL_LINES
)
GL
.
glBegin
(
GL
.
GL_LINES
)
GL
.
glVertex3f
(
self
.
p1
.
x
,
self
.
p1
.
y
,
self
.
p1
.
z
)
GL
.
glVertex3f
(
self
.
p1
[
0
],
self
.
p1
[
1
],
self
.
p1
[
2
]
)
GL
.
glVertex3f
(
self
.
p2
.
x
,
self
.
p2
.
y
,
self
.
p2
.
z
)
GL
.
glVertex3f
(
self
.
p2
[
0
],
self
.
p2
[
1
],
self
.
p2
[
2
]
)
GL
.
glEnd
()
GL
.
glEnd
()
# (optional) draw a cone for visualizing the direction of each line
# (optional) draw a cone for visualizing the direction of each line
if
show_directions
and
(
self
.
len
>
0
):
if
show_directions
and
(
self
.
len
>
0
):
...
@@ -196,24 +197,24 @@ class Line(IDGenerator, TransformableContainer):
...
@@ -196,24 +197,24 @@ class Line(IDGenerator, TransformableContainer):
0 and 1.
0 and 1.
"""
"""
x1
,
x2
,
x3
,
x4
=
self
.
p1
,
self
.
p2
,
line
.
p1
,
line
.
p2
x1
,
x2
,
x3
,
x4
=
self
.
p1
,
self
.
p2
,
line
.
p1
,
line
.
p2
a
=
x2
.
sub
(
x1
)
a
=
psub
(
x2
,
x1
)
b
=
x4
.
sub
(
x3
)
b
=
psub
(
x4
,
x3
)
c
=
x3
.
sub
(
x1
)
c
=
psub
(
x3
,
x1
)
# see http://mathworld.wolfram.com/Line-LineIntersection.html (24)
# see http://mathworld.wolfram.com/Line-LineIntersection.html (24)
try
:
try
:
factor
=
c
.
cross
(
b
)
.
dot
(
a
.
cross
(
b
))
/
a
.
cross
(
b
)
.
normsq
factor
=
pdot
(
pcross
(
c
,
b
),
pcross
(
a
,
b
))
/
pnormsq
(
pcross
(
a
,
b
))
except
ZeroDivisionError
:
except
ZeroDivisionError
:
# lines are parallel
# lines are parallel
# check if they are _one_ line
# check if they are _one_ line
if
a
.
cross
(
c
)
.
norm
!=
0
:
if
pnorm
(
pcross
(
a
,
c
))
!=
0
:
# the lines are parallel with a distance
# the lines are parallel with a distance
return
None
,
None
return
None
,
None
# the lines are on one straight
# the lines are on one straight
candidates
=
[]
candidates
=
[]
if
self
.
is_point_inside
(
x3
):
if
self
.
is_point_inside
(
x3
):
candidates
.
append
((
x3
,
c
.
norm
/
a
.
norm
))
candidates
.
append
((
x3
,
pnorm
(
c
)
/
pnorm
(
a
)
))
elif
self
.
is_point_inside
(
x4
):
elif
self
.
is_point_inside
(
x4
):
candidates
.
append
((
x4
,
line
.
p2
.
sub
(
self
.
p1
)
.
norm
/
a
.
norm
))
candidates
.
append
((
x4
,
pnorm
(
psub
(
line
.
p2
,
self
.
p1
))
/
pnorm
(
a
)
))
elif
line
.
is_point_inside
(
x1
):
elif
line
.
is_point_inside
(
x1
):
candidates
.
append
((
x1
,
0
))
candidates
.
append
((
x1
,
0
))
elif
line
.
is_point_inside
(
x2
):
elif
line
.
is_point_inside
(
x2
):
...
@@ -224,13 +225,13 @@ class Line(IDGenerator, TransformableContainer):
...
@@ -224,13 +225,13 @@ class Line(IDGenerator, TransformableContainer):
candidates
.
sort
(
key
=
lambda
(
cp
,
dist
):
dist
)
candidates
.
sort
(
key
=
lambda
(
cp
,
dist
):
dist
)
return
candidates
[
0
]
return
candidates
[
0
]
if
infinite_lines
or
(
-
epsilon
<=
factor
<=
1
+
epsilon
):
if
infinite_lines
or
(
-
epsilon
<=
factor
<=
1
+
epsilon
):
intersection
=
x1
.
add
(
a
.
mul
(
factor
))
intersection
=
padd
(
x1
,
pmul
(
a
,
factor
))
# check if the intersection is between x3 and x4
# check if the intersection is between x3 and x4
if
infinite_lines
:
if
infinite_lines
:
return
intersection
,
factor
return
intersection
,
factor
elif
(
min
(
x3
.
x
,
x4
.
x
)
-
epsilon
<=
intersection
.
x
<=
max
(
x3
.
x
,
x4
.
x
)
+
epsilon
)
\
elif
(
min
(
x3
[
0
],
x4
[
0
])
-
epsilon
<=
intersection
[
0
]
<=
max
(
x3
[
0
],
x4
[
0
]
)
+
epsilon
)
\
and
(
min
(
x3
.
y
,
x4
.
y
)
-
epsilon
<=
intersection
.
y
<=
max
(
x3
.
y
,
x4
.
y
)
+
epsilon
)
\
and
(
min
(
x3
[
1
],
x4
[
1
])
-
epsilon
<=
intersection
[
1
]
<=
max
(
x3
[
1
],
x4
[
1
]
)
+
epsilon
)
\
and
(
min
(
x3
.
z
,
x4
.
z
)
-
epsilon
<=
intersection
.
z
<=
max
(
x3
.
z
,
x4
.
z
)
+
epsilon
):
and
(
min
(
x3
[
2
],
x4
[
2
])
-
epsilon
<=
intersection
[
2
]
<=
max
(
x3
[
2
],
x4
[
2
]
)
+
epsilon
):
return
intersection
,
factor
return
intersection
,
factor
else
:
else
:
# intersection outside of the length of line(x3, x4)
# intersection outside of the length of line(x3, x4)
...
@@ -247,15 +248,15 @@ class Line(IDGenerator, TransformableContainer):
...
@@ -247,15 +248,15 @@ class Line(IDGenerator, TransformableContainer):
else
:
else
:
# the line needs to be cropped
# the line needs to be cropped
# generate the six planes of the cube for possible intersections
# generate the six planes of the cube for possible intersections
minp
=
Point
(
minx
,
miny
,
minz
)
minp
=
(
minx
,
miny
,
minz
)
maxp
=
Point
(
maxx
,
maxy
,
maxz
)
maxp
=
(
maxx
,
maxy
,
maxz
)
planes
=
[
planes
=
[
Plane
(
minp
,
Point
(
1
,
0
,
0
)),
Plane
(
minp
,
(
1
,
0
,
0
)),
Plane
(
minp
,
Point
(
0
,
1
,
0
)),
Plane
(
minp
,
(
0
,
1
,
0
)),
Plane
(
minp
,
Point
(
0
,
0
,
1
)),
Plane
(
minp
,
(
0
,
0
,
1
)),
Plane
(
maxp
,
Point
(
1
,
0
,
0
)),
Plane
(
maxp
,
(
1
,
0
,
0
)),
Plane
(
maxp
,
Point
(
0
,
1
,
0
)),
Plane
(
maxp
,
(
0
,
1
,
0
)),
Plane
(
maxp
,
Point
(
0
,
0
,
1
)),
Plane
(
maxp
,
(
0
,
0
,
1
)),
]
]
# calculate all intersections
# calculate all intersections
intersections
=
[
plane
.
intersect_point
(
self
.
dir
,
self
.
p1
)
intersections
=
[
plane
.
intersect_point
(
self
.
dir
,
self
.
p1
)
...
...
pycam/Geometry/Matrix.py
View file @
9b939792
...
@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
# various matrix related functions for PyCAM
# various matrix related functions for PyCAM
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.utils
import
sqrt
,
number
,
epsilon
from
pycam.Geometry.utils
import
sqrt
,
number
,
epsilon
import
math
import
math
...
@@ -54,23 +54,6 @@ def get_dot_product(a, b):
...
@@ -54,23 +54,6 @@ def get_dot_product(a, b):
"""
"""
return
sum
(
l1
*
l2
for
l1
,
l2
in
zip
(
a
,
b
))
return
sum
(
l1
*
l2
for
l1
,
l2
in
zip
(
a
,
b
))
def
get_cross_product
(
a
,
b
):
""" calculate the cross product of two 3d vectors
@type a: tuple(float) | list(float) | pycam.Geometry.Point
@value a: the first vector to be multiplied
@type b: tuple(float) | list(float) | pycam.Geometry.Point
@value b: the second vector to be multiplied
@rtype: tuple(float)
@return: the cross product is a 3d vector
"""
if
isinstance
(
a
,
Point
):
a
=
(
a
.
x
,
a
.
y
,
a
.
z
)
if
isinstance
(
b
,
Point
):
b
=
(
b
.
x
,
b
.
y
,
b
.
z
)
return
(
a
[
1
]
*
b
[
2
]
-
a
[
2
]
*
b
[
1
],
a
[
2
]
*
b
[
0
]
-
a
[
0
]
*
b
[
2
],
a
[
0
]
*
b
[
1
]
-
a
[
1
]
*
b
[
0
])
def
get_length
(
vector
):
def
get_length
(
vector
):
""" calculate the lengt of a 3d vector
""" calculate the lengt of a 3d vector
...
@@ -101,13 +84,10 @@ def get_rotation_matrix_from_to(v_orig, v_dest):
...
@@ -101,13 +84,10 @@ def get_rotation_matrix_from_to(v_orig, v_dest):
@rtype: tuple(tuple(float))
@rtype: tuple(tuple(float))
@return: the roation matrix (3x3)
@return: the roation matrix (3x3)
"""
"""
if
isinstance
(
v_orig
,
Point
):
v_orig
=
(
v_orig
.
x
,
v_orig
.
y
,
v_orig
.
z
)
if
isinstance
(
v_dest
,
Point
):
v_dest
=
(
v_dest
.
x
,
v_dest
.
y
,
v_dest
.
z
)
v_orig_length
=
get_length
(
v_orig
)
v_orig_length
=
get_length
(
v_orig
)
v_dest_length
=
get_length
(
v_dest
)
v_dest_length
=
get_length
(
v_dest
)
cross_product
=
get_length
(
get_cross_product
(
v_orig
,
v_dest
))
cross_product
=
get_length
(
pcross
(
v_orig
,
v_dest
))
try
:
try
:
arcsin
=
cross_product
/
(
v_orig_length
*
v_dest_length
)
arcsin
=
cross_product
/
(
v_orig_length
*
v_dest_length
)
except
ZeroDivisionError
:
except
ZeroDivisionError
:
...
@@ -121,9 +101,9 @@ def get_rotation_matrix_from_to(v_orig, v_dest):
...
@@ -121,9 +101,9 @@ def get_rotation_matrix_from_to(v_orig, v_dest):
# calculate the rotation axis
# calculate the rotation axis
# The rotation axis is equal to the cross product of the original and
# The rotation axis is equal to the cross product of the original and
# destination vectors.
# destination vectors.
rot_axis
=
Point
(
v_orig
[
1
]
*
v_dest
[
2
]
-
v_orig
[
2
]
*
v_dest
[
1
],
rot_axis
=
pnormalized
(
(
v_orig
[
1
]
*
v_dest
[
2
]
-
v_orig
[
2
]
*
v_dest
[
1
],
v_orig
[
2
]
*
v_dest
[
0
]
-
v_orig
[
0
]
*
v_dest
[
2
],
v_orig
[
2
]
*
v_dest
[
0
]
-
v_orig
[
0
]
*
v_dest
[
2
],
v_orig
[
0
]
*
v_dest
[
1
]
-
v_orig
[
1
]
*
v_dest
[
0
])
.
normalized
(
)
v_orig
[
0
]
*
v_dest
[
1
]
-
v_orig
[
1
]
*
v_dest
[
0
]))
if
not
rot_axis
:
if
not
rot_axis
:
return
None
return
None
# get the rotation matrix
# get the rotation matrix
...
@@ -131,15 +111,15 @@ def get_rotation_matrix_from_to(v_orig, v_dest):
...
@@ -131,15 +111,15 @@ def get_rotation_matrix_from_to(v_orig, v_dest):
c
=
math
.
cos
(
rot_angle
)
c
=
math
.
cos
(
rot_angle
)
s
=
math
.
sin
(
rot_angle
)
s
=
math
.
sin
(
rot_angle
)
t
=
1
-
c
t
=
1
-
c
return
((
t
*
rot_axis
.
x
*
rot_axis
.
x
+
c
,
return
((
t
*
rot_axis
[
0
]
*
rot_axis
[
0
]
+
c
,
t
*
rot_axis
.
x
*
rot_axis
.
y
-
s
*
rot_axis
.
z
,
t
*
rot_axis
[
0
]
*
rot_axis
[
1
]
-
s
*
rot_axis
[
2
]
,
t
*
rot_axis
.
x
*
rot_axis
.
z
+
s
*
rot_axis
.
y
),
t
*
rot_axis
[
0
]
*
rot_axis
[
2
]
+
s
*
rot_axis
[
1
]
),
(
t
*
rot_axis
.
x
*
rot_axis
.
y
+
s
*
rot_axis
.
z
,
(
t
*
rot_axis
[
0
]
*
rot_axis
[
1
]
+
s
*
rot_axis
[
2
]
,
t
*
rot_axis
.
y
*
rot_axis
.
y
+
c
,
t
*
rot_axis
[
1
]
*
rot_axis
[
1
]
+
c
,
t
*
rot_axis
.
y
*
rot_axis
.
z
-
s
*
rot_axis
.
x
),
t
*
rot_axis
[
1
]
*
rot_axis
[
2
]
-
s
*
rot_axis
[
0
]
),
(
t
*
rot_axis
.
x
*
rot_axis
.
z
-
s
*
rot_axis
.
y
,
(
t
*
rot_axis
[
0
]
*
rot_axis
[
2
]
-
s
*
rot_axis
[
1
]
,
t
*
rot_axis
.
y
*
rot_axis
.
z
+
s
*
rot_axis
.
x
,
t
*
rot_axis
[
1
]
*
rot_axis
[
2
]
+
s
*
rot_axis
[
0
]
,
t
*
rot_axis
.
z
*
rot_axis
.
z
+
c
))
t
*
rot_axis
[
2
]
*
rot_axis
[
2
]
+
c
))
def
get_rotation_matrix_axis_angle
(
rot_axis
,
rot_angle
,
use_radians
=
True
):
def
get_rotation_matrix_axis_angle
(
rot_axis
,
rot_angle
,
use_radians
=
True
):
""" calculate rotation matrix for a normalized vector and an angle
""" calculate rotation matrix for a normalized vector and an angle
...
...
pycam/Geometry/Model.py
View file @
9b939792
...
@@ -31,7 +31,7 @@ from pycam.Geometry.Triangle import Triangle
...
@@ -31,7 +31,7 @@ from pycam.Geometry.Triangle import Triangle
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Polygon
import
Polygon
from
pycam.Geometry.Polygon
import
Polygon
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.TriangleKdtree
import
TriangleKdtree
from
pycam.Geometry.TriangleKdtree
import
TriangleKdtree
from
pycam.Geometry.Matrix
import
TRANSFORMATIONS
from
pycam.Geometry.Matrix
import
TRANSFORMATIONS
from
pycam.Toolpath
import
Bounds
from
pycam.Toolpath
import
Bounds
...
@@ -109,7 +109,7 @@ class BaseModel(IDGenerator, TransformableContainer):
...
@@ -109,7 +109,7 @@ class BaseModel(IDGenerator, TransformableContainer):
return
sum
([
len
(
igroup
)
for
igroup
in
self
.
_item_groups
])
return
sum
([
len
(
igroup
)
for
igroup
in
self
.
_item_groups
])
def
next
(
self
):
def
next
(
self
):
for
item_group
in
self
.
_item_groups
:
for
item_group
in
self
.
_item_groups
:
for
item
in
item_group
:
for
item
in
item_group
:
if
isinstance
(
item
,
list
):
if
isinstance
(
item
,
list
):
for
subitem
in
item
:
for
subitem
in
item
:
...
@@ -324,7 +324,7 @@ class Model(BaseModel):
...
@@ -324,7 +324,7 @@ class Model(BaseModel):
# Find all groups with the same direction (see 'normal') that
# Find all groups with the same direction (see 'normal') that
# share at least one edge with the current triangle.
# share at least one edge with the current triangle.
touch_groups
=
[]
touch_groups
=
[]
if
t
.
normal
.
z
==
0
:
if
t
.
normal
[
2
]
==
0
:
# ignore vertical triangles
# ignore vertical triangles
continue
continue
for
group_index
,
group
in
enumerate
(
groups
):
for
group_index
,
group
in
enumerate
(
groups
):
...
@@ -359,7 +359,7 @@ class ContourModel(BaseModel):
...
@@ -359,7 +359,7 @@ class ContourModel(BaseModel):
self
.
name
=
"contourmodel
%
d"
%
self
.
id
self
.
name
=
"contourmodel
%
d"
%
self
.
id
if
plane
is
None
:
if
plane
is
None
:
# the default plane points upwards along the z axis
# the default plane points upwards along the z axis
plane
=
Plane
(
Point
(
0
,
0
,
0
),
Vector
(
0
,
0
,
1
))
plane
=
Plane
(
(
0
,
0
,
0
),
(
0
,
0
,
1
,
'v'
))
self
.
_plane
=
plane
self
.
_plane
=
plane
self
.
_line_groups
=
[]
self
.
_line_groups
=
[]
self
.
_item_groups
.
append
(
self
.
_line_groups
)
self
.
_item_groups
.
append
(
self
.
_line_groups
)
...
@@ -804,7 +804,7 @@ class PolygonGroup(object):
...
@@ -804,7 +804,7 @@ class PolygonGroup(object):
self
.
inner
=
inner_list
self
.
inner
=
inner_list
self
.
callback
=
callback
self
.
callback
=
callback
self
.
lines
=
outer
.
get_lines
()
self
.
lines
=
outer
.
get_lines
()
self
.
z_level
=
self
.
lines
[
0
]
.
p1
.
z
self
.
z_level
=
self
.
lines
[
0
]
.
p1
[
2
]
for
poly
in
inner_list
:
for
poly
in
inner_list
:
self
.
lines
.
extend
(
poly
.
get_lines
())
self
.
lines
.
extend
(
poly
.
get_lines
())
...
@@ -836,7 +836,7 @@ class PolygonGroup(object):
...
@@ -836,7 +836,7 @@ class PolygonGroup(object):
# create the backside plane
# create the backside plane
backside_points
=
[]
backside_points
=
[]
for
p
in
item
.
get_points
():
for
p
in
item
.
get_points
():
backside_points
.
insert
(
0
,
Point
(
p
.
x
,
p
.
y
,
self
.
z_level
))
backside_points
.
insert
(
0
,
(
p
[
0
],
p
[
1
]
,
self
.
z_level
))
triangle_optimizer
.
append
(
Triangle
(
*
backside_points
))
triangle_optimizer
.
append
(
Triangle
(
*
backside_points
))
if
self
.
callback
and
self
.
callback
():
if
self
.
callback
and
self
.
callback
():
return
None
return
None
...
@@ -873,7 +873,7 @@ class PolygonGroup(object):
...
@@ -873,7 +873,7 @@ class PolygonGroup(object):
# the contour points of the model will always be at level zero
# the contour points of the model will always be at level zero
a
[
2
]
=
self
.
z_level
a
[
2
]
=
self
.
z_level
b
[
2
]
=
self
.
z_level
b
[
2
]
=
self
.
z_level
return
Line
(
Point
(
*
a
),
Point
(
*
b
)
)
return
Line
(
a
,
b
)
valid_indices
=
[
index
for
index
,
p
in
enumerate
(
coords
)
valid_indices
=
[
index
for
index
,
p
in
enumerate
(
coords
)
if
not
p
[
2
]
is
None
]
if
not
p
[
2
]
is
None
]
none_indices
=
[
index
for
index
,
p
in
enumerate
(
coords
)
if
p
[
2
]
is
None
]
none_indices
=
[
index
for
index
,
p
in
enumerate
(
coords
)
if
p
[
2
]
is
None
]
...
@@ -891,7 +891,7 @@ class PolygonGroup(object):
...
@@ -891,7 +891,7 @@ class PolygonGroup(object):
fan_points
.
append
(
cp
)
fan_points
.
append
(
cp
)
final_points
.
append
(
cp
)
final_points
.
append
(
cp
)
else
:
else
:
final_points
.
append
(
Point
(
*
coords
[
index
])
)
final_points
.
append
(
coords
[
index
]
)
# check if the three fan_points are in line
# check if the three fan_points are in line
if
len
(
fan_points
)
==
3
:
if
len
(
fan_points
)
==
3
:
fan_points
.
sort
()
fan_points
.
sort
()
...
@@ -905,7 +905,7 @@ class PolygonGroup(object):
...
@@ -905,7 +905,7 @@ class PolygonGroup(object):
# is hardly possible, anyway.
# is hardly possible, anyway.
for
index
in
range
(
4
):
for
index
in
range
(
4
):
if
index
in
valid_indices
:
if
index
in
valid_indices
:
final_points
.
append
(
Point
(
*
coords
[
index
])
)
final_points
.
append
(
coords
[
index
]
)
else
:
else
:
probe_line
=
get_line
(
index
-
1
,
index
)
probe_line
=
get_line
(
index
-
1
,
index
)
cp
=
self
.
_get_closest_line_collision
(
probe_line
)
cp
=
self
.
_get_closest_line_collision
(
probe_line
)
...
@@ -913,7 +913,7 @@ class PolygonGroup(object):
...
@@ -913,7 +913,7 @@ class PolygonGroup(object):
else
:
else
:
for
index
in
range
(
4
):
for
index
in
range
(
4
):
if
index
in
valid_indices
:
if
index
in
valid_indices
:
final_points
.
append
(
Point
(
*
coords
[
index
])
)
final_points
.
append
(
coords
[
index
]
)
else
:
else
:
if
((
index
+
1
)
%
4
)
in
valid_indices
:
if
((
index
+
1
)
%
4
)
in
valid_indices
:
other_index
=
index
+
1
other_index
=
index
+
1
...
@@ -925,7 +925,7 @@ class PolygonGroup(object):
...
@@ -925,7 +925,7 @@ class PolygonGroup(object):
elif
valid_count
==
3
:
elif
valid_count
==
3
:
for
index
in
range
(
4
):
for
index
in
range
(
4
):
if
index
in
valid_indices
:
if
index
in
valid_indices
:
final_points
.
append
(
Point
(
*
coords
[
index
])
)
final_points
.
append
(
coords
[
index
]
)
else
:
else
:
# add two points
# add two points
for
other_index
in
(
index
-
1
,
index
+
1
):
for
other_index
in
(
index
-
1
,
index
+
1
):
...
@@ -933,7 +933,7 @@ class PolygonGroup(object):
...
@@ -933,7 +933,7 @@ class PolygonGroup(object):
cp
=
self
.
_get_closest_line_collision
(
probe_line
)
cp
=
self
.
_get_closest_line_collision
(
probe_line
)
final_points
.
append
(
cp
)
final_points
.
append
(
cp
)
else
:
else
:
final_points
.
extend
(
[
Point
(
*
coord
)
for
coord
in
coords
]
)
final_points
.
extend
(
coords
)
valid_points
=
[]
valid_points
=
[]
for
p
in
final_points
:
for
p
in
final_points
:
if
not
(
p
is
None
)
and
not
(
p
in
valid_points
):
if
not
(
p
is
None
)
and
not
(
p
in
valid_points
):
...
@@ -970,17 +970,17 @@ class PolygonGroup(object):
...
@@ -970,17 +970,17 @@ class PolygonGroup(object):
return
grid
return
grid
def
calculate_point_height
(
self
,
x
,
y
,
func
):
def
calculate_point_height
(
self
,
x
,
y
,
func
):
point
=
Point
(
x
,
y
,
self
.
outer
.
minz
)
point
=
(
x
,
y
,
self
.
outer
.
minz
)
if
not
self
.
outer
.
is_point_inside
(
point
):
if
not
self
.
outer
.
is_point_inside
(
point
):
return
None
return
None
for
poly
in
self
.
inner
:
for
poly
in
self
.
inner
:
if
poly
.
is_point_inside
(
point
):
if
poly
.
is_point_inside
(
point
):
return
None
return
None
point
=
Point
(
x
,
y
,
self
.
outer
.
minz
)
point
=
(
x
,
y
,
self
.
outer
.
minz
)
line_distances
=
[]
line_distances
=
[]
for
line
in
self
.
lines
:
for
line
in
self
.
lines
:
cross_product
=
line
.
dir
.
cross
(
point
.
sub
(
line
.
p1
))
cross_product
=
pcross
(
line
.
dir
,
psub
(
point
,
line
.
p1
))
if
cross_product
.
z
>
0
:
if
cross_product
[
2
]
>
0
:
close_points
=
[]
close_points
=
[]
close_point
=
line
.
closest_point
(
point
)
close_point
=
line
.
closest_point
(
point
)
if
not
line
.
is_point_inside
(
close_point
):
if
not
line
.
is_point_inside
(
close_point
):
...
@@ -989,8 +989,8 @@ class PolygonGroup(object):
...
@@ -989,8 +989,8 @@ class PolygonGroup(object):
else
:
else
:
close_points
.
append
(
close_point
)
close_points
.
append
(
close_point
)
for
p
in
close_points
:
for
p
in
close_points
:
direction
=
p
oint
.
sub
(
p
)
direction
=
p
sub
(
point
,
p
)
dist
=
direction
.
norm
dist
=
pnorm
(
direction
)
line_distances
.
append
(
dist
)
line_distances
.
append
(
dist
)
elif
cross_product
.
z
==
0
:
elif
cross_product
.
z
==
0
:
# the point is on the line
# the point is on the line
...
@@ -1012,10 +1012,10 @@ class TriangleOptimizer(object):
...
@@ -1012,10 +1012,10 @@ class TriangleOptimizer(object):
def
append
(
self
,
triangle
):
def
append
(
self
,
triangle
):
# use a simple tuple instead of an object as the dict's key
# use a simple tuple instead of an object as the dict's key
normal
_coords
=
triangle
.
normal
.
x
,
triangle
.
normal
.
y
,
triangle
.
normal
.
z
normal
=
triangle
.
normal
if
not
normal
_coords
in
self
.
groups
:
if
not
normal
in
self
.
groups
:
self
.
groups
[
normal
_coords
]
=
[]
self
.
groups
[
normal
]
=
[]
self
.
groups
[
normal
_coords
]
.
append
(
triangle
)
self
.
groups
[
normal
]
.
append
(
triangle
)
def
optimize
(
self
):
def
optimize
(
self
):
for
group
in
self
.
groups
.
values
():
for
group
in
self
.
groups
.
values
():
...
@@ -1068,7 +1068,7 @@ class Rectangle(IDGenerator, TransformableContainer):
...
@@ -1068,7 +1068,7 @@ class Rectangle(IDGenerator, TransformableContainer):
orders
=
((
p1
,
p2
,
p3
,
p4
),
(
p1
,
p2
,
p4
,
p3
),
(
p1
,
p3
,
p2
,
p4
),
orders
=
((
p1
,
p2
,
p3
,
p4
),
(
p1
,
p2
,
p4
,
p3
),
(
p1
,
p3
,
p2
,
p4
),
(
p1
,
p3
,
p4
,
p2
),
(
p1
,
p4
,
p2
,
p3
),
(
p1
,
p4
,
p3
,
p2
))
(
p1
,
p3
,
p4
,
p2
),
(
p1
,
p4
,
p2
,
p3
),
(
p1
,
p4
,
p3
,
p2
))
for
order
in
orders
:
for
order
in
orders
:
if
abs
(
order
[
0
]
.
sub
(
order
[
2
])
.
norm
-
order
[
1
]
.
sub
(
order
[
3
])
.
norm
)
<
epsilon
:
if
abs
(
pnorm
(
psub
(
order
[
0
],
order
[
2
]))
-
pnorm
(
psub
(
order
[
1
],
order
[
3
]))
)
<
epsilon
:
t1
=
Triangle
(
order
[
0
],
order
[
1
],
order
[
2
])
t1
=
Triangle
(
order
[
0
],
order
[
1
],
order
[
2
])
t2
=
Triangle
(
order
[
2
],
order
[
3
],
order
[
0
])
t2
=
Triangle
(
order
[
2
],
order
[
3
],
order
[
0
])
if
t1
.
normal
==
t2
.
normal
==
normal
:
if
t1
.
normal
==
t2
.
normal
==
normal
:
...
@@ -1085,22 +1085,22 @@ class Rectangle(IDGenerator, TransformableContainer):
...
@@ -1085,22 +1085,22 @@ class Rectangle(IDGenerator, TransformableContainer):
self
.
reset_cache
()
self
.
reset_cache
()
def
reset_cache
(
self
):
def
reset_cache
(
self
):
self
.
maxx
=
max
([
p
.
x
for
p
in
self
.
get_points
()])
self
.
maxx
=
max
([
p
[
0
]
for
p
in
self
.
get_points
()])
self
.
minx
=
max
([
p
.
x
for
p
in
self
.
get_points
()])
self
.
minx
=
max
([
p
[
0
]
for
p
in
self
.
get_points
()])
self
.
maxy
=
max
([
p
.
y
for
p
in
self
.
get_points
()])
self
.
maxy
=
max
([
p
[
1
]
for
p
in
self
.
get_points
()])
self
.
miny
=
max
([
p
.
y
for
p
in
self
.
get_points
()])
self
.
miny
=
max
([
p
[
1
]
for
p
in
self
.
get_points
()])
self
.
maxz
=
max
([
p
.
z
for
p
in
self
.
get_points
()])
self
.
maxz
=
max
([
p
[
2
]
for
p
in
self
.
get_points
()])
self
.
minz
=
max
([
p
.
z
for
p
in
self
.
get_points
()])
self
.
minz
=
max
([
p
[
2
]
for
p
in
self
.
get_points
()])
self
.
normal
=
Triangle
(
self
.
p1
,
self
.
p2
,
self
.
p3
)
.
normal
.
normalized
(
)
self
.
normal
=
pnormalized
(
Triangle
(
self
.
p1
,
self
.
p2
,
self
.
p3
)
.
normal
)
def
get_points
(
self
):
def
get_points
(
self
):
return
(
self
.
p1
,
self
.
p2
,
self
.
p3
,
self
.
p4
)
return
(
self
.
p1
,
self
.
p2
,
self
.
p3
,
self
.
p4
)
def
next
(
self
):
def
next
(
self
):
yield
self
.
p1
yield
"p1"
yield
self
.
p2
yield
"p2"
yield
self
.
p3
yield
"p3"
yield
self
.
p4
yield
"p4"
def
__repr__
(
self
):
def
__repr__
(
self
):
return
"Rectangle
%
d<
%
s,
%
s,
%
s,
%
s>"
%
(
self
.
id
,
self
.
p1
,
self
.
p2
,
return
"Rectangle
%
d<
%
s,
%
s,
%
s,
%
s>"
%
(
self
.
id
,
self
.
p1
,
self
.
p2
,
...
@@ -1132,8 +1132,7 @@ class Rectangle(IDGenerator, TransformableContainer):
...
@@ -1132,8 +1132,7 @@ class Rectangle(IDGenerator, TransformableContainer):
if
len
(
unique_vertices
)
!=
2
:
if
len
(
unique_vertices
)
!=
2
:
log
.
error
(
"Invalid number of vertices:
%
s"
%
unique_vertices
)
log
.
error
(
"Invalid number of vertices:
%
s"
%
unique_vertices
)
return
None
return
None
if
abs
(
unique_vertices
[
0
]
.
sub
(
unique_vertices
[
1
])
.
norm
-
\
if
abs
(
pnorm
(
psub
(
unique_verticies
[
0
],
unique_verticies
[
1
]))
-
pnorm
(
psub
(
shared_vertices
[
0
],
shared_vertices
[
1
])))
<
epsilon
:
shared_vertices
[
0
]
.
sub
(
shared_vertices
[
1
])
.
norm
)
<
epsilon
:
try
:
try
:
return
Rectangle
(
unique_vertices
[
0
],
unique_vertices
[
1
],
return
Rectangle
(
unique_vertices
[
0
],
unique_vertices
[
1
],
shared_vertices
[
0
],
shared_vertices
[
1
],
shared_vertices
[
0
],
shared_vertices
[
1
],
...
...
pycam/Geometry/Plane.py
View file @
9b939792
...
@@ -22,7 +22,8 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,7 +22,8 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from
pycam.Geometry
import
TransformableContainer
,
IDGenerator
from
pycam.Geometry
import
TransformableContainer
,
IDGenerator
from
pycam.Geometry.utils
import
INFINITE
,
epsilon
from
pycam.Geometry.utils
import
INFINITE
,
epsilon
from
pycam.Geometry.Point
import
Vector
from
pycam.Geometry.PointUtils
import
*
# "Line" is imported later to avoid circular imports
# "Line" is imported later to avoid circular imports
#from pycam.Geometry.Line import Line
#from pycam.Geometry.Line import Line
...
@@ -34,11 +35,11 @@ class Plane(IDGenerator, TransformableContainer):
...
@@ -34,11 +35,11 @@ class Plane(IDGenerator, TransformableContainer):
def
__init__
(
self
,
point
,
normal
=
None
):
def
__init__
(
self
,
point
,
normal
=
None
):
super
(
Plane
,
self
)
.
__init__
()
super
(
Plane
,
self
)
.
__init__
()
if
normal
is
None
:
if
normal
is
None
:
normal
=
Vector
(
0
,
0
,
1
)
normal
=
(
0
,
0
,
1
,
'v'
)
self
.
p
=
point
self
.
p
=
point
self
.
n
=
normal
self
.
n
=
normal
if
not
isinstance
(
self
.
n
,
Vector
)
:
if
not
len
(
self
.
n
)
>
3
:
self
.
n
=
self
.
n
.
get_vector
(
)
self
.
n
=
(
self
.
n
[
0
],
self
.
n
[
1
],
self
.
n
[
2
],
'v'
)
def
__repr__
(
self
):
def
__repr__
(
self
):
return
"Plane<
%
s,
%
s>"
%
(
self
.
p
,
self
.
n
)
return
"Plane<
%
s,
%
s>"
%
(
self
.
p
,
self
.
n
)
...
@@ -53,11 +54,11 @@ class Plane(IDGenerator, TransformableContainer):
...
@@ -53,11 +54,11 @@ class Plane(IDGenerator, TransformableContainer):
return
cmp
(
str
(
self
),
str
(
other
))
return
cmp
(
str
(
self
),
str
(
other
))
def
copy
(
self
):
def
copy
(
self
):
return
self
.
__class__
(
self
.
p
.
copy
(),
self
.
n
.
copy
()
)
return
self
.
__class__
(
self
.
p
,
self
.
n
)
def
next
(
self
):
def
next
(
self
):
yield
self
.
p
yield
"p"
yield
self
.
n
yield
"n"
def
get_children_count
(
self
):
def
get_children_count
(
self
):
# a plane always consists of two points
# a plane always consists of two points
...
@@ -65,21 +66,21 @@ class Plane(IDGenerator, TransformableContainer):
...
@@ -65,21 +66,21 @@ class Plane(IDGenerator, TransformableContainer):
def
reset_cache
(
self
):
def
reset_cache
(
self
):
# we need to prevent the "normal" from growing
# we need to prevent the "normal" from growing
norm
=
self
.
n
.
normalized
(
)
norm
=
pnormalized
(
self
.
n
)
if
norm
:
if
norm
:
self
.
n
=
norm
self
.
n
=
norm
def
intersect_point
(
self
,
direction
,
point
):
def
intersect_point
(
self
,
direction
,
point
):
if
(
not
direction
is
None
)
and
(
direction
.
norm
!=
1
):
if
(
not
direction
is
None
)
and
(
pnorm
(
direction
)
!=
1
):
# calculations will go wrong, if the direction is not a unit vector
# calculations will go wrong, if the direction is not a unit vector
direction
=
direction
.
normalized
(
)
direction
=
pnormalized
(
direction
)
if
direction
is
None
:
if
direction
is
None
:
return
(
None
,
INFINITE
)
return
(
None
,
INFINITE
)
denom
=
self
.
n
.
dot
(
direction
)
denom
=
pdot
(
self
.
n
,
direction
)
if
denom
==
0
:
if
denom
==
0
:
return
(
None
,
INFINITE
)
return
(
None
,
INFINITE
)
l
=
-
(
self
.
n
.
dot
(
point
)
-
self
.
n
.
dot
(
self
.
p
))
/
denom
l
=
-
(
pdot
(
self
.
n
,
point
)
-
pdot
(
self
.
n
,
self
.
p
))
/
denom
cp
=
p
oint
.
add
(
direction
.
mul
(
l
))
cp
=
p
add
(
point
,
pmul
(
direction
,
l
))
return
(
cp
,
l
)
return
(
cp
,
l
)
def
intersect_triangle
(
self
,
triangle
,
counter_clockwise
=
False
):
def
intersect_triangle
(
self
,
triangle
,
counter_clockwise
=
False
):
...
@@ -101,7 +102,7 @@ class Plane(IDGenerator, TransformableContainer):
...
@@ -101,7 +102,7 @@ class Plane(IDGenerator, TransformableContainer):
# a distance that is lower than the length of the edge.
# a distance that is lower than the length of the edge.
if
(
not
cp
is
None
)
and
(
-
epsilon
<
l
<
edge
.
len
-
epsilon
):
if
(
not
cp
is
None
)
and
(
-
epsilon
<
l
<
edge
.
len
-
epsilon
):
collisions
.
append
(
cp
)
collisions
.
append
(
cp
)
elif
(
cp
is
None
)
and
(
self
.
n
.
dot
(
edge
.
dir
)
==
0
):
elif
(
cp
is
None
)
and
(
pdot
(
self
.
n
,
edge
.
dir
)
==
0
):
cp
,
dist
=
self
.
intersect_point
(
self
.
n
,
point
)
cp
,
dist
=
self
.
intersect_point
(
self
.
n
,
point
)
if
abs
(
dist
)
<
epsilon
:
if
abs
(
dist
)
<
epsilon
:
# the edge is on the plane
# the edge is on the plane
...
@@ -116,8 +117,8 @@ class Plane(IDGenerator, TransformableContainer):
...
@@ -116,8 +117,8 @@ class Plane(IDGenerator, TransformableContainer):
# no further calculation, if the line is zero-sized
# no further calculation, if the line is zero-sized
if
collision_line
.
len
==
0
:
if
collision_line
.
len
==
0
:
return
collision_line
return
collision_line
cross
=
self
.
n
.
cross
(
collision_line
.
dir
)
cross
=
pcross
(
self
.
n
,
collision_line
.
dir
)
if
(
cross
.
dot
(
triangle
.
normal
)
<
0
)
==
bool
(
not
counter_clockwise
):
if
(
pdot
(
cross
,
triangle
.
normal
)
<
0
)
==
bool
(
not
counter_clockwise
):
# anti-clockwise direction -> revert the direction of the line
# anti-clockwise direction -> revert the direction of the line
collision_line
=
Line
(
collision_line
.
p2
,
collision_line
.
p1
)
collision_line
=
Line
(
collision_line
.
p2
,
collision_line
.
p1
)
return
collision_line
return
collision_line
...
...
pycam/Geometry/Point.py
deleted
100755 → 0
View file @
df4e35e1
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
Copyright 2008-2009 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from
pycam.Geometry.utils
import
epsilon
,
sqrt
,
number
from
pycam.Geometry
import
IDGenerator
def
_is_near
(
x
,
y
):
return
abs
(
x
-
y
)
<
epsilon
class
Point
(
IDGenerator
):
__slots__
=
[
"id"
,
"x"
,
"y"
,
"z"
,
"_norm"
,
"_normsq"
]
def
__init__
(
self
,
x
,
y
,
z
):
super
(
Point
,
self
)
.
__init__
()
self
.
x
=
number
(
x
)
self
.
y
=
number
(
y
)
self
.
z
=
number
(
z
)
self
.
reset_cache
()
@
property
def
norm
(
self
):
if
self
.
_norm
is
None
:
self
.
_norm
=
sqrt
(
self
.
normsq
)
return
self
.
_norm
@
property
def
normsq
(
self
):
if
self
.
_normsq
is
None
:
self
.
_normsq
=
self
.
dot
(
self
)
return
self
.
_normsq
def
copy
(
self
):
return
self
.
__class__
(
float
(
self
.
x
),
float
(
self
.
y
),
float
(
self
.
z
))
def
__repr__
(
self
):
return
"Point
%
d<
%
g,
%
g,
%
g>"
%
(
self
.
id
,
self
.
x
,
self
.
y
,
self
.
z
)
def
__cmp__
(
self
,
other
):
""" Two points are equal if all dimensions are identical.
Otherwise the result is based on the individual x/y/z comparisons.
"""
if
self
.
__class__
==
other
.
__class__
:
if
(
self
.
id
==
other
.
id
)
or
\
((
_is_near
(
self
.
x
,
other
.
x
))
and
\
(
_is_near
(
self
.
y
,
other
.
y
))
and
\
(
_is_near
(
self
.
z
,
other
.
z
))):
return
0
elif
not
_is_near
(
self
.
x
,
other
.
x
):
return
cmp
(
self
.
x
,
other
.
x
)
elif
not
_is_near
(
self
.
y
,
other
.
y
):
return
cmp
(
self
.
y
,
other
.
y
)
else
:
return
cmp
(
self
.
z
,
other
.
z
)
else
:
return
cmp
(
str
(
self
),
str
(
other
))
def
transform_by_matrix
(
self
,
matrix
,
transformed_list
=
None
,
callback
=
None
):
# accept 3x4 matrices as well as 3x3 matrices
offsets
=
[]
for
column
in
matrix
:
if
len
(
column
)
<
4
:
offsets
.
append
(
0
)
else
:
offsets
.
append
(
column
[
3
])
x
=
self
.
x
*
matrix
[
0
][
0
]
+
self
.
y
*
matrix
[
0
][
1
]
\
+
self
.
z
*
matrix
[
0
][
2
]
+
offsets
[
0
]
y
=
self
.
x
*
matrix
[
1
][
0
]
+
self
.
y
*
matrix
[
1
][
1
]
\
+
self
.
z
*
matrix
[
1
][
2
]
+
offsets
[
1
]
z
=
self
.
x
*
matrix
[
2
][
0
]
+
self
.
y
*
matrix
[
2
][
1
]
\
+
self
.
z
*
matrix
[
2
][
2
]
+
offsets
[
2
]
self
.
x
=
x
self
.
y
=
y
self
.
z
=
z
if
callback
:
callback
()
self
.
reset_cache
()
def
reset_cache
(
self
):
self
.
_norm
=
None
self
.
_normsq
=
None
def
mul
(
self
,
c
):
c
=
number
(
c
)
return
Point
(
self
.
x
*
c
,
self
.
y
*
c
,
self
.
z
*
c
)
def
div
(
self
,
c
):
c
=
number
(
c
)
return
Point
(
self
.
x
/
c
,
self
.
y
/
c
,
self
.
z
/
c
)
def
add
(
self
,
p
):
return
Point
(
self
.
x
+
p
.
x
,
self
.
y
+
p
.
y
,
self
.
z
+
p
.
z
)
def
sub
(
self
,
p
):
return
Point
(
self
.
x
-
p
.
x
,
self
.
y
-
p
.
y
,
self
.
z
-
p
.
z
)
def
dot
(
self
,
p
):
return
self
.
x
*
p
.
x
+
self
.
y
*
p
.
y
+
self
.
z
*
p
.
z
def
cross
(
self
,
p
):
return
Point
(
self
.
y
*
p
.
z
-
p
.
y
*
self
.
z
,
p
.
x
*
self
.
z
-
self
.
x
*
p
.
z
,
self
.
x
*
p
.
y
-
p
.
x
*
self
.
y
)
def
normalized
(
self
):
n
=
self
.
norm
if
n
==
0
:
return
None
else
:
return
self
.
__class__
(
self
.
x
/
n
,
self
.
y
/
n
,
self
.
z
/
n
)
def
is_inside
(
self
,
minx
=
None
,
maxx
=
None
,
miny
=
None
,
maxy
=
None
,
minz
=
None
,
maxz
=
None
):
return
((
minx
is
None
)
or
(
minx
-
epsilon
<=
self
.
x
))
\
and
((
maxx
is
None
)
or
(
self
.
x
<=
maxx
+
epsilon
))
\
and
((
miny
is
None
)
or
(
miny
-
epsilon
<=
self
.
y
))
\
and
((
maxy
is
None
)
or
(
self
.
y
<=
maxy
+
epsilon
))
\
and
((
minz
is
None
)
or
(
minz
-
epsilon
<=
self
.
z
))
\
and
((
maxz
is
None
)
or
(
self
.
z
<=
maxz
+
epsilon
))
def
get_vector
(
self
):
return
Vector
(
self
.
x
,
self
.
y
,
self
.
z
)
class
Vector
(
Point
):
""" The Vector class is similar to the Point class. The only difference
is that vectors are not shifted during transformations. This feature
is necessary for normals (e.g. of Triangles or Planes).
"""
__slots__
=
[]
def
transform_by_matrix
(
self
,
matrix
,
transformed_list
=
None
,
callback
=
None
):
x
=
self
.
x
*
matrix
[
0
][
0
]
+
self
.
y
*
matrix
[
0
][
1
]
\
+
self
.
z
*
matrix
[
0
][
2
]
y
=
self
.
x
*
matrix
[
1
][
0
]
+
self
.
y
*
matrix
[
1
][
1
]
\
+
self
.
z
*
matrix
[
1
][
2
]
z
=
self
.
x
*
matrix
[
2
][
0
]
+
self
.
y
*
matrix
[
2
][
1
]
\
+
self
.
z
*
matrix
[
2
][
2
]
self
.
x
=
x
self
.
y
=
y
self
.
z
=
z
if
callback
:
callback
()
self
.
reset_cache
()
def
__repr__
(
self
):
return
"Vector
%
d<
%
g,
%
g,
%
g>"
%
(
self
.
id
,
self
.
x
,
self
.
y
,
self
.
z
)
pycam/Geometry/PointKdtree.py
View file @
9b939792
...
@@ -21,7 +21,6 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -21,7 +21,6 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.utils
import
epsilon
from
pycam.Geometry.utils
import
epsilon
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.kdtree
import
Node
,
kdtree
from
pycam.Geometry.kdtree
import
Node
,
kdtree
...
@@ -37,7 +36,7 @@ class PointKdtree(kdtree):
...
@@ -37,7 +36,7 @@ class PointKdtree(kdtree):
self
.
tolerance
=
tolerance
self
.
tolerance
=
tolerance
nodes
=
[]
nodes
=
[]
for
p
in
points
:
for
p
in
points
:
n
=
Node
(
p
,
(
p
.
x
,
p
.
y
,
p
.
z
)
)
n
=
Node
(
p
,
p
)
nodes
.
append
(
n
)
nodes
.
append
(
n
)
kdtree
.
__init__
(
self
,
nodes
,
cutoff
,
cutoff_distance
)
kdtree
.
__init__
(
self
,
nodes
,
cutoff
,
cutoff_distance
)
...
@@ -48,7 +47,6 @@ class PointKdtree(kdtree):
...
@@ -48,7 +47,6 @@ class PointKdtree(kdtree):
return
dx
*
dx
+
dy
*
dy
+
dz
*
dz
return
dx
*
dx
+
dy
*
dy
+
dz
*
dz
def
Point
(
self
,
x
,
y
,
z
):
def
Point
(
self
,
x
,
y
,
z
):
#return Point(x,y,z)
if
self
.
_n
:
if
self
.
_n
:
n
=
self
.
_n
n
=
self
.
_n
n
.
bound
=
(
x
,
y
,
z
)
n
.
bound
=
(
x
,
y
,
z
)
...
@@ -59,7 +57,7 @@ class PointKdtree(kdtree):
...
@@ -59,7 +57,7 @@ class PointKdtree(kdtree):
self
.
_n
=
n
self
.
_n
=
n
return
nn
.
obj
return
nn
.
obj
else
:
else
:
n
.
obj
=
Point
(
x
,
y
,
z
)
n
.
obj
=
(
x
,
y
,
z
)
self
.
_n
=
None
self
.
_n
=
None
self
.
insert
(
n
)
self
.
insert
(
n
)
return
n
.
obj
return
n
.
obj
...
...
pycam/Geometry/PointUtils.py
0 → 100644
View file @
9b939792
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
Copyright 2008-2009 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from
pycam.Geometry.utils
import
epsilon
,
sqrt
,
number
def
_is_near
(
x
,
y
):
return
abs
(
x
-
y
)
<
epsilon
def
pnorm
(
a
):
return
sqrt
(
pdot
(
a
,
a
))
def
pnormsq
(
a
):
return
pdot
(
a
,
a
)
def
pcmp
(
a
,
b
):
""" Two points are equal if all dimensions are identical.
Otherwise the result is based on the individual x/y/z comparisons.
"""
if
(
_is_near
(
a
[
0
],
b
[
0
])
and
_is_near
(
a
[
1
],
b
[
1
])
and
_is_near
(
a
[
2
],
b
[
2
])):
return
0
elif
not
_is_near
(
a
[
0
],
b
[
0
]):
return
cmp
(
a
[
0
],
b
[
0
])
elif
not
_is_near
(
a
[
1
],
b
[
1
]):
return
cmp
(
a
[
1
],
b
[
1
])
else
:
return
cmp
(
a
[
2
],
b
[
2
])
def
ptransform_by_matrix
(
a
,
matrix
,
transformed_list
=
None
):
if
len
(
a
)
>
3
:
return
(
a
[
0
]
*
matrix
[
0
][
0
]
+
a
[
1
]
*
matrix
[
0
][
1
]
+
a
[
2
]
*
matrix
[
0
][
2
],
a
[
0
]
*
matrix
[
1
][
0
]
+
a
[
1
]
*
matrix
[
1
][
1
]
+
a
[
2
]
*
matrix
[
1
][
2
],
a
[
0
]
*
matrix
[
2
][
0
]
+
a
[
1
]
*
matrix
[
2
][
1
]
+
a
[
2
]
*
matrix
[
2
][
2
])
+
a
[
3
:]
else
:
# accept 3x4 matrices as well as 3x3 matrices
offsets
=
[]
for
column
in
matrix
:
if
len
(
column
)
<
4
:
offsets
.
append
(
0
)
else
:
offsets
.
append
(
column
[
3
])
return
(
a
[
0
]
*
matrix
[
0
][
0
]
+
a
[
1
]
*
matrix
[
0
][
1
]
+
a
[
2
]
*
matrix
[
0
][
2
]
+
offsets
[
0
],
a
[
0
]
*
matrix
[
1
][
0
]
+
a
[
1
]
*
matrix
[
1
][
1
]
+
a
[
2
]
*
matrix
[
1
][
2
]
+
offsets
[
1
],
a
[
0
]
*
matrix
[
2
][
0
]
+
a
[
1
]
*
matrix
[
2
][
1
]
+
a
[
2
]
*
matrix
[
2
][
2
]
+
offsets
[
2
])
def
pmul
(
a
,
c
):
c
=
number
(
c
)
return
(
a
[
0
]
*
c
,
a
[
1
]
*
c
,
a
[
2
]
*
c
)
def
pdiv
(
a
,
c
):
c
=
number
(
c
)
return
(
a
[
0
]
/
c
,
a
[
0
]
/
c
,
a
[
0
]
/
c
)
def
padd
(
a
,
b
):
return
(
a
[
0
]
+
b
[
0
],
a
[
1
]
+
b
[
1
],
a
[
2
]
+
b
[
2
])
def
psub
(
a
,
b
):
return
(
a
[
0
]
-
b
[
0
],
a
[
1
]
-
b
[
1
],
a
[
2
]
-
b
[
2
])
def
pdot
(
a
,
b
):
return
a
[
0
]
*
b
[
0
]
+
a
[
1
]
*
b
[
1
]
+
a
[
2
]
*
b
[
2
]
def
pcross
(
a
,
b
):
return
(
a
[
1
]
*
b
[
2
]
-
b
[
1
]
*
a
[
2
],
b
[
0
]
*
a
[
2
]
-
a
[
0
]
*
b
[
2
],
a
[
0
]
*
b
[
1
]
-
b
[
0
]
*
a
[
1
])
def
pnormalized
(
a
):
n
=
pnorm
(
a
)
if
n
==
0
:
return
None
else
:
return
(
a
[
0
]
/
n
,
a
[
1
]
/
n
,
a
[
2
]
/
n
)
+
a
[
3
:]
def
pis_inside
(
a
,
minx
=
None
,
maxx
=
None
,
miny
=
None
,
maxy
=
None
,
minz
=
None
,
maxz
=
None
):
return
((
minx
is
None
)
or
(
minx
-
epsilon
<=
a
[
0
]))
\
and
((
maxx
is
None
)
or
(
a
[
0
]
<=
maxx
+
epsilon
))
\
and
((
miny
is
None
)
or
(
miny
-
epsilon
<=
a
[
1
]))
\
and
((
maxy
is
None
)
or
(
a
[
1
]
<=
maxy
+
epsilon
))
\
and
((
minz
is
None
)
or
(
minz
-
epsilon
<=
a
[
2
]))
\
and
((
maxz
is
None
)
or
(
a
[
2
]
<=
maxz
+
epsilon
))
pycam/Geometry/Polygon.py
View file @
9b939792
...
@@ -21,11 +21,12 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -21,11 +21,12 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry
import
TransformableContainer
,
IDGenerator
,
get_bisector
from
pycam.Geometry
import
TransformableContainer
,
IDGenerator
,
get_bisector
from
pycam.Geometry.utils
import
number
,
epsilon
from
pycam.Geometry.utils
import
number
,
epsilon
import
pycam.Utils.log
from
pycam.Utils
import
log
log
=
log
.
get_logger
()
# import later to avoid circular imports
# import later to avoid circular imports
#from pycam.Geometry.Model import ContourModel
#from pycam.Geometry.Model import ContourModel
...
@@ -39,9 +40,6 @@ except ImportError:
...
@@ -39,9 +40,6 @@ except ImportError:
LINE_WIDTH_INNER
=
0.7
LINE_WIDTH_INNER
=
0.7
LINE_WIDTH_OUTER
=
1.3
LINE_WIDTH_OUTER
=
1.3
log
=
pycam
.
Utils
.
log
.
get_logger
()
class
PolygonInTree
(
IDGenerator
):
class
PolygonInTree
(
IDGenerator
):
""" This class is a wrapper around Polygon objects that is used for sorting.
""" This class is a wrapper around Polygon objects that is used for sorting.
"""
"""
...
@@ -73,7 +71,7 @@ class PolygonInTree(IDGenerator):
...
@@ -73,7 +71,7 @@ class PolygonInTree(IDGenerator):
pass
pass
def
get_cost
(
self
,
other
):
def
get_cost
(
self
,
other
):
return
other
.
start
.
sub
(
self
.
end
)
.
norm
return
pnorm
(
psub
(
other
.
start
,
self
.
end
))
class
PolygonPositionSorter
(
object
):
class
PolygonPositionSorter
(
object
):
...
@@ -218,7 +216,7 @@ class Polygon(TransformableContainer):
...
@@ -218,7 +216,7 @@ class Polygon(TransformableContainer):
super
(
Polygon
,
self
)
.
__init__
()
super
(
Polygon
,
self
)
.
__init__
()
if
plane
is
None
:
if
plane
is
None
:
# the default plane points upwards along the z axis
# the default plane points upwards along the z axis
plane
=
Plane
(
Point
(
0
,
0
,
0
),
Vector
(
0
,
0
,
1
))
plane
=
Plane
(
(
0
,
0
,
0
),
(
0
,
0
,
1
,
'v'
))
self
.
plane
=
plane
self
.
plane
=
plane
self
.
_points
=
[]
self
.
_points
=
[]
self
.
is_closed
=
False
self
.
is_closed
=
False
...
@@ -252,8 +250,7 @@ class Polygon(TransformableContainer):
...
@@ -252,8 +250,7 @@ class Polygon(TransformableContainer):
self
.
_update_limits
(
line
.
p2
)
self
.
_update_limits
(
line
.
p2
)
elif
self
.
_points
[
-
1
]
==
line
.
p1
:
elif
self
.
_points
[
-
1
]
==
line
.
p1
:
# the new Line can be added to the end of the polygon
# the new Line can be added to the end of the polygon
if
line
.
dir
==
self
.
_points
[
-
1
]
.
sub
(
if
line
.
dir
==
pnormalized
(
psub
(
self
.
_points
[
-
1
],
self
.
_points
[
-
2
])):
self
.
_points
[
-
2
])
.
normalized
():
# Remove the last point, if the previous point combination
# Remove the last point, if the previous point combination
# is in line with the new Line. This avoids unnecessary
# is in line with the new Line. This avoids unnecessary
# points on straight lines.
# points on straight lines.
...
@@ -267,9 +264,7 @@ class Polygon(TransformableContainer):
...
@@ -267,9 +264,7 @@ class Polygon(TransformableContainer):
self
.
reset_cache
()
self
.
reset_cache
()
else
:
else
:
# the new Line can be added to the beginning of the polygon
# the new Line can be added to the beginning of the polygon
if
(
len
(
self
.
_points
)
>
1
)
\
if
(
len
(
self
.
_points
)
>
1
)
and
(
line
.
dir
==
pnormalized
(
psub
(
self
.
_points
[
1
],
self
.
_points
[
0
]))):
and
(
line
.
dir
==
self
.
_points
[
1
]
.
sub
(
self
.
_points
[
0
])
.
normalized
()):
# Avoid points on straight lines - see above.
# Avoid points on straight lines - see above.
self
.
_points
.
pop
(
0
)
self
.
_points
.
pop
(
0
)
if
line
.
p1
!=
self
.
_points
[
-
1
]:
if
line
.
p1
!=
self
.
_points
[
-
1
]:
...
@@ -325,8 +320,7 @@ class Polygon(TransformableContainer):
...
@@ -325,8 +320,7 @@ class Polygon(TransformableContainer):
return
False
return
False
def
next
(
self
):
def
next
(
self
):
for
point
in
self
.
_points
:
yield
"_points"
yield
point
yield
self
.
plane
yield
self
.
plane
def
get_children_count
(
self
):
def
get_children_count
(
self
):
...
@@ -350,11 +344,11 @@ class Polygon(TransformableContainer):
...
@@ -350,11 +344,11 @@ class Polygon(TransformableContainer):
for
index
in
range
(
len
(
self
.
_points
)):
for
index
in
range
(
len
(
self
.
_points
)):
p1
=
self
.
_points
[
index
]
p1
=
self
.
_points
[
index
]
p2
=
self
.
_points
[(
index
+
1
)
%
len
(
self
.
_points
)]
p2
=
self
.
_points
[(
index
+
1
)
%
len
(
self
.
_points
)]
value
[
0
]
+=
p1
.
y
*
p2
.
z
-
p1
.
z
*
p2
.
y
value
[
0
]
+=
p1
[
1
]
*
p2
[
2
]
-
p1
[
2
]
*
p2
[
1
]
value
[
1
]
+=
p1
.
z
*
p2
.
x
-
p1
.
x
*
p2
.
z
value
[
1
]
+=
p1
[
2
]
*
p2
[
0
]
-
p1
[
0
]
*
p2
[
2
]
value
[
2
]
+=
p1
.
x
*
p2
.
y
-
p1
.
y
*
p2
.
x
value
[
2
]
+=
p1
[
0
]
*
p2
[
1
]
-
p1
[
1
]
*
p2
[
0
]
result
=
self
.
plane
.
n
.
x
*
value
[
0
]
+
self
.
plane
.
n
.
y
*
value
[
1
]
\
result
=
self
.
plane
.
n
[
0
]
*
value
[
0
]
+
self
.
plane
.
n
[
1
]
*
value
[
1
]
\
+
self
.
plane
.
n
.
z
*
value
[
2
]
+
self
.
plane
.
n
[
2
]
*
value
[
2
]
self
.
_area_cache
=
result
/
2
self
.
_area_cache
=
result
/
2
return
self
.
_area_cache
return
self
.
_area_cache
...
@@ -368,26 +362,23 @@ class Polygon(TransformableContainer):
...
@@ -368,26 +362,23 @@ class Polygon(TransformableContainer):
for
index
in
range
(
len
(
self
.
_points
)):
for
index
in
range
(
len
(
self
.
_points
)):
p1
=
self
.
_points
[
index
]
p1
=
self
.
_points
[
index
]
p2
=
self
.
_points
[(
index
+
1
)
%
len
(
self
.
_points
)]
p2
=
self
.
_points
[(
index
+
1
)
%
len
(
self
.
_points
)]
cxy
+=
(
p1
.
x
+
p2
.
x
)
*
(
p1
.
x
*
p2
.
y
-
p1
.
y
*
p2
.
x
)
cxy
+=
(
p1
[
0
]
+
p2
[
0
])
*
(
p1
[
0
]
*
p2
[
1
]
-
p1
[
1
]
*
p2
[
0
]
)
cxz
+=
(
p1
.
x
+
p2
.
x
)
*
(
p1
.
x
*
p2
.
z
-
p1
.
z
*
p2
.
x
)
cxz
+=
(
p1
[
0
]
+
p2
[
0
])
*
(
p1
[
0
]
*
p2
[
2
]
-
p1
[
2
]
*
p2
[
0
]
)
cyx
+=
(
p1
.
y
+
p2
.
y
)
*
(
p1
.
x
*
p2
.
y
-
p1
.
y
*
p2
.
x
)
cyx
+=
(
p1
[
1
]
+
p2
[
1
])
*
(
p1
[
0
]
*
p2
[
1
]
-
p1
[
1
]
*
p2
[
0
]
)
cyz
+=
(
p1
.
y
+
p2
.
y
)
*
(
p1
.
y
*
p2
.
z
-
p1
.
z
*
p2
.
y
)
cyz
+=
(
p1
[
1
]
+
p2
[
1
])
*
(
p1
[
1
]
*
p2
[
2
]
-
p1
[
2
]
*
p2
[
1
]
)
czx
+=
(
p1
.
z
+
p2
.
z
)
*
(
p1
.
z
*
p2
.
x
-
p1
.
x
*
p2
.
z
)
czx
+=
(
p1
[
2
]
+
p2
[
2
])
*
(
p1
[
2
]
*
p2
[
0
]
-
p1
[
0
]
*
p2
[
2
]
)
czy
+=
(
p1
.
z
+
p2
.
z
)
*
(
p1
.
y
*
p2
.
z
-
p1
.
z
*
p2
.
y
)
czy
+=
(
p1
[
2
]
+
p2
[
2
])
*
(
p1
[
1
]
*
p2
[
2
]
-
p1
[
2
]
*
p2
[
1
]
)
if
abs
(
self
.
maxz
-
self
.
minz
)
<
epsilon
:
if
abs
(
self
.
maxz
-
self
.
minz
)
<
epsilon
:
return
Point
(
cxy
/
(
6
*
area
),
cyx
/
(
6
*
area
),
self
.
minz
)
return
(
cxy
/
(
6
*
area
),
cyx
/
(
6
*
area
),
self
.
minz
)
elif
abs
(
self
.
maxy
-
self
.
miny
)
<
epsilon
:
elif
abs
(
self
.
maxy
-
self
.
miny
)
<
epsilon
:
return
Point
(
cxz
/
(
6
*
area
),
self
.
miny
,
czx
/
(
6
*
area
))
return
(
cxz
/
(
6
*
area
),
self
.
miny
,
czx
/
(
6
*
area
))
elif
abs
(
self
.
maxx
-
self
.
minx
)
<
epsilon
:
elif
abs
(
self
.
maxx
-
self
.
minx
)
<
epsilon
:
return
Point
(
self
.
minx
,
cyz
/
(
6
*
area
),
czy
/
(
6
*
area
))
return
(
self
.
minx
,
cyz
/
(
6
*
area
),
czy
/
(
6
*
area
))
else
:
else
:
# calculate area of xy projection
# calculate area of xy projection
poly_xy
=
self
.
get_plane_projection
(
Plane
(
Point
(
0
,
0
,
0
),
poly_xy
=
self
.
get_plane_projection
(
Plane
((
0
,
0
,
0
),(
0
,
0
,
1
)))
Point
(
0
,
0
,
1
)))
poly_xz
=
self
.
get_plane_projection
(
Plane
((
0
,
0
,
0
),(
0
,
1
,
0
)))
poly_xz
=
self
.
get_plane_projection
(
Plane
(
Point
(
0
,
0
,
0
),
poly_yz
=
self
.
get_plane_projection
(
Plane
((
0
,
0
,
0
),(
1
,
0
,
0
)))
Point
(
0
,
1
,
0
)))
poly_yz
=
self
.
get_plane_projection
(
Plane
(
Point
(
0
,
0
,
0
),
Point
(
1
,
0
,
0
)))
if
(
poly_xy
is
None
)
or
(
poly_xz
is
None
)
or
(
poly_yz
is
None
):
if
(
poly_xy
is
None
)
or
(
poly_xz
is
None
)
or
(
poly_yz
is
None
):
log
.
warn
(
"Invalid polygon projection for barycenter:
%
s"
\
log
.
warn
(
"Invalid polygon projection for barycenter:
%
s"
\
%
str
(
self
))
%
str
(
self
))
...
@@ -421,16 +412,14 @@ class Polygon(TransformableContainer):
...
@@ -421,16 +412,14 @@ class Polygon(TransformableContainer):
or
(
not
self
.
is_closed
and
index
==
len
(
self
.
_points
)
-
1
):
or
(
not
self
.
is_closed
and
index
==
len
(
self
.
_points
)
-
1
):
return
None
return
None
else
:
else
:
return
self
.
_points
[
index
]
.
add
(
self
.
_points
[(
index
+
1
)
%
\
return
pdiv
(
padd
(
self
.
_points
[
index
],
self
.
_points
[(
index
+
1
)
%
len
(
self
.
_points
)]),
2
)
len
(
self
.
_points
)])
.
div
(
2
)
def
get_lengths
(
self
):
def
get_lengths
(
self
):
result
=
[]
result
=
[]
for
index
in
range
(
len
(
self
.
_points
)
-
1
):
for
index
in
range
(
len
(
self
.
_points
)
-
1
):
result
.
append
(
self
.
_points
[
index
+
1
]
.
sub
(
result
.
append
(
pnorm
(
psub
(
self
.
_points
[
index
+
1
],
self
.
_points
[
index
])))
self
.
_points
[
index
])
.
norm
)
if
self
.
is_closed
:
if
self
.
is_closed
:
result
.
append
(
self
.
_points
[
0
]
.
sub
(
self
.
_points
[
-
1
])
.
norm
)
result
.
append
(
pnorm
(
psub
(
self
.
_points
[
0
],
self
.
_points
[
-
1
]))
)
return
result
return
result
def
get_max_inside_distance
(
self
):
def
get_max_inside_distance
(
self
):
...
@@ -438,12 +427,12 @@ class Polygon(TransformableContainer):
...
@@ -438,12 +427,12 @@ class Polygon(TransformableContainer):
"""
"""
if
len
(
self
.
_points
)
<
2
:
if
len
(
self
.
_points
)
<
2
:
return
None
return
None
distance
=
self
.
_points
[
1
]
.
sub
(
self
.
_points
[
0
])
.
norm
distance
=
pnorm
(
psub
(
self
.
_points
[
1
],
self
.
_points
[
0
]))
for
p1
in
self
.
_points
:
for
p1
in
self
.
_points
:
for
p2
in
self
.
_points
:
for
p2
in
self
.
_points
:
if
p1
is
p2
:
if
p1
is
p2
:
continue
continue
distance
=
max
(
distance
,
p
2
.
sub
(
p1
)
.
norm
)
distance
=
max
(
distance
,
p
norm
(
psub
(
p2
,
p1
))
)
return
distance
return
distance
def
is_outer
(
self
):
def
is_outer
(
self
):
...
@@ -474,8 +463,7 @@ class Polygon(TransformableContainer):
...
@@ -474,8 +463,7 @@ class Polygon(TransformableContainer):
if
not
self
.
is_closed
:
if
not
self
.
is_closed
:
return
False
return
False
# First: check if the point is within the boundary of the polygon.
# First: check if the point is within the boundary of the polygon.
if
not
p
.
is_inside
(
self
.
minx
,
self
.
maxx
,
self
.
miny
,
self
.
maxy
,
if
not
pis_inside
(
p
,
self
.
minx
,
self
.
maxx
,
self
.
miny
,
self
.
maxy
,
self
.
minz
,
self
.
maxz
):
self
.
minz
,
self
.
maxz
):
# the point is outside the rectangle boundary
# the point is outside the rectangle boundary
return
False
return
False
# see http://www.alienryderflex.com/polygon/
# see http://www.alienryderflex.com/polygon/
...
@@ -491,14 +479,14 @@ class Polygon(TransformableContainer):
...
@@ -491,14 +479,14 @@ class Polygon(TransformableContainer):
# the y level of the point. This solves the problem of intersections
# the y level of the point. This solves the problem of intersections
# through shared vertices or lines that go along the y level of the
# through shared vertices or lines that go along the y level of the
# point.
# point.
if
((
p1
.
y
<
p
.
y
)
and
(
p
.
y
<=
p2
.
y
))
\
if
((
p1
[
1
]
<
p
[
1
])
and
(
p
[
1
]
<=
p2
[
1
]
))
\
or
((
p2
.
y
<
p
.
y
)
and
(
p
.
y
<=
p1
.
y
)):
or
((
p2
[
1
]
<
p
[
1
])
and
(
p
[
1
]
<=
p1
[
1
]
)):
part_y
=
(
p
.
y
-
p1
.
y
)
/
(
p2
.
y
-
p1
.
y
)
part_y
=
(
p
[
1
]
-
p1
[
1
])
/
(
p2
[
1
]
-
p1
[
1
]
)
intersection_x
=
p1
.
x
+
part_y
*
(
p2
.
x
-
p1
.
x
)
intersection_x
=
p1
[
0
]
+
part_y
*
(
p2
[
0
]
-
p1
[
0
]
)
if
intersection_x
<
p
.
x
+
epsilon
:
if
intersection_x
<
p
[
0
]
+
epsilon
:
# count intersections to the left
# count intersections to the left
intersection_count_left
+=
1
intersection_count_left
+=
1
if
intersection_x
>
p
.
x
-
epsilon
:
if
intersection_x
>
p
[
0
]
-
epsilon
:
# count intersections to the right
# count intersections to the right
intersection_count_right
+=
1
intersection_count_right
+=
1
# odd intersection count -> inside
# odd intersection count -> inside
...
@@ -548,7 +536,7 @@ class Polygon(TransformableContainer):
...
@@ -548,7 +536,7 @@ class Polygon(TransformableContainer):
GL
.
glLineWidth
(
LINE_WIDTH_OUTER
)
GL
.
glLineWidth
(
LINE_WIDTH_OUTER
)
GL
.
glBegin
(
GL
.
GL_LINE_LOOP
)
GL
.
glBegin
(
GL
.
GL_LINE_LOOP
)
for
point
in
self
.
_points
:
for
point
in
self
.
_points
:
GL
.
glVertex3f
(
point
.
x
,
point
.
y
,
point
.
z
)
GL
.
glVertex3f
(
point
[
0
],
point
[
1
],
point
[
2
]
)
GL
.
glEnd
()
GL
.
glEnd
()
if
not
is_outer
:
if
not
is_outer
:
GL
.
glColor
(
*
color
)
GL
.
glColor
(
*
color
)
...
@@ -560,19 +548,19 @@ class Polygon(TransformableContainer):
...
@@ -560,19 +548,19 @@ class Polygon(TransformableContainer):
def
_update_limits
(
self
,
point
):
def
_update_limits
(
self
,
point
):
if
self
.
minx
is
None
:
if
self
.
minx
is
None
:
self
.
minx
=
point
.
x
self
.
minx
=
point
[
0
]
self
.
maxx
=
point
.
x
self
.
maxx
=
point
[
0
]
self
.
miny
=
point
.
y
self
.
miny
=
point
[
1
]
self
.
maxy
=
point
.
y
self
.
maxy
=
point
[
1
]
self
.
minz
=
point
.
z
self
.
minz
=
point
[
2
]
self
.
maxz
=
point
.
z
self
.
maxz
=
point
[
2
]
else
:
else
:
self
.
minx
=
min
(
self
.
minx
,
point
.
x
)
self
.
minx
=
min
(
self
.
minx
,
point
[
0
]
)
self
.
maxx
=
max
(
self
.
maxx
,
point
.
x
)
self
.
maxx
=
max
(
self
.
maxx
,
point
[
0
]
)
self
.
miny
=
min
(
self
.
miny
,
point
.
y
)
self
.
miny
=
min
(
self
.
miny
,
point
[
1
]
)
self
.
maxy
=
max
(
self
.
maxy
,
point
.
y
)
self
.
maxy
=
max
(
self
.
maxy
,
point
[
1
]
)
self
.
minz
=
min
(
self
.
minz
,
point
.
z
)
self
.
minz
=
min
(
self
.
minz
,
point
[
2
]
)
self
.
maxz
=
max
(
self
.
maxz
,
point
.
z
)
self
.
maxz
=
max
(
self
.
maxz
,
point
[
2
]
)
self
.
_lines_cache
=
None
self
.
_lines_cache
=
None
self
.
_area_cache
=
None
self
.
_area_cache
=
None
...
@@ -596,12 +584,12 @@ class Polygon(TransformableContainer):
...
@@ -596,12 +584,12 @@ class Polygon(TransformableContainer):
def
get_shifted_vertex
(
index
,
offset
):
def
get_shifted_vertex
(
index
,
offset
):
p1
=
self
.
_points
[
index
]
p1
=
self
.
_points
[
index
]
p2
=
self
.
_points
[(
index
+
1
)
%
len
(
self
.
_points
)]
p2
=
self
.
_points
[(
index
+
1
)
%
len
(
self
.
_points
)]
cross_offset
=
p
2
.
sub
(
p1
)
.
cross
(
self
.
plane
.
n
)
.
normalized
(
)
cross_offset
=
p
normalized
(
pcross
(
psub
(
p2
,
p1
),
self
.
plane
.
n
)
)
bisector_normalized
=
self
.
get_bisector
(
index
)
bisector_normalized
=
self
.
get_bisector
(
index
)
factor
=
cross_offset
.
dot
(
bisector_normalized
)
factor
=
pdot
(
cross_offset
,
bisector_normalized
)
if
factor
!=
0
:
if
factor
!=
0
:
bisector_sized
=
bisector_normalized
.
mul
(
offset
/
factor
)
bisector_sized
=
pmul
(
bisector_normalized
,
offset
/
factor
)
return
p
1
.
add
(
bisector_sized
)
return
p
add
(
p1
,
bisector_sized
)
else
:
else
:
return
p2
return
p2
if
offset
*
2
>=
self
.
get_max_inside_distance
():
if
offset
*
2
>=
self
.
get_max_inside_distance
():
...
@@ -613,7 +601,7 @@ class Polygon(TransformableContainer):
...
@@ -613,7 +601,7 @@ class Polygon(TransformableContainer):
max_dist
=
1000
*
epsilon
max_dist
=
1000
*
epsilon
def
test_point_near
(
p
,
others
):
def
test_point_near
(
p
,
others
):
for
o
in
others
:
for
o
in
others
:
if
p
.
sub
(
o
)
.
norm
<
max_dist
:
if
p
norm
(
psub
(
p
,
o
))
<
max_dist
:
return
True
return
True
return
False
return
False
reverse_lines
=
[]
reverse_lines
=
[]
...
@@ -622,12 +610,11 @@ class Polygon(TransformableContainer):
...
@@ -622,12 +610,11 @@ class Polygon(TransformableContainer):
next_index
=
(
index
+
1
)
%
len
(
points
)
next_index
=
(
index
+
1
)
%
len
(
points
)
p1
=
points
[
index
]
p1
=
points
[
index
]
p2
=
points
[
next_index
]
p2
=
points
[
next_index
]
diff
=
p2
.
sub
(
p1
)
diff
=
psub
(
p2
,
p1
)
old_dir
=
self
.
_points
[
next_index
]
.
sub
(
old_dir
=
pnormalized
(
psub
(
self
.
_points
[
next_index
],
self
.
_points
[
index
]))
self
.
_points
[
index
])
.
normalized
()
if
pnormalized
(
diff
)
!=
old_dir
:
if
diff
.
normalized
()
!=
old_dir
:
# the direction turned around
# the direction turned around
if
diff
.
norm
>
max_dist
:
if
pnorm
(
diff
)
>
max_dist
:
# the offset was too big
# the offset was too big
return
None
return
None
else
:
else
:
...
@@ -658,7 +645,7 @@ class Polygon(TransformableContainer):
...
@@ -658,7 +645,7 @@ class Polygon(TransformableContainer):
# no lines are left
# no lines are left
print
"out 2"
print
"out 2"
return
[]
return
[]
if
p
rev_line
.
p2
.
sub
(
next_line
.
p1
)
.
norm
>
max_dist
:
if
p
norm
(
psub
(
prev_line
.
p2
,
next_line
.
p1
))
>
max_dist
:
cp
,
dist
=
prev_line
.
get_intersection
(
next_line
)
cp
,
dist
=
prev_line
.
get_intersection
(
next_line
)
else
:
else
:
cp
=
prev_line
.
p2
cp
=
prev_line
.
p2
...
@@ -705,9 +692,8 @@ class Polygon(TransformableContainer):
...
@@ -705,9 +692,8 @@ class Polygon(TransformableContainer):
# maybe we have been here before
# maybe we have been here before
if
not
cp
in
split_points
:
if
not
cp
in
split_points
:
split_points
.
append
(
cp
)
split_points
.
append
(
cp
)
elif
(
cp
.
sub
(
line
.
p1
)
.
norm
<
max_dist
)
\
elif
(
pnorm
(
psub
(
cp
,
line
.
p1
))
<
max_dist
)
or
(
pnorm
(
psub
(
cp
,
line
.
p2
))
<
max_dist
):
or
(
cp
.
sub
(
line
.
p2
)
.
norm
<
max_dist
):
if
pnorm
(
psub
(
cp
,
lines
.
p1
))
<
pnorm
(
psub
(
cp
,
line
.
p2
)):
if
cp
.
sub
(
line
.
p1
)
.
norm
<
cp
.
sub
(
line
.
p2
)
.
norm
:
non_reversed
[
index
]
=
Line
(
cp
,
line
.
p2
)
non_reversed
[
index
]
=
Line
(
cp
,
line
.
p2
)
else
:
else
:
non_reversed
[
index
]
=
Line
(
line
.
p1
,
cp
)
non_reversed
[
index
]
=
Line
(
line
.
p1
,
cp
)
...
@@ -783,7 +769,6 @@ class Polygon(TransformableContainer):
...
@@ -783,7 +769,6 @@ class Polygon(TransformableContainer):
if
len
(
group
)
<=
2
:
if
len
(
group
)
<=
2
:
continue
continue
poly
=
Polygon
(
self
.
plane
)
poly
=
Polygon
(
self
.
plane
)
#print "**************************************"
for
line
in
group
:
for
line
in
group
:
try
:
try
:
poly
.
append
(
line
)
poly
.
append
(
line
)
...
@@ -863,12 +848,12 @@ class Polygon(TransformableContainer):
...
@@ -863,12 +848,12 @@ class Polygon(TransformableContainer):
def
get_shifted_vertex
(
index
,
offset
):
def
get_shifted_vertex
(
index
,
offset
):
p1
=
self
.
_points
[
index
]
p1
=
self
.
_points
[
index
]
p2
=
self
.
_points
[(
index
+
1
)
%
len
(
self
.
_points
)]
p2
=
self
.
_points
[(
index
+
1
)
%
len
(
self
.
_points
)]
cross_offset
=
p
2
.
sub
(
p1
)
.
cross
(
self
.
plane
.
n
)
.
normalized
(
)
cross_offset
=
p
normalized
(
pcross
(
psub
(
p2
,
p1
),
self
.
plane
.
n
)
)
bisector_normalized
=
self
.
get_bisector
(
index
)
bisector_normalized
=
self
.
get_bisector
(
index
)
factor
=
cross_offset
.
dot
(
bisector_normalized
)
factor
=
pdot
(
cross_offset
,
bisector_normalized
)
if
factor
!=
0
:
if
factor
!=
0
:
bisector_sized
=
bisector_normalized
.
mul
(
offset
/
factor
)
bisector_sized
=
pmul
(
bisector_normalized
,
offset
/
factor
)
return
p
1
.
add
(
bisector_sized
)
return
p
add
(
p1
,
bisector_sized
)
else
:
else
:
return
p2
return
p2
def
simplify_polygon_intersections
(
lines
):
def
simplify_polygon_intersections
(
lines
):
...
@@ -896,8 +881,7 @@ class Polygon(TransformableContainer):
...
@@ -896,8 +881,7 @@ class Polygon(TransformableContainer):
line1
=
new_group
[
index1
]
line1
=
new_group
[
index1
]
line2
=
new_group
[
index2
]
line2
=
new_group
[
index2
]
intersection
,
factor
=
line1
.
get_intersection
(
line2
)
intersection
,
factor
=
line1
.
get_intersection
(
line2
)
if
intersection
and
(
intersection
!=
line1
.
p1
)
\
if
intersection
and
(
pnorm
(
psub
(
intersection
,
line1
.
p1
))
>
epsilon
)
and
(
pnorm
(
psub
(
intersection
,
line1
.
p2
))
>
epsilon
):
and
(
intersection
!=
line1
.
p2
):
del
new_group
[
index1
]
del
new_group
[
index1
]
new_group
.
insert
(
index1
,
new_group
.
insert
(
index1
,
Line
(
line1
.
p1
,
intersection
))
Line
(
line1
.
p1
,
intersection
))
...
@@ -911,7 +895,7 @@ class Polygon(TransformableContainer):
...
@@ -911,7 +895,7 @@ class Polygon(TransformableContainer):
if
not
index1
+
1
in
group_starts
:
if
not
index1
+
1
in
group_starts
:
group_starts
.
append
(
index1
+
1
)
group_starts
.
append
(
index1
+
1
)
# don't update index2 -> maybe there are other hits
# don't update index2 -> maybe there are other hits
elif
intersection
and
(
intersection
==
line1
.
p1
):
elif
intersection
and
(
pnorm
(
psub
(
intersection
,
line1
.
p1
))
<
epsilon
):
if
not
index1
in
group_starts
:
if
not
index1
in
group_starts
:
group_starts
.
append
(
index1
)
group_starts
.
append
(
index1
)
index2
+=
1
index2
+=
1
...
@@ -929,6 +913,7 @@ class Polygon(TransformableContainer):
...
@@ -929,6 +913,7 @@ class Polygon(TransformableContainer):
for
group_start
in
group_starts
:
for
group_start
in
group_starts
:
groups
.
append
(
new_group
[
last_start
:
group_start
])
groups
.
append
(
new_group
[
last_start
:
group_start
])
last_start
=
group_start
last_start
=
group_start
# Add the remaining lines to the first group or as a new
# Add the remaining lines to the first group or as a new
# group.
# group.
if
groups
[
0
][
0
]
.
p1
==
new_group
[
-
1
]
.
p2
:
if
groups
[
0
][
0
]
.
p1
==
new_group
[
-
1
]
.
p2
:
...
@@ -979,9 +964,9 @@ class Polygon(TransformableContainer):
...
@@ -979,9 +964,9 @@ class Polygon(TransformableContainer):
for
index
in
range
(
len
(
self
.
_points
)):
for
index
in
range
(
len
(
self
.
_points
)):
points
.
append
(
get_shifted_vertex
(
index
,
offset
))
points
.
append
(
get_shifted_vertex
(
index
,
offset
))
new_lines
=
[]
new_lines
=
[]
for
index
in
range
(
len
(
points
)):
for
index
in
range
(
len
(
points
)
-
1
):
p1
=
points
[
index
]
p1
=
points
[
index
]
p2
=
points
[(
index
+
1
)
%
len
(
points
)
]
p2
=
points
[(
index
+
1
)]
new_lines
.
append
(
Line
(
p1
,
p2
))
new_lines
.
append
(
Line
(
p1
,
p2
))
if
callback
and
callback
():
if
callback
and
callback
():
return
None
return
None
...
@@ -1003,21 +988,7 @@ class Polygon(TransformableContainer):
...
@@ -1003,21 +988,7 @@ class Polygon(TransformableContainer):
group
=
Polygon
(
self
.
plane
)
group
=
Polygon
(
self
.
plane
)
for
line
in
lines
:
for
line
in
lines
:
group
.
append
(
line
)
group
.
append
(
line
)
if
group
.
is_outer
()
!=
self_is_outer
:
# We ignore groups that changed the direction. These
# parts of the original group are flipped due to the
# offset.
log
.
debug
(
"Ignoring reversed polygon:
%
s /
%
s"
%
\
(
self
.
get_area
(),
group
.
get_area
()))
continue
# Remove polygons that should be inside the original,
# but due to float inaccuracies they are not.
if
((
self
.
is_outer
()
and
(
offset
<
0
))
\
or
(
not
self
.
is_outer
()
and
(
offset
>
0
)))
\
and
(
not
self
.
is_polygon_inside
(
group
)):
log
.
debug
(
"Ignoring inaccurate polygon:
%
s /
%
s"
\
%
(
self
.
get_area
(),
group
.
get_area
()))
continue
groups
.
append
(
group
)
groups
.
append
(
group
)
if
not
groups
:
if
not
groups
:
log
.
debug
(
"Skipping offset polygon: toggled polygon removed"
)
log
.
debug
(
"Skipping offset polygon: toggled polygon removed"
)
...
@@ -1044,15 +1015,14 @@ class Polygon(TransformableContainer):
...
@@ -1044,15 +1015,14 @@ class Polygon(TransformableContainer):
if
offset
==
0
:
if
offset
==
0
:
return
Line
(
line
.
p1
,
line
.
p2
)
return
Line
(
line
.
p1
,
line
.
p2
)
else
:
else
:
cross_offset
=
line
.
dir
.
cross
(
self
.
plane
.
n
)
.
normalized
()
.
mul
(
offset
)
cross_offset
=
pmul
(
pnormalized
(
pcross
(
line
.
dir
,
self
.
plane
.
n
)),
offset
)
# Prolong the line at the beginning and at the end - to allow
# Prolong the line at the beginning and at the end - to allow
# overlaps. Use factor "2" to take care for star-like structure
# overlaps. Use factor "2" to take care for star-like structure
# where a complete convex triangle would get cropped (two lines
# where a complete convex triangle would get cropped (two lines
# get lost instead of just one). Use the "abs" value to
# get lost instead of just one). Use the "abs" value to
# compensate negative offsets.
# compensate negative offsets.
in_line
=
line
.
dir
.
mul
(
2
*
abs
(
offset
))
in_line
=
pmul
(
line
.
dir
,
2
*
abs
(
offset
))
return
Line
(
line
.
p1
.
add
(
cross_offset
)
.
sub
(
in_line
),
return
Line
(
psub
(
padd
(
line
.
p1
,
cross_offset
),
in_line
),
padd
(
padd
(
line
.
p2
,
cross_offset
),
in_line
))
line
.
p2
.
add
(
cross_offset
)
.
add
(
in_line
))
def
do_lines_intersection
(
l1
,
l2
):
def
do_lines_intersection
(
l1
,
l2
):
""" calculate the new intersection between two neighbouring lines
""" calculate the new intersection between two neighbouring lines
"""
"""
...
@@ -1064,12 +1034,12 @@ class Polygon(TransformableContainer):
...
@@ -1064,12 +1034,12 @@ class Polygon(TransformableContainer):
# one line was already marked as obsolete
# one line was already marked as obsolete
return
return
x1
,
x2
,
x3
,
x4
=
l2
.
p1
,
l2
.
p2
,
l1
.
p1
,
l1
.
p2
x1
,
x2
,
x3
,
x4
=
l2
.
p1
,
l2
.
p2
,
l1
.
p1
,
l1
.
p2
a
=
x2
.
sub
(
x1
)
a
=
psub
(
x2
,
x1
)
b
=
x4
.
sub
(
x3
)
b
=
psub
(
x4
,
x3
)
c
=
x3
.
sub
(
x1
)
c
=
psub
(
x3
,
x1
)
# see http://mathworld.wolfram.com/Line-LineIntersection.html (24)
# see http://mathworld.wolfram.com/Line-LineIntersection.html (24)
try
:
try
:
factor
=
c
.
cross
(
b
)
.
dot
(
a
.
cross
(
b
))
/
a
.
cross
(
b
)
.
normsq
factor
=
pdot
(
pcross
(
c
,
b
),
pcross
(
a
,
b
))
/
pnormsq
(
pcross
(
a
,
b
))
except
ZeroDivisionError
:
except
ZeroDivisionError
:
l2
.
p1
=
None
l2
.
p1
=
None
return
return
...
@@ -1077,7 +1047,7 @@ class Polygon(TransformableContainer):
...
@@ -1077,7 +1047,7 @@ class Polygon(TransformableContainer):
# The intersection is always supposed to be within p1 and p2.
# The intersection is always supposed to be within p1 and p2.
l2
.
p1
=
None
l2
.
p1
=
None
else
:
else
:
intersection
=
x1
.
add
(
a
.
mul
(
factor
))
intersection
=
padd
(
x1
,
pmul
(
a
,
factor
))
if
Line
(
l1
.
p1
,
intersection
)
.
dir
!=
l1
.
dir
:
if
Line
(
l1
.
p1
,
intersection
)
.
dir
!=
l1
.
dir
:
# Remove lines that would change their direction due to the
# Remove lines that would change their direction due to the
# new intersection. These are usually lines that become
# new intersection. These are usually lines that become
...
@@ -1320,12 +1290,12 @@ class Polygon(TransformableContainer):
...
@@ -1320,12 +1290,12 @@ class Polygon(TransformableContainer):
for
index
in
range
(
len
(
collisions
)
-
1
):
for
index
in
range
(
len
(
collisions
)
-
1
):
p1
=
collisions
[
index
][
0
]
p1
=
collisions
[
index
][
0
]
p2
=
collisions
[
index
+
1
][
0
]
p2
=
collisions
[
index
+
1
][
0
]
if
p
1
.
sub
(
p2
)
.
norm
<
epsilon
:
if
p
norm
(
psub
(
p1
,
p2
))
<
epsilon
:
# ignore zero-length lines
# ignore zero-length lines
continue
continue
# Use the middle between p1 and p2 to check the
# Use the middle between p1 and p2 to check the
# inner/outer state.
# inner/outer state.
p_middle
=
p
1
.
add
(
p2
)
.
div
(
2
)
p_middle
=
p
div
(
padd
(
p1
,
p2
),
2
)
p_inside
=
poly2
.
is_point_inside
(
p_middle
)
\
p_inside
=
poly2
.
is_point_inside
(
p_middle
)
\
and
not
poly2
.
is_point_on_outline
(
p_middle
)
and
not
poly2
.
is_point_on_outline
(
p_middle
)
if
not
p_inside
:
if
not
p_inside
:
...
@@ -1365,12 +1335,12 @@ class Polygon(TransformableContainer):
...
@@ -1365,12 +1335,12 @@ class Polygon(TransformableContainer):
intersections
.
sort
(
key
=
lambda
(
cp
,
d
):
d
)
intersections
.
sort
(
key
=
lambda
(
cp
,
d
):
d
)
intersections
.
insert
(
0
,
(
proj_line
.
p1
,
0
))
intersections
.
insert
(
0
,
(
proj_line
.
p1
,
0
))
intersections
.
append
((
proj_line
.
p2
,
1
))
intersections
.
append
((
proj_line
.
p2
,
1
))
get_original_point
=
lambda
d
:
line
.
p1
.
add
(
line
.
vector
.
mul
(
d
))
get_original_point
=
lambda
d
:
padd
(
line
.
p1
,
pmul
(
line
.
vector
,
d
))
for
index
in
range
(
len
(
intersections
)
-
1
):
for
index
in
range
(
len
(
intersections
)
-
1
):
p1
,
d1
=
intersections
[
index
]
p1
,
d1
=
intersections
[
index
]
p2
,
d2
=
intersections
[
index
+
1
]
p2
,
d2
=
intersections
[
index
+
1
]
if
p1
!=
p2
:
if
p1
!=
p2
:
middle
=
p
1
.
add
(
p2
)
.
div
(
2
)
middle
=
p
div
(
padd
(
p1
,
p2
),
2
)
new_line
=
Line
(
get_original_point
(
d1
),
get_original_point
(
d2
))
new_line
=
Line
(
get_original_point
(
d1
),
get_original_point
(
d2
))
if
self
.
is_point_inside
(
middle
):
if
self
.
is_point_inside
(
middle
):
inner
.
append
(
new_line
)
inner
.
append
(
new_line
)
...
...
pycam/Geometry/PolygonExtractor.py
View file @
9b939792
...
@@ -80,7 +80,7 @@ class PolygonExtractor(object):
...
@@ -80,7 +80,7 @@ class PolygonExtractor(object):
print
"points="
,
path
.
points
print
"points="
,
path
.
points
i
=
0
i
=
0
while
i
<
len
(
path
.
points
)
-
1
:
while
i
<
len
(
path
.
points
)
-
1
:
if
path
.
points
[
i
]
.
x
>
path
.
points
[
i
+
1
]
.
x
:
if
path
.
points
[
i
]
[
0
]
>
path
.
points
[
i
+
1
][
0
]
:
if
DEBUG_POLYGONEXTRACTOR2
:
if
DEBUG_POLYGONEXTRACTOR2
:
print
"drop point
%
d:"
%
path
.
points
[
i
]
.
id
print
"drop point
%
d:"
%
path
.
points
[
i
]
.
id
path
.
points
=
path
.
points
[:
i
]
+
path
.
points
[
i
+
1
:]
path
.
points
=
path
.
points
[:
i
]
+
path
.
points
[
i
+
1
:]
...
@@ -95,7 +95,7 @@ class PolygonExtractor(object):
...
@@ -95,7 +95,7 @@ class PolygonExtractor(object):
print
"
%
d:"
%
path
.
id
,
print
"
%
d:"
%
path
.
id
,
print
"
%
d ->"
%
path
.
top_join
.
id
print
"
%
d ->"
%
path
.
top_join
.
id
for
point
in
path
.
points
:
for
point
in
path
.
points
:
print
"
%
d(
%
g,
%
g)"
%
(
point
.
id
,
point
.
x
,
point
.
y
),
print
"
%
d(
%
g,
%
g)"
%
(
point
.
id
,
point
[
0
],
point
[
1
]
),
print
"->
%
d"
%
path
.
bot_join
.
id
print
"->
%
d"
%
path
.
bot_join
.
id
path_list
=
[]
path_list
=
[]
...
@@ -133,7 +133,7 @@ class PolygonExtractor(object):
...
@@ -133,7 +133,7 @@ class PolygonExtractor(object):
for
path
in
path_list
:
for
path
in
path_list
:
print
"path
%
d(w=
%
d): "
%
(
path
.
id
,
path
.
winding
),
print
"path
%
d(w=
%
d): "
%
(
path
.
id
,
path
.
winding
),
for
point
in
path
.
points
:
for
point
in
path
.
points
:
print
"
%
d(
%
g,
%
g)"
%
(
point
.
id
,
point
.
x
,
point
.
y
),
print
"
%
d(
%
g,
%
g)"
%
(
point
.
id
,
point
[
0
],
point
[
1
]
),
print
print
if
self
.
current_dir
==
0
:
if
self
.
current_dir
==
0
:
...
@@ -156,13 +156,13 @@ class PolygonExtractor(object):
...
@@ -156,13 +156,13 @@ class PolygonExtractor(object):
self
.
svg
.
fill
(
"red"
)
self
.
svg
.
fill
(
"red"
)
else
:
else
:
self
.
svg
.
fill
(
"blue"
)
self
.
svg
.
fill
(
"blue"
)
self
.
svg
.
AddDot
(
p
.
x
,
p
.
y
)
self
.
svg
.
AddDot
(
p
[
0
],
p
[
1
]
)
self
.
svg
.
AddText
(
p
.
x
,
p
.
y
,
str
(
p
.
id
))
self
.
svg
.
AddText
(
p
[
0
],
p
[
1
]
,
str
(
p
.
id
))
if
prev
:
if
prev
:
self
.
svg
.
AddLine
(
p
.
x
,
p
.
y
,
prev
.
x
,
prev
.
y
)
self
.
svg
.
AddLine
(
p
[
0
],
p
[
1
],
prev
[
0
],
prev
[
1
]
)
prev
=
p
prev
=
p
p
=
path
.
points
[
0
]
p
=
path
.
points
[
0
]
self
.
svg
.
AddLine
(
p
.
x
,
p
.
y
,
prev
.
x
,
prev
.
y
)
self
.
svg
.
AddLine
(
p
[
0
],
p
[
1
],
prev
[
0
],
prev
[
1
]
)
self
.
svg
.
close
()
self
.
svg
.
close
()
self
.
cont
.
close
()
self
.
cont
.
close
()
...
@@ -176,8 +176,8 @@ class PolygonExtractor(object):
...
@@ -176,8 +176,8 @@ class PolygonExtractor(object):
def
append
(
self
,
p
):
def
append
(
self
,
p
):
if
DEBUG_POLYGONEXTRACTOR3
:
if
DEBUG_POLYGONEXTRACTOR3
:
p
.
dir
=
self
.
current_dir
p
.
dir
=
self
.
current_dir
self
.
svg
.
AddDot
(
p
.
x
,
p
.
y
)
self
.
svg
.
AddDot
(
p
[
0
],
p
[
1
]
)
self
.
svg
.
AddText
(
p
.
x
,
p
.
y
,
str
(
p
.
id
))
self
.
svg
.
AddText
(
p
[
0
],
p
[
1
]
,
str
(
p
.
id
))
self
.
curr_line
.
append
(
p
)
self
.
curr_line
.
append
(
p
)
def
end_scanline
(
self
):
def
end_scanline
(
self
):
...
@@ -187,7 +187,7 @@ class PolygonExtractor(object):
...
@@ -187,7 +187,7 @@ class PolygonExtractor(object):
if
self
.
policy
==
PolygonExtractor
.
CONTOUR
and
self
.
hor_path_list
:
if
self
.
policy
==
PolygonExtractor
.
CONTOUR
and
self
.
hor_path_list
:
next_x
=
-
INFINITE
next_x
=
-
INFINITE
if
len
(
self
.
curr_line
)
>
0
:
if
len
(
self
.
curr_line
)
>
0
:
next_x
=
self
.
curr_line
[
0
]
.
x
next_x
=
self
.
curr_line
[
0
]
[
0
]
self
.
delta_x
=
next_x
-
self
.
last_x
self
.
delta_x
=
next_x
-
self
.
last_x
self
.
last_x
=
next_x
self
.
last_x
=
next_x
else
:
else
:
...
@@ -204,7 +204,7 @@ class PolygonExtractor(object):
...
@@ -204,7 +204,7 @@ class PolygonExtractor(object):
inside
=
False
inside
=
False
s
=
""
s
=
""
for
point
in
scanline
:
for
point
in
scanline
:
next_x
=
point
.
x
next_x
=
point
[
0
]
if
inside
:
if
inside
:
s
+=
"*"
*
int
(
next_x
-
last
)
s
+=
"*"
*
int
(
next_x
-
last
)
else
:
else
:
...
@@ -217,17 +217,17 @@ class PolygonExtractor(object):
...
@@ -217,17 +217,17 @@ class PolygonExtractor(object):
print
"active paths: "
,
print
"active paths: "
,
for
path
in
self
.
curr_path_list
:
for
path
in
self
.
curr_path_list
:
print
"
%
d(
%
g,
%
g)"
\
print
"
%
d(
%
g,
%
g)"
\
%
(
path
.
id
,
path
.
points
[
-
1
]
.
x
,
path
.
points
[
-
1
]
.
y
),
%
(
path
.
id
,
path
.
points
[
-
1
]
[
0
],
path
.
points
[
-
1
][
1
]
),
print
print
print
"prev points: "
,
print
"prev points: "
,
for
point
in
self
.
prev_line
:
for
point
in
self
.
prev_line
:
print
"(
%
g,
%
g)"
%
(
point
.
x
,
point
.
y
),
print
"(
%
g,
%
g)"
%
(
point
[
0
],
point
[
1
]
),
print
print
print
"active points: "
,
print
"active points: "
,
for
point
in
scanline
:
for
point
in
scanline
:
print
"
%
d(
%
g,
%
g)"
%
(
point
.
id
,
point
.
x
,
point
.
y
),
print
"
%
d(
%
g,
%
g)"
%
(
point
.
id
,
point
[
0
],
point
[
1
]
),
print
print
prev_point
=
Iterator
(
self
.
prev_line
)
prev_point
=
Iterator
(
self
.
prev_line
)
...
@@ -246,13 +246,13 @@ class PolygonExtractor(object):
...
@@ -246,13 +246,13 @@ class PolygonExtractor(object):
p0
=
Path
()
p0
=
Path
()
p0
.
winding
=
winding
+
1
p0
.
winding
=
winding
+
1
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"new path
%
d(
%
g,
%
g)"
%
(
p0
.
id
,
c0
.
x
,
c0
.
y
)
print
"new path
%
d(
%
g,
%
g)"
%
(
p0
.
id
,
c0
[
0
],
c0
[
1
]
)
p0
.
append
(
c0
)
p0
.
append
(
c0
)
self
.
curr_path_list
.
append
(
p0
)
self
.
curr_path_list
.
append
(
p0
)
p1
=
Path
()
p1
=
Path
()
p1
.
winding
=
winding
p1
.
winding
=
winding
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"new path
%
d(
%
g,
%
g)"
%
(
p1
.
id
,
c1
.
x
,
c1
.
y
)
print
"new path
%
d(
%
g,
%
g)"
%
(
p1
.
id
,
c1
[
0
],
c1
[
1
]
)
p1
.
append
(
c1
)
p1
.
append
(
c1
)
self
.
curr_path_list
.
append
(
p1
)
self
.
curr_path_list
.
append
(
p1
)
p0
.
top_join
=
p1
p0
.
top_join
=
p1
...
@@ -282,16 +282,16 @@ class PolygonExtractor(object):
...
@@ -282,16 +282,16 @@ class PolygonExtractor(object):
c1
=
curr_point
.
peek
(
1
)
c1
=
curr_point
.
peek
(
1
)
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"overlap test: p0=
%
g p1=
%
g"
%
(
p0
.
x
,
p1
.
x
)
print
"overlap test: p0=
%
g p1=
%
g"
%
(
p0
[
0
],
p1
[
0
]
)
print
"overlap test: c0=
%
g c1=
%
g"
%
(
c0
.
x
,
c1
.
x
)
print
"overlap test: c0=
%
g c1=
%
g"
%
(
c0
[
0
],
c1
[
0
]
)
if
c1
.
x
<
p0
.
x
:
if
c1
[
0
]
<
p0
[
0
]
:
# new segment is completely to the left
# new segment is completely to the left
# new path starts
# new path starts
s0
=
Path
()
s0
=
Path
()
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"new path
%
d(
%
g,
%
g) w=
%
d"
\
print
"new path
%
d(
%
g,
%
g) w=
%
d"
\
%
(
s0
.
id
,
c0
.
x
,
c0
.
y
,
winding
+
1
)
%
(
s0
.
id
,
c0
[
0
],
c0
[
0
]
,
winding
+
1
)
s0
.
append
(
c0
)
s0
.
append
(
c0
)
curr_path
.
insert
(
s0
)
curr_path
.
insert
(
s0
)
s1
=
Path
()
s1
=
Path
()
...
@@ -299,14 +299,14 @@ class PolygonExtractor(object):
...
@@ -299,14 +299,14 @@ class PolygonExtractor(object):
s1
.
winding
=
winding
s1
.
winding
=
winding
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"new path
%
d(
%
g,
%
g) w=
%
d"
\
print
"new path
%
d(
%
g,
%
g) w=
%
d"
\
%
(
s1
.
id
,
c1
.
x
,
c1
.
y
,
winding
)
%
(
s1
.
id
,
c1
[
0
],
c1
[
1
]
,
winding
)
s1
.
append
(
c1
)
s1
.
append
(
c1
)
curr_path
.
insert
(
s1
)
curr_path
.
insert
(
s1
)
curr_point
.
next
()
curr_point
.
next
()
curr_point
.
next
()
curr_point
.
next
()
s0
.
top_join
=
s1
s0
.
top_join
=
s1
s1
.
top_join
=
s0
s1
.
top_join
=
s0
elif
c0
.
x
>
p1
.
x
:
elif
c0
[
0
]
>
p1
[
0
]
:
# new segment is completely to the right
# new segment is completely to the right
# old path ends
# old path ends
s0
=
curr_path
.
takeNext
()
s0
=
curr_path
.
takeNext
()
...
@@ -342,9 +342,9 @@ class PolygonExtractor(object):
...
@@ -342,9 +342,9 @@ class PolygonExtractor(object):
p2
=
prev_point
.
peek
(
1
)
p2
=
prev_point
.
peek
(
1
)
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"join test: p0=
%
g p1=
%
g p2=
%
g"
\
print
"join test: p0=
%
g p1=
%
g p2=
%
g"
\
%
(
p0
.
x
,
p1
.
x
,
p2
.
x
)
%
(
p0
[
0
],
p1
[
0
],
p2
[
0
]
)
print
"join test: c0=
%
g c1=
%
g"
%
(
c0
.
x
,
c1
.
x
)
print
"join test: c0=
%
g c1=
%
g"
%
(
c0
[
0
],
c1
[
0
]
)
if
p2
.
x
<=
c1
.
x
:
if
p2
[
0
]
<=
c1
[
0
]
:
overlap_p
=
True
overlap_p
=
True
if
self
.
policy
==
PolygonExtractor
.
CONTOUR
:
if
self
.
policy
==
PolygonExtractor
.
CONTOUR
:
s0
=
curr_path
.
takeNext
()
s0
=
curr_path
.
takeNext
()
...
@@ -384,10 +384,10 @@ class PolygonExtractor(object):
...
@@ -384,10 +384,10 @@ class PolygonExtractor(object):
if
curr_point
.
remains
()
>=
2
:
if
curr_point
.
remains
()
>=
2
:
c2
=
curr_point
.
peek
(
1
)
c2
=
curr_point
.
peek
(
1
)
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"split test: p0=
%
g p1=
%
g"
%
(
p0
.
x
,
p1
.
x
)
print
"split test: p0=
%
g p1=
%
g"
%
(
p0
[
0
],
p1
[
0
]
)
print
"split test: c0=
%
g c1=
%
g c2=
%
g"
\
print
"split test: c0=
%
g c1=
%
g c2=
%
g"
\
%
(
c0
.
x
,
c1
.
x
,
c2
.
x
)
%
(
c0
[
0
],
c1
[
0
],
c2
[
0
]
)
if
c2
.
x
<=
p1
.
x
:
if
c2
[
0
]
<=
p1
[
0
]
:
overlap_c
=
True
overlap_c
=
True
s0
=
Path
()
s0
=
Path
()
s1
=
Path
()
s1
=
Path
()
...
@@ -419,14 +419,14 @@ class PolygonExtractor(object):
...
@@ -419,14 +419,14 @@ class PolygonExtractor(object):
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"add to path
%
d(
%
g,
%
g)"
\
print
"add to path
%
d(
%
g,
%
g)"
\
%
(
left_path
.
id
,
left_point
.
x
,
left_point
.
y
)
%
(
left_path
.
id
,
left_point
[
0
],
left_point
[
1
]
)
left_path
.
append
(
left_point
)
left_path
.
append
(
left_point
)
right_path
.
append
(
right_point
)
right_path
.
append
(
right_point
)
if
right_path
==
curr_path
.
peek
():
if
right_path
==
curr_path
.
peek
():
curr_path
.
next
()
curr_path
.
next
()
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"add to path
%
d(
%
g,
%
g)"
\
print
"add to path
%
d(
%
g,
%
g)"
\
%
(
right_path
.
id
,
right_point
.
x
,
right_point
.
y
)
%
(
right_path
.
id
,
right_point
[
0
],
right_point
[
1
]
)
winding
=
right_path
.
winding
winding
=
right_path
.
winding
prev_point
.
next
()
prev_point
.
next
()
curr_point
.
next
()
curr_point
.
next
()
...
@@ -434,8 +434,8 @@ class PolygonExtractor(object):
...
@@ -434,8 +434,8 @@ class PolygonExtractor(object):
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"active paths: "
,
print
"active paths: "
,
for
path
in
self
.
curr_path_list
:
for
path
in
self
.
curr_path_list
:
print
"
%
d(
%
g,
%
g,w=
%
d)"
%
(
path
.
id
,
path
.
points
[
-
1
]
.
x
,
print
"
%
d(
%
g,
%
g,w=
%
d)"
%
(
path
.
id
,
path
.
points
[
-
1
]
[
0
]
,
path
.
points
[
-
1
]
.
y
,
path
.
winding
),
path
.
points
[
-
1
]
[
1
]
,
path
.
winding
),
print
print
self
.
prev_line
=
scanline
self
.
prev_line
=
scanline
...
@@ -448,11 +448,11 @@ class PolygonExtractor(object):
...
@@ -448,11 +448,11 @@ class PolygonExtractor(object):
self
.
cont
.
fill
(
"red"
)
self
.
cont
.
fill
(
"red"
)
else
:
else
:
self
.
cont
.
fill
(
"blue"
)
self
.
cont
.
fill
(
"blue"
)
self
.
cont
.
AddDot
(
p
.
x
,
p
.
y
)
self
.
cont
.
AddDot
(
p
[
0
],
p
[
1
]
)
self
.
cont
.
fill
(
"black"
)
self
.
cont
.
fill
(
"black"
)
self
.
cont
.
AddText
(
p
.
x
,
p
.
y
,
str
(
p
.
id
))
self
.
cont
.
AddText
(
p
[
0
],
p
[
1
]
,
str
(
p
.
id
))
if
prev
:
if
prev
:
self
.
cont
.
AddLine
(
prev
.
x
,
prev
.
y
,
p
.
x
,
p
.
y
)
self
.
cont
.
AddLine
(
prev
[
0
],
prev
[
1
],
p
[
0
],
p
[
1
]
)
prev
=
p
prev
=
p
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
...
@@ -460,7 +460,7 @@ class PolygonExtractor(object):
...
@@ -460,7 +460,7 @@ class PolygonExtractor(object):
inside
=
False
inside
=
False
s
=
""
s
=
""
for
point
in
scanline
:
for
point
in
scanline
:
next_y
=
point
.
y
next_y
=
point
[
1
]
if
inside
:
if
inside
:
s
+=
"*"
*
int
(
next_y
-
last
)
s
+=
"*"
*
int
(
next_y
-
last
)
else
:
else
:
...
@@ -473,17 +473,17 @@ class PolygonExtractor(object):
...
@@ -473,17 +473,17 @@ class PolygonExtractor(object):
print
"active paths: "
,
print
"active paths: "
,
for
path
in
self
.
curr_path_list
:
for
path
in
self
.
curr_path_list
:
print
"
%
d(
%
g,
%
g)"
\
print
"
%
d(
%
g,
%
g)"
\
%
(
path
.
id
,
path
.
points
[
-
1
]
.
x
,
path
.
points
[
-
1
]
.
y
),
%
(
path
.
id
,
path
.
points
[
-
1
]
[
0
],
path
.
points
[
-
1
][
1
]
),
print
print
print
"prev points: "
,
print
"prev points: "
,
for
point
in
self
.
prev_line
:
for
point
in
self
.
prev_line
:
print
"(
%
g,
%
g)"
%
(
point
.
x
,
point
.
y
),
print
"(
%
g,
%
g)"
%
(
point
[
0
],
point
[
1
]
),
print
print
print
"active points: "
,
print
"active points: "
,
for
point
in
scanline
:
for
point
in
scanline
:
print
"
%
d(
%
g,
%
g)"
%
(
point
.
id
,
point
.
x
,
point
.
y
),
print
"
%
d(
%
g,
%
g)"
%
(
point
.
id
,
point
[
0
],
point
[
1
]
),
print
print
prev_point
=
Iterator
(
self
.
prev_line
)
prev_point
=
Iterator
(
self
.
prev_line
)
...
@@ -502,13 +502,13 @@ class PolygonExtractor(object):
...
@@ -502,13 +502,13 @@ class PolygonExtractor(object):
p0
=
Path
()
p0
=
Path
()
p0
.
winding
=
winding
+
1
p0
.
winding
=
winding
+
1
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"new path
%
d(
%
g,
%
g)"
%
(
p0
.
id
,
c0
.
x
,
c0
.
y
)
print
"new path
%
d(
%
g,
%
g)"
%
(
p0
.
id
,
c0
[
0
],
c0
[
1
]
)
p0
.
append
(
c0
)
p0
.
append
(
c0
)
self
.
curr_path_list
.
append
(
p0
)
self
.
curr_path_list
.
append
(
p0
)
p1
=
Path
()
p1
=
Path
()
p1
.
winding
=
winding
p1
.
winding
=
winding
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"new path
%
d(
%
g,
%
g)"
%
(
p1
.
id
,
c1
.
x
,
c1
.
y
)
print
"new path
%
d(
%
g,
%
g)"
%
(
p1
.
id
,
c1
[
0
],
c1
[
1
]
)
p1
.
append
(
c1
)
p1
.
append
(
c1
)
self
.
curr_path_list
.
append
(
p1
)
self
.
curr_path_list
.
append
(
p1
)
p0
.
top_join
=
p1
p0
.
top_join
=
p1
...
@@ -538,16 +538,16 @@ class PolygonExtractor(object):
...
@@ -538,16 +538,16 @@ class PolygonExtractor(object):
c1
=
curr_point
.
peek
(
1
)
c1
=
curr_point
.
peek
(
1
)
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"overlap test: p0=
%
g p1=
%
g"
%
(
p0
.
x
,
p1
.
x
)
print
"overlap test: p0=
%
g p1=
%
g"
%
(
p0
[
0
],
p1
[
0
]
)
print
"overlap test: c0=
%
g c1=
%
g"
%
(
c0
.
x
,
c1
.
x
)
print
"overlap test: c0=
%
g c1=
%
g"
%
(
c0
[
0
],
c1
[
0
]
)
if
c1
.
y
<
p0
.
y
:
if
c1
[
1
]
<
p0
[
1
]
:
# new segment is completely to the left
# new segment is completely to the left
# new path starts
# new path starts
s0
=
Path
()
s0
=
Path
()
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"new path
%
d(
%
g,
%
g) w=
%
d"
\
print
"new path
%
d(
%
g,
%
g) w=
%
d"
\
%
(
s0
.
id
,
c0
.
x
,
c0
.
y
,
winding
+
1
)
%
(
s0
.
id
,
c0
[
0
],
c0
[
1
]
,
winding
+
1
)
s0
.
append
(
c0
)
s0
.
append
(
c0
)
curr_path
.
insert
(
s0
)
curr_path
.
insert
(
s0
)
s1
=
Path
()
s1
=
Path
()
...
@@ -555,14 +555,14 @@ class PolygonExtractor(object):
...
@@ -555,14 +555,14 @@ class PolygonExtractor(object):
s1
.
winding
=
winding
s1
.
winding
=
winding
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"new path
%
d(
%
g,
%
g) w=
%
d"
\
print
"new path
%
d(
%
g,
%
g) w=
%
d"
\
%
(
s1
.
id
,
c1
.
x
,
c1
.
y
,
winding
)
%
(
s1
.
id
,
c1
[
0
],
c1
[
1
]
,
winding
)
s1
.
append
(
c1
)
s1
.
append
(
c1
)
curr_path
.
insert
(
s1
)
curr_path
.
insert
(
s1
)
curr_point
.
next
()
curr_point
.
next
()
curr_point
.
next
()
curr_point
.
next
()
s0
.
top_join
=
s1
s0
.
top_join
=
s1
s1
.
top_join
=
s0
s1
.
top_join
=
s0
elif
c0
.
y
>
p1
.
y
:
elif
c0
[
1
]
>
p1
[
1
]
:
# new segment is completely to the right
# new segment is completely to the right
# old path ends
# old path ends
s0
=
curr_path
.
takeNext
()
s0
=
curr_path
.
takeNext
()
...
@@ -598,9 +598,9 @@ class PolygonExtractor(object):
...
@@ -598,9 +598,9 @@ class PolygonExtractor(object):
p2
=
prev_point
.
peek
(
1
)
p2
=
prev_point
.
peek
(
1
)
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"join test: p0=
%
g p1=
%
g p2=
%
g"
\
print
"join test: p0=
%
g p1=
%
g p2=
%
g"
\
%
(
p0
.
x
,
p1
.
x
,
p2
.
x
)
%
(
p0
[
0
],
p1
[
0
],
p2
[
0
]
)
print
"join test: c0=
%
g c1=
%
g"
%
(
c0
.
x
,
c1
.
x
)
print
"join test: c0=
%
g c1=
%
g"
%
(
c0
[
0
],
c1
[
0
]
)
if
p2
.
y
<=
c1
.
y
:
if
p2
[
1
]
<=
c1
[
1
]
:
overlap_p
=
True
overlap_p
=
True
if
self
.
policy
==
PolygonExtractor
.
CONTOUR
:
if
self
.
policy
==
PolygonExtractor
.
CONTOUR
:
s0
=
curr_path
.
takeNext
()
s0
=
curr_path
.
takeNext
()
...
@@ -640,10 +640,10 @@ class PolygonExtractor(object):
...
@@ -640,10 +640,10 @@ class PolygonExtractor(object):
if
curr_point
.
remains
()
>=
2
:
if
curr_point
.
remains
()
>=
2
:
c2
=
curr_point
.
peek
(
1
)
c2
=
curr_point
.
peek
(
1
)
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"split test: p0=
%
g p1=
%
g"
%
(
p0
.
x
,
p1
.
x
)
print
"split test: p0=
%
g p1=
%
g"
%
(
p0
[
0
],
p1
[
0
]
)
print
"split test: c0=
%
g c1=
%
g c2=
%
g"
\
print
"split test: c0=
%
g c1=
%
g c2=
%
g"
\
%
(
c0
.
x
,
c1
.
x
,
c2
.
x
)
%
(
c0
[
0
],
c1
[
0
],
c2
[
0
]
)
if
c2
.
y
<=
p1
.
y
:
if
c2
[
1
]
<=
p1
[
1
]
:
overlap_c
=
True
overlap_c
=
True
s0
=
Path
()
s0
=
Path
()
s1
=
Path
()
s1
=
Path
()
...
@@ -675,14 +675,14 @@ class PolygonExtractor(object):
...
@@ -675,14 +675,14 @@ class PolygonExtractor(object):
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"add to path
%
d(
%
g,
%
g)"
\
print
"add to path
%
d(
%
g,
%
g)"
\
%
(
left_path
.
id
,
left_point
.
x
,
left_point
.
y
)
%
(
left_path
.
id
,
left_point
[
0
],
left_point
[
1
]
)
left_path
.
append
(
left_point
)
left_path
.
append
(
left_point
)
right_path
.
append
(
right_point
)
right_path
.
append
(
right_point
)
if
right_path
==
curr_path
.
peek
():
if
right_path
==
curr_path
.
peek
():
curr_path
.
next
()
curr_path
.
next
()
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"add to path
%
d(
%
g,
%
g)"
\
print
"add to path
%
d(
%
g,
%
g)"
\
%
(
right_path
.
id
,
right_point
.
x
,
right_point
.
y
)
%
(
right_path
.
id
,
right_point
[
0
],
right_point
[
1
]
)
winding
=
right_path
.
winding
winding
=
right_path
.
winding
prev_point
.
next
()
prev_point
.
next
()
curr_point
.
next
()
curr_point
.
next
()
...
@@ -690,8 +690,8 @@ class PolygonExtractor(object):
...
@@ -690,8 +690,8 @@ class PolygonExtractor(object):
if
DEBUG_POLYGONEXTRACTOR
:
if
DEBUG_POLYGONEXTRACTOR
:
print
"active paths: "
,
print
"active paths: "
,
for
path
in
self
.
curr_path_list
:
for
path
in
self
.
curr_path_list
:
print
"
%
d(
%
g,
%
g,w=
%
d)"
%
(
path
.
id
,
path
.
points
[
-
1
]
.
x
,
print
"
%
d(
%
g,
%
g,w=
%
d)"
%
(
path
.
id
,
path
.
points
[
-
1
]
[
0
]
,
path
.
points
[
-
1
]
.
y
,
path
.
winding
),
path
.
points
[
-
1
]
[
1
]
,
path
.
winding
),
print
print
self
.
prev_line
=
scanline
self
.
prev_line
=
scanline
...
@@ -702,26 +702,26 @@ class PolygonExtractor(object):
...
@@ -702,26 +702,26 @@ class PolygonExtractor(object):
hor_path_list
=
[]
hor_path_list
=
[]
for
s
in
self
.
hor_path_list
:
for
s
in
self
.
hor_path_list
:
allsame
=
True
allsame
=
True
miny
=
s
.
points
[
0
]
.
y
miny
=
s
.
points
[
0
]
[
1
]
maxy
=
s
.
points
[
0
]
.
y
maxy
=
s
.
points
[
0
]
[
1
]
for
p
in
s
.
points
:
for
p
in
s
.
points
:
if
not
p
.
x
==
s
.
points
[
0
]
.
x
:
if
not
p
[
0
]
==
s
.
points
[
0
][
0
]
:
allsame
=
False
allsame
=
False
if
p
.
y
<
miny
:
if
p
[
1
]
<
miny
:
miny
=
p
.
y
miny
=
p
[
1
]
if
p
.
y
>
maxy
:
if
p
[
1
]
>
maxy
:
maxy
=
p
.
y
maxy
=
p
[
1
]
if
allsame
:
if
allsame
:
if
DEBUG_POLYGONEXTRACTOR2
:
if
DEBUG_POLYGONEXTRACTOR2
:
print
"all same !"
print
"all same !"
s0
=
Path
()
s0
=
Path
()
for
p
in
s
.
points
:
for
p
in
s
.
points
:
if
p
.
y
==
miny
:
if
p
[
1
]
==
miny
:
s0
.
append
(
p
)
s0
.
append
(
p
)
hor_path_list
.
append
(
s0
)
hor_path_list
.
append
(
s0
)
s1
=
Path
()
s1
=
Path
()
for
p
in
s
.
points
:
for
p
in
s
.
points
:
if
p
.
y
==
maxy
:
if
p
[
1
]
==
maxy
:
s1
.
append
(
p
)
s1
.
append
(
p
)
hor_path_list
.
append
(
s1
)
hor_path_list
.
append
(
s1
)
continue
continue
...
@@ -729,28 +729,28 @@ class PolygonExtractor(object):
...
@@ -729,28 +729,28 @@ class PolygonExtractor(object):
p_iter
=
CyclicIterator
(
s
.
points
)
p_iter
=
CyclicIterator
(
s
.
points
)
p
=
s
.
points
[
0
]
p
=
s
.
points
[
0
]
next_p
=
p_iter
.
next
()
next_p
=
p_iter
.
next
()
while
not
((
prev
.
x
>=
p
.
x
)
and
(
next_p
.
x
>
p
.
x
)):
while
not
((
prev
[
0
]
>=
p
[
0
])
and
(
next_p
[
0
]
>
p
[
0
]
)):
p
=
next_p
p
=
next_p
next_p
=
p_iter
.
next
()
next_p
=
p_iter
.
next
()
count
=
0
count
=
0
while
count
<
len
(
s
.
points
):
while
count
<
len
(
s
.
points
):
s0
=
Path
()
s0
=
Path
()
while
next_p
.
x
>=
p
.
x
:
while
next_p
[
0
]
>=
p
[
0
]
:
s0
.
append
(
p
)
s0
.
append
(
p
)
p
=
next_p
p
=
next_p
next_p
=
p_iter
.
next
()
next_p
=
p_iter
.
next
()
count
+=
1
count
+=
1
s0
.
append
(
p
)
s0
.
append
(
p
)
while
(
len
(
s0
.
points
)
>
1
)
\
while
(
len
(
s0
.
points
)
>
1
)
\
and
(
s0
.
points
[
0
]
.
x
==
s0
.
points
[
1
]
.
x
):
and
(
s0
.
points
[
0
]
[
0
]
==
s0
.
points
[
1
][
0
]
):
s0
.
points
=
s0
.
points
[
1
:]
s0
.
points
=
s0
.
points
[
1
:]
while
(
len
(
s0
.
points
)
>
1
)
\
while
(
len
(
s0
.
points
)
>
1
)
\
and
(
s0
.
points
[
-
2
]
.
x
==
s0
.
points
[
-
1
]
.
x
):
and
(
s0
.
points
[
-
2
]
[
0
]
==
s0
.
points
[
-
1
][
0
]
):
s0
.
points
=
s0
.
points
[
0
:
-
1
]
s0
.
points
=
s0
.
points
[
0
:
-
1
]
hor_path_list
.
append
(
s0
)
hor_path_list
.
append
(
s0
)
s1
=
Path
()
s1
=
Path
()
while
next_p
.
x
<=
p
.
x
:
while
next_p
[
0
]
<=
p
[
0
]
:
s1
.
append
(
p
)
s1
.
append
(
p
)
p
=
next_p
p
=
next_p
next_p
=
p_iter
.
next
()
next_p
=
p_iter
.
next
()
...
@@ -758,13 +758,13 @@ class PolygonExtractor(object):
...
@@ -758,13 +758,13 @@ class PolygonExtractor(object):
s1
.
append
(
p
)
s1
.
append
(
p
)
s1
.
reverse
()
s1
.
reverse
()
while
(
len
(
s1
.
points
)
>
1
)
\
while
(
len
(
s1
.
points
)
>
1
)
\
and
(
s1
.
points
[
0
]
.
x
==
s1
.
points
[
1
]
.
x
):
and
(
s1
.
points
[
0
]
[
0
]
==
s1
.
points
[
1
][
0
]
):
s1
.
points
=
s1
.
points
[
1
:]
s1
.
points
=
s1
.
points
[
1
:]
while
(
len
(
s1
.
points
)
>
1
)
\
while
(
len
(
s1
.
points
)
>
1
)
\
and
(
s1
.
points
[
-
2
]
.
x
==
s1
.
points
[
-
1
]
.
x
):
and
(
s1
.
points
[
-
2
]
[
0
]
==
s1
.
points
[
-
1
][
0
]
):
s1
.
points
=
s1
.
points
[:
-
1
]
s1
.
points
=
s1
.
points
[:
-
1
]
hor_path_list
.
append
(
s1
)
hor_path_list
.
append
(
s1
)
hor_path_list
.
sort
(
cmp
=
lambda
a
,
b
:
cmp
(
a
.
points
[
0
]
.
x
,
b
.
points
[
0
]
.
x
))
hor_path_list
.
sort
(
cmp
=
lambda
a
,
b
:
cmp
(
a
.
points
[
0
]
[
0
],
b
.
points
[
0
][
0
]
))
if
DEBUG_POLYGONEXTRACTOR2
:
if
DEBUG_POLYGONEXTRACTOR2
:
print
"ver_hor_path_list = "
,
hor_path_list
print
"ver_hor_path_list = "
,
hor_path_list
for
s
in
hor_path_list
:
for
s
in
hor_path_list
:
...
@@ -785,12 +785,12 @@ class PolygonExtractor(object):
...
@@ -785,12 +785,12 @@ class PolygonExtractor(object):
next_x
=
INFINITE
next_x
=
INFINITE
if
self
.
ver_hor_path_list
\
if
self
.
ver_hor_path_list
\
and
(
self
.
ver_hor_path_list
[
0
]
.
points
[
0
]
.
x
<
next_x
):
and
(
self
.
ver_hor_path_list
[
0
]
.
points
[
0
]
[
0
]
<
next_x
):
next_x
=
self
.
ver_hor_path_list
[
0
]
.
points
[
0
]
.
x
next_x
=
self
.
ver_hor_path_list
[
0
]
.
points
[
0
]
[
0
]
if
self
.
act_hor_path_list
\
if
self
.
act_hor_path_list
\
and
(
self
.
act_hor_path_list
[
0
]
.
points
[
0
]
.
x
<
next_x
):
and
(
self
.
act_hor_path_list
[
0
]
.
points
[
0
]
[
0
]
<
next_x
):
next_x
=
self
.
act_hor_path_list
[
0
]
.
points
[
0
]
.
x
next_x
=
self
.
act_hor_path_list
[
0
]
.
points
[
0
]
[
0
]
if
next_x
>=
_next_x
:
if
next_x
>=
_next_x
:
return
return
...
@@ -801,13 +801,13 @@ class PolygonExtractor(object):
...
@@ -801,13 +801,13 @@ class PolygonExtractor(object):
print
"next_x ="
,
next_x
print
"next_x ="
,
next_x
if
self
.
ver_hor_path_list
\
if
self
.
ver_hor_path_list
\
and
(
self
.
ver_hor_path_list
[
0
]
.
points
[
0
]
.
x
<=
next_x
):
and
(
self
.
ver_hor_path_list
[
0
]
.
points
[
0
]
[
0
]
<=
next_x
):
while
self
.
ver_hor_path_list
\
while
self
.
ver_hor_path_list
\
and
(
self
.
ver_hor_path_list
[
0
]
.
points
[
0
]
.
x
<=
next_x
):
and
(
self
.
ver_hor_path_list
[
0
]
.
points
[
0
]
[
0
]
<=
next_x
):
self
.
act_hor_path_list
.
append
(
self
.
ver_hor_path_list
[
0
])
self
.
act_hor_path_list
.
append
(
self
.
ver_hor_path_list
[
0
])
self
.
ver_hor_path_list
=
self
.
ver_hor_path_list
[
1
:]
self
.
ver_hor_path_list
=
self
.
ver_hor_path_list
[
1
:]
self
.
act_hor_path_list
.
sort
(
cmp
=
lambda
a
,
b
:
self
.
act_hor_path_list
.
sort
(
cmp
=
lambda
a
,
b
:
cmp
(
a
.
points
[
0
]
.
x
,
b
.
points
[
0
]
.
x
))
cmp
(
a
.
points
[
0
]
[
0
],
b
.
points
[
0
][
0
]
))
scanline
=
[]
scanline
=
[]
i
=
0
i
=
0
...
@@ -816,7 +816,7 @@ class PolygonExtractor(object):
...
@@ -816,7 +816,7 @@ class PolygonExtractor(object):
if
DEBUG_POLYGONEXTRACTOR2
:
if
DEBUG_POLYGONEXTRACTOR2
:
print
"s ="
,
s
print
"s ="
,
s
scanline
.
append
(
s
.
points
[
0
])
scanline
.
append
(
s
.
points
[
0
])
if
s
.
points
[
0
]
.
x
<=
next_x
:
if
s
.
points
[
0
]
[
0
]
<=
next_x
:
if
len
(
s
.
points
)
<=
1
:
if
len
(
s
.
points
)
<=
1
:
if
DEBUG_POLYGONEXTRACTOR2
:
if
DEBUG_POLYGONEXTRACTOR2
:
print
"remove list"
print
"remove list"
...
@@ -830,17 +830,17 @@ class PolygonExtractor(object):
...
@@ -830,17 +830,17 @@ class PolygonExtractor(object):
if
DEBUG_POLYGONEXTRACTOR2
:
if
DEBUG_POLYGONEXTRACTOR2
:
print
"remove point"
,
s
.
points
[
0
]
print
"remove point"
,
s
.
points
[
0
]
s
.
points
=
s
.
points
[
1
:]
s
.
points
=
s
.
points
[
1
:]
if
len
(
s
.
points
)
>
0
and
s
.
points
[
0
]
.
x
==
next_x
:
if
len
(
s
.
points
)
>
0
and
s
.
points
[
0
]
[
0
]
==
next_x
:
# TODO: the variable "repeat" is never used.
# TODO: the variable "repeat" is never used.
# Any idea?
# Any idea?
repeat
=
True
repeat
=
True
i
+=
1
i
+=
1
self
.
act_hor_path_list
.
sort
(
cmp
=
lambda
a
,
b
:
self
.
act_hor_path_list
.
sort
(
cmp
=
lambda
a
,
b
:
cmp
(
a
.
points
[
0
]
.
x
,
b
.
points
[
0
]
.
x
))
cmp
(
a
.
points
[
0
]
[
0
],
b
.
points
[
0
][
0
]
))
if
len
(
scanline
)
==
0
:
if
len
(
scanline
)
==
0
:
return
return
scanline
.
sort
(
cmp
=
lambda
a
,
b
:
cmp
(
a
.
y
,
b
.
y
))
scanline
.
sort
(
cmp
=
lambda
a
,
b
:
cmp
(
a
[
1
],
b
[
1
]
))
if
DEBUG_POLYGONEXTRACTOR2
:
if
DEBUG_POLYGONEXTRACTOR2
:
print
"scanline' ="
,
scanline
print
"scanline' ="
,
scanline
print
"ver_hor_path_list ="
,
self
.
ver_hor_path_list
print
"ver_hor_path_list ="
,
self
.
ver_hor_path_list
...
...
pycam/Geometry/Triangle.py
View file @
9b939792
...
@@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License
...
@@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry
import
TransformableContainer
,
IDGenerator
from
pycam.Geometry
import
TransformableContainer
,
IDGenerator
...
@@ -53,55 +53,46 @@ class Triangle(IDGenerator, TransformableContainer):
...
@@ -53,55 +53,46 @@ class Triangle(IDGenerator, TransformableContainer):
self
.
reset_cache
()
self
.
reset_cache
()
def
reset_cache
(
self
):
def
reset_cache
(
self
):
self
.
minx
=
min
(
self
.
p1
.
x
,
self
.
p2
.
x
,
self
.
p3
.
x
)
self
.
minx
=
min
(
self
.
p1
[
0
],
self
.
p2
[
0
],
self
.
p3
[
0
]
)
self
.
miny
=
min
(
self
.
p1
.
y
,
self
.
p2
.
y
,
self
.
p3
.
y
)
self
.
miny
=
min
(
self
.
p1
[
1
],
self
.
p2
[
1
],
self
.
p3
[
1
]
)
self
.
minz
=
min
(
self
.
p1
.
z
,
self
.
p2
.
z
,
self
.
p3
.
z
)
self
.
minz
=
min
(
self
.
p1
[
2
],
self
.
p2
[
2
],
self
.
p3
[
2
]
)
self
.
maxx
=
max
(
self
.
p1
.
x
,
self
.
p2
.
x
,
self
.
p3
.
x
)
self
.
maxx
=
max
(
self
.
p1
[
0
],
self
.
p2
[
0
],
self
.
p3
[
0
]
)
self
.
maxy
=
max
(
self
.
p1
.
y
,
self
.
p2
.
y
,
self
.
p3
.
y
)
self
.
maxy
=
max
(
self
.
p1
[
1
],
self
.
p2
[
1
],
self
.
p3
[
1
]
)
self
.
maxz
=
max
(
self
.
p1
.
z
,
self
.
p2
.
z
,
self
.
p3
.
z
)
self
.
maxz
=
max
(
self
.
p1
[
2
],
self
.
p2
[
2
],
self
.
p3
[
2
]
)
self
.
e1
=
Line
(
self
.
p1
,
self
.
p2
)
self
.
e1
=
Line
(
self
.
p1
,
self
.
p2
)
self
.
e2
=
Line
(
self
.
p2
,
self
.
p3
)
self
.
e2
=
Line
(
self
.
p2
,
self
.
p3
)
self
.
e3
=
Line
(
self
.
p3
,
self
.
p1
)
self
.
e3
=
Line
(
self
.
p3
,
self
.
p1
)
# calculate normal, if p1-p2-pe are in clockwise order
# calculate normal, if p1-p2-pe are in clockwise order
if
self
.
normal
is
None
:
if
self
.
normal
is
None
:
self
.
normal
=
self
.
p3
.
sub
(
self
.
p1
)
.
cross
(
self
.
p2
.
sub
(
\
self
.
normal
=
pnormalized
(
pcross
(
psub
(
self
.
p3
,
self
.
p1
),
psub
(
self
.
p2
,
self
.
p1
)))
self
.
p1
))
.
normalized
()
if
not
len
(
self
.
normal
)
>
3
:
if
not
isinstance
(
self
.
normal
,
Vector
):
self
.
normal
=
(
self
.
normal
[
0
],
self
.
normal
[
1
],
self
.
normal
[
2
],
'v'
)
self
.
normal
=
self
.
normal
.
get_vector
()
self
.
center
=
pdiv
(
padd
(
padd
(
self
.
p1
,
self
.
p2
),
self
.
p3
),
3
)
# make sure that the normal has always a unit length
self
.
normal
=
self
.
normal
.
normalized
()
self
.
center
=
self
.
p1
.
add
(
self
.
p2
)
.
add
(
self
.
p3
)
.
div
(
3
)
self
.
plane
=
Plane
(
self
.
center
,
self
.
normal
)
self
.
plane
=
Plane
(
self
.
center
,
self
.
normal
)
# calculate circumcircle (resulting in radius and middle)
# calculate circumcircle (resulting in radius and middle)
denom
=
self
.
p2
.
sub
(
self
.
p1
)
.
cross
(
self
.
p3
.
sub
(
self
.
p2
))
.
norm
denom
=
pnorm
(
pcross
(
psub
(
self
.
p2
,
self
.
p1
),
psub
(
self
.
p3
,
self
.
p2
)))
self
.
radius
=
(
self
.
p2
.
sub
(
self
.
p1
)
.
norm
\
self
.
radius
=
(
pnorm
(
psub
(
self
.
p2
,
self
.
p1
))
*
pnorm
(
psub
(
self
.
p3
,
self
.
p2
))
*
pnorm
(
psub
(
self
.
p3
,
self
.
p1
)))
/
(
2
*
denom
)
*
self
.
p3
.
sub
(
self
.
p2
)
.
norm
*
self
.
p3
.
sub
(
self
.
p1
)
.
norm
)
\
/
(
2
*
denom
)
self
.
radiussq
=
self
.
radius
**
2
self
.
radiussq
=
self
.
radius
**
2
denom2
=
2
*
denom
*
denom
denom2
=
2
*
denom
*
denom
alpha
=
self
.
p3
.
sub
(
self
.
p2
)
.
normsq
\
alpha
=
pnormsq
(
psub
(
self
.
p3
,
self
.
p2
))
*
pdot
(
psub
(
self
.
p1
,
self
.
p2
),
psub
(
self
.
p1
,
self
.
p3
))
/
denom2
*
self
.
p1
.
sub
(
self
.
p2
)
.
dot
(
self
.
p1
.
sub
(
self
.
p3
))
/
denom2
beta
=
pnormsq
(
psub
(
self
.
p1
,
self
.
p3
))
*
pdot
(
psub
(
self
.
p2
,
self
.
p1
),
psub
(
self
.
p2
,
self
.
p3
))
/
denom2
beta
=
self
.
p1
.
sub
(
self
.
p3
)
.
normsq
\
gamma
=
pnormsq
(
psub
(
self
.
p1
,
self
.
p2
))
*
pdot
(
psub
(
self
.
p3
,
self
.
p1
),
psub
(
self
.
p3
,
self
.
p2
))
/
denom2
*
self
.
p2
.
sub
(
self
.
p1
)
.
dot
(
self
.
p2
.
sub
(
self
.
p3
))
/
denom2
self
.
middle
=
(
self
.
p1
[
0
]
*
alpha
+
self
.
p2
[
0
]
*
beta
+
self
.
p3
[
0
]
*
gamma
,
gamma
=
self
.
p1
.
sub
(
self
.
p2
)
.
normsq
\
self
.
p1
[
1
]
*
alpha
+
self
.
p2
[
1
]
*
beta
+
self
.
p3
[
1
]
*
gamma
,
*
self
.
p3
.
sub
(
self
.
p1
)
.
dot
(
self
.
p3
.
sub
(
self
.
p2
))
/
denom2
self
.
p1
[
2
]
*
alpha
+
self
.
p2
[
2
]
*
beta
+
self
.
p3
[
2
]
*
gamma
)
self
.
middle
=
Point
(
self
.
p1
.
x
*
alpha
+
self
.
p2
.
x
*
beta
+
self
.
p3
.
x
*
gamma
,
self
.
p1
.
y
*
alpha
+
self
.
p2
.
y
*
beta
+
self
.
p3
.
y
*
gamma
,
self
.
p1
.
z
*
alpha
+
self
.
p2
.
z
*
beta
+
self
.
p3
.
z
*
gamma
)
def
__repr__
(
self
):
def
__repr__
(
self
):
return
"Triangle
%
d<
%
s,
%
s,
%
s>"
%
(
self
.
id
,
self
.
p1
,
self
.
p2
,
self
.
p3
)
return
"Triangle
%
d<
%
s,
%
s,
%
s>"
%
(
self
.
id
,
self
.
p1
,
self
.
p2
,
self
.
p3
)
def
copy
(
self
):
def
copy
(
self
):
return
self
.
__class__
(
self
.
p1
.
copy
(),
self
.
p2
.
copy
(),
self
.
p3
.
copy
()
,
return
self
.
__class__
(
self
.
p1
,
self
.
p2
,
self
.
p3
,
self
.
normal
.
copy
()
)
self
.
normal
)
def
next
(
self
):
def
next
(
self
):
yield
self
.
p1
yield
"p1"
yield
self
.
p2
yield
"p2"
yield
self
.
p3
yield
"p3"
yield
self
.
normal
yield
"normal"
def
get_points
(
self
):
def
get_points
(
self
):
return
(
self
.
p1
,
self
.
p2
,
self
.
p3
)
return
(
self
.
p1
,
self
.
p2
,
self
.
p3
)
...
@@ -118,25 +109,25 @@ class Triangle(IDGenerator, TransformableContainer):
...
@@ -118,25 +109,25 @@ class Triangle(IDGenerator, TransformableContainer):
GL
.
glBegin
(
GL
.
GL_TRIANGLES
)
GL
.
glBegin
(
GL
.
GL_TRIANGLES
)
# use normals to improve lighting (contributed by imyrek)
# use normals to improve lighting (contributed by imyrek)
normal_t
=
self
.
normal
normal_t
=
self
.
normal
GL
.
glNormal3f
(
normal_t
.
x
,
normal_t
.
y
,
normal_t
.
z
)
GL
.
glNormal3f
(
normal_t
[
0
],
normal_t
[
1
],
normal_t
[
2
]
)
# The triangle's points are in clockwise order, but GL expects
# The triangle's points are in clockwise order, but GL expects
# counter-clockwise sorting.
# counter-clockwise sorting.
GL
.
glVertex3f
(
self
.
p1
.
x
,
self
.
p1
.
y
,
self
.
p1
.
z
)
GL
.
glVertex3f
(
self
.
p1
[
0
],
self
.
p1
[
1
],
self
.
p1
[
2
]
)
GL
.
glVertex3f
(
self
.
p3
.
x
,
self
.
p3
.
y
,
self
.
p3
.
z
)
GL
.
glVertex3f
(
self
.
p3
[
0
],
self
.
p3
[
1
],
self
.
p3
[
2
]
)
GL
.
glVertex3f
(
self
.
p2
.
x
,
self
.
p2
.
y
,
self
.
p2
.
z
)
GL
.
glVertex3f
(
self
.
p2
[
0
],
self
.
p2
[
1
],
self
.
p2
[
2
]
)
GL
.
glEnd
()
GL
.
glEnd
()
if
show_directions
:
# display surface normals
if
show_directions
:
# display surface normals
n
=
self
.
normal
n
=
self
.
normal
c
=
self
.
center
c
=
self
.
center
d
=
0.5
d
=
0.5
GL
.
glBegin
(
GL
.
GL_LINES
)
GL
.
glBegin
(
GL
.
GL_LINES
)
GL
.
glVertex3f
(
c
.
x
,
c
.
y
,
c
.
z
)
GL
.
glVertex3f
(
c
[
0
],
c
[
1
],
c
[
2
]
)
GL
.
glVertex3f
(
c
.
x
+
n
.
x
*
d
,
c
.
y
+
n
.
y
*
d
,
c
.
z
+
n
.
z
*
d
)
GL
.
glVertex3f
(
c
[
0
]
+
n
[
0
]
*
d
,
c
[
1
]
+
n
[
1
]
*
d
,
c
[
2
]
+
n
[
2
]
*
d
)
GL
.
glEnd
()
GL
.
glEnd
()
if
False
:
# display bounding sphere
if
False
:
# display bounding sphere
GL
.
glPushMatrix
()
GL
.
glPushMatrix
()
middle
=
self
.
middle
middle
=
self
.
middle
GL
.
glTranslate
(
middle
.
x
,
middle
.
y
,
middle
.
z
)
GL
.
glTranslate
(
middle
[
0
],
middle
[
1
],
middle
[
2
]
)
if
not
hasattr
(
self
,
"_sphere"
):
if
not
hasattr
(
self
,
"_sphere"
):
self
.
_sphere
=
GLU
.
gluNewQuadric
()
self
.
_sphere
=
GLU
.
gluNewQuadric
()
GLU
.
gluSphere
(
self
.
_sphere
,
self
.
radius
,
10
,
10
)
GLU
.
gluSphere
(
self
.
_sphere
,
self
.
radius
,
10
,
10
)
...
@@ -144,15 +135,15 @@ class Triangle(IDGenerator, TransformableContainer):
...
@@ -144,15 +135,15 @@ class Triangle(IDGenerator, TransformableContainer):
if
pycam
.
Utils
.
log
.
is_debug
():
# draw triangle id on triangle face
if
pycam
.
Utils
.
log
.
is_debug
():
# draw triangle id on triangle face
GL
.
glPushMatrix
()
GL
.
glPushMatrix
()
c
=
self
.
center
c
=
self
.
center
GL
.
glTranslate
(
c
.
x
,
c
.
y
,
c
.
z
)
GL
.
glTranslate
(
c
[
0
],
c
[
1
],
c
[
2
]
)
p12
=
self
.
p1
.
add
(
self
.
p2
)
.
mul
(
0.5
)
p12
=
pmul
(
padd
(
self
.
p1
,
self
.
p2
),
0.5
)
p3_12
=
self
.
p3
.
sub
(
p12
)
.
normalized
(
)
p3_12
=
pnormalized
(
psub
(
self
.
p3
,
p12
)
)
p2_1
=
self
.
p1
.
sub
(
self
.
p2
)
.
normalized
(
)
p2_1
=
pnormalized
(
psub
(
self
.
p1
,
self
.
p2
)
)
pn
=
p
2_1
.
cross
(
p3_12
)
pn
=
p
cross
(
p2_1
,
p3_12
)
GL
.
glMultMatrixf
((
p2_1
.
x
,
p2_1
.
y
,
p2_1
.
z
,
0
,
p3_12
.
x
,
p3_12
.
y
,
GL
.
glMultMatrixf
((
p2_1
[
0
],
p2_1
[
1
],
p2_1
[
2
],
0
,
p3_12
[
0
],
p3_12
[
1
]
,
p3_12
.
z
,
0
,
pn
.
x
,
pn
.
y
,
pn
.
z
,
0
,
0
,
0
,
0
,
1
))
p3_12
[
2
],
0
,
pn
[
0
],
pn
[
1
],
pn
[
2
]
,
0
,
0
,
0
,
0
,
1
))
n
=
self
.
normal
.
mul
(
0.01
)
n
=
pmul
(
self
.
normal
,
0.01
)
GL
.
glTranslatef
(
n
.
x
,
n
.
y
,
n
.
z
)
GL
.
glTranslatef
(
n
[
0
],
n
[
1
],
n
[
2
]
)
maxdim
=
max
((
self
.
maxx
-
self
.
minx
),
(
self
.
maxy
-
self
.
miny
),
maxdim
=
max
((
self
.
maxx
-
self
.
minx
),
(
self
.
maxy
-
self
.
miny
),
(
self
.
maxz
-
self
.
minz
))
(
self
.
maxz
-
self
.
minz
))
factor
=
0.001
factor
=
0.001
...
@@ -167,18 +158,18 @@ class Triangle(IDGenerator, TransformableContainer):
...
@@ -167,18 +158,18 @@ class Triangle(IDGenerator, TransformableContainer):
GL
.
glPopMatrix
()
GL
.
glPopMatrix
()
if
False
:
# draw point id on triangle face
if
False
:
# draw point id on triangle face
c
=
self
.
center
c
=
self
.
center
p12
=
self
.
p1
.
add
(
self
.
p2
)
.
mul
(
0.5
)
p12
=
pmul
(
padd
(
self
.
p1
,
self
.
p2
),
0.5
)
p3_12
=
self
.
p3
.
sub
(
p12
)
.
normalized
(
)
p3_12
=
pnormalized
(
psub
(
self
.
p3
,
p12
)
)
p2_1
=
self
.
p1
.
sub
(
self
.
p2
)
.
normalized
(
)
p2_1
=
pnormalized
(
psub
(
self
.
p1
,
self
.
p2
)
)
pn
=
p
2_1
.
cross
(
p3_12
)
pn
=
p
cross
(
p2_1
,
p3_12
)
n
=
self
.
normal
.
mul
(
0.01
)
n
=
pmul
(
self
.
normal
,
0.01
)
for
p
in
(
self
.
p1
,
self
.
p2
,
self
.
p3
):
for
p
in
(
self
.
p1
,
self
.
p2
,
self
.
p3
):
GL
.
glPushMatrix
()
GL
.
glPushMatrix
()
pp
=
p
.
sub
(
p
.
sub
(
c
)
.
mul
(
0.3
))
pp
=
p
sub
(
p
,
pmul
(
psub
(
p
,
c
),
0.3
))
GL
.
glTranslate
(
pp
.
x
,
pp
.
y
,
pp
.
z
)
GL
.
glTranslate
(
pp
[
0
],
pp
[
1
],
pp
[
2
]
)
GL
.
glMultMatrixf
((
p2_1
.
x
,
p2_1
.
y
,
p2_1
.
z
,
0
,
p3_12
.
x
,
p3_12
.
y
,
GL
.
glMultMatrixf
((
p2_1
[
0
],
p2_1
[
1
],
p2_1
[
2
],
0
,
p3_12
[
0
],
p3_12
[
1
]
,
p3_12
.
z
,
0
,
pn
.
x
,
pn
.
y
,
pn
.
z
,
0
,
0
,
0
,
0
,
1
))
p3_12
[
2
],
0
,
pn
[
0
],
pn
[
1
],
pn
[
2
]
,
0
,
0
,
0
,
0
,
1
))
GL
.
glTranslatef
(
n
.
x
,
n
.
y
,
n
.
z
)
GL
.
glTranslatef
(
n
[
0
],
n
[
1
],
n
[
2
]
)
GL
.
glScalef
(
0.001
,
0.001
,
0.001
)
GL
.
glScalef
(
0.001
,
0.001
,
0.001
)
w
=
0
w
=
0
for
ch
in
str
(
p
.
id
):
for
ch
in
str
(
p
.
id
):
...
@@ -191,15 +182,15 @@ class Triangle(IDGenerator, TransformableContainer):
...
@@ -191,15 +182,15 @@ class Triangle(IDGenerator, TransformableContainer):
def
is_point_inside
(
self
,
p
):
def
is_point_inside
(
self
,
p
):
# http://www.blackpawn.com/texts/pointinpoly/default.html
# http://www.blackpawn.com/texts/pointinpoly/default.html
# Compute vectors
# Compute vectors
v0
=
self
.
p3
.
sub
(
self
.
p1
)
v0
=
psub
(
self
.
p3
,
self
.
p1
)
v1
=
self
.
p2
.
sub
(
self
.
p1
)
v1
=
psub
(
self
.
p2
,
self
.
p1
)
v2
=
p
.
sub
(
self
.
p1
)
v2
=
p
sub
(
p
,
self
.
p1
)
# Compute dot products
# Compute dot products
dot00
=
v0
.
dot
(
v0
)
dot00
=
pdot
(
v0
,
v0
)
dot01
=
v0
.
dot
(
v1
)
dot01
=
pdot
(
v0
,
v1
)
dot02
=
v0
.
dot
(
v2
)
dot02
=
pdot
(
v0
,
v2
)
dot11
=
v1
.
dot
(
v1
)
dot11
=
pdot
(
v1
,
v1
)
dot12
=
v1
.
dot
(
v2
)
dot12
=
pdot
(
v1
,
v2
)
# Compute barycentric coordinates
# Compute barycentric coordinates
denom
=
dot00
*
dot11
-
dot01
*
dot01
denom
=
dot00
*
dot11
-
dot01
*
dot01
if
denom
==
0
:
if
denom
==
0
:
...
@@ -218,9 +209,9 @@ class Triangle(IDGenerator, TransformableContainer):
...
@@ -218,9 +209,9 @@ class Triangle(IDGenerator, TransformableContainer):
if
depth
==
0
:
if
depth
==
0
:
sub
.
append
(
self
)
sub
.
append
(
self
)
else
:
else
:
p4
=
self
.
p1
.
add
(
self
.
p2
)
.
div
(
2
)
p4
=
pdiv
(
padd
(
self
.
p1
,
self
.
p2
),
2
)
p5
=
self
.
p2
.
add
(
self
.
p3
)
.
div
(
2
)
p5
=
pdiv
(
padd
(
self
.
p2
,
self
.
p3
),
2
)
p6
=
self
.
p3
.
add
(
self
.
p1
)
.
div
(
2
)
p6
=
pdiv
(
padd
(
self
.
p3
,
self
.
p1
),
2
)
sub
+=
Triangle
(
self
.
p1
,
p4
,
p6
)
.
subdivide
(
depth
-
1
)
sub
+=
Triangle
(
self
.
p1
,
p4
,
p6
)
.
subdivide
(
depth
-
1
)
sub
+=
Triangle
(
p6
,
p5
,
self
.
p3
)
.
subdivide
(
depth
-
1
)
sub
+=
Triangle
(
p6
,
p5
,
self
.
p3
)
.
subdivide
(
depth
-
1
)
sub
+=
Triangle
(
p6
,
p4
,
p5
)
.
subdivide
(
depth
-
1
)
sub
+=
Triangle
(
p6
,
p4
,
p5
)
.
subdivide
(
depth
-
1
)
...
@@ -228,6 +219,6 @@ class Triangle(IDGenerator, TransformableContainer):
...
@@ -228,6 +219,6 @@ class Triangle(IDGenerator, TransformableContainer):
return
sub
return
sub
def
get_area
(
self
):
def
get_area
(
self
):
cross
=
self
.
p2
.
sub
(
self
.
p1
)
.
cross
(
self
.
p3
.
sub
(
self
.
p1
))
cross
=
pcross
(
psub
(
self
.
p2
,
self
.
p1
),
psub
(
self
.
p3
,
self
.
p1
))
return
cross
.
norm
/
2
return
pnorm
(
cross
)
/
2
pycam/Geometry/TriangleKdtree.py
View file @
9b939792
...
@@ -79,10 +79,10 @@ class TriangleKdtree(kdtree):
...
@@ -79,10 +79,10 @@ class TriangleKdtree(kdtree):
def
__init__
(
self
,
triangles
,
cutoff
=
3
,
cutoff_distance
=
1.0
):
def
__init__
(
self
,
triangles
,
cutoff
=
3
,
cutoff_distance
=
1.0
):
nodes
=
[]
nodes
=
[]
for
t
in
triangles
:
for
t
in
triangles
:
n
=
Node
(
t
,
(
min
(
t
.
p1
.
x
,
t
.
p2
.
x
,
t
.
p3
.
x
),
n
=
Node
(
t
,
(
min
(
t
.
p1
[
0
],
t
.
p2
[
0
],
t
.
p3
[
0
]
),
max
(
t
.
p1
.
x
,
t
.
p2
.
x
,
t
.
p3
.
x
),
max
(
t
.
p1
[
0
],
t
.
p2
[
0
],
t
.
p3
[
0
]
),
min
(
t
.
p1
.
y
,
t
.
p2
.
y
,
t
.
p3
.
y
),
min
(
t
.
p1
[
1
],
t
.
p2
[
1
],
t
.
p3
[
1
]
),
max
(
t
.
p1
.
y
,
t
.
p2
.
y
,
t
.
p3
.
y
)))
max
(
t
.
p1
[
1
],
t
.
p2
[
1
],
t
.
p3
[
1
]
)))
nodes
.
append
(
n
)
nodes
.
append
(
n
)
super
(
TriangleKdtree
,
self
)
.
__init__
(
nodes
,
cutoff
,
cutoff_distance
)
super
(
TriangleKdtree
,
self
)
.
__init__
(
nodes
,
cutoff
,
cutoff_distance
)
...
...
pycam/Geometry/__init__.py
View file @
9b939792
...
@@ -21,11 +21,15 @@ You should have received a copy of the GNU General Public License
...
@@ -21,11 +21,15 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
__all__
=
[
"utils"
,
"Line"
,
"Model"
,
"Path"
,
"Plane"
,
"
Point"
,
"
Triangle"
,
__all__
=
[
"utils"
,
"Line"
,
"Model"
,
"Path"
,
"Plane"
,
"Triangle"
,
"PolygonExtractor"
,
"TriangleKdtree"
,
"intersection"
,
"kdtree"
,
"PolygonExtractor"
,
"TriangleKdtree"
,
"intersection"
,
"kdtree"
,
"Matrix"
,
"Polygon"
,
"Letters"
]
"Matrix"
,
"Polygon"
,
"Letters"
,
"PointUtils"
]
from
pycam.Geometry.PointUtils
import
*
from
pycam.Geometry.utils
import
epsilon
,
ceil
from
pycam.Geometry.utils
import
epsilon
,
ceil
from
pycam.Utils
import
log
import
types
log
=
log
.
get_logger
()
import
math
import
math
...
@@ -33,17 +37,17 @@ def get_bisector(p1, p2, p3, up_vector):
...
@@ -33,17 +37,17 @@ def get_bisector(p1, p2, p3, up_vector):
""" Calculate the bisector between p1, p2 and p3, whereas p2 is the origin
""" Calculate the bisector between p1, p2 and p3, whereas p2 is the origin
of the angle.
of the angle.
"""
"""
d1
=
p
2
.
sub
(
p1
)
.
normalized
(
)
d1
=
p
normalized
(
psub
(
p2
,
p1
)
)
d2
=
p
2
.
sub
(
p3
)
.
normalized
(
)
d2
=
p
normalized
(
psub
(
p2
,
p3
)
)
bisector_dir
=
d1
.
add
(
d2
)
.
normalized
(
)
bisector_dir
=
pnormalized
(
padd
(
d1
,
d2
)
)
if
bisector_dir
is
None
:
if
bisector_dir
is
None
:
# the two vectors pointed to opposite directions
# the two vectors pointed to opposite directions
bisector_dir
=
d1
.
cross
(
up_vector
)
.
normalized
(
)
bisector_dir
=
pnormalized
(
pcross
(
d1
,
up_vector
)
)
else
:
else
:
skel_up_vector
=
bisector_dir
.
cross
(
p2
.
sub
(
p1
))
skel_up_vector
=
pcross
(
bisector_dir
,
psub
(
p2
,
p1
))
if
up_vector
.
dot
(
skel_up_vector
)
<
0
:
if
pdot
(
up_vector
,
skel_up_vector
)
<
0
:
# reverse the skeleton vector to point outwards
# reverse the skeleton vector to point outwards
bisector_dir
=
bisector_dir
.
mul
(
-
1
)
bisector_dir
=
pmul
(
bisector_dir
,
-
1
)
return
bisector_dir
return
bisector_dir
def
get_angle_pi
(
p1
,
p2
,
p3
,
up_vector
,
pi_factor
=
False
):
def
get_angle_pi
(
p1
,
p2
,
p3
,
up_vector
,
pi_factor
=
False
):
...
@@ -57,20 +61,19 @@ def get_angle_pi(p1, p2, p3, up_vector, pi_factor=False):
...
@@ -57,20 +61,19 @@ def get_angle_pi(p1, p2, p3, up_vector, pi_factor=False):
p2--------p1
p2--------p1
The result is in a range between 0 and 2*PI.
The result is in a range between 0 and 2*PI.
"""
"""
d1
=
p
2
.
sub
(
p1
)
.
normalized
(
)
d1
=
p
normalized
(
psub
(
p2
,
p1
)
)
d2
=
p
2
.
sub
(
p3
)
.
normalized
(
)
d2
=
p
normalized
(
psub
(
p2
,
p3
)
)
if
(
d1
is
None
)
or
(
d2
is
None
):
if
(
d1
is
None
)
or
(
d2
is
None
):
return
2
*
math
.
pi
return
2
*
math
.
pi
angle
=
math
.
acos
(
d1
.
dot
(
d2
))
angle
=
math
.
acos
(
pdot
(
d1
,
d2
))
# check the direction of the points (clockwise/anti)
# check the direction of the points (clockwise/anti)
# The code is taken from Polygon.get_area
# The code is taken from Polygon.get_area
value
=
[
0
,
0
,
0
]
value
=
[
0
,
0
,
0
]
for
(
pa
,
pb
)
in
((
p1
,
p2
),
(
p2
,
p3
),
(
p3
,
p1
)):
for
(
pa
,
pb
)
in
((
p1
,
p2
),
(
p2
,
p3
),
(
p3
,
p1
)):
value
[
0
]
+=
pa
.
y
*
pb
.
z
-
pa
.
z
*
pb
.
y
value
[
0
]
+=
pa
[
1
]
*
pb
[
2
]
-
pa
[
2
]
*
pb
[
1
]
value
[
1
]
+=
pa
.
z
*
pb
.
x
-
pa
.
x
*
pb
.
z
value
[
1
]
+=
pa
[
2
]
*
pb
[
0
]
-
pa
[
0
]
*
pb
[
2
]
value
[
2
]
+=
pa
.
x
*
pb
.
y
-
pa
.
y
*
pb
.
x
value
[
2
]
+=
pa
[
0
]
*
pb
[
1
]
-
pa
[
1
]
*
pb
[
0
]
area
=
up_vector
.
x
*
value
[
0
]
+
up_vector
.
y
*
value
[
1
]
\
area
=
up_vector
[
0
]
*
value
[
0
]
+
up_vector
[
1
]
*
value
[
1
]
+
up_vector
[
2
]
*
value
[
2
]
+
up_vector
.
z
*
value
[
2
]
if
area
>
0
:
if
area
>
0
:
# The points are in anti-clockwise order. Thus the angle is greater
# The points are in anti-clockwise order. Thus the angle is greater
# than 180 degree.
# than 180 degree.
...
@@ -113,8 +116,8 @@ def get_points_of_arc(center, radius, a1, a2, plane=None, cords=32):
...
@@ -113,8 +116,8 @@ def get_points_of_arc(center, radius, a1, a2, plane=None, cords=32):
angle_segment
=
angle_diff
/
num_of_segments
angle_segment
=
angle_diff
/
num_of_segments
points
=
[]
points
=
[]
get_angle_point
=
lambda
angle
:
(
get_angle_point
=
lambda
angle
:
(
center
.
x
+
radius
*
math
.
cos
(
angle
),
center
[
0
]
+
radius
*
math
.
cos
(
angle
),
center
.
y
+
radius
*
math
.
sin
(
angle
))
center
[
1
]
+
radius
*
math
.
sin
(
angle
))
points
.
append
(
get_angle_point
(
a1
))
points
.
append
(
get_angle_point
(
a1
))
for
index
in
range
(
num_of_segments
):
for
index
in
range
(
num_of_segments
):
points
.
append
(
get_angle_point
(
a1
+
angle_segment
*
(
index
+
1
)))
points
.
append
(
get_angle_point
(
a1
+
angle_segment
*
(
index
+
1
)))
...
@@ -131,23 +134,23 @@ def get_bezier_lines(points_with_bulge, segments=32):
...
@@ -131,23 +134,23 @@ def get_bezier_lines(points_with_bulge, segments=32):
if
not
bulge1
and
not
bulge2
:
if
not
bulge1
and
not
bulge2
:
# straight line
# straight line
return
[
Line
.
Line
(
p1
,
p2
)]
return
[
Line
.
Line
(
p1
,
p2
)]
straight_dir
=
p
2
.
sub
(
p1
)
.
normalized
(
)
straight_dir
=
p
normalized
(
psub
(
p2
,
p1
)
)
#bulge1 = max(-1.0, min(1.0, bulge1))
#bulge1 = max(-1.0, min(1.0, bulge1))
bulge1
=
math
.
atan
(
bulge1
)
bulge1
=
math
.
atan
(
bulge1
)
rot_matrix
=
Matrix
.
get_rotation_matrix_axis_angle
((
0
,
0
,
1
),
rot_matrix
=
Matrix
.
get_rotation_matrix_axis_angle
((
0
,
0
,
1
),
-
2
*
bulge1
,
use_radians
=
True
)
-
2
*
bulge1
,
use_radians
=
True
)
dir1_mat
=
Matrix
.
multiply_vector_matrix
((
straight_dir
.
x
,
dir1_mat
=
Matrix
.
multiply_vector_matrix
((
straight_dir
[
0
]
,
straight_dir
.
y
,
straight_dir
.
z
),
rot_matrix
)
straight_dir
[
1
],
straight_dir
[
2
]
),
rot_matrix
)
dir1
=
Point
.
Vector
(
dir1_mat
[
0
],
dir1_mat
[
1
],
dir1_mat
[
2
]
)
dir1
=
(
dir1_mat
[
0
],
dir1_mat
[
1
],
dir1_mat
[
2
],
'v'
)
if
bulge2
is
None
:
if
bulge2
is
None
:
bulge2
=
bulge1
bulge2
=
bulge1
else
:
else
:
bulge2
=
math
.
atan
(
bulge2
)
bulge2
=
math
.
atan
(
bulge2
)
rot_matrix
=
Matrix
.
get_rotation_matrix_axis_angle
((
0
,
0
,
1
),
rot_matrix
=
Matrix
.
get_rotation_matrix_axis_angle
((
0
,
0
,
1
),
2
*
bulge2
,
use_radians
=
True
)
2
*
bulge2
,
use_radians
=
True
)
dir2_mat
=
Matrix
.
multiply_vector_matrix
((
straight_dir
.
x
,
dir2_mat
=
Matrix
.
multiply_vector_matrix
((
straight_dir
[
0
]
,
straight_dir
.
y
,
straight_dir
.
z
),
rot_matrix
)
straight_dir
[
1
],
straight_dir
[
2
]
),
rot_matrix
)
dir2
=
Point
.
Vector
(
dir2_mat
[
0
],
dir2_mat
[
1
],
dir2_mat
[
2
]
)
dir2
=
(
dir2_mat
[
0
],
dir2_mat
[
1
],
dir2_mat
[
2
],
'v'
)
# interpretation of bulge1 and bulge2:
# interpretation of bulge1 and bulge2:
# /// taken from http://paulbourke.net/dataformats/dxf/dxf10.html ///
# /// taken from http://paulbourke.net/dataformats/dxf/dxf10.html ///
# The bulge is the tangent of 1/4 the included angle for an arc
# The bulge is the tangent of 1/4 the included angle for an arc
...
@@ -155,7 +158,7 @@ def get_bezier_lines(points_with_bulge, segments=32):
...
@@ -155,7 +158,7 @@ def get_bezier_lines(points_with_bulge, segments=32):
# point to the end point; a bulge of 0 indicates a straight segment,
# point to the end point; a bulge of 0 indicates a straight segment,
# and a bulge of 1 is a semicircle.
# and a bulge of 1 is a semicircle.
alpha
=
2
*
(
abs
(
bulge1
)
+
abs
(
bulge2
))
alpha
=
2
*
(
abs
(
bulge1
)
+
abs
(
bulge2
))
dist
=
p
2
.
sub
(
p1
)
.
norm
dist
=
p
norm
(
psub
(
p2
,
p1
))
# calculate the radius of the circumcircle - avoiding divide-by-zero
# calculate the radius of the circumcircle - avoiding divide-by-zero
if
(
abs
(
alpha
)
<
epsilon
)
or
(
abs
(
math
.
pi
-
alpha
)
<
epsilon
):
if
(
abs
(
alpha
)
<
epsilon
)
or
(
abs
(
math
.
pi
-
alpha
)
<
epsilon
):
radius
=
dist
/
2.0
radius
=
dist
/
2.0
...
@@ -165,16 +168,13 @@ def get_bezier_lines(points_with_bulge, segments=32):
...
@@ -165,16 +168,13 @@ def get_bezier_lines(points_with_bulge, segments=32):
# The calculation of "factor" is based on random guessing - but it
# The calculation of "factor" is based on random guessing - but it
# seems to work well.
# seems to work well.
factor
=
4
*
radius
*
math
.
tan
(
alpha
/
4.0
)
factor
=
4
*
radius
*
math
.
tan
(
alpha
/
4.0
)
dir1
=
dir1
.
mul
(
factor
)
dir1
=
pmul
(
dir1
,
factor
)
dir2
=
dir2
.
mul
(
factor
)
dir2
=
pmul
(
dir2
,
factor
)
for
index
in
range
(
segments
+
1
):
for
index
in
range
(
segments
+
1
):
# t: 0..1
# t: 0..1
t
=
float
(
index
)
/
segments
t
=
float
(
index
)
/
segments
# see: http://en.wikipedia.org/wiki/Cubic_Hermite_spline
# see: http://en.wikipedia.org/wiki/Cubic_Hermite_spline
p
=
p1
.
mul
(
2
*
t
**
3
-
3
*
t
**
2
+
1
)
.
add
(
p
=
padd
(
pmul
(
p1
,
2
*
t
**
3
-
3
*
t
**
2
+
1
)
,
padd
(
pmul
(
dir1
,
t
**
3
-
2
*
t
**
2
+
t
),
padd
(
pmul
(
p2
,
-
2
*
t
**
3
+
3
*
t
**
2
)
,
pmul
(
dir2
,
t
**
3
-
t
**
2
))))
dir1
.
mul
(
t
**
3
-
2
*
t
**
2
+
t
)
.
add
(
p2
.
mul
(
-
2
*
t
**
3
+
3
*
t
**
2
)
.
add
(
dir2
.
mul
(
t
**
3
-
t
**
2
))))
result_points
.
append
(
p
)
result_points
.
append
(
p
)
# create lines
# create lines
result
=
[]
result
=
[]
...
@@ -232,16 +232,24 @@ class TransformableContainer(object):
...
@@ -232,16 +232,24 @@ class TransformableContainer(object):
# Use the 'id' builtin to prevent expensive object comparions.
# Use the 'id' builtin to prevent expensive object comparions.
for
item
in
self
.
next
():
for
item
in
self
.
next
():
if
isinstance
(
item
,
TransformableContainer
):
if
isinstance
(
item
,
TransformableContainer
):
item
.
transform_by_matrix
(
matrix
,
transformed_list
,
item
.
transform_by_matrix
(
matrix
,
transformed_list
,
callback
=
callback
)
callback
=
callback
)
elif
not
id
(
item
)
in
transformed_list
:
elif
not
id
(
item
)
in
transformed_list
:
# non-TransformableContainer do not care to update the
# non-TransformableContainer do not care to update the
# 'transformed_list'. Thus we need to do it.
# 'transformed_list'. Thus we need to do it.
transformed_list
.
append
(
id
(
item
))
#
transformed_list.append(id(item))
# Don't transmit the 'transformed_list' if the object is
# Don't transmit the 'transformed_list' if the object is
# not a TransformableContainer. It is not necessary and it
# not a TransformableContainer. It is not necessary and it
# is hard to understand on the lowest level (e.g. Point).
# is hard to understand on the lowest level (e.g. Point).
item
.
transform_by_matrix
(
matrix
,
callback
=
callback
)
if
isinstance
(
item
,
str
):
theval
=
getattr
(
self
,
item
)
if
isinstance
(
theval
,
tuple
):
setattr
(
self
,
item
,
ptransform_by_matrix
(
theval
,
matrix
))
elif
isinstance
(
theval
,
list
):
setattr
(
self
,
item
,
[
ptransform_by_matrix
(
x
,
matrix
)
for
x
in
theval
])
elif
isinstance
(
item
,
tuple
):
log
.
error
(
"ERROR!! A tuple (Point, Vector) made it into base transform_by_matrix without a back reference. Point/Vector remains unchanged."
)
else
:
item
.
transform_by_matrix
(
matrix
,
callback
=
callback
)
# run the callback - e.g. for a progress counter
# run the callback - e.g. for a progress counter
if
callback
and
callback
():
if
callback
and
callback
():
# user requesteded abort
# user requesteded abort
...
...
pycam/Geometry/intersection.py
View file @
9b939792
...
@@ -26,7 +26,7 @@ from pycam.Utils.polynomials import poly4_roots
...
@@ -26,7 +26,7 @@ from pycam.Utils.polynomials import poly4_roots
from
pycam.Geometry.utils
import
INFINITE
,
sqrt
,
epsilon
from
pycam.Geometry.utils
import
INFINITE
,
sqrt
,
epsilon
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
def
isNear
(
a
,
b
):
def
isNear
(
a
,
b
):
return
abs
(
a
-
b
)
<
epsilon
return
abs
(
a
-
b
)
<
epsilon
...
@@ -60,14 +60,14 @@ def intersect_lines(xl, zl, nxl, nzl, xm, zm, nxm, nzm):
...
@@ -60,14 +60,14 @@ def intersect_lines(xl, zl, nxl, nzl, xm, zm, nxm, nzm):
def
intersect_cylinder_point
(
center
,
axis
,
radius
,
radiussq
,
direction
,
point
):
def
intersect_cylinder_point
(
center
,
axis
,
radius
,
radiussq
,
direction
,
point
):
# take a plane along direction and axis
# take a plane along direction and axis
n
=
direction
.
cross
(
axis
)
.
normalized
(
)
n
=
pnormalized
(
pcross
(
direction
,
axis
)
)
# distance of the point to this plane
# distance of the point to this plane
d
=
n
.
dot
(
point
)
-
n
.
dot
(
center
)
d
=
pdot
(
n
,
point
)
-
pdot
(
n
,
center
)
if
abs
(
d
)
>
radius
-
epsilon
:
if
abs
(
d
)
>
radius
-
epsilon
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
# ccl is on cylinder
# ccl is on cylinder
d2
=
sqrt
(
radiussq
-
d
*
d
)
d2
=
sqrt
(
radiussq
-
d
*
d
)
ccl
=
center
.
add
(
n
.
mul
(
d
))
.
add
(
direction
.
mul
(
d2
))
ccl
=
padd
(
padd
(
center
,
pmul
(
n
,
d
)),
pmul
(
direction
,
d2
))
# take plane through ccl and axis
# take plane through ccl and axis
plane
=
Plane
(
ccl
,
direction
)
plane
=
Plane
(
ccl
,
direction
)
# intersect point with plane
# intersect point with plane
...
@@ -77,26 +77,26 @@ def intersect_cylinder_point(center, axis, radius, radiussq, direction, point):
...
@@ -77,26 +77,26 @@ def intersect_cylinder_point(center, axis, radius, radiussq, direction, point):
def
intersect_cylinder_line
(
center
,
axis
,
radius
,
radiussq
,
direction
,
edge
):
def
intersect_cylinder_line
(
center
,
axis
,
radius
,
radiussq
,
direction
,
edge
):
d
=
edge
.
dir
d
=
edge
.
dir
# take a plane throught the line and along the cylinder axis (1)
# take a plane throught the line and along the cylinder axis (1)
n
=
d
.
cross
(
axis
)
n
=
pcross
(
d
,
axis
)
if
n
.
norm
==
0
:
if
pnorm
(
n
)
==
0
:
# no contact point, but should check here if cylinder *always*
# no contact point, but should check here if cylinder *always*
# intersects line...
# intersects line...
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
n
=
n
.
normalized
(
)
n
=
pnormalized
(
n
)
# the contact line between the cylinder and this plane (1)
# the contact line between the cylinder and this plane (1)
# is where the surface normal is perpendicular to the plane
# is where the surface normal is perpendicular to the plane
# so line := ccl + \lambda * axis
# so line := ccl + \lambda * axis
if
n
.
dot
(
direction
)
<
0
:
if
pdot
(
n
,
direction
)
<
0
:
ccl
=
center
.
sub
(
n
.
mul
(
radius
))
ccl
=
psub
(
center
,
pmul
(
n
,
radius
))
else
:
else
:
ccl
=
center
.
add
(
n
.
mul
(
radius
))
ccl
=
padd
(
center
,
pmul
(
n
,
radius
))
# now extrude the contact line along the direction, this is a plane (2)
# now extrude the contact line along the direction, this is a plane (2)
n2
=
direction
.
cross
(
axis
)
n2
=
pcross
(
direction
,
axis
)
if
n2
.
norm
==
0
:
if
pnorm
(
n2
)
==
0
:
# no contact point, but should check here if cylinder *always*
# no contact point, but should check here if cylinder *always*
# intersects line...
# intersects line...
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
n2
=
n2
.
normalized
(
)
n2
=
pnormalized
(
n2
)
plane1
=
Plane
(
ccl
,
n2
)
plane1
=
Plane
(
ccl
,
n2
)
# intersect this plane with the line, this gives us the contact point
# intersect this plane with the line, this gives us the contact point
(
cp
,
l
)
=
plane1
.
intersect_point
(
d
,
edge
.
p1
)
(
cp
,
l
)
=
plane1
.
intersect_point
(
d
,
edge
.
p1
)
...
@@ -108,23 +108,23 @@ def intersect_cylinder_line(center, axis, radius, radiussq, direction, edge):
...
@@ -108,23 +108,23 @@ def intersect_cylinder_line(center, axis, radius, radiussq, direction, edge):
# the intersection of this plane (3) with the line through the contact point
# the intersection of this plane (3) with the line through the contact point
# gives us the cutter contact point
# gives us the cutter contact point
(
ccp
,
l
)
=
plane2
.
intersect_point
(
direction
,
cp
)
(
ccp
,
l
)
=
plane2
.
intersect_point
(
direction
,
cp
)
cp
=
ccp
.
add
(
direction
.
mul
(
-
l
))
cp
=
padd
(
ccp
,
pmul
(
direction
,
-
l
))
return
(
ccp
,
cp
,
-
l
)
return
(
ccp
,
cp
,
-
l
)
def
intersect_circle_plane
(
center
,
radius
,
direction
,
triangle
):
def
intersect_circle_plane
(
center
,
radius
,
direction
,
triangle
):
# let n be the normal to the plane
# let n be the normal to the plane
n
=
triangle
.
normal
n
=
triangle
.
normal
if
n
.
dot
(
direction
)
==
0
:
if
pdot
(
n
,
direction
)
==
0
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
# project onto z=0
# project onto z=0
n2
=
Point
(
n
.
x
,
n
.
y
,
0
)
n2
=
(
n
[
0
],
n
[
1
]
,
0
)
if
n2
.
norm
==
0
:
if
pnorm
(
n2
)
==
0
:
(
cp
,
d
)
=
triangle
.
plane
.
intersect_point
(
direction
,
center
)
(
cp
,
d
)
=
triangle
.
plane
.
intersect_point
(
direction
,
center
)
ccp
=
cp
.
sub
(
direction
.
mul
(
d
))
ccp
=
psub
(
cp
,
pmul
(
direction
,
d
))
return
(
ccp
,
cp
,
d
)
return
(
ccp
,
cp
,
d
)
n2
=
n2
.
normalized
(
)
n2
=
pnormalized
(
n2
)
# the cutter contact point is on the circle, where the surface normal is n
# the cutter contact point is on the circle, where the surface normal is n
ccp
=
center
.
add
(
n2
.
mul
(
-
radius
))
ccp
=
padd
(
center
,
pmul
(
n2
,
-
radius
))
# intersect the plane with a line through the contact point
# intersect the plane with a line through the contact point
(
cp
,
d
)
=
triangle
.
plane
.
intersect_point
(
direction
,
ccp
)
(
cp
,
d
)
=
triangle
.
plane
.
intersect_point
(
direction
,
ccp
)
return
(
ccp
,
cp
,
d
)
return
(
ccp
,
cp
,
d
)
...
@@ -135,45 +135,45 @@ def intersect_circle_point(center, axis, radius, radiussq, direction, point):
...
@@ -135,45 +135,45 @@ def intersect_circle_point(center, axis, radius, radiussq, direction, point):
# intersect with line gives ccp
# intersect with line gives ccp
(
ccp
,
l
)
=
plane
.
intersect_point
(
direction
,
point
)
(
ccp
,
l
)
=
plane
.
intersect_point
(
direction
,
point
)
# check if inside circle
# check if inside circle
if
ccp
and
(
center
.
sub
(
ccp
)
.
normsq
<
radiussq
-
epsilon
):
if
ccp
and
(
pnormsq
(
psub
(
center
,
ccp
))
<
radiussq
-
epsilon
):
return
(
ccp
,
point
,
-
l
)
return
(
ccp
,
point
,
-
l
)
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
def
intersect_circle_line
(
center
,
axis
,
radius
,
radiussq
,
direction
,
edge
):
def
intersect_circle_line
(
center
,
axis
,
radius
,
radiussq
,
direction
,
edge
):
# make a plane by sliding the line along the direction (1)
# make a plane by sliding the line along the direction (1)
d
=
edge
.
dir
d
=
edge
.
dir
if
d
.
dot
(
axis
)
==
0
:
if
pdot
(
d
,
axis
)
==
0
:
if
direction
.
dot
(
axis
)
==
0
:
if
pdot
(
direction
,
axis
)
==
0
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
plane
=
Plane
(
center
,
axis
)
plane
=
Plane
(
center
,
axis
)
(
p1
,
l
)
=
plane
.
intersect_point
(
direction
,
edge
.
p1
)
(
p1
,
l
)
=
plane
.
intersect_point
(
direction
,
edge
.
p1
)
(
p2
,
l
)
=
plane
.
intersect_point
(
direction
,
edge
.
p2
)
(
p2
,
l
)
=
plane
.
intersect_point
(
direction
,
edge
.
p2
)
pc
=
Line
(
p1
,
p2
)
.
closest_point
(
center
)
pc
=
Line
(
p1
,
p2
)
.
closest_point
(
center
)
d_sq
=
p
c
.
sub
(
center
)
.
normsq
d_sq
=
p
normsq
(
psub
(
pc
,
center
))
if
d_sq
>=
radiussq
:
if
d_sq
>=
radiussq
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
a
=
sqrt
(
radiussq
-
d_sq
)
a
=
sqrt
(
radiussq
-
d_sq
)
d1
=
p
1
.
sub
(
pc
)
.
dot
(
d
)
d1
=
p
dot
(
psub
(
p1
,
pc
),
d
)
d2
=
p
2
.
sub
(
pc
)
.
dot
(
d
)
d2
=
p
dot
(
psub
(
p2
,
pc
),
d
)
ccp
=
None
ccp
=
None
cp
=
None
cp
=
None
if
abs
(
d1
)
<
a
-
epsilon
:
if
abs
(
d1
)
<
a
-
epsilon
:
ccp
=
p1
ccp
=
p1
cp
=
p
1
.
sub
(
direction
.
mul
(
l
))
cp
=
p
sub
(
p1
,
pmul
(
direction
,
l
))
elif
abs
(
d2
)
<
a
-
epsilon
:
elif
abs
(
d2
)
<
a
-
epsilon
:
ccp
=
p2
ccp
=
p2
cp
=
p
2
.
sub
(
direction
.
mul
(
l
))
cp
=
p
sub
(
p2
,
pmul
(
direction
,
l
))
elif
((
d1
<
-
a
+
epsilon
)
and
(
d2
>
a
-
epsilon
))
\
elif
((
d1
<
-
a
+
epsilon
)
and
(
d2
>
a
-
epsilon
))
\
or
((
d2
<
-
a
+
epsilon
)
and
(
d1
>
a
-
epsilon
)):
or
((
d2
<
-
a
+
epsilon
)
and
(
d1
>
a
-
epsilon
)):
ccp
=
pc
ccp
=
pc
cp
=
p
c
.
sub
(
direction
.
mul
(
l
))
cp
=
p
sub
(
pc
,
pmul
(
direction
,
l
))
return
(
ccp
,
cp
,
-
l
)
return
(
ccp
,
cp
,
-
l
)
n
=
d
.
cross
(
direction
)
n
=
pcross
(
d
,
direction
)
if
n
.
norm
==
0
:
if
pnorm
(
n
)
==
0
:
# no contact point, but should check here if circle *always* intersects
# no contact point, but should check here if circle *always* intersects
# line...
# line...
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
n
=
n
.
normalized
(
)
n
=
pnormalized
(
n
)
# take a plane through the base
# take a plane through the base
plane
=
Plane
(
center
,
axis
)
plane
=
Plane
(
center
,
axis
)
# intersect base with line
# intersect base with line
...
@@ -181,39 +181,39 @@ def intersect_circle_line(center, axis, radius, radiussq, direction, edge):
...
@@ -181,39 +181,39 @@ def intersect_circle_line(center, axis, radius, radiussq, direction, edge):
if
not
lp
:
if
not
lp
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
# intersection of 2 planes: lp + \lambda v
# intersection of 2 planes: lp + \lambda v
v
=
axis
.
cross
(
n
)
v
=
pcross
(
axis
,
n
)
if
v
.
norm
==
0
:
if
pnorm
(
v
)
==
0
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
v
=
v
.
normalized
(
)
v
=
pnormalized
(
v
)
# take plane through intersection line and parallel to axis
# take plane through intersection line and parallel to axis
n2
=
v
.
cross
(
axis
)
n2
=
pcross
(
v
,
axis
)
if
n2
.
norm
==
0
:
if
pnorm
(
n2
)
==
0
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
n2
=
n2
.
normalized
(
)
n2
=
pnormalized
(
n2
)
# distance from center to this plane
# distance from center to this plane
dist
=
n2
.
dot
(
center
)
-
n2
.
dot
(
lp
)
dist
=
pdot
(
n2
,
center
)
-
pdot
(
n2
,
lp
)
distsq
=
dist
*
dist
distsq
=
dist
*
dist
if
distsq
>
radiussq
-
epsilon
:
if
distsq
>
radiussq
-
epsilon
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
# must be on circle
# must be on circle
dist2
=
sqrt
(
radiussq
-
distsq
)
dist2
=
sqrt
(
radiussq
-
distsq
)
if
d
.
dot
(
axis
)
<
0
:
if
pdot
(
d
,
axis
)
<
0
:
dist2
=
-
dist2
dist2
=
-
dist2
ccp
=
center
.
sub
(
n2
.
mul
(
dist
))
.
sub
(
v
.
mul
(
dist2
))
ccp
=
psub
(
center
,
psub
(
pmul
(
n2
,
dist
),
pmul
(
v
,
dist2
)
))
plane
=
Plane
(
edge
.
p1
,
d
.
cross
(
direction
)
.
cross
(
d
))
plane
=
Plane
(
edge
.
p1
,
pcross
(
pcross
(
d
,
direction
),
d
))
(
cp
,
l
)
=
plane
.
intersect_point
(
direction
,
ccp
)
(
cp
,
l
)
=
plane
.
intersect_point
(
direction
,
ccp
)
return
(
ccp
,
cp
,
l
)
return
(
ccp
,
cp
,
l
)
def
intersect_sphere_plane
(
center
,
radius
,
direction
,
triangle
):
def
intersect_sphere_plane
(
center
,
radius
,
direction
,
triangle
):
# let n be the normal to the plane
# let n be the normal to the plane
n
=
triangle
.
normal
n
=
triangle
.
normal
if
n
.
dot
(
direction
)
==
0
:
if
pdot
(
n
,
direction
)
==
0
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
# the cutter contact point is on the sphere, where the surface normal is n
# the cutter contact point is on the sphere, where the surface normal is n
if
n
.
dot
(
direction
)
<
0
:
if
pdot
(
n
,
direction
)
<
0
:
ccp
=
center
.
sub
(
n
.
mul
(
radius
))
ccp
=
psub
(
center
,
pmul
(
n
,
radius
))
else
:
else
:
ccp
=
center
.
add
(
n
.
mul
(
radius
))
ccp
=
padd
(
center
,
pmul
(
n
,
radius
))
# intersect the plane with a line through the contact point
# intersect the plane with a line through the contact point
(
cp
,
d
)
=
triangle
.
plane
.
intersect_point
(
direction
,
ccp
)
(
cp
,
d
)
=
triangle
.
plane
.
intersect_point
(
direction
,
ccp
)
return
(
ccp
,
cp
,
d
)
return
(
ccp
,
cp
,
d
)
...
@@ -224,10 +224,10 @@ def intersect_sphere_point(center, radius, radiussq, direction, point):
...
@@ -224,10 +224,10 @@ def intersect_sphere_point(center, radius, radiussq, direction, point):
# sphere equation
# sphere equation
# (2) (x-x_0)^2 = R^2
# (2) (x-x_0)^2 = R^2
# (1) in (2) gives a quadratic in \lambda
# (1) in (2) gives a quadratic in \lambda
p0_x0
=
center
.
sub
(
point
)
p0_x0
=
psub
(
center
,
point
)
a
=
direction
.
normsq
a
=
pnormsq
(
direction
)
b
=
2
*
p
0_x0
.
dot
(
direction
)
b
=
2
*
p
dot
(
p0_x0
,
direction
)
c
=
p
0_x0
.
normsq
-
radiussq
c
=
p
normsq
(
p0_x0
)
-
radiussq
d
=
b
*
b
-
4
*
a
*
c
d
=
b
*
b
-
4
*
a
*
c
if
d
<
0
:
if
d
<
0
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
...
@@ -236,21 +236,21 @@ def intersect_sphere_point(center, radius, radiussq, direction, point):
...
@@ -236,21 +236,21 @@ def intersect_sphere_point(center, radius, radiussq, direction, point):
else
:
else
:
l
=
(
-
b
-
sqrt
(
d
))
/
(
2
*
a
)
l
=
(
-
b
-
sqrt
(
d
))
/
(
2
*
a
)
# cutter contact point
# cutter contact point
ccp
=
p
oint
.
add
(
direction
.
mul
(
-
l
))
ccp
=
p
add
(
point
,
pmul
(
direction
,
-
l
))
return
(
ccp
,
point
,
l
)
return
(
ccp
,
point
,
l
)
def
intersect_sphere_line
(
center
,
radius
,
radiussq
,
direction
,
edge
):
def
intersect_sphere_line
(
center
,
radius
,
radiussq
,
direction
,
edge
):
# make a plane by sliding the line along the direction (1)
# make a plane by sliding the line along the direction (1)
d
=
edge
.
dir
d
=
edge
.
dir
n
=
d
.
cross
(
direction
)
n
=
pcross
(
n
,
direction
)
if
n
.
norm
==
0
:
if
pnorm
(
n
)
==
0
:
# no contact point, but should check here if sphere *always* intersects
# no contact point, but should check here if sphere *always* intersects
# line...
# line...
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
n
=
n
.
normalized
(
)
n
=
pnormalized
(
n
)
# calculate the distance from the sphere center to the plane
# calculate the distance from the sphere center to the plane
dist
=
-
center
.
dot
(
n
)
+
edge
.
p1
.
dot
(
n
)
dist
=
-
pdot
(
center
,
n
)
+
pdot
(
edge
.
p1
,
n
)
if
abs
(
dist
)
>
radius
-
epsilon
:
if
abs
(
dist
)
>
radius
-
epsilon
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
# this gives us the intersection circle on the sphere
# this gives us the intersection circle on the sphere
...
@@ -259,13 +259,13 @@ def intersect_sphere_line(center, radius, radiussq, direction, edge):
...
@@ -259,13 +259,13 @@ def intersect_sphere_line(center, radius, radiussq, direction, edge):
# find the center on the circle closest to this plane
# find the center on the circle closest to this plane
# which means the other component is perpendicular to this plane (2)
# which means the other component is perpendicular to this plane (2)
n2
=
n
.
cross
(
d
)
.
normalized
(
)
n2
=
pnormalized
(
pcross
(
n
,
d
)
)
# the contact point is on a big circle through the sphere...
# the contact point is on a big circle through the sphere...
dist2
=
sqrt
(
radiussq
-
dist
*
dist
)
dist2
=
sqrt
(
radiussq
-
dist
*
dist
)
# ... and it's on the plane (1)
# ... and it's on the plane (1)
ccp
=
center
.
add
(
n
.
mul
(
dist
))
.
add
(
n2
.
mul
(
dist2
))
ccp
=
padd
(
center
,
padd
(
pmul
(
n
,
dist
),
pmul
(
n2
,
dist2
)
))
# now intersect a line through this point with the plane (2)
# now intersect a line through this point with the plane (2)
plane
=
Plane
(
edge
.
p1
,
n2
)
plane
=
Plane
(
edge
.
p1
,
n2
)
...
@@ -276,19 +276,19 @@ def intersect_torus_plane(center, axis, majorradius, minorradius, direction,
...
@@ -276,19 +276,19 @@ def intersect_torus_plane(center, axis, majorradius, minorradius, direction,
triangle
):
triangle
):
# take normal to the plane
# take normal to the plane
n
=
triangle
.
normal
n
=
triangle
.
normal
if
n
.
dot
(
direction
)
==
0
:
if
pdot
(
n
,
direction
)
==
0
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
if
n
.
dot
(
axis
)
==
1
:
if
pdot
(
n
,
axis
)
==
1
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
# find place on torus where surface normal is n
# find place on torus where surface normal is n
b
=
n
.
mul
(
-
1
)
b
=
pmul
(
n
,
-
1
)
z
=
axis
z
=
axis
a
=
b
.
sub
(
z
.
mul
(
z
.
dot
(
b
)))
a
=
psub
(
b
,
pmul
(
z
,
pdot
(
z
,
b
)))
a_sq
=
a
.
normsq
a_sq
=
pnormsq
(
a
)
if
a_sq
<=
0
:
if
a_sq
<=
0
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
a
=
a
.
div
(
sqrt
(
a_sq
))
a
=
pdiv
(
a
,
sqrt
(
a_sq
))
ccp
=
center
.
add
(
a
.
mul
(
majorradius
))
.
add
(
b
.
mul
(
minorradius
))
ccp
=
padd
(
padd
(
center
,
pmul
(
a
,
majorradius
)),
pmul
(
b
,
minorradius
))
# find intersection with plane
# find intersection with plane
(
cp
,
l
)
=
triangle
.
plane
.
intersect_point
(
direction
,
ccp
)
(
cp
,
l
)
=
triangle
.
plane
.
intersect_point
(
direction
,
ccp
)
return
(
ccp
,
cp
,
l
)
return
(
ccp
,
cp
,
l
)
...
@@ -296,11 +296,11 @@ def intersect_torus_plane(center, axis, majorradius, minorradius, direction,
...
@@ -296,11 +296,11 @@ def intersect_torus_plane(center, axis, majorradius, minorradius, direction,
def
intersect_torus_point
(
center
,
axis
,
majorradius
,
minorradius
,
majorradiussq
,
def
intersect_torus_point
(
center
,
axis
,
majorradius
,
minorradius
,
majorradiussq
,
minorradiussq
,
direction
,
point
):
minorradiussq
,
direction
,
point
):
dist
=
0
dist
=
0
if
(
direction
.
x
==
0
)
and
(
direction
.
y
==
0
):
if
(
direction
[
0
]
==
0
)
and
(
direction
[
1
]
==
0
):
# drop
# drop
minlsq
=
(
majorradius
-
minorradius
)
**
2
minlsq
=
(
majorradius
-
minorradius
)
**
2
maxlsq
=
(
majorradius
+
minorradius
)
**
2
maxlsq
=
(
majorradius
+
minorradius
)
**
2
l_sq
=
(
point
.
x
-
center
.
x
)
**
2
+
(
point
.
y
-
center
.
y
)
**
2
l_sq
=
(
point
[
0
]
-
center
[
0
])
**
2
+
(
point
[
1
]
-
center
[
1
]
)
**
2
if
(
l_sq
<
minlsq
+
epsilon
)
or
(
l_sq
>
maxlsq
-
epsilon
):
if
(
l_sq
<
minlsq
+
epsilon
)
or
(
l_sq
>
maxlsq
-
epsilon
):
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
l
=
sqrt
(
l_sq
)
l
=
sqrt
(
l_sq
)
...
@@ -308,33 +308,33 @@ def intersect_torus_point(center, axis, majorradius, minorradius, majorradiussq,
...
@@ -308,33 +308,33 @@ def intersect_torus_point(center, axis, majorradius, minorradius, majorradiussq,
if
z_sq
<
0
:
if
z_sq
<
0
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
z
=
sqrt
(
z_sq
)
z
=
sqrt
(
z_sq
)
ccp
=
Point
(
point
.
x
,
point
.
y
,
center
.
z
-
z
)
ccp
=
(
point
[
0
],
point
[
1
],
center
[
2
]
-
z
)
dist
=
ccp
.
z
-
point
.
z
dist
=
ccp
[
2
]
-
point
[
2
]
elif
direction
.
z
==
0
:
elif
direction
[
2
]
==
0
:
# push
# push
z
=
point
.
z
-
center
.
z
z
=
point
[
2
]
-
center
[
2
]
if
abs
(
z
)
>
minorradius
-
epsilon
:
if
abs
(
z
)
>
minorradius
-
epsilon
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
l
=
majorradius
+
sqrt
(
minorradiussq
-
z
*
z
)
l
=
majorradius
+
sqrt
(
minorradiussq
-
z
*
z
)
n
=
axis
.
cross
(
direction
)
n
=
pcross
(
axis
,
direction
)
d
=
n
.
dot
(
point
)
-
n
.
dot
(
center
)
d
=
pdot
(
n
,
point
)
-
pdot
(
n
,
center
)
if
abs
(
d
)
>
l
-
epsilon
:
if
abs
(
d
)
>
l
-
epsilon
:
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
a
=
sqrt
(
l
*
l
-
d
*
d
)
a
=
sqrt
(
l
*
l
-
d
*
d
)
ccp
=
center
.
add
(
n
.
mul
(
d
)
.
add
(
direction
.
mul
(
a
)
))
ccp
=
padd
(
padd
(
center
,
pmul
(
n
,
d
)),
pmul
(
direction
,
a
))
ccp
.
z
=
point
.
z
ccp
=
(
ccp
[
0
],
ccp
[
1
],
point
[
2
])
dist
=
p
oint
.
sub
(
ccp
)
.
dot
(
direction
)
dist
=
p
dot
(
psub
(
point
,
ccp
),
direction
)
else
:
else
:
# general case
# general case
x
=
p
oint
.
sub
(
center
)
x
=
p
sub
(
point
,
center
)
v
=
direction
.
mul
(
-
1
)
v
=
pmul
(
direction
,
-
1
)
x_x
=
x
.
dot
(
x
)
x_x
=
pdot
(
x
,
x
)
x_v
=
x
.
dot
(
v
)
x_v
=
pdot
(
x
,
v
)
x1
=
Point
(
x
.
x
,
x
.
y
,
0
)
x1
=
(
x
[
0
],
x
[
1
]
,
0
)
v1
=
Point
(
v
.
x
,
v
.
y
,
0
)
v1
=
(
v
[
0
],
v
[
1
]
,
0
)
x1_x1
=
x1
.
dot
(
x1
)
x1_x1
=
pdot
(
x1
,
x1
)
x1_v1
=
x1
.
dot
(
v1
)
x1_v1
=
pdot
(
x1
,
v1
)
v1_v1
=
v1
.
dot
(
v1
)
v1_v1
=
pdot
(
v1
,
v1
)
R2
=
majorradiussq
R2
=
majorradiussq
r2
=
minorradiussq
r2
=
minorradiussq
a
=
1.0
a
=
1.0
...
@@ -347,7 +347,7 @@ def intersect_torus_point(center, axis, majorradius, minorradius, majorradiussq,
...
@@ -347,7 +347,7 @@ def intersect_torus_point(center, axis, majorradius, minorradius, majorradiussq,
return
(
None
,
None
,
INFINITE
)
return
(
None
,
None
,
INFINITE
)
else
:
else
:
l
=
min
(
r
)
l
=
min
(
r
)
ccp
=
p
oint
.
add
(
direction
.
mul
(
-
l
))
ccp
=
p
add
(
point
,
pmul
(
direction
,
-
l
))
dist
=
l
dist
=
l
return
(
ccp
,
point
,
dist
)
return
(
ccp
,
point
,
dist
)
pycam/Gui/OpenGLTools.py
View file @
9b939792
...
@@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License
...
@@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.utils
import
sqrt
from
pycam.Geometry.utils
import
sqrt
# careful import
# careful import
...
@@ -55,38 +55,33 @@ def keep_matrix(func):
...
@@ -55,38 +55,33 @@ def keep_matrix(func):
@
keep_matrix
@
keep_matrix
def
draw_direction_cone
(
p1
,
p2
,
position
=
0.5
,
precision
=
12
,
size
=
0.1
):
def
draw_direction_cone
(
p1
,
p2
,
position
=
0.5
,
precision
=
12
,
size
=
0.1
):
# convert p1 and p2 from list/tuple to Point
distance
=
psub
(
p2
,
p1
)
if
not
hasattr
(
p1
,
"sub"
):
length
=
pnorm
(
distance
)
p1
=
Point
(
*
p1
)
direction
=
pnormalized
(
distance
)
if
not
hasattr
(
p2
,
"sub"
):
p2
=
Point
(
*
p2
)
distance
=
p2
.
sub
(
p1
)
length
=
distance
.
norm
direction
=
distance
.
normalized
()
if
direction
is
None
:
if
direction
is
None
:
# zero-length line
# zero-length line
return
return
cone_length
=
length
*
size
cone_length
=
length
*
size
cone_radius
=
cone_length
/
3.0
cone_radius
=
cone_length
/
3.0
# move the cone to the middle of the line
# move the cone to the middle of the line
GL
.
glTranslatef
((
p1
.
x
+
p2
.
x
)
*
position
,
GL
.
glTranslatef
((
p1
[
0
]
+
p2
[
0
]
)
*
position
,
(
p1
.
y
+
p2
.
y
)
*
position
,
(
p1
.
z
+
p2
.
z
)
*
position
)
(
p1
[
1
]
+
p2
[
1
])
*
position
,
(
p1
[
2
]
+
p2
[
2
]
)
*
position
)
# rotate the cone according to the line direction
# rotate the cone according to the line direction
# The cross product is a good rotation axis.
# The cross product is a good rotation axis.
cross
=
direction
.
cross
(
Point
(
0
,
0
,
-
1
))
cross
=
pcross
(
direction
,
(
0
,
0
,
-
1
))
if
cross
.
norm
!=
0
:
if
pnorm
(
cross
)
!=
0
:
# The line direction is not in line with the z axis.
# The line direction is not in line with the z axis.
try
:
try
:
angle
=
math
.
asin
(
sqrt
(
direction
.
x
**
2
+
direction
.
y
**
2
))
angle
=
math
.
asin
(
sqrt
(
direction
[
0
]
**
2
+
direction
[
1
]
**
2
))
except
ValueError
:
except
ValueError
:
# invalid angle - just ignore this cone
# invalid angle - just ignore this cone
return
return
# convert from radians to degree
# convert from radians to degree
angle
=
angle
/
math
.
pi
*
180
angle
=
angle
/
math
.
pi
*
180
if
direction
.
z
<
0
:
if
direction
[
2
]
<
0
:
angle
=
180
-
angle
angle
=
180
-
angle
GL
.
glRotatef
(
angle
,
cross
.
x
,
cross
.
y
,
cross
.
z
)
GL
.
glRotatef
(
angle
,
cross
[
0
],
cross
[
1
],
cross
[
2
]
)
elif
direction
.
z
==
-
1
:
elif
direction
[
2
]
==
-
1
:
# The line goes down the z axis - turn it around.
# The line goes down the z axis - turn it around.
GL
.
glRotatef
(
180
,
1
,
0
,
0
)
GL
.
glRotatef
(
180
,
1
,
0
,
0
)
else
:
else
:
...
...
pycam/Importers/CXFImporter.py
View file @
9b939792
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from
pycam.Geometry.Letters
import
Charset
from
pycam.Geometry.Letters
import
Charset
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry
import
get_points_of_arc
from
pycam.Geometry
import
get_points_of_arc
import
pycam.Utils.log
import
pycam.Utils.log
import
pycam.Utils
import
pycam.Utils
...
@@ -144,13 +144,13 @@ class CXFParser(object):
...
@@ -144,13 +144,13 @@ class CXFParser(object):
type_char
=
line
[
0
]
.
upper
()
type_char
=
line
[
0
]
.
upper
()
if
(
type_def
==
"L"
)
and
(
len
(
coords
)
==
4
):
if
(
type_def
==
"L"
)
and
(
len
(
coords
)
==
4
):
# line
# line
p1
=
Point
(
coords
[
0
],
coords
[
1
],
0
)
p1
=
(
coords
[
0
],
coords
[
1
],
0
)
p2
=
Point
(
coords
[
2
],
coords
[
3
],
0
)
p2
=
(
coords
[
2
],
coords
[
3
],
0
)
char_definition
.
append
(
Line
(
p1
,
p2
))
char_definition
.
append
(
Line
(
p1
,
p2
))
elif
(
type_def
in
(
"A"
,
"AR"
))
and
(
len
(
coords
)
==
5
):
elif
(
type_def
in
(
"A"
,
"AR"
))
and
(
len
(
coords
)
==
5
):
# arc
# arc
previous
=
None
previous
=
None
center
=
Point
(
coords
[
0
],
coords
[
1
],
0
)
center
=
(
coords
[
0
],
coords
[
1
],
0
)
radius
=
coords
[
2
]
radius
=
coords
[
2
]
start_angle
,
end_angle
=
coords
[
3
],
coords
[
4
]
start_angle
,
end_angle
=
coords
[
3
],
coords
[
4
]
if
type_def
==
"AR"
:
if
type_def
==
"AR"
:
...
@@ -158,7 +158,7 @@ class CXFParser(object):
...
@@ -158,7 +158,7 @@ class CXFParser(object):
start_angle
,
end_angle
=
end_angle
,
start_angle
start_angle
,
end_angle
=
end_angle
,
start_angle
for
p
in
get_points_of_arc
(
center
,
radius
,
start_angle
,
for
p
in
get_points_of_arc
(
center
,
radius
,
start_angle
,
end_angle
):
end_angle
):
current
=
Point
(
p
[
0
],
p
[
1
],
0
)
current
=
(
p
[
0
],
p
[
1
],
0
)
if
not
previous
is
None
:
if
not
previous
is
None
:
char_definition
.
append
(
Line
(
previous
,
current
))
char_definition
.
append
(
Line
(
previous
,
current
))
previous
=
current
previous
=
current
...
...
pycam/Importers/DXFImporter.py
View file @
9b939792
...
@@ -21,7 +21,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -21,7 +21,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.Triangle
import
Triangle
from
pycam.Geometry.Triangle
import
Triangle
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
import
pycam.Geometry.Model
import
pycam.Geometry.Model
import
pycam.Geometry.Matrix
import
pycam.Geometry.Matrix
...
@@ -142,8 +142,8 @@ class DXFParser(object):
...
@@ -142,8 +142,8 @@ class DXFParser(object):
current_group
=
[]
current_group
=
[]
groups
.
append
(
current_group
)
groups
.
append
(
current_group
)
def
get_distance_between_groups
(
group1
,
group2
):
def
get_distance_between_groups
(
group1
,
group2
):
forward
=
group1
[
-
1
]
.
p2
.
sub
(
group2
[
0
]
.
p1
)
.
norm
forward
=
pnorm
(
psub
(
group1
[
-
1
]
.
p2
,
group2
[
0
]
.
p1
))
backward
=
group2
[
-
1
]
.
p2
.
sub
(
group1
[
0
]
.
p1
)
.
norm
backward
=
pnorm
(
psub
(
group2
[
-
1
]
.
p2
,
group1
[
0
]
.
p1
))
return
min
(
forward
,
backward
)
return
min
(
forward
,
backward
)
remaining_groups
=
groups
[:]
remaining_groups
=
groups
[:]
ordered_groups
=
[]
ordered_groups
=
[]
...
@@ -305,7 +305,7 @@ class DXFParser(object):
...
@@ -305,7 +305,7 @@ class DXFParser(object):
"between line
%
d and
%
d"
%
(
start_line
,
end_line
))
"between line
%
d and
%
d"
%
(
start_line
,
end_line
))
else
:
else
:
self
.
_open_sequence_items
.
append
(
self
.
_open_sequence_items
.
append
(
(
Point
(
point
[
0
],
point
[
1
],
point
[
2
]),
bulge
))
((
point
[
0
],
point
[
1
],
point
[
2
]),
bulge
))
def
parse_polyline
(
self
,
init
):
def
parse_polyline
(
self
,
init
):
start_line
=
self
.
line_number
start_line
=
self
.
line_number
...
@@ -342,6 +342,8 @@ class DXFParser(object):
...
@@ -342,6 +342,8 @@ class DXFParser(object):
next_point
=
points
[
index
+
1
]
next_point
=
points
[
index
+
1
]
if
point
!=
next_point
:
if
point
!=
next_point
:
self
.
lines
.
append
(
Line
(
point
,
next_point
))
self
.
lines
.
append
(
Line
(
point
,
next_point
))
if
(
"VERTEX_FLAGS"
in
params
)
and
(
params
[
"VERTEX_FLAGS"
]
==
"EXTRA_VERTEX"
):
self
.
lines
.
append
(
Line
(
points
[
-
1
],
points
[
0
]))
self
.
_open_sequence_items
=
[]
self
.
_open_sequence_items
=
[]
self
.
_open_sequence_params
=
{}
self
.
_open_sequence_params
=
{}
self
.
_open_sequence
=
None
self
.
_open_sequence
=
None
...
@@ -358,7 +360,7 @@ class DXFParser(object):
...
@@ -358,7 +360,7 @@ class DXFParser(object):
"date in line
%
d:
%
s"
%
\
"date in line
%
d:
%
s"
%
\
(
self
.
line_number
,
p_array
))
(
self
.
line_number
,
p_array
))
p_array
[
index
]
=
0
p_array
[
index
]
=
0
points
.
append
((
Point
(
p_array
[
0
],
p_array
[
1
],
p_array
[
2
]),
bulge
))
points
.
append
(((
p_array
[
0
],
p_array
[
1
],
p_array
[
2
]),
bulge
))
current_point
=
[
None
,
None
,
None
]
current_point
=
[
None
,
None
,
None
]
bulge
=
None
bulge
=
None
extra_vertex_flag
=
False
extra_vertex_flag
=
False
...
@@ -755,15 +757,15 @@ class DXFParser(object):
...
@@ -755,15 +757,15 @@ class DXFParser(object):
+
"
%
d and
%
d"
%
(
start_line
,
end_line
))
+
"
%
d and
%
d"
%
(
start_line
,
end_line
))
else
:
else
:
# no color height adjustment for 3DFACE
# no color height adjustment for 3DFACE
point1
=
Point
(
p1
[
0
],
p1
[
1
],
p1
[
2
]
)
point1
=
tuple
(
p1
)
point2
=
Point
(
p2
[
0
],
p2
[
1
],
p2
[
2
]
)
point2
=
tuple
(
p2
)
point3
=
Point
(
p3
[
0
],
p3
[
1
],
p3
[
2
]
)
point3
=
tuple
(
p3
)
triangles
=
[]
triangles
=
[]
triangles
.
append
((
point1
,
point2
,
point3
))
triangles
.
append
((
point1
,
point2
,
point3
))
# DXF specifies, that p3=p4 if triangles (instead of quads) are
# DXF specifies, that p3=p4 if triangles (instead of quads) are
# written.
# written.
if
(
not
None
in
p4
)
and
(
p3
!=
p4
):
if
(
not
None
in
p4
)
and
(
p3
!=
p4
):
point4
=
Point
(
p4
[
0
],
p4
[
1
],
p4
[
2
])
point4
=
(
p4
[
0
],
p4
[
1
],
p4
[
2
])
triangles
.
append
((
point3
,
point4
,
point1
))
triangles
.
append
((
point3
,
point4
,
point1
))
for
t
in
triangles
:
for
t
in
triangles
:
if
(
t
[
0
]
!=
t
[
1
])
and
(
t
[
0
]
!=
t
[
2
])
and
(
t
[
1
]
!=
t
[
2
]):
if
(
t
[
0
]
!=
t
[
1
])
and
(
t
[
0
]
!=
t
[
2
])
and
(
t
[
1
]
!=
t
[
2
]):
...
@@ -811,7 +813,7 @@ class DXFParser(object):
...
@@ -811,7 +813,7 @@ class DXFParser(object):
# use the color code as the z coordinate
# use the color code as the z coordinate
p1
[
2
]
=
float
(
color
)
/
255
p1
[
2
]
=
float
(
color
)
/
255
p2
[
2
]
=
float
(
color
)
/
255
p2
[
2
]
=
float
(
color
)
/
255
line
=
Line
(
Point
(
p1
[
0
],
p1
[
1
],
p1
[
2
]),
Point
(
p2
[
0
],
p2
[
1
],
p2
[
2
]))
line
=
Line
(
(
p1
[
0
],
p1
[
1
],
p1
[
2
]),
(
p2
[
0
],
p2
[
1
],
p2
[
2
]))
if
line
.
p1
!=
line
.
p2
:
if
line
.
p1
!=
line
.
p2
:
self
.
lines
.
append
(
line
)
self
.
lines
.
append
(
line
)
else
:
else
:
...
@@ -862,18 +864,17 @@ class DXFParser(object):
...
@@ -862,18 +864,17 @@ class DXFParser(object):
if
self
.
_color_as_height
and
(
not
color
is
None
):
if
self
.
_color_as_height
and
(
not
color
is
None
):
# use the color code as the z coordinate
# use the color code as the z coordinate
center
[
2
]
=
float
(
color
)
/
255
center
[
2
]
=
float
(
color
)
/
255
center
=
Point
(
center
[
0
],
center
[
1
],
center
[
2
])
center
=
tuple
(
center
)
xy_point_coords
=
pycam
.
Geometry
.
get_points_of_arc
(
center
,
radius
,
xy_point_coords
=
pycam
.
Geometry
.
get_points_of_arc
(
center
,
radius
,
angle_start
,
angle_end
)
angle_start
,
angle_end
)
# Somehow the order of points seems to be the opposite of what is
# Somehow the order of points seems to be the opposite of what is
# expected.
# expected.
xy_point_coords
.
reverse
()
xy_point_coords
.
reverse
()
if
len
(
xy_point_coords
)
>
1
:
if
len
(
xy_point_coords
)
>
1
:
for
index
in
range
(
len
(
xy_point_coords
)
-
1
):
for
index
in
range
(
len
(
xy_point_coords
)
-
1
):
p1
=
xy_point_coords
[
index
]
p1
=
xy_point_coords
[
index
]
p1
=
Point
(
p1
[
0
],
p1
[
1
],
center
.
z
)
p1
=
(
p1
[
0
],
p1
[
1
],
center
[
2
]
)
p2
=
xy_point_coords
[
index
+
1
]
p2
=
xy_point_coords
[
index
+
1
]
p2
=
Point
(
p2
[
0
],
p2
[
1
],
center
.
z
)
p2
=
(
p2
[
0
],
p2
[
1
],
center
[
2
]
)
if
p1
!=
p2
:
if
p1
!=
p2
:
self
.
lines
.
append
(
Line
(
p1
,
p2
))
self
.
lines
.
append
(
Line
(
p1
,
p2
))
else
:
else
:
...
...
pycam/Importers/STLImporter.py
View file @
9b939792
...
@@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License
...
@@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.Triangle
import
Triangle
from
pycam.Geometry.Triangle
import
Triangle
from
pycam.Geometry.PointKdtree
import
PointKdtree
from
pycam.Geometry.PointKdtree
import
PointKdtree
from
pycam.Geometry.utils
import
epsilon
from
pycam.Geometry.utils
import
epsilon
...
@@ -40,17 +40,17 @@ vertices = 0
...
@@ -40,17 +40,17 @@ vertices = 0
edges
=
0
edges
=
0
kdtree
=
None
kdtree
=
None
lastUniqueVertex
=
(
None
,
None
,
None
)
def
UniqueVertex
(
x
,
y
,
z
):
def
UniqueVertex
(
x
,
y
,
z
):
global
vertices
global
vertices
,
lastUniqueVertex
if
kdtree
:
if
kdtree
:
last
=
Point
.
id
p
=
kdtree
.
Point
(
x
,
y
,
z
)
p
=
kdtree
.
Point
(
x
,
y
,
z
)
if
p
.
id
==
last
:
if
p
==
lastUniqueVertex
:
vertices
+=
1
vertices
+=
1
return
p
return
p
else
:
else
:
vertices
+=
1
vertices
+=
1
return
Point
(
x
,
y
,
z
)
return
(
x
,
y
,
z
)
def
ImportModel
(
filename
,
use_kdtree
=
True
,
callback
=
None
,
**
kwargs
):
def
ImportModel
(
filename
,
use_kdtree
=
True
,
callback
=
None
,
**
kwargs
):
global
vertices
,
edges
,
kdtree
global
vertices
,
edges
,
kdtree
...
@@ -127,7 +127,7 @@ def ImportModel(filename, use_kdtree=True, callback=None, **kwargs):
...
@@ -127,7 +127,7 @@ def ImportModel(filename, use_kdtree=True, callback=None, **kwargs):
a2
=
unpack
(
"<f"
,
f
.
read
(
4
))[
0
]
a2
=
unpack
(
"<f"
,
f
.
read
(
4
))[
0
]
a3
=
unpack
(
"<f"
,
f
.
read
(
4
))[
0
]
a3
=
unpack
(
"<f"
,
f
.
read
(
4
))[
0
]
n
=
Vector
(
float
(
a1
),
float
(
a2
),
float
(
a3
)
)
n
=
(
float
(
a1
),
float
(
a2
),
float
(
a3
),
'v'
)
v11
=
unpack
(
"<f"
,
f
.
read
(
4
))[
0
]
v11
=
unpack
(
"<f"
,
f
.
read
(
4
))[
0
]
v12
=
unpack
(
"<f"
,
f
.
read
(
4
))[
0
]
v12
=
unpack
(
"<f"
,
f
.
read
(
4
))[
0
]
...
@@ -150,9 +150,9 @@ def ImportModel(filename, use_kdtree=True, callback=None, **kwargs):
...
@@ -150,9 +150,9 @@ def ImportModel(filename, use_kdtree=True, callback=None, **kwargs):
# not used
# not used
attribs
=
unpack
(
"<H"
,
f
.
read
(
2
))
attribs
=
unpack
(
"<H"
,
f
.
read
(
2
))
dotcross
=
n
.
dot
(
p2
.
sub
(
p1
)
.
cross
(
p3
.
sub
(
p1
)))
dotcross
=
pdot
(
n
,
pcross
(
psub
(
p2
,
p1
),
psub
(
p3
,
p1
)))
if
a1
==
a2
==
a3
==
0
:
if
a1
==
a2
==
a3
==
0
:
dotcross
=
p
2
.
sub
(
p1
)
.
cross
(
p3
.
sub
(
p1
))
.
z
dotcross
=
p
cross
(
psub
(
p2
,
p1
),
psub
(
p3
,
p1
))[
2
]
n
=
None
n
=
None
if
dotcross
>
0
:
if
dotcross
>
0
:
...
@@ -209,8 +209,7 @@ def ImportModel(filename, use_kdtree=True, callback=None, **kwargs):
...
@@ -209,8 +209,7 @@ def ImportModel(filename, use_kdtree=True, callback=None, **kwargs):
if
m
:
if
m
:
m
=
normal
.
match
(
line
)
m
=
normal
.
match
(
line
)
if
m
:
if
m
:
n
=
Vector
(
float
(
m
.
group
(
'x'
)),
float
(
m
.
group
(
'y'
)),
n
=
(
float
(
m
.
group
(
'x'
)),
float
(
m
.
group
(
'y'
)),
float
(
m
.
group
(
'z'
)),
'v'
)
float
(
m
.
group
(
'z'
)))
else
:
else
:
n
=
None
n
=
None
continue
continue
...
@@ -243,7 +242,7 @@ def ImportModel(filename, use_kdtree=True, callback=None, **kwargs):
...
@@ -243,7 +242,7 @@ def ImportModel(filename, use_kdtree=True, callback=None, **kwargs):
n
,
p1
,
p2
,
p3
=
None
,
None
,
None
,
None
n
,
p1
,
p2
,
p3
=
None
,
None
,
None
,
None
continue
continue
if
not
n
:
if
not
n
:
n
=
p
2
.
sub
(
p1
)
.
cross
(
p3
.
sub
(
p1
))
.
normalized
(
)
n
=
p
normalized
(
pcross
(
psub
(
p2
,
p1
),
psub
(
p3
,
p1
))
)
# validate the normal
# validate the normal
# The three vertices of a triangle in an STL file are supposed
# The three vertices of a triangle in an STL file are supposed
...
@@ -254,7 +253,7 @@ def ImportModel(filename, use_kdtree=True, callback=None, **kwargs):
...
@@ -254,7 +253,7 @@ def ImportModel(filename, use_kdtree=True, callback=None, **kwargs):
dotcross
=
0
dotcross
=
0
else
:
else
:
# make sure the points are in ClockWise order
# make sure the points are in ClockWise order
dotcross
=
n
.
dot
(
p2
.
sub
(
p1
)
.
cross
(
p3
.
sub
(
p1
)))
dotcross
=
pdot
(
n
,
pcross
(
psub
(
p2
,
p1
),
psub
(
p3
,
p1
)))
if
dotcross
>
0
:
if
dotcross
>
0
:
# Triangle expects the vertices in clockwise order
# Triangle expects the vertices in clockwise order
t
=
Triangle
(
p1
,
p3
,
p2
,
n
)
t
=
Triangle
(
p1
,
p3
,
p2
,
n
)
...
...
pycam/Importers/TestModel.py
View file @
9b939792
...
@@ -22,22 +22,21 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,22 +22,21 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from
pycam.Geometry.Triangle
import
Triangle
from
pycam.Geometry.Triangle
import
Triangle
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Model
import
Model
from
pycam.Geometry.Model
import
Model
def
get_test_model
():
def
get_test_model
():
points
=
[]
points
=
[]
points
.
append
(
Point
(
-
2
,
1
,
4
))
points
.
append
((
-
2
,
1
,
4
))
points
.
append
(
Point
(
2
,
1
,
4
))
points
.
append
((
2
,
1
,
4
))
points
.
append
(
Point
(
0
,
-
2
,
4
))
points
.
append
((
0
,
-
2
,
4
))
points
.
append
(
Point
(
-
5
,
2
,
2
))
points
.
append
((
-
5
,
2
,
2
))
points
.
append
(
Point
(
-
1
,
3
,
2
))
points
.
append
((
-
1
,
3
,
2
))
points
.
append
(
Point
(
5
,
2
,
2
))
points
.
append
((
5
,
2
,
2
))
points
.
append
(
Point
(
4
,
-
1
,
2
))
points
.
append
((
4
,
-
1
,
2
))
points
.
append
(
Point
(
2
,
-
4
,
2
))
points
.
append
((
2
,
-
4
,
2
))
points
.
append
(
Point
(
-
2
,
-
4
,
2
))
points
.
append
((
-
2
,
-
4
,
2
))
points
.
append
(
Point
(
-
3
,
-
2
,
2
))
points
.
append
((
-
3
,
-
2
,
2
))
lines
=
[]
lines
=
[]
lines
.
append
(
Line
(
points
[
0
],
points
[
1
]))
lines
.
append
(
Line
(
points
[
0
],
points
[
1
]))
...
...
pycam/PathGenerators/ContourFollow.py
View file @
9b939792
...
@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
# take a look at the related blog posting describing this algorithm:
# take a look at the related blog posting describing this algorithm:
# http://fab.senselab.org/node/43
# http://fab.senselab.org/node/43
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Plane
import
Plane
from
pycam.PathGenerators
import
get_free_paths_ode
,
get_free_paths_triangles
from
pycam.PathGenerators
import
get_free_paths_ode
,
get_free_paths_triangles
...
@@ -50,7 +50,7 @@ def _process_one_triangle((model, cutter, up_vector, triangle, z)):
...
@@ -50,7 +50,7 @@ def _process_one_triangle((model, cutter, up_vector, triangle, z)):
# Case 1a
# Case 1a
return
result
,
None
return
result
,
None
# ignore triangles pointing upwards or downwards
# ignore triangles pointing upwards or downwards
if
triangle
.
normal
.
cross
(
up_vector
)
.
norm
==
0
:
if
pnorm
(
pcross
(
triangle
.
normal
,
up_vector
))
==
0
:
# Case 1b
# Case 1b
return
result
,
None
return
result
,
None
edge_collisions
=
get_collision_waterline_of_triangle
(
model
,
cutter
,
edge_collisions
=
get_collision_waterline_of_triangle
(
model
,
cutter
,
...
@@ -197,7 +197,7 @@ class ContourFollow(object):
...
@@ -197,7 +197,7 @@ class ContourFollow(object):
def
__init__
(
self
,
path_processor
,
physics
=
None
):
def
__init__
(
self
,
path_processor
,
physics
=
None
):
self
.
pa
=
path_processor
self
.
pa
=
path_processor
self
.
_up_vector
=
Vector
(
0
,
0
,
1
)
self
.
_up_vector
=
(
0
,
0
,
1
,
'v'
)
self
.
physics
=
physics
self
.
physics
=
physics
self
.
_processed_triangles
=
[]
self
.
_processed_triangles
=
[]
if
self
.
physics
:
if
self
.
physics
:
...
@@ -343,13 +343,13 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
...
@@ -343,13 +343,13 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
for
index
in
range
(
3
):
for
index
in
range
(
3
):
edge
=
Line
(
proj_points
[
index
-
1
],
proj_points
[
index
])
edge
=
Line
(
proj_points
[
index
-
1
],
proj_points
[
index
])
# the edge should be clockwise around the model
# the edge should be clockwise around the model
if
edge
.
dir
.
cross
(
triangle
.
normal
)
.
dot
(
up_vector
)
<
0
:
if
pdot
(
pcross
(
edge
.
dir
,
triangle
.
normal
),
up_vector
)
<
0
:
edge
=
Line
(
edge
.
p2
,
edge
.
p1
)
edge
=
Line
(
edge
.
p2
,
edge
.
p1
)
edges
.
append
((
edge
,
proj_points
[
index
-
2
]))
edges
.
append
((
edge
,
proj_points
[
index
-
2
]))
outer_edges
=
[]
outer_edges
=
[]
for
edge
,
other_point
in
edges
:
for
edge
,
other_point
in
edges
:
# pick only edges, where the other point is on the right side
# pick only edges, where the other point is on the right side
if
other_point
.
sub
(
edge
.
p1
)
.
cross
(
edge
.
dir
)
.
dot
(
up_vector
)
>
0
:
if
pdot
(
pcross
(
psub
(
other_point
,
edge
.
p1
),
edge
.
dir
),
up_vector
)
>
0
:
outer_edges
.
append
(
edge
)
outer_edges
.
append
(
edge
)
if
len
(
outer_edges
)
==
0
:
if
len
(
outer_edges
)
==
0
:
# the points seem to be an one line
# the points seem to be an one line
...
@@ -361,14 +361,14 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
...
@@ -361,14 +361,14 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
outer_edges
=
[
long_edge
]
outer_edges
=
[
long_edge
]
else
:
else
:
edge
=
Line
(
proj_points
[
0
],
proj_points
[
1
])
edge
=
Line
(
proj_points
[
0
],
proj_points
[
1
])
if
edge
.
dir
.
cross
(
triangle
.
normal
)
.
dot
(
up_vector
)
<
0
:
if
pdot
(
pcross
(
edge
.
dir
,
triangle
.
normal
),
up_vector
)
<
0
:
edge
=
Line
(
edge
.
p2
,
edge
.
p1
)
edge
=
Line
(
edge
.
p2
,
edge
.
p1
)
outer_edges
=
[
edge
]
outer_edges
=
[
edge
]
else
:
else
:
# some parts of the triangle are above and some below the cutter level
# some parts of the triangle are above and some below the cutter level
# Cases (2a), (2b), (3a) and (3b)
# Cases (2a), (2b), (3a) and (3b)
points_above
=
[
plane
.
get_point_projection
(
p
)
points_above
=
[
plane
.
get_point_projection
(
p
)
for
p
in
triangle
.
get_points
()
if
p
.
z
>
z
]
for
p
in
triangle
.
get_points
()
if
p
[
2
]
>
z
]
waterline
=
plane
.
intersect_triangle
(
triangle
)
waterline
=
plane
.
intersect_triangle
(
triangle
)
if
waterline
is
None
:
if
waterline
is
None
:
if
len
(
points_above
)
==
0
:
if
len
(
points_above
)
==
0
:
...
@@ -380,7 +380,7 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
...
@@ -380,7 +380,7 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
# "triangle.minz >= z" statement above).
# "triangle.minz >= z" statement above).
outer_edges
=
[]
outer_edges
=
[]
elif
not
[
p
for
p
in
triangle
.
get_points
()
elif
not
[
p
for
p
in
triangle
.
get_points
()
if
p
.
z
>
z
+
epsilon
]:
if
p
[
2
]
>
z
+
epsilon
]:
# same as above: fix for inaccurate floating calculations
# same as above: fix for inaccurate floating calculations
outer_edges
=
[]
outer_edges
=
[]
else
:
else
:
...
@@ -397,8 +397,7 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
...
@@ -397,8 +397,7 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
outer_edges
=
[
waterline
]
outer_edges
=
[
waterline
]
elif
len
(
points_above
)
==
1
:
elif
len
(
points_above
)
==
1
:
other_point
=
points_above
[
0
]
other_point
=
points_above
[
0
]
dot
=
other_point
.
sub
(
waterline
.
p1
)
.
cross
(
waterline
.
dir
)
.
dot
(
dot
=
pdot
(
pcross
(
psub
(
other_point
,
waterline
.
p1
),
waterline
.
dir
),
up_vector
)
up_vector
)
if
dot
>
0
:
if
dot
>
0
:
# Case (2b)
# Case (2b)
outer_edges
=
[
waterline
]
outer_edges
=
[
waterline
]
...
@@ -409,7 +408,7 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
...
@@ -409,7 +408,7 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
edges
.
append
(
Line
(
waterline
.
p2
,
other_point
))
edges
.
append
(
Line
(
waterline
.
p2
,
other_point
))
outer_edges
=
[]
outer_edges
=
[]
for
edge
in
edges
:
for
edge
in
edges
:
if
edge
.
dir
.
cross
(
triangle
.
normal
)
.
dot
(
up_vector
)
<
0
:
if
pdot
(
pcross
(
edge
.
dir
,
triangle
.
normal
),
up_vector
)
<
0
:
outer_edges
.
append
(
Line
(
edge
.
p2
,
edge
.
p1
))
outer_edges
.
append
(
Line
(
edge
.
p2
,
edge
.
p1
))
else
:
else
:
outer_edges
.
append
(
edge
)
outer_edges
.
append
(
edge
)
...
@@ -422,15 +421,14 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
...
@@ -422,15 +421,14 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
edges
.
append
(
Line
(
waterline
.
p2
,
other_point
))
edges
.
append
(
Line
(
waterline
.
p2
,
other_point
))
edges
.
sort
(
key
=
lambda
x
:
x
.
len
)
edges
.
sort
(
key
=
lambda
x
:
x
.
len
)
edge
=
edges
[
-
1
]
edge
=
edges
[
-
1
]
if
edge
.
dir
.
cross
(
triangle
.
normal
)
.
dot
(
up_vector
)
<
0
:
if
pdot
(
pcross
(
edge
.
dir
,
triangle
.
normal
),
up_vector
)
<
0
:
outer_edges
=
[
Line
(
edge
.
p2
,
edge
.
p1
)]
outer_edges
=
[
Line
(
edge
.
p2
,
edge
.
p1
)]
else
:
else
:
outer_edges
=
[
edge
]
outer_edges
=
[
edge
]
else
:
else
:
# two points above
# two points above
other_point
=
points_above
[
0
]
other_point
=
points_above
[
0
]
dot
=
other_point
.
sub
(
waterline
.
p1
)
.
cross
(
waterline
.
dir
)
.
dot
(
dot
=
pdot
(
pcross
(
psub
(
other_point
,
waterline
.
p1
),
waterline
.
dir
),
up_vector
)
up_vector
)
if
dot
>
0
:
if
dot
>
0
:
# Case (2b)
# Case (2b)
# the other two points are on the right side
# the other two points are on the right side
...
@@ -438,7 +436,7 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
...
@@ -438,7 +436,7 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
elif
dot
<
0
:
elif
dot
<
0
:
# Case (3a)
# Case (3a)
edge
=
Line
(
points_above
[
0
],
points_above
[
1
])
edge
=
Line
(
points_above
[
0
],
points_above
[
1
])
if
edge
.
dir
.
cross
(
triangle
.
normal
)
.
dot
(
up_vector
)
<
0
:
if
pdot
(
pcross
(
edge
.
dir
,
triangle
.
normal
),
up_vector
)
<
0
:
outer_edges
=
[
Line
(
edge
.
p2
,
edge
.
p1
)]
outer_edges
=
[
Line
(
edge
.
p2
,
edge
.
p1
)]
else
:
else
:
outer_edges
=
[
edge
]
outer_edges
=
[
edge
]
...
@@ -471,21 +469,20 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
...
@@ -471,21 +469,20 @@ def get_collision_waterline_of_triangle(model, cutter, up_vector, triangle, z):
direction
=
up_vector
.
cross
(
edge
.
dir
)
.
normalized
()
direction
=
up_vector
.
cross
(
edge
.
dir
)
.
normalized
()
if
direction
is
None
:
if
direction
is
None
:
continue
continue
direction
=
direction
.
mul
(
max_length
)
direction
=
pmul
(
direction
,
max_length
)
edge_dir
=
edge
.
p2
.
sub
(
edge
.
p1
)
edge_dir
=
psub
(
edge
.
p2
,
edge
.
p1
)
# TODO: Adapt the number of potential starting positions to the length
# TODO: Adapt the number of potential starting positions to the length
# of the line. Don't use 0.0 and 1.0 - this could result in ambiguous
# of the line. Don't use 0.0 and 1.0 - this could result in ambiguous
# collisions with triangles sharing these vertices.
# collisions with triangles sharing these vertices.
for
factor
in
(
0.5
,
epsilon
,
1.0
-
epsilon
,
0.25
,
0.75
):
for
factor
in
(
0.5
,
epsilon
,
1.0
-
epsilon
,
0.25
,
0.75
):
start
=
edge
.
p1
.
add
(
edge_dir
.
mul
(
factor
))
start
=
padd
(
edge
.
p1
,
pmul
(
edge_dir
,
factor
))
# We need to use the triangle collision algorithm here - because we
# We need to use the triangle collision algorithm here - because we
# need the point of collision in the triangle.
# need the point of collision in the triangle.
collisions
=
get_free_paths_triangles
([
model
],
cutter
,
start
,
collisions
=
get_free_paths_triangles
([
model
],
cutter
,
start
,
padd
(
start
,
direction
),
return_triangles
=
True
)
start
.
add
(
direction
),
return_triangles
=
True
)
for
index
,
coll
in
enumerate
(
collisions
):
for
index
,
coll
in
enumerate
(
collisions
):
if
(
index
%
2
==
0
)
and
(
not
coll
[
1
]
is
None
)
\
if
(
index
%
2
==
0
)
and
(
not
coll
[
1
]
is
None
)
\
and
(
not
coll
[
2
]
is
None
)
\
and
(
not
coll
[
2
]
is
None
)
\
and
(
coll
[
0
]
.
sub
(
start
)
.
dot
(
direction
)
>
0
):
and
(
pdot
(
psub
(
coll
[
0
],
start
),
direction
)
>
0
):
cl
,
hit_t
,
cp
=
coll
cl
,
hit_t
,
cp
=
coll
break
break
else
:
else
:
...
...
pycam/PathGenerators/DropCutter.py
View file @
9b939792
...
@@ -27,6 +27,7 @@ from pycam.Utils.threading import run_in_parallel
...
@@ -27,6 +27,7 @@ from pycam.Utils.threading import run_in_parallel
import
pycam.Geometry.Model
import
pycam.Geometry.Model
import
pycam.Utils.log
import
pycam.Utils.log
log
=
pycam
.
Utils
.
log
.
get_logger
()
log
=
pycam
.
Utils
.
log
.
get_logger
()
...
@@ -52,12 +53,11 @@ class DropCutter(object):
...
@@ -52,12 +53,11 @@ class DropCutter(object):
# Transfer the grid (a generator) into a list of lists and count the
# Transfer the grid (a generator) into a list of lists and count the
# items.
# items.
lines
=
[]
# usually there is only one layer - but an xy-grid consists of two
# usually there is only one layer - but an xy-grid consists of two
lines
=
[]
for
layer
in
motion_grid
:
for
layer
in
motion_grid
:
for
line
in
layer
:
lines
.
extend
(
layer
)
lines
.
append
(
line
)
num_of_lines
=
len
(
lines
)
num_of_lines
=
len
(
lines
)
progress_counter
=
ProgressCounter
(
len
(
lines
),
draw_callback
)
progress_counter
=
ProgressCounter
(
len
(
lines
),
draw_callback
)
current_line
=
0
current_line
=
0
...
@@ -66,15 +66,13 @@ class DropCutter(object):
...
@@ -66,15 +66,13 @@ class DropCutter(object):
args
=
[]
args
=
[]
for
one_grid_line
in
lines
:
for
one_grid_line
in
lines
:
# simplify the data (useful for remote processing)
args
.
append
(([(
x
,
y
)
for
x
,
y
,
z
in
one_grid_line
],
minz
,
maxz
,
model
,
cutter
,
self
.
physics
))
xy_coords
=
[(
pos
.
x
,
pos
.
y
)
for
pos
in
one_grid_line
]
args
.
append
((
xy_coords
,
minz
,
maxz
,
model
,
cutter
,
self
.
physics
))
for
points
in
run_in_parallel
(
_process_one_grid_line
,
args
,
for
points
in
run_in_parallel
(
_process_one_grid_line
,
args
,
callback
=
progress_counter
.
update
):
callback
=
progress_counter
.
update
):
self
.
pa
.
new_scanline
()
self
.
pa
.
new_scanline
()
if
draw_callback
and
draw_callback
(
text
=
"DropCutter: processing
"
\
if
draw_callback
and
draw_callback
(
text
=
"DropCutter: processing
line
%
d/
%
d"
+
"line
%
d/
%
d"
%
(
current_line
+
1
,
num_of_lines
)):
%
(
current_line
+
1
,
num_of_lines
)):
# cancel requested
# cancel requested
quit_requested
=
True
quit_requested
=
True
break
break
...
...
pycam/PathGenerators/EngraveCutter.py
View file @
9b939792
...
@@ -22,7 +22,6 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,7 +22,6 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
import
pycam.PathProcessors.PathAccumulator
import
pycam.PathProcessors.PathAccumulator
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.utils
import
ceil
from
pycam.Geometry.utils
import
ceil
...
...
pycam/PathGenerators/PushCutter.py
View file @
9b939792
...
@@ -26,6 +26,7 @@ import pycam.PathProcessors
...
@@ -26,6 +26,7 @@ import pycam.PathProcessors
from
pycam.Geometry.utils
import
ceil
from
pycam.Geometry.utils
import
ceil
from
pycam.Utils.threading
import
run_in_parallel
from
pycam.Utils.threading
import
run_in_parallel
from
pycam.Utils
import
ProgressCounter
from
pycam.Utils
import
ProgressCounter
from
pycam.Geometry.PointUtils
import
*
import
pycam.Utils.log
import
pycam.Utils.log
import
math
import
math
...
@@ -127,7 +128,7 @@ class PushCutter(object):
...
@@ -127,7 +128,7 @@ class PushCutter(object):
for
line
in
layer_grid
:
for
line
in
layer_grid
:
p1
,
p2
=
line
p1
,
p2
=
line
# calculate the required calculation depth (recursion)
# calculate the required calculation depth (recursion)
distance
=
p
2
.
sub
(
p1
)
.
norm
distance
=
p
norm
(
psub
(
p2
,
p1
))
# TODO: accessing cutter.radius here is slightly ugly
# TODO: accessing cutter.radius here is slightly ugly
depth
=
math
.
log
(
accuracy
*
distance
/
cutter
.
radius
)
/
math
.
log
(
2
)
depth
=
math
.
log
(
accuracy
*
distance
/
cutter
.
radius
)
/
math
.
log
(
2
)
depth
=
min
(
max
(
ceil
(
depth
),
4
),
max_depth
)
depth
=
min
(
max
(
ceil
(
depth
),
4
),
max_depth
)
...
...
pycam/PathGenerators/__init__.py
View file @
9b939792
...
@@ -24,7 +24,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -24,7 +24,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
__all__
=
[
"DropCutter"
,
"PushCutter"
,
"EngraveCutter"
,
"ContourFollow"
]
__all__
=
[
"DropCutter"
,
"PushCutter"
,
"EngraveCutter"
,
"ContourFollow"
]
from
pycam.Geometry.utils
import
INFINITE
,
epsilon
,
sqrt
from
pycam.Geometry.utils
import
INFINITE
,
epsilon
,
sqrt
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
import
pycam.Utils.threading
import
pycam.Utils.threading
...
@@ -64,15 +64,15 @@ def get_free_paths_triangles(models, cutter, p1, p2, return_triangles=False):
...
@@ -64,15 +64,15 @@ def get_free_paths_triangles(models, cutter, p1, p2, return_triangles=False):
all_results
.
extend
(
one_result
)
all_results
.
extend
(
one_result
)
return
all_results
return
all_results
backward
=
p
1
.
sub
(
p2
)
.
normalized
(
)
backward
=
p
normalized
(
psub
(
p1
,
p2
)
)
forward
=
p
2
.
sub
(
p1
)
.
normalized
(
)
forward
=
p
normalized
(
psub
(
p2
,
p1
)
)
xyz_dist
=
p
2
.
sub
(
p1
)
.
norm
xyz_dist
=
p
norm
(
psub
(
p2
,
p1
))
minx
=
min
(
p1
.
x
,
p2
.
x
)
minx
=
min
(
p1
[
0
],
p2
[
0
]
)
maxx
=
max
(
p1
.
x
,
p2
.
x
)
maxx
=
max
(
p1
[
0
],
p2
[
0
]
)
miny
=
min
(
p1
.
y
,
p2
.
y
)
miny
=
min
(
p1
[
1
],
p2
[
1
]
)
maxy
=
max
(
p1
.
y
,
p2
.
y
)
maxy
=
max
(
p1
[
1
],
p2
[
1
]
)
minz
=
min
(
p1
.
z
,
p2
.
z
)
minz
=
min
(
p1
[
2
],
p2
[
2
]
)
# find all hits along scan line
# find all hits along scan line
hits
=
[]
hits
=
[]
...
@@ -161,15 +161,15 @@ def get_free_paths_ode(physics, p1, p2, depth=8):
...
@@ -161,15 +161,15 @@ def get_free_paths_ode(physics, p1, p2, depth=8):
"""
"""
points
=
[]
points
=
[]
# "resize" the drill along the while x/y range and check for a collision
# "resize" the drill along the while x/y range and check for a collision
physics
.
extend_drill
(
p2
.
x
-
p1
.
x
,
p2
.
y
-
p1
.
y
,
p2
.
z
-
p1
.
z
)
physics
.
extend_drill
(
p2
[
0
]
-
p1
[
0
],
p2
[
1
]
-
p1
[
1
],
p2
[
2
]
-
p1
[
2
]
)
physics
.
set_drill_position
((
p1
.
x
,
p1
.
y
,
p1
.
z
))
physics
.
set_drill_position
((
p1
[
0
],
p1
[
1
],
p1
[
2
]
))
if
physics
.
check_collision
():
if
physics
.
check_collision
():
# collision detected
# collision detected
if
depth
>
0
:
if
depth
>
0
:
middle_x
=
(
p1
.
x
+
p2
.
x
)
/
2
middle_x
=
(
p1
[
0
]
+
p2
[
0
]
)
/
2
middle_y
=
(
p1
.
y
+
p2
.
y
)
/
2
middle_y
=
(
p1
[
1
]
+
p2
[
1
]
)
/
2
middle_z
=
(
p1
.
z
+
p2
.
z
)
/
2
middle_z
=
(
p1
[
2
]
+
p2
[
2
]
)
/
2
p_middle
=
Point
(
middle_x
,
middle_y
,
middle_z
)
p_middle
=
(
middle_x
,
middle_y
,
middle_z
)
group1
=
get_free_paths_ode
(
physics
,
p1
,
p_middle
,
depth
-
1
)
group1
=
get_free_paths_ode
(
physics
,
p1
,
p_middle
,
depth
-
1
)
group2
=
get_free_paths_ode
(
physics
,
p_middle
,
p2
,
depth
-
1
)
group2
=
get_free_paths_ode
(
physics
,
p_middle
,
p2
,
depth
-
1
)
if
group1
and
group2
and
(
group1
[
-
1
]
==
group2
[
0
]):
if
group1
and
group2
and
(
group1
[
-
1
]
==
group2
[
0
]):
...
@@ -222,12 +222,12 @@ def get_max_height_ode(physics, x, y, minz, maxz):
...
@@ -222,12 +222,12 @@ def get_max_height_ode(physics, x, y, minz, maxz):
# skip this point (by going up to safety height)
# skip this point (by going up to safety height)
return
None
return
None
else
:
else
:
return
Point
(
x
,
y
,
safe_z
)
return
(
x
,
y
,
safe_z
)
def
get_max_height_triangles
(
model
,
cutter
,
x
,
y
,
minz
,
maxz
):
def
get_max_height_triangles
(
model
,
cutter
,
x
,
y
,
minz
,
maxz
):
if
model
is
None
:
if
model
is
None
:
return
Point
(
x
,
y
,
minz
)
return
(
x
,
y
,
minz
)
p
=
Point
(
x
,
y
,
maxz
)
p
=
(
x
,
y
,
maxz
)
height_max
=
None
height_max
=
None
box_x_min
=
cutter
.
get_minx
(
p
)
box_x_min
=
cutter
.
get_minx
(
p
)
box_x_max
=
cutter
.
get_maxx
(
p
)
box_x_max
=
cutter
.
get_maxx
(
p
)
...
@@ -239,8 +239,8 @@ def get_max_height_triangles(model, cutter, x, y, minz, maxz):
...
@@ -239,8 +239,8 @@ def get_max_height_triangles(model, cutter, x, y, minz, maxz):
box_y_max
,
box_z_max
)
box_y_max
,
box_z_max
)
for
t
in
triangles
:
for
t
in
triangles
:
cut
=
cutter
.
drop
(
t
,
start
=
p
)
cut
=
cutter
.
drop
(
t
,
start
=
p
)
if
cut
and
((
height_max
is
None
)
or
(
cut
.
z
>
height_max
)):
if
cut
and
((
height_max
is
None
)
or
(
cut
[
2
]
>
height_max
)):
height_max
=
cut
.
z
height_max
=
cut
[
2
]
# don't do a complete boundary check for the height
# don't do a complete boundary check for the height
# this avoids zero-cuts for models that exceed the bounding box height
# this avoids zero-cuts for models that exceed the bounding box height
if
(
height_max
is
None
)
or
(
height_max
<
minz
+
epsilon
):
if
(
height_max
is
None
)
or
(
height_max
<
minz
+
epsilon
):
...
@@ -248,18 +248,18 @@ def get_max_height_triangles(model, cutter, x, y, minz, maxz):
...
@@ -248,18 +248,18 @@ def get_max_height_triangles(model, cutter, x, y, minz, maxz):
if
height_max
>
maxz
+
epsilon
:
if
height_max
>
maxz
+
epsilon
:
return
None
return
None
else
:
else
:
return
Point
(
x
,
y
,
height_max
)
return
(
x
,
y
,
height_max
)
def
_check_deviance_of_adjacent_points
(
p1
,
p2
,
p3
,
min_distance
):
def
_check_deviance_of_adjacent_points
(
p1
,
p2
,
p3
,
min_distance
):
straight
=
p
3
.
sub
(
p1
)
straight
=
p
sub
(
p3
,
p1
)
added
=
p
2
.
sub
(
p1
)
.
norm
+
p3
.
sub
(
p2
)
.
norm
added
=
p
norm
(
psub
(
p2
,
p1
))
+
pnorm
(
psub
(
p3
,
p2
))
# compare only the x/y distance of p1 and p3 with min_distance
# compare only the x/y distance of p1 and p3 with min_distance
if
straight
.
x
**
2
+
straight
.
y
**
2
<
min_distance
**
2
:
if
straight
[
0
]
**
2
+
straight
[
1
]
**
2
<
min_distance
**
2
:
# the points are too close together
# the points are too close together
return
True
return
True
else
:
else
:
# allow 0.1% deviance - this is an angle of around 2 degrees
# allow 0.1% deviance - this is an angle of around 2 degrees
return
(
added
/
straight
.
norm
)
<
1.001
return
(
added
/
pnorm
(
straight
)
)
<
1.001
def
get_max_height_dynamic
(
model
,
cutter
,
positions
,
minz
,
maxz
,
physics
=
None
):
def
get_max_height_dynamic
(
model
,
cutter
,
positions
,
minz
,
maxz
,
physics
=
None
):
max_depth
=
8
max_depth
=
8
...
@@ -291,11 +291,11 @@ def get_max_height_dynamic(model, cutter, positions, minz, maxz, physics=None):
...
@@ -291,11 +291,11 @@ def get_max_height_dynamic(model, cutter, positions, minz, maxz, physics=None):
# distribute the new point two before the middle and one after
# distribute the new point two before the middle and one after
if
depth_count
%
3
!=
2
:
if
depth_count
%
3
!=
2
:
# insert between the 1st and 2nd point
# insert between the 1st and 2nd point
middle
=
((
p1
.
x
+
p2
.
x
)
/
2
,
(
p1
.
y
+
p2
.
y
)
/
2
)
middle
=
((
p1
[
0
]
+
p2
[
0
])
/
2
,
(
p1
[
1
]
+
p2
[
1
]
)
/
2
)
result
.
insert
(
index
+
1
,
get_max_height
(
middle
[
0
],
middle
[
1
]))
result
.
insert
(
index
+
1
,
get_max_height
(
middle
[
0
],
middle
[
1
]))
else
:
else
:
# insert between the 2nd and 3rd point
# insert between the 2nd and 3rd point
middle
=
((
p2
.
x
+
p3
.
x
)
/
2
,
(
p2
.
y
+
p3
.
y
)
/
2
)
middle
=
((
p2
[
0
]
+
p3
[
0
])
/
2
,
(
p2
[
1
]
+
p3
[
1
]
)
/
2
)
result
.
insert
(
index
+
2
,
get_max_height
(
middle
[
0
],
middle
[
1
]))
result
.
insert
(
index
+
2
,
get_max_height
(
middle
[
0
],
middle
[
1
]))
depth_count
+=
1
depth_count
+=
1
else
:
else
:
...
...
pycam/PathProcessors/ContourCutter.py
View file @
9b939792
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
import
pycam.PathProcessors
import
pycam.PathProcessors
from
pycam.Geometry.PolygonExtractor
import
PolygonExtractor
from
pycam.Geometry.PolygonExtractor
import
PolygonExtractor
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Toolpath
import
simplify_toolpath
from
pycam.Toolpath
import
simplify_toolpath
class
ContourCutter
(
pycam
.
PathProcessors
.
BasePathProcessor
):
class
ContourCutter
(
pycam
.
PathProcessors
.
BasePathProcessor
):
...
@@ -33,12 +33,12 @@ class ContourCutter(pycam.PathProcessors.BasePathProcessor):
...
@@ -33,12 +33,12 @@ class ContourCutter(pycam.PathProcessors.BasePathProcessor):
self
.
polygon_extractor
=
None
self
.
polygon_extractor
=
None
self
.
points
=
[]
self
.
points
=
[]
self
.
reverse
=
reverse
self
.
reverse
=
reverse
self
.
__forward
=
Point
(
1
,
1
,
0
)
self
.
__forward
=
(
1
,
1
,
0
)
def
append
(
self
,
point
):
def
append
(
self
,
point
):
# Sort the points in positive x/y direction - otherwise the
# Sort the points in positive x/y direction - otherwise the
# PolygonExtractor breaks.
# PolygonExtractor breaks.
if
self
.
points
and
(
p
oint
.
sub
(
self
.
points
[
0
])
.
dot
(
self
.
__forward
)
<
0
):
if
self
.
points
and
(
p
dot
(
psub
(
point
,
self
.
points
[
0
]),
self
.
__forward
)
<
0
):
self
.
points
.
insert
(
0
,
point
)
self
.
points
.
insert
(
0
,
point
)
else
:
else
:
self
.
points
.
append
(
point
)
self
.
points
.
append
(
point
)
...
...
pycam/PathProcessors/__init__.py
View file @
9b939792
...
@@ -41,10 +41,10 @@ class BasePathProcessor(object):
...
@@ -41,10 +41,10 @@ class BasePathProcessor(object):
def
sort_layered
(
self
,
upper_first
=
True
):
def
sort_layered
(
self
,
upper_first
=
True
):
if
upper_first
:
if
upper_first
:
compare_height
=
lambda
path1
,
path2
:
\
compare_height
=
lambda
path1
,
path2
:
\
path1
.
points
[
0
]
.
z
<
path2
.
points
[
0
]
.
z
path1
.
points
[
0
]
[
2
]
<
path2
.
points
[
0
][
2
]
else
:
else
:
compare_height
=
lambda
path1
,
path2
:
\
compare_height
=
lambda
path1
,
path2
:
\
path1
.
points
[
0
]
.
z
>
path2
.
points
[
0
]
.
z
path1
.
points
[
0
]
[
2
]
>
path2
.
points
[
0
][
2
]
finished
=
False
finished
=
False
while
not
finished
:
while
not
finished
:
index
=
0
index
=
0
...
...
pycam/Plugins/Fonts.py
View file @
9b939792
...
@@ -253,8 +253,8 @@ class Fonts(pycam.Plugins.PluginBase):
...
@@ -253,8 +253,8 @@ class Fonts(pycam.Plugins.PluginBase):
# add the first point again to close the polygon
# add the first point again to close the polygon
points
.
append
(
points
[
0
])
points
.
append
(
points
[
0
])
for
point
in
points
:
for
point
in
points
:
x
=
get_virtual_x
(
point
.
x
)
x
=
get_virtual_x
(
point
[
0
]
)
y
=
get_virtual_y
(
point
.
y
)
y
=
get_virtual_y
(
point
[
1
]
)
draw_points
.
append
((
x
,
y
))
draw_points
.
append
((
x
,
y
))
drawing_area
.
draw_lines
(
gc
,
draw_points
)
drawing_area
.
draw_lines
(
gc
,
draw_points
)
final_gc
=
final_drawing_area
.
new_gc
()
final_gc
=
final_drawing_area
.
new_gc
()
...
...
pycam/Plugins/ModelProjection.py
View file @
9b939792
...
@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -23,7 +23,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
import
pycam.Plugins
import
pycam.Plugins
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Point
Utils
import
*
class
ModelProjection
(
pycam
.
Plugins
.
PluginBase
):
class
ModelProjection
(
pycam
.
Plugins
.
PluginBase
):
...
@@ -87,8 +87,8 @@ class ModelProjection(pycam.Plugins.PluginBase):
...
@@ -87,8 +87,8 @@ class ModelProjection(pycam.Plugins.PluginBase):
(
"ProjectionModelCustom"
,
(
"ProjectionModelCustom"
,
self
.
gui
.
get_object
(
"ProjectionZLevel"
)
.
get_value
())):
self
.
gui
.
get_object
(
"ProjectionZLevel"
)
.
get_value
())):
if
self
.
gui
.
get_object
(
objname
)
.
get_active
():
if
self
.
gui
.
get_object
(
objname
)
.
get_active
():
plane
=
Plane
(
Point
(
0
,
0
,
z_level
),
Vector
(
0
,
0
,
1
))
plane
=
Plane
(
(
0
,
0
,
z_level
),
(
0
,
0
,
1
,
'v'
))
self
.
log
.
info
(
"Projecting 3D model at level z=
%
g"
%
plane
.
p
.
z
)
self
.
log
.
info
(
"Projecting 3D model at level z=
%
g"
%
plane
.
p
[
2
]
)
new_model
=
model
.
get_waterline_contour
(
plane
,
new_model
=
model
.
get_waterline_contour
(
plane
,
callback
=
progress
.
update
)
callback
=
progress
.
update
)
if
new_model
:
if
new_model
:
...
...
pycam/Plugins/OpenGLViewModel.py
View file @
9b939792
...
@@ -21,7 +21,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -21,7 +21,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
import
pycam.Plugins
import
pycam.Plugins
import
pycam.Geometry.Point
from
pycam.Geometry.PointUtils
import
*
GTK_COLOR_MAX
=
65535.0
GTK_COLOR_MAX
=
65535.0
...
@@ -144,30 +144,27 @@ class OpenGLViewModelTriangle(pycam.Plugins.PluginBase):
...
@@ -144,30 +144,27 @@ class OpenGLViewModelTriangle(pycam.Plugins.PluginBase):
model
=
models
[
index
]
model
=
models
[
index
]
if
not
hasattr
(
model
,
"triangles"
):
if
not
hasattr
(
model
,
"triangles"
):
continue
continue
get_coords
=
lambda
p
:
(
p
.
x
,
p
.
y
,
p
.
z
)
def
calc_normal
(
main
,
normals
):
def
calc_normal
(
main
,
normals
):
suitable
=
pycam
.
Geometry
.
Point
.
Vector
(
0
,
0
,
0
)
suitable
=
(
0
,
0
,
0
,
'v'
)
for
normal
,
weight
in
normals
:
for
normal
,
weight
in
normals
:
dot
=
main
.
dot
(
normal
)
dot
=
pdot
(
main
,
normal
)
if
dot
>
0
:
if
dot
>
0
:
suitable
=
suitable
.
add
(
normal
.
mul
(
weight
*
dot
))
suitable
=
padd
(
suitable
,
pmul
(
normal
,
weight
*
dot
))
return
suitable
.
normalized
(
)
return
pnormalized
(
suitable
)
vertices
=
{}
vertices
=
{}
for
t
in
model
.
triangles
():
for
t
in
model
.
triangles
():
for
p
in
(
t
.
p1
,
t
.
p2
,
t
.
p3
):
for
p
in
(
t
.
p1
,
t
.
p2
,
t
.
p3
):
coords
=
get_coords
(
p
)
if
not
p
in
vertices
:
if
not
coords
in
vertices
:
vertices
[
p
]
=
[]
vertices
[
coords
]
=
[]
vertices
[
p
]
.
append
((
pnormalized
(
t
.
normal
),
t
.
get_area
()))
vertices
[
coords
]
.
append
((
t
.
normal
.
normalized
(),
t
.
get_area
()))
GL
.
glBegin
(
GL
.
GL_TRIANGLES
)
GL
.
glBegin
(
GL
.
GL_TRIANGLES
)
for
t
in
model
.
triangles
():
for
t
in
model
.
triangles
():
# The triangle's points are in clockwise order, but GL expects
# The triangle's points are in clockwise order, but GL expects
# counter-clockwise sorting.
# counter-clockwise sorting.
for
p
in
(
t
.
p1
,
t
.
p3
,
t
.
p2
):
for
p
in
(
t
.
p1
,
t
.
p3
,
t
.
p2
):
coords
=
get_coords
(
p
)
normal
=
calc_normal
(
pnormalized
(
t
.
normal
),
vertices
[
p
])
normal
=
calc_normal
(
t
.
normal
.
normalized
(),
vertices
[
coords
])
GL
.
glNormal3f
(
normal
[
0
],
normal
[
1
],
normal
[
2
])
GL
.
glNormal3f
(
normal
.
x
,
normal
.
y
,
normal
.
z
)
GL
.
glVertex3f
(
p
[
0
],
p
[
1
],
p
[
2
])
GL
.
glVertex3f
(
p
.
x
,
p
.
y
,
p
.
z
)
GL
.
glEnd
()
GL
.
glEnd
()
removal_list
.
append
(
index
)
removal_list
.
append
(
index
)
# remove all models that we processed
# remove all models that we processed
...
...
pycam/Plugins/OpenGLViewToolpath.py
View file @
9b939792
...
@@ -75,9 +75,38 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase):
...
@@ -75,9 +75,38 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase):
def
draw_toolpaths
(
self
):
def
draw_toolpaths
(
self
):
if
self
.
_is_visible
():
if
self
.
_is_visible
():
for
toolpath
in
self
.
core
.
get
(
"toolpaths"
)
.
get_visible
():
for
toolpath
in
self
.
core
.
get
(
"toolpaths"
)
.
get_visible
():
moves
=
toolpath
.
get_moves
(
self
.
core
.
get
(
"gcode_safety_height"
))
moves
=
toolpath
.
get_moves_for_opengl
(
self
.
core
.
get
(
"gcode_safety_height"
))
self
.
_draw_toolpath_moves
(
moves
)
self
.
_draw_toolpath_moves2
(
moves
)
#moves = toolpath.get_moves(self.core.get("gcode_safety_height"))
#self._draw_toolpath_moves(moves)
def
_draw_toolpath_moves2
(
self
,
paths
):
GL
=
self
.
_GL
GL
.
glDisable
(
GL
.
GL_LIGHTING
)
color_rapid
=
self
.
core
.
get
(
"color_toolpath_return"
)
color_cut
=
self
.
core
.
get
(
"color_toolpath_cut"
)
show_directions
=
self
.
core
.
get
(
"show_directions"
)
GL
.
glMatrixMode
(
GL
.
GL_MODELVIEW
)
GL
.
glLoadIdentity
()
coords
=
paths
[
0
]
try
:
coords
.
bind
()
GL
.
glEnableClientState
(
GL
.
GL_VERTEX_ARRAY
)
GL
.
glVertexPointerf
(
coords
)
for
path
in
paths
[
1
]:
if
path
[
2
]:
GL
.
glColor4f
(
color_rapid
[
"red"
],
color_rapid
[
"green"
],
color_rapid
[
"blue"
],
color_rapid
[
"alpha"
])
else
:
GL
.
glColor4f
(
color_cut
[
"red"
],
color_cut
[
"green"
],
color_cut
[
"blue"
],
color_cut
[
"alpha"
])
if
show_directions
:
GL
.
glDisable
(
GL
.
GL_CULL_FACE
)
GL
.
glDrawElements
(
GL
.
GL_TRIANGLES
,
len
(
path
[
1
]),
GL
.
GL_UNSIGNED_INT
,
path
[
1
])
GL
.
glEnable
(
GL
.
GL_CULL_FACE
)
GL
.
glDrawElements
(
GL
.
GL_LINE_STRIP
,
len
(
path
[
0
]),
GL
.
GL_UNSIGNED_INT
,
path
[
0
])
finally
:
coords
.
unbind
()
## Simulate still depends on this pathway
def
_draw_toolpath_moves
(
self
,
moves
):
def
_draw_toolpath_moves
(
self
,
moves
):
GL
=
self
.
_GL
GL
=
self
.
_GL
GL
.
glDisable
(
GL
.
GL_LIGHTING
)
GL
.
glDisable
(
GL
.
GL_LIGHTING
)
...
@@ -102,9 +131,9 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase):
...
@@ -102,9 +131,9 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase):
GL
.
glFinish
()
GL
.
glFinish
()
GL
.
glBegin
(
GL
.
GL_LINE_STRIP
)
GL
.
glBegin
(
GL
.
GL_LINE_STRIP
)
if
not
last_position
is
None
:
if
not
last_position
is
None
:
GL
.
glVertex3f
(
last_position
.
x
,
last_position
.
y
,
last_position
.
z
)
GL
.
glVertex3f
(
*
last_position
)
last_rapid
=
rapid
last_rapid
=
rapid
GL
.
glVertex3f
(
position
.
x
,
position
.
y
,
position
.
z
)
GL
.
glVertex3f
(
*
position
)
last_position
=
position
last_position
=
position
GL
.
glEnd
()
GL
.
glEnd
()
if
show_directions
:
if
show_directions
:
...
@@ -112,4 +141,3 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase):
...
@@ -112,4 +141,3 @@ class OpenGLViewToolpath(pycam.Plugins.PluginBase):
p1
=
moves
[
index
][
0
]
p1
=
moves
[
index
][
0
]
p2
=
moves
[
index
+
1
][
0
]
p2
=
moves
[
index
+
1
][
0
]
pycam
.
Gui
.
OpenGLTools
.
draw_direction_cone
(
p1
,
p2
)
pycam
.
Gui
.
OpenGLTools
.
draw_direction_cone
(
p1
,
p2
)
pycam/Plugins/OpenGLWindow.py
View file @
9b939792
...
@@ -34,7 +34,7 @@ import gtk
...
@@ -34,7 +34,7 @@ import gtk
import
math
import
math
from
pycam.Gui.OpenGLTools
import
draw_complete_model_view
from
pycam.Gui.OpenGLTools
import
draw_complete_model_view
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
import
pycam.Geometry.Matrix
as
Matrix
import
pycam.Geometry.Matrix
as
Matrix
from
pycam.Geometry.utils
import
sqrt
,
number
from
pycam.Geometry.utils
import
sqrt
,
number
import
pycam.Plugins
import
pycam.Plugins
...
@@ -815,12 +815,11 @@ class Camera(object):
...
@@ -815,12 +815,11 @@ class Camera(object):
if
(
None
,
None
)
in
low_high
:
if
(
None
,
None
)
in
low_high
:
return
return
max_dim
=
max
([
high
-
low
for
low
,
high
in
low_high
])
max_dim
=
max
([
high
-
low
for
low
,
high
in
low_high
])
distv
=
Point
(
v
[
"distance"
][
0
],
v
[
"distance"
][
1
],
distv
=
pnormalized
((
v
[
"distance"
][
0
],
v
[
"distance"
][
1
],
v
[
"distance"
][
2
]))
v
[
"distance"
][
2
])
.
normalized
()
# The multiplier "1.25" is based on experiments. 1.414 (sqrt(2)) should
# The multiplier "1.25" is based on experiments. 1.414 (sqrt(2)) should
# be roughly sufficient for showing the diagonal of any model.
# be roughly sufficient for showing the diagonal of any model.
distv
=
distv
.
mul
(
(
max_dim
*
1.25
)
/
number
(
math
.
sin
(
v
[
"fovy"
]
/
2
)))
distv
=
pmul
(
distv
,
(
max_dim
*
1.25
)
/
number
(
math
.
sin
(
v
[
"fovy"
]
/
2
)))
self
.
view
[
"distance"
]
=
(
distv
.
x
,
distv
.
y
,
distv
.
z
)
self
.
view
[
"distance"
]
=
distv
# Adjust the "far" distance for the camera to make sure, that huge
# Adjust the "far" distance for the camera to make sure, that huge
# models (e.g. x=1000) are still visible.
# models (e.g. x=1000) are still visible.
self
.
view
[
"zfar"
]
=
100
*
max_dim
self
.
view
[
"zfar"
]
=
100
*
max_dim
...
@@ -976,9 +975,8 @@ class Camera(object):
...
@@ -976,9 +975,8 @@ class Camera(object):
# Calculate the proportion of each model axis according to the x axis of
# Calculate the proportion of each model axis according to the x axis of
# the screen.
# the screen.
distv
=
self
.
view
[
"distance"
]
distv
=
self
.
view
[
"distance"
]
distv
=
Point
(
distv
[
0
],
distv
[
1
],
distv
[
2
])
.
normalized
()
distv
=
pnormalized
((
distv
[
0
],
distv
[
1
],
distv
[
2
]))
factors_x
=
distv
.
cross
(
Point
(
v_up
[
0
],
v_up
[
1
],
v_up
[
2
]))
.
normalized
()
factors_x
=
pnormalized
(
pcross
(
distv
,
(
v_up
[
0
],
v_up
[
1
],
v_up
[
2
])))
factors_x
=
(
factors_x
.
x
,
factors_x
.
y
,
factors_x
.
z
)
return
(
factors_x
,
factors_y
)
return
(
factors_x
,
factors_y
)
pycam/Plugins/ToolpathCrop.py
View file @
9b939792
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
import
pycam.Plugins
import
pycam.Plugins
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Plane
import
Plane
import
pycam.Gui.ControlsGTK
import
pycam.Gui.ControlsGTK
...
@@ -145,7 +145,7 @@ class ToolpathCrop(pycam.Plugins.PluginBase):
...
@@ -145,7 +145,7 @@ class ToolpathCrop(pycam.Plugins.PluginBase):
polygons
.
append
(
poly
.
copy
())
polygons
.
append
(
poly
.
copy
())
elif
hasattr
(
model
,
"get_waterline_contour"
):
elif
hasattr
(
model
,
"get_waterline_contour"
):
z_slice
=
self
.
gui
.
get_object
(
"ToolpathCropZSlice"
)
.
get_value
()
z_slice
=
self
.
gui
.
get_object
(
"ToolpathCropZSlice"
)
.
get_value
()
plane
=
Plane
(
Point
(
0
,
0
,
z_slice
))
plane
=
Plane
((
0
,
0
,
z_slice
))
for
poly
in
model
.
get_waterline_contour
(
plane
)
.
get_polygons
():
for
poly
in
model
.
get_waterline_contour
(
plane
)
.
get_polygons
():
polygons
.
append
(
poly
.
copy
())
polygons
.
append
(
poly
.
copy
())
# add an offset if requested
# add an offset if requested
...
...
pycam/Plugins/ToolpathExport.py
View file @
9b939792
...
@@ -24,7 +24,7 @@ import os
...
@@ -24,7 +24,7 @@ import os
import
pycam.Plugins
import
pycam.Plugins
from
pycam.Exporters.GCodeExporter
import
PATH_MODES
from
pycam.Exporters.GCodeExporter
import
PATH_MODES
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
FILTER_GCODE
=
((
"GCode files"
,
(
"*.ngc"
,
"*.nc"
,
"*.gc"
,
"*.gcode"
)),)
FILTER_GCODE
=
((
"GCode files"
,
(
"*.ngc"
,
"*.nc"
,
"*.gc"
,
"*.gcode"
)),)
...
@@ -181,7 +181,7 @@ class ToolpathExport(pycam.Plugins.PluginBase):
...
@@ -181,7 +181,7 @@ class ToolpathExport(pycam.Plugins.PluginBase):
pos_x
=
self
.
core
.
get
(
"touch_off_position_x"
)
pos_x
=
self
.
core
.
get
(
"touch_off_position_x"
)
pos_y
=
self
.
core
.
get
(
"touch_off_position_y"
)
pos_y
=
self
.
core
.
get
(
"touch_off_position_y"
)
pos_z
=
self
.
core
.
get
(
"touch_off_position_z"
)
pos_z
=
self
.
core
.
get
(
"touch_off_position_z"
)
touch_off_pos
=
Point
(
pos_x
,
pos_y
,
pos_z
)
touch_off_pos
=
(
pos_x
,
pos_y
,
pos_z
)
else
:
else
:
touch_off_pos
=
None
touch_off_pos
=
None
generator
=
generator_func
(
destination
,
generator
=
generator_func
(
destination
,
...
...
pycam/Plugins/ToolpathGrid.py
View file @
9b939792
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
import
pycam.Plugins
import
pycam.Plugins
import
pycam.Geometry.Point
from
pycam.Geometry.PointUtils
import
*
class
ToolpathGrid
(
pycam
.
Plugins
.
PluginBase
):
class
ToolpathGrid
(
pycam
.
Plugins
.
PluginBase
):
...
@@ -97,11 +97,10 @@ class ToolpathGrid(pycam.Plugins.PluginBase):
...
@@ -97,11 +97,10 @@ class ToolpathGrid(pycam.Plugins.PluginBase):
new_paths
=
[]
new_paths
=
[]
for
x
in
range
(
x_count
):
for
x
in
range
(
x_count
):
for
y
in
range
(
y_count
):
for
y
in
range
(
y_count
):
shift
=
pycam
.
Geometry
.
Point
.
Vector
(
x
*
(
x_space
+
x_dim
),
shift
=
(
x
*
(
x_space
+
x_dim
),
y
*
(
y_space
+
y_dim
),
0
,
'v'
)
y
*
(
y_space
+
y_dim
),
0
)
for
path
in
toolpath
.
paths
:
for
path
in
toolpath
.
paths
:
new_path
=
pycam
.
Geometry
.
Path
.
Path
()
new_path
=
pycam
.
Geometry
.
Path
.
Path
()
new_path
.
points
=
[
shift
.
add
(
p
)
for
p
in
path
.
points
]
new_path
.
points
=
[
padd
(
shift
,
p
)
for
p
in
path
.
points
]
new_paths
.
append
(
new_path
)
new_paths
.
append
(
new_path
)
if
not
self
.
gui
.
get_object
(
"KeepOriginal"
)
.
get_active
():
if
not
self
.
gui
.
get_object
(
"KeepOriginal"
)
.
get_active
():
toolpath
.
paths
=
new_paths
toolpath
.
paths
=
new_paths
...
...
pycam/Simulation/ODEBlocks.py
View file @
9b939792
...
@@ -21,7 +21,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -21,7 +21,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
import
pycam.Cutters
import
pycam.Cutters
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
import
ode
import
ode
try
:
try
:
...
@@ -70,25 +70,25 @@ class ODEBlocks(object):
...
@@ -70,25 +70,25 @@ class ODEBlocks(object):
self
.
y_step_width
,
self
.
z_width
))
self
.
y_step_width
,
self
.
z_width
))
box
.
setBody
(
body
)
box
.
setBody
(
body
)
box
.
setPosition
((
x_pos
,
y_pos
,
z_pos
))
box
.
setPosition
((
x_pos
,
y_pos
,
z_pos
))
box
.
position
=
Point
(
x_pos
,
y_pos
,
z_pos
)
box
.
position
=
(
x_pos
,
y_pos
,
z_pos
)
self
.
boxes
.
append
(
box
)
self
.
boxes
.
append
(
box
)
def
process_cutter_movement
(
self
,
location_start
,
location_end
):
def
process_cutter_movement
(
self
,
location_start
,
location_end
):
# TODO: fix this workaround in the cutters shape defintions (or in ODE?)
# TODO: fix this workaround in the cutters shape defintions (or in ODE?)
# for now we may only move from low x/y values to higher x/y values
# for now we may only move from low x/y values to higher x/y values
if
(
location_start
.
x
>
location_end
.
x
)
\
if
(
location_start
[
0
]
>
location_end
[
0
]
)
\
or
(
location_start
.
y
>
location_end
.
y
):
or
(
location_start
[
1
]
>
location_end
[
1
]
):
location_start
,
location_end
=
location_end
,
location_start
location_start
,
location_end
=
location_end
,
location_start
cutter_body
=
ode
.
Body
(
self
.
world
)
cutter_body
=
ode
.
Body
(
self
.
world
)
cutter_shape
,
cutter_position_func
=
self
.
cutter
.
get_shape
(
"ODE"
)
cutter_shape
,
cutter_position_func
=
self
.
cutter
.
get_shape
(
"ODE"
)
self
.
space
.
add
(
cutter_shape
)
self
.
space
.
add
(
cutter_shape
)
cutter_shape
.
space
=
self
.
space
cutter_shape
.
space
=
self
.
space
cutter_shape
.
setBody
(
cutter_body
)
cutter_shape
.
setBody
(
cutter_body
)
cutter_position_func
(
location_start
.
x
,
location_start
.
y
,
cutter_position_func
(
location_start
[
0
],
location_start
[
1
]
,
location_start
.
z
)
location_start
[
2
]
)
cutter_shape
.
extend_shape
(
location_end
.
x
-
location_start
.
x
,
cutter_shape
.
extend_shape
(
location_end
[
0
]
-
location_start
[
0
]
,
location_end
.
y
-
location_start
.
y
,
location_end
[
1
]
-
location_start
[
1
]
,
location_end
.
z
-
location_start
.
z
)
location_end
[
2
]
-
location_start
[
2
]
)
aabb
=
cutter_shape
.
getAABB
()
aabb
=
cutter_shape
.
getAABB
()
cutter_height
=
aabb
[
5
]
-
aabb
[
4
]
cutter_height
=
aabb
[
5
]
-
aabb
[
4
]
# add a ray along the drill to work around an ODE bug in v0.11.1
# add a ray along the drill to work around an ODE bug in v0.11.1
...
@@ -112,8 +112,8 @@ class ODEBlocks(object):
...
@@ -112,8 +112,8 @@ class ODEBlocks(object):
aabb
=
box
.
getAABB
()
aabb
=
box
.
getAABB
()
end_height
,
start_height
=
aabb
[
-
2
:]
end_height
,
start_height
=
aabb
[
-
2
:]
height_half
=
(
start_height
-
end_height
)
/
2.0
height_half
=
(
start_height
-
end_height
)
/
2.0
x_pos
=
box
.
position
.
x
x_pos
=
box
.
position
[
0
]
y_pos
=
box
.
position
.
y
y_pos
=
box
.
position
[
1
]
new_z
=
end_height
new_z
=
end_height
box
.
setPosition
((
x_pos
,
y_pos
,
end_height
-
height_half
))
box
.
setPosition
((
x_pos
,
y_pos
,
end_height
-
height_half
))
loops_left
=
12
loops_left
=
12
...
@@ -137,7 +137,7 @@ class ODEBlocks(object):
...
@@ -137,7 +137,7 @@ class ODEBlocks(object):
z_pos
=
new_z
-
new_height
/
2.0
z_pos
=
new_z
-
new_height
/
2.0
new_box
=
ode
.
GeomBox
(
self
.
space
,
(
aabb
[
1
]
-
aabb
[
0
],
aabb
[
3
]
-
aabb
[
2
],
new_box
=
ode
.
GeomBox
(
self
.
space
,
(
aabb
[
1
]
-
aabb
[
0
],
aabb
[
3
]
-
aabb
[
2
],
new_height
))
new_height
))
new_box
.
position
=
Point
(
x_pos
,
y_pos
,
z_pos
)
new_box
.
position
=
(
x_pos
,
y_pos
,
z_pos
)
new_box
.
setBody
(
box
.
getBody
())
new_box
.
setBody
(
box
.
getBody
())
new_box
.
setPosition
((
x_pos
,
y_pos
,
z_pos
))
new_box
.
setPosition
((
x_pos
,
y_pos
,
z_pos
))
self
.
boxes
.
insert
(
box_index
,
new_box
)
self
.
boxes
.
insert
(
box_index
,
new_box
)
...
@@ -199,30 +199,30 @@ class ODEBlocks(object):
...
@@ -199,30 +199,30 @@ class ODEBlocks(object):
if
(
0
<=
ix
<
len
(
height_field
))
\
if
(
0
<=
ix
<
len
(
height_field
))
\
and
(
0
<=
iy
<
len
(
height_field
[
ix
])):
and
(
0
<=
iy
<
len
(
height_field
[
ix
])):
point
=
height_field
[
ix
][
iy
]
point
=
height_field
[
ix
][
iy
]
height_sum
+=
point
.
z
height_sum
+=
point
[
2
]
x_positions
.
append
(
point
.
x
)
x_positions
.
append
(
point
[
0
]
)
y_positions
.
append
(
point
.
y
)
y_positions
.
append
(
point
[
1
]
)
divisor
+=
1
divisor
+=
1
# Use the middle between the x positions of two adjacent boxes,
# Use the middle between the x positions of two adjacent boxes,
# _if_ there is a neighbour attached to that corner.
# _if_ there is a neighbour attached to that corner.
if
(
min
(
x_positions
)
<
height_field
[
x
][
y
]
.
x
)
\
if
(
min
(
x_positions
)
<
height_field
[
x
][
y
]
[
0
]
)
\
or
(
max
(
x_positions
)
>
height_field
[
x
][
y
]
.
x
):
or
(
max
(
x_positions
)
>
height_field
[
x
][
y
]
[
0
]
):
x_value
=
(
min
(
x_positions
)
+
max
(
x_positions
))
/
2.0
x_value
=
(
min
(
x_positions
)
+
max
(
x_positions
))
/
2.0
else
:
else
:
# There is no adjacent box in x direction. Use the step size
# There is no adjacent box in x direction. Use the step size
# to calculate the x value of this edge.
# to calculate the x value of this edge.
x_value
=
height_field
[
x
][
y
]
.
x
\
x_value
=
height_field
[
x
][
y
]
[
0
]
\
+
offsets
[
0
]
*
self
.
x_step_width
/
2.0
+
offsets
[
0
]
*
self
.
x_step_width
/
2.0
# same as above for y instead of x
# same as above for y instead of x
if
(
min
(
y_positions
)
<
height_field
[
x
][
y
]
.
y
)
\
if
(
min
(
y_positions
)
<
height_field
[
x
][
y
]
[
1
]
)
\
or
(
max
(
y_positions
)
>
height_field
[
x
][
y
]
.
y
):
or
(
max
(
y_positions
)
>
height_field
[
x
][
y
]
[
1
]
):
y_value
=
(
min
(
y_positions
)
+
max
(
y_positions
))
/
2.0
y_value
=
(
min
(
y_positions
)
+
max
(
y_positions
))
/
2.0
else
:
else
:
y_value
=
height_field
[
x
][
y
]
.
y
\
y_value
=
height_field
[
x
][
y
]
[
1
]
\
+
offsets
[
1
]
*
self
.
y_step_width
/
2.0
+
offsets
[
1
]
*
self
.
y_step_width
/
2.0
# Create a Point instance describing the position and the
# Create a Point instance describing the position and the
# average height.
# average height.
points
.
append
(
Point
(
x_value
,
y_value
,
height_sum
/
divisor
))
points
.
append
((
x_value
,
y_value
,
height_sum
/
divisor
))
return
points
return
points
# draw the surface
# draw the surface
GL
.
glBegin
(
GL
.
GL_QUADS
)
GL
.
glBegin
(
GL
.
GL_QUADS
)
...
@@ -233,11 +233,11 @@ class ODEBlocks(object):
...
@@ -233,11 +233,11 @@ class ODEBlocks(object):
points_around
=
get_box_height_points
(
x
,
y
)
points_around
=
get_box_height_points
(
x
,
y
)
# Calculate the "normal" of polygon. We picked up three random
# Calculate the "normal" of polygon. We picked up three random
# points of this quadrilateral.
# points of this quadrilateral.
n
=
self
.
_normal
(
points_around
[
1
]
.
z
,
points_around
[
2
]
.
z
,
n
=
self
.
_normal
(
points_around
[
1
]
[
2
],
points_around
[
2
][
2
]
,
points_around
[
3
]
.
z
)
points_around
[
3
]
[
2
]
)
GL
.
glNormal3f
(
n
[
0
],
n
[
1
],
n
[
2
])
GL
.
glNormal3f
(
n
[
0
],
n
[
1
],
n
[
2
])
for
point
in
points_around
:
for
point
in
points_around
:
GL
.
glVertex3f
(
point
.
x
,
point
.
y
,
point
.
z
)
GL
.
glVertex3f
(
point
[
0
],
point
[
1
],
point
[
2
]
)
# go through the conditions for an edge box and use the
# go through the conditions for an edge box and use the
# appropriate corners for the side faces of the material
# appropriate corners for the side faces of the material
for
condition
,
i1
,
i2
in
((
x
==
0
,
3
,
0
),
(
y
==
0
,
0
,
1
),
for
condition
,
i1
,
i2
in
((
x
==
0
,
3
,
0
),
(
y
==
0
,
0
,
1
),
...
@@ -245,16 +245,16 @@ class ODEBlocks(object):
...
@@ -245,16 +245,16 @@ class ODEBlocks(object):
(
y
==
self
.
y_steps
-
1
,
2
,
3
)):
(
y
==
self
.
y_steps
-
1
,
2
,
3
)):
# check if this point belongs to an edge of the material
# check if this point belongs to an edge of the material
if
condition
:
if
condition
:
n
=
self
.
_normal
(
points_around
[
1
]
.
z
,
points_around
[
2
]
.
z
,
n
=
self
.
_normal
(
points_around
[
1
]
[
2
],
points_around
[
2
][
2
]
,
points_around
[
3
]
.
z
)
points_around
[
3
]
[
2
]
)
GL
.
glNormal3f
(
n
[
0
],
n
[
1
],
n
[
2
])
GL
.
glNormal3f
(
n
[
0
],
n
[
1
],
n
[
2
])
GL
.
glVertex3f
(
points_around
[
i1
]
.
x
,
points_around
[
i1
]
.
y
,
GL
.
glVertex3f
(
points_around
[
i1
]
[
0
],
points_around
[
i1
][
1
]
,
self
.
z_offset
)
self
.
z_offset
)
GL
.
glVertex3f
(
points_around
[
i1
]
.
x
,
points_around
[
i1
]
.
y
,
GL
.
glVertex3f
(
points_around
[
i1
]
[
0
],
points_around
[
i1
][
1
]
,
points_around
[
i1
]
.
z
)
points_around
[
i1
]
.
z
)
GL
.
glVertex3f
(
points_around
[
i2
]
.
x
,
points_around
[
i2
]
.
y
,
GL
.
glVertex3f
(
points_around
[
i2
]
[
0
],
points_around
[
i2
][
1
]
,
points_around
[
i2
]
.
z
)
points_around
[
i2
]
.
z
)
GL
.
glVertex3f
(
points_around
[
i2
]
.
x
,
points_around
[
i2
]
.
y
,
GL
.
glVertex3f
(
points_around
[
i2
]
[
0
],
points_around
[
i2
][
1
]
,
self
.
z_offset
)
self
.
z_offset
)
GL
.
glEnd
()
GL
.
glEnd
()
pycam/Simulation/ZBuffer.py
View file @
9b939792
...
@@ -21,7 +21,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -21,7 +21,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.utils
import
sqrt
from
pycam.Geometry.utils
import
sqrt
from
pycam.Geometry.Point
import
Point
from
pycam.Geometry.Point
Utils
import
*
import
ctypes
import
ctypes
import
math
import
math
...
@@ -128,12 +128,12 @@ class ZBuffer(object):
...
@@ -128,12 +128,12 @@ class ZBuffer(object):
py
=
self
.
y
[
y
]
py
=
self
.
y
[
y
]
for
x
in
range
(
minx
,
maxx
):
for
x
in
range
(
minx
,
maxx
):
px
=
self
.
x
[
x
]
px
=
self
.
x
[
x
]
v0x
=
t
.
p3
.
x
-
t
.
p1
.
x
v0x
=
t
.
p3
[
0
]
-
t
.
p1
[
0
]
v0y
=
t
.
p3
.
y
-
t
.
p1
.
y
v0y
=
t
.
p3
[
1
]
-
t
.
p1
[
1
]
v1x
=
t
.
p2
.
x
-
t
.
p1
.
x
v1x
=
t
.
p2
[
0
]
-
t
.
p1
[
0
]
v1y
=
t
.
p2
.
y
-
t
.
p1
.
y
v1y
=
t
.
p2
[
1
]
-
t
.
p1
[
1
]
v2x
=
px
-
t
.
p1
.
x
v2x
=
px
-
t
.
p1
[
0
]
v2y
=
py
-
t
.
p1
.
y
v2y
=
py
-
t
.
p1
[
1
]
dot00
=
v0x
*
v0x
+
v0y
*
v0y
dot00
=
v0x
*
v0x
+
v0y
*
v0y
dot01
=
v0x
*
v1x
+
v0y
*
v1y
dot01
=
v0x
*
v1x
+
v0y
*
v1y
dot02
=
v0x
*
v2x
+
v0y
*
v2y
dot02
=
v0x
*
v2x
+
v0y
*
v2y
...
@@ -143,9 +143,9 @@ class ZBuffer(object):
...
@@ -143,9 +143,9 @@ class ZBuffer(object):
u
=
(
dot11
*
dot02
-
dot01
*
dot12
)
*
invDenom
u
=
(
dot11
*
dot02
-
dot01
*
dot12
)
*
invDenom
v
=
(
dot00
*
dot12
-
dot01
*
dot02
)
*
invDenom
v
=
(
dot00
*
dot12
-
dot01
*
dot02
)
*
invDenom
if
(
u
>=
-
EPSILON
)
and
(
v
>=
-
EPSILON
)
and
(
u
+
v
<=
1
-
EPSILON
):
if
(
u
>=
-
EPSILON
)
and
(
v
>=
-
EPSILON
)
and
(
u
+
v
<=
1
-
EPSILON
):
v0z
=
t
.
p3
.
z
-
t
.
p1
.
z
v0z
=
t
.
p3
[
2
]
-
t
.
p1
[
2
]
v1z
=
t
.
p2
.
z
-
t
.
p1
.
z
v1z
=
t
.
p2
[
2
]
-
t
.
p1
[
2
]
pz
=
t
.
p1
.
z
+
v0z
*
u
+
v1z
*
v
pz
=
t
.
p1
[
2
]
+
v0z
*
u
+
v1z
*
v
if
pz
>
self
.
buf
[
y
][
x
]
.
z
:
if
pz
>
self
.
buf
[
y
][
x
]
.
z
:
self
.
buf
[
y
][
x
]
.
z
=
pz
self
.
buf
[
y
][
x
]
.
z
=
pz
self
.
buf
[
y
+
0
][
x
+
0
]
.
changed
=
True
self
.
buf
[
y
+
0
][
x
+
0
]
.
changed
=
True
...
@@ -155,8 +155,8 @@ class ZBuffer(object):
...
@@ -155,8 +155,8 @@ class ZBuffer(object):
self
.
changed
=
True
self
.
changed
=
True
def
add_cutter
(
self
,
c
):
def
add_cutter
(
self
,
c
):
cx
=
c
.
location
.
x
cx
=
c
.
location
[
0
]
cy
=
c
.
location
.
y
cy
=
c
.
location
[
1
]
rsq
=
c
.
radiussq
rsq
=
c
.
radiussq
minx
=
int
((
c
.
minx
-
self
.
minx
)
/
(
self
.
maxx
-
self
.
minx
)
*
self
.
xres
)
\
minx
=
int
((
c
.
minx
-
self
.
minx
)
/
(
self
.
maxx
-
self
.
minx
)
*
self
.
xres
)
\
-
1
-
1
...
@@ -182,13 +182,15 @@ class ZBuffer(object):
...
@@ -182,13 +182,15 @@ class ZBuffer(object):
maxy
=
self
.
yres
-
1
maxy
=
self
.
yres
-
1
if
miny
>
self
.
yres
-
1
:
if
miny
>
self
.
yres
-
1
:
miny
=
self
.
yres
-
1
miny
=
self
.
yres
-
1
p
=
Point
(
0
,
0
,
0
)
p
=
(
0
,
0
,
0
)
zaxis
=
Point
(
0
,
0
,
-
1
)
zaxis
=
(
0
,
0
,
-
1
)
for
y
in
range
(
miny
,
maxy
):
for
y
in
range
(
miny
,
maxy
):
p
.
y
=
py
=
self
.
y
[
y
]
py
=
self
.
y
[
y
]
p
=
(
p
[
0
],
py
,
p
[
2
])
for
x
in
range
(
minx
,
maxx
):
for
x
in
range
(
minx
,
maxx
):
p
.
x
=
px
=
self
.
x
[
x
]
px
=
self
.
x
[
x
]
p
=
(
px
,
p
[
1
],
p
[
2
])
if
(
px
-
cx
)
*
(
px
-
cx
)
+
(
py
-
cy
)
*
(
py
-
cy
)
\
if
(
px
-
cx
)
*
(
px
-
cx
)
+
(
py
-
cy
)
*
(
py
-
cy
)
\
<=
rsq
+
EPSILON
:
<=
rsq
+
EPSILON
:
(
cl
,
ccp
,
cp
,
l
)
=
c
.
intersect_point
(
zaxis
,
p
)
(
cl
,
ccp
,
cp
,
l
)
=
c
.
intersect_point
(
zaxis
,
p
)
...
...
pycam/Toolpath/Generator.py
View file @
9b939792
...
@@ -159,7 +159,7 @@ def generate_toolpath(model, tool_settings=None,
...
@@ -159,7 +159,7 @@ def generate_toolpath(model, tool_settings=None,
warning
=
"The contour model contains colliding line groups. "
+
\
warning
=
"The contour model contains colliding line groups. "
+
\
"This can cause problems with an engraving offset.
\n
"
+
\
"This can cause problems with an engraving offset.
\n
"
+
\
"A collision was detected at (
%.2
f,
%.2
f,
%.2
f)."
%
\
"A collision was detected at (
%.2
f,
%.2
f,
%.2
f)."
%
\
(
result
.
x
,
result
.
y
,
result
.
z
)
(
result
[
0
],
result
[
1
],
result
[
2
]
)
log
.
warning
(
warning
)
log
.
warning
(
warning
)
else
:
else
:
# no collisions and no user interruption
# no collisions and no user interruption
...
...
pycam/Toolpath/MotionGrid.py
View file @
9b939792
...
@@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License
...
@@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.utils
import
epsilon
from
pycam.Geometry.utils
import
epsilon
from
pycam.Geometry.Polygon
import
PolygonSorter
from
pycam.Geometry.Polygon
import
PolygonSorter
...
@@ -91,9 +91,9 @@ def get_fixed_grid_line(start, end, line_pos, z, step_width=None,
...
@@ -91,9 +91,9 @@ def get_fixed_grid_line(start, end, line_pos, z, step_width=None,
else
:
else
:
steps
=
floatrange
(
start
,
end
,
inc
=
step_width
)
steps
=
floatrange
(
start
,
end
,
inc
=
step_width
)
if
grid_direction
==
GRID_DIRECTION_X
:
if
grid_direction
==
GRID_DIRECTION_X
:
get_point
=
lambda
pos
:
Point
(
pos
,
line_pos
,
z
)
get_point
=
lambda
pos
:
(
pos
,
line_pos
,
z
)
else
:
else
:
get_point
=
lambda
pos
:
Point
(
line_pos
,
pos
,
z
)
get_point
=
lambda
pos
:
(
line_pos
,
pos
,
z
)
for
pos
in
steps
:
for
pos
in
steps
:
yield
get_point
(
pos
)
yield
get_point
(
pos
)
...
@@ -208,7 +208,7 @@ def _get_position(minx, maxx, miny, maxy, z, position):
...
@@ -208,7 +208,7 @@ def _get_position(minx, maxx, miny, maxy, z, position):
y
=
miny
y
=
miny
else
:
else
:
y
=
maxy
y
=
maxy
return
Point
(
x
,
y
,
z
)
return
(
x
,
y
,
z
)
def
get_spiral_layer_lines
(
minx
,
maxx
,
miny
,
maxy
,
z
,
line_distance_x
,
def
get_spiral_layer_lines
(
minx
,
maxx
,
miny
,
maxy
,
z
,
line_distance_x
,
line_distance_y
,
grid_direction
,
start_position
,
current_location
):
line_distance_y
,
grid_direction
,
start_position
,
current_location
):
...
@@ -255,27 +255,29 @@ def get_spiral_layer(minx, maxx, miny, maxy, z, line_distance, step_width,
...
@@ -255,27 +255,29 @@ def get_spiral_layer(minx, maxx, miny, maxy, z, line_distance, step_width,
previous
=
None
previous
=
None
for
index
,
(
start
,
end
)
in
enumerate
(
lines
):
for
index
,
(
start
,
end
)
in
enumerate
(
lines
):
radius
=
0.5
*
min
(
line_distance_x
,
line_distance_y
)
radius
=
0.5
*
min
(
line_distance_x
,
line_distance_y
)
edge_vector
=
end
.
sub
(
start
)
edge_vector
=
psub
(
end
,
start
)
#edge_vector = end.sub(start)
# TODO: ellipse would be better than arc
# TODO: ellipse would be better than arc
offset
=
edge_vector
.
normalized
()
.
mul
(
radius
)
offset
=
pmul
(
pnormalized
(
edge_vector
),
radius
)
#offset = edge_vector.normalized().mul(radius)
if
previous
:
if
previous
:
start
=
start
.
add
(
offset
)
start
=
padd
(
start
,
offset
)
center
=
p
revious
.
add
(
offset
)
center
=
p
add
(
previous
,
offset
)
up_vector
=
p
revious
.
sub
(
center
)
.
cross
(
start
.
sub
(
center
))
.
normalized
(
)
up_vector
=
p
normalized
(
pcross
(
psub
(
previous
,
center
),
psub
(
start
,
center
))
)
north
=
center
.
add
(
Vector
(
1.0
,
0.0
,
0.0
))
north
=
padd
(
center
,
(
1.0
,
0.0
,
0.0
,
'v'
))
angle_start
=
pycam
.
Geometry
.
get_angle_pi
(
north
,
center
,
previous
,
up_vector
,
pi_factor
=
True
)
*
180.0
angle_start
=
pycam
.
Geometry
.
get_angle_pi
(
north
,
center
,
previous
,
up_vector
,
pi_factor
=
True
)
*
180.0
angle_end
=
pycam
.
Geometry
.
get_angle_pi
(
north
,
center
,
start
,
up_vector
,
pi_factor
=
True
)
*
180.0
angle_end
=
pycam
.
Geometry
.
get_angle_pi
(
north
,
center
,
start
,
up_vector
,
pi_factor
=
True
)
*
180.0
# TODO: remove these exceptions based on up_vector.z (get_points_of_arc does not respect the plane, yet)
# TODO: remove these exceptions based on up_vector.z (get_points_of_arc does not respect the plane, yet)
if
up_vector
.
z
<
0
:
if
up_vector
[
2
]
<
0
:
angle_start
,
angle_end
=
-
angle_end
,
-
angle_start
angle_start
,
angle_end
=
-
angle_end
,
-
angle_start
arc_points
=
pycam
.
Geometry
.
get_points_of_arc
(
center
,
radius
,
angle_start
,
angle_end
)
arc_points
=
pycam
.
Geometry
.
get_points_of_arc
(
center
,
radius
,
angle_start
,
angle_end
)
if
up_vector
.
z
<
0
:
if
up_vector
[
2
]
<
0
:
arc_points
.
reverse
()
arc_points
.
reverse
()
for
arc_index
in
range
(
len
(
arc_points
)
-
1
):
for
arc_index
in
range
(
len
(
arc_points
)
-
1
):
p1_coord
=
arc_points
[
arc_index
]
p1_coord
=
arc_points
[
arc_index
]
p2_coord
=
arc_points
[
arc_index
+
1
]
p2_coord
=
arc_points
[
arc_index
+
1
]
p1
=
Point
(
p1_coord
[
0
],
p1_coord
[
1
],
z
)
p1
=
(
p1_coord
[
0
],
p1_coord
[
1
],
z
)
p2
=
Point
(
p2_coord
[
0
],
p2_coord
[
1
],
z
)
p2
=
(
p2_coord
[
0
],
p2_coord
[
1
],
z
)
rounded_lines
.
append
((
p1
,
p2
))
rounded_lines
.
append
((
p1
,
p2
))
if
index
!=
len
(
lines
)
-
1
:
if
index
!=
len
(
lines
)
-
1
:
end
=
end
.
sub
(
offset
)
end
=
end
.
sub
(
offset
)
...
@@ -294,7 +296,7 @@ def get_spiral_layer(minx, maxx, miny, maxy, z, line_distance, step_width,
...
@@ -294,7 +296,7 @@ def get_spiral_layer(minx, maxx, miny, maxy, z, line_distance, step_width,
else
:
else
:
steps
=
floatrange
(
0.0
,
line
.
len
,
inc
=
step_width
)
steps
=
floatrange
(
0.0
,
line
.
len
,
inc
=
step_width
)
for
step
in
steps
:
for
step
in
steps
:
next_point
=
line
.
p1
.
add
(
line
.
dir
.
mul
(
step
))
next_point
=
padd
(
line
.
p1
,
pmul
(
line
.
dir
,
step
))
points
.
append
(
next_point
)
points
.
append
(
next_point
)
if
reverse
:
if
reverse
:
points
.
reverse
()
points
.
reverse
()
...
@@ -328,7 +330,7 @@ def get_spiral((low, high), layer_distance, line_distance=None,
...
@@ -328,7 +330,7 @@ def get_spiral((low, high), layer_distance, line_distance=None,
def
get_lines_layer
(
lines
,
z
,
last_z
=
None
,
step_width
=
None
,
def
get_lines_layer
(
lines
,
z
,
last_z
=
None
,
step_width
=
None
,
milling_style
=
MILLING_STYLE_CONVENTIONAL
):
milling_style
=
MILLING_STYLE_CONVENTIONAL
):
get_proj_point
=
lambda
proj_point
:
Point
(
proj_point
.
x
,
proj_point
.
y
,
z
)
get_proj_point
=
lambda
proj_point
:
(
proj_point
[
0
],
proj_point
[
1
]
,
z
)
projected_lines
=
[]
projected_lines
=
[]
for
line
in
lines
:
for
line
in
lines
:
if
(
not
last_z
is
None
)
and
(
last_z
<
line
.
minz
):
if
(
not
last_z
is
None
)
and
(
last_z
<
line
.
minz
):
...
@@ -337,9 +339,9 @@ def get_lines_layer(lines, z, last_z=None, step_width=None,
...
@@ -337,9 +339,9 @@ def get_lines_layer(lines, z, last_z=None, step_width=None,
elif
line
.
minz
<
z
<
line
.
maxz
:
elif
line
.
minz
<
z
<
line
.
maxz
:
# Split the line at the point at z level and do the calculation
# Split the line at the point at z level and do the calculation
# for both point pairs.
# for both point pairs.
factor
=
(
z
-
line
.
p1
.
z
)
/
(
line
.
p2
.
z
-
line
.
p1
.
z
)
factor
=
(
z
-
line
.
p1
[
2
])
/
(
line
.
p2
[
2
]
-
line
.
p1
[
2
]
)
plane_point
=
line
.
p1
.
add
(
line
.
vector
.
mul
(
factor
))
plane_point
=
padd
(
line
.
p1
,
pmul
(
line
.
vector
,
factor
))
if
line
.
p1
.
z
<
z
:
if
line
.
p1
[
2
]
<
z
:
p1
=
get_proj_point
(
line
.
p1
)
p1
=
get_proj_point
(
line
.
p1
)
p2
=
line
.
p2
p2
=
line
.
p2
else
:
else
:
...
@@ -348,10 +350,10 @@ def get_lines_layer(lines, z, last_z=None, step_width=None,
...
@@ -348,10 +350,10 @@ def get_lines_layer(lines, z, last_z=None, step_width=None,
projected_lines
.
append
(
Line
(
p1
,
plane_point
))
projected_lines
.
append
(
Line
(
p1
,
plane_point
))
yield
Line
(
plane_point
,
p2
)
yield
Line
(
plane_point
,
p2
)
elif
line
.
minz
<
last_z
<
line
.
maxz
:
elif
line
.
minz
<
last_z
<
line
.
maxz
:
plane
=
Plane
(
Point
(
0
,
0
,
last_z
),
Vector
(
0
,
0
,
1
))
plane
=
Plane
(
(
0
,
0
,
last_z
),
(
0
,
0
,
1
,
'v'
))
cp
=
plane
.
intersect_point
(
line
.
dir
,
line
.
p1
)[
0
]
cp
=
plane
.
intersect_point
(
line
.
dir
,
line
.
p1
)[
0
]
# we can be sure that there is an intersection
# we can be sure that there is an intersection
if
line
.
p1
.
z
>
last_z
:
if
line
.
p1
[
2
]
>
last_z
:
p1
,
p2
=
cp
,
line
.
p2
p1
,
p2
=
cp
,
line
.
p2
else
:
else
:
p1
,
p2
=
line
.
p1
,
cp
p1
,
p2
=
line
.
p1
,
cp
...
@@ -378,7 +380,7 @@ def get_lines_layer(lines, z, last_z=None, step_width=None,
...
@@ -378,7 +380,7 @@ def get_lines_layer(lines, z, last_z=None, step_width=None,
else
:
else
:
steps
=
floatrange
(
0.0
,
line
.
len
,
inc
=
step_width
)
steps
=
floatrange
(
0.0
,
line
.
len
,
inc
=
step_width
)
for
step
in
steps
:
for
step
in
steps
:
next_point
=
line
.
p1
.
add
(
line
.
dir
.
mul
(
step
))
next_point
=
padd
(
line
.
p1
,
pmul
(
line
.
dir
,
step
))
points
.
append
(
next_point
)
points
.
append
(
next_point
)
yield
points
yield
points
...
...
pycam/Toolpath/SupportGrid.py
View file @
9b939792
...
@@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License
...
@@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
"""
from
pycam.Geometry.Point
import
Point
,
Vector
from
pycam.Geometry.Point
Utils
import
*
from
pycam.Geometry.Triangle
import
Triangle
from
pycam.Geometry.Triangle
import
Triangle
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Plane
import
Plane
from
pycam.Geometry.Model
import
Model
from
pycam.Geometry.Model
import
Model
...
@@ -34,16 +34,16 @@ def _get_triangles_for_face(pts):
...
@@ -34,16 +34,16 @@ def _get_triangles_for_face(pts):
return
(
t1
,
t2
)
return
(
t1
,
t2
)
def
_add_cuboid_to_model
(
model
,
start
,
direction
,
height
,
width
):
def
_add_cuboid_to_model
(
model
,
start
,
direction
,
height
,
width
):
up
=
Vector
(
0
,
0
,
1
)
.
mul
(
height
)
up
=
pmul
((
0
,
0
,
1
,
'v'
),
height
)
ortho_dir
=
direction
.
cross
(
up
)
.
normalized
(
)
ortho_dir
=
pnormalized
(
pcross
(
direction
,
up
)
)
start1
=
start
.
add
(
ortho_dir
.
mul
(
-
width
/
2
))
start1
=
padd
(
start
,
pmul
(
ortho_dir
,
-
width
/
2
))
start2
=
start1
.
add
(
up
)
start2
=
padd
(
start1
,
up
)
start3
=
start2
.
add
(
ortho_dir
.
mul
(
width
))
start3
=
padd
(
start2
,
pmul
(
ortho_dir
,
width
))
start4
=
start3
.
sub
(
up
)
start4
=
psub
(
start3
,
up
)
end1
=
start1
.
add
(
direction
)
end1
=
padd
(
start1
,
direction
)
end2
=
start2
.
add
(
direction
)
end2
=
padd
(
start2
,
direction
)
end3
=
start3
.
add
(
direction
)
end3
=
padd
(
start3
,
direction
)
end4
=
start4
.
add
(
direction
)
end4
=
padd
(
start4
,
direction
)
faces
=
((
start1
,
start2
,
start3
,
start4
),
(
start1
,
end1
,
end2
,
start2
),
faces
=
((
start1
,
start2
,
start3
,
start4
),
(
start1
,
end1
,
end2
,
start2
),
(
start2
,
end2
,
end3
,
start3
),
(
start3
,
end3
,
end4
,
start4
),
(
start2
,
end2
,
end3
,
start3
),
(
start3
,
end3
,
end4
,
start4
),
(
start4
,
end4
,
end1
,
start1
),
(
end4
,
end3
,
end2
,
end1
))
(
start4
,
end4
,
end1
,
start1
),
(
end4
,
end3
,
end2
,
end1
))
...
@@ -54,14 +54,14 @@ def _add_cuboid_to_model(model, start, direction, height, width):
...
@@ -54,14 +54,14 @@ def _add_cuboid_to_model(model, start, direction, height, width):
def
_add_aligned_cuboid_to_model
(
minx
,
maxx
,
miny
,
maxy
,
minz
,
maxz
):
def
_add_aligned_cuboid_to_model
(
minx
,
maxx
,
miny
,
maxy
,
minz
,
maxz
):
points
=
(
points
=
(
Point
(
minx
,
miny
,
minz
),
(
minx
,
miny
,
minz
),
Point
(
maxx
,
miny
,
minz
),
(
maxx
,
miny
,
minz
),
Point
(
maxx
,
maxy
,
minz
),
(
maxx
,
maxy
,
minz
),
Point
(
minx
,
maxy
,
minz
),
(
minx
,
maxy
,
minz
),
Point
(
minx
,
miny
,
maxz
),
(
minx
,
miny
,
maxz
),
Point
(
maxx
,
miny
,
maxz
),
(
maxx
,
miny
,
maxz
),
Point
(
maxx
,
maxy
,
maxz
),
(
maxx
,
maxy
,
maxz
),
Point
(
minx
,
maxy
,
maxz
))
(
minx
,
maxy
,
maxz
))
triangles
=
[]
triangles
=
[]
# lower face
# lower face
triangles
.
extend
(
_get_triangles_for_face
(
triangles
.
extend
(
_get_triangles_for_face
(
...
@@ -159,10 +159,10 @@ def get_support_distributed(model, z_plane, average_distance,
...
@@ -159,10 +159,10 @@ def get_support_distributed(model, z_plane, average_distance,
result
=
Model
()
result
=
Model
()
if
not
hasattr
(
model
,
"get_polygons"
):
if
not
hasattr
(
model
,
"get_polygons"
):
model
=
model
.
get_waterline_contour
(
model
=
model
.
get_waterline_contour
(
Plane
(
Point
(
0
,
0
,
max
(
model
.
minz
,
z_plane
)),
Vector
(
0
,
0
,
1
)))
Plane
(
(
0
,
0
,
max
(
model
.
minz
,
z_plane
)),
(
0
,
0
,
1
,
'v'
)))
if
model
:
if
model
:
model
=
model
.
get_flat_projection
(
Plane
(
Point
(
0
,
0
,
z_plane
),
model
=
model
.
get_flat_projection
(
Plane
((
0
,
0
,
z_plane
),
Vector
(
0
,
0
,
1
)))
(
0
,
0
,
1
,
'v'
)))
if
model
and
bounds
:
if
model
and
bounds
:
model
=
model
.
get_cropped_model_by_bounds
(
bounds
)
model
=
model
.
get_cropped_model_by_bounds
(
bounds
)
if
model
:
if
model
:
...
@@ -184,24 +184,21 @@ def get_support_distributed(model, z_plane, average_distance,
...
@@ -184,24 +184,21 @@ def get_support_distributed(model, z_plane, average_distance,
bridges
=
bridge_calculator
(
polygon
,
z_plane
,
min_bridges_per_polygon
,
bridges
=
bridge_calculator
(
polygon
,
z_plane
,
min_bridges_per_polygon
,
average_distance
,
avoid_distance
)
average_distance
,
avoid_distance
)
for
pos
,
direction
in
bridges
:
for
pos
,
direction
in
bridges
:
_add_cuboid_to_model
(
result
,
pos
,
direction
.
mul
(
length
),
height
,
_add_cuboid_to_model
(
result
,
pos
,
pmul
(
direction
,
length
),
height
,
thickness
)
thickness
)
return
result
return
result
class
_BridgeCorner
(
object
):
class
_BridgeCorner
(
object
):
# currently we only use the xy plane
# currently we only use the xy plane
up_vector
=
Vector
(
0
,
0
,
1
)
up_vector
=
(
0
,
0
,
1
,
'v'
)
def
__init__
(
self
,
barycenter
,
location
,
p1
,
p2
,
p3
):
def
__init__
(
self
,
barycenter
,
location
,
p1
,
p2
,
p3
):
self
.
location
=
location
self
.
location
=
location
self
.
position
=
p2
self
.
position
=
p2
self
.
direction
=
pycam
.
Geometry
.
get_bisector
(
p1
,
p2
,
p3
,
self
.
direction
=
pnormalized
(
pycam
.
Geometry
.
get_bisector
(
p1
,
p2
,
p3
,
self
.
up_vector
))
self
.
up_vector
)
.
normalized
()
preferred_direction
=
pnormalized
(
psub
(
p2
,
barycenter
))
preferred_direction
=
p2
.
sub
(
barycenter
)
.
normalized
()
# direction_factor: 0..1 (bigger -> better)
# direction_factor: 0..1 (bigger -> better)
direction_factor
=
(
preferred_direction
.
dot
(
self
.
direction
)
+
1
)
/
2
direction_factor
=
(
pdot
(
preferred_direction
,
self
.
direction
)
+
1
)
/
2
angle
=
pycam
.
Geometry
.
get_angle_pi
(
p1
,
p2
,
p3
,
angle
=
pycam
.
Geometry
.
get_angle_pi
(
p1
,
p2
,
p3
,
self
.
up_vector
,
pi_factor
=
True
)
self
.
up_vector
,
pi_factor
=
True
)
# angle_factor: 0..1 (bigger -> better)
# angle_factor: 0..1 (bigger -> better)
if
angle
>
0.5
:
if
angle
>
0.5
:
# use only angles > 90 degree
# use only angles > 90 degree
...
@@ -275,7 +272,7 @@ def _get_edge_bridges(polygon, z_plane, min_bridges, average_distance,
...
@@ -275,7 +272,7 @@ def _get_edge_bridges(polygon, z_plane, min_bridges, average_distance,
avoid_distance
):
avoid_distance
):
def
is_near_list
(
point_list
,
point
,
distance
):
def
is_near_list
(
point_list
,
point
,
distance
):
for
p
in
point_list
:
for
p
in
point_list
:
if
p
.
sub
(
point
)
.
norm
<=
distance
:
if
p
norm
(
psub
(
p
,
point
))
<=
distance
:
return
True
return
True
return
False
return
False
lines
=
polygon
.
get_lines
()
lines
=
polygon
.
get_lines
()
...
@@ -308,8 +305,8 @@ def _get_edge_bridges(polygon, z_plane, min_bridges, average_distance,
...
@@ -308,8 +305,8 @@ def _get_edge_bridges(polygon, z_plane, min_bridges, average_distance,
if
is_near_list
(
bridge_positions
,
position
,
avoid_distance
):
if
is_near_list
(
bridge_positions
,
position
,
avoid_distance
):
line
=
polygon
.
get_lines
()[
line_index
]
line
=
polygon
.
get_lines
()[
line_index
]
# calculate two alternative points on the same line
# calculate two alternative points on the same line
position1
=
p
osition
.
add
(
line
.
p1
)
.
div
(
2
)
position1
=
p
div
(
padd
(
position
,
line
.
p1
),
2
)
position2
=
p
osition
.
add
(
line
.
p2
)
.
div
(
2
)
position2
=
p
div
(
padd
(
position
,
line
.
p2
),
2
)
if
is_near_list
(
bridge_positions
,
position1
,
avoid_distance
):
if
is_near_list
(
bridge_positions
,
position1
,
avoid_distance
):
if
is_near_list
(
bridge_positions
,
position2
,
if
is_near_list
(
bridge_positions
,
position2
,
avoid_distance
):
avoid_distance
):
...
@@ -324,9 +321,8 @@ def _get_edge_bridges(polygon, z_plane, min_bridges, average_distance,
...
@@ -324,9 +321,8 @@ def _get_edge_bridges(polygon, z_plane, min_bridges, average_distance,
# append the original position (ignoring z_plane)
# append the original position (ignoring z_plane)
bridge_positions
.
append
(
position
)
bridge_positions
.
append
(
position
)
# move the point to z_plane
# move the point to z_plane
position
=
Point
(
position
.
x
,
position
.
y
,
z_plane
)
position
=
(
position
[
0
],
position
[
1
],
z_plane
)
bridge_dir
=
lines
[
line_index
]
.
dir
.
cross
(
bridge_dir
=
pnormalized
(
pcross
(
lines
[
line_index
]
.
dir
,
polygon
.
plane
.
n
))
polygon
.
plane
.
n
)
.
normalized
()
result
.
append
((
position
,
bridge_dir
))
result
.
append
((
position
,
bridge_dir
))
return
result
return
result
pycam/Toolpath/__init__.py
View file @
9b939792
...
@@ -22,20 +22,23 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
...
@@ -22,20 +22,23 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
__all__
=
[
"simplify_toolpath"
,
"ToolpathList"
,
"Toolpath"
,
"Generator"
]
__all__
=
[
"simplify_toolpath"
,
"ToolpathList"
,
"Toolpath"
,
"Generator"
]
from
pycam.Geometry.Point
import
Point
import
OpenGL.GL
as
GL
from
OpenGL.arrays
import
vbo
import
numpy
from
numpy
import
array
from
pycam.Geometry.PointUtils
import
*
from
pycam.Geometry.Path
import
Path
from
pycam.Geometry.Path
import
Path
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.Line
import
Line
from
pycam.Geometry.utils
import
number
,
epsilon
from
pycam.Geometry.utils
import
number
,
epsilon
import
pycam.Utils.log
import
random
import
random
import
os
import
os
import
math
log
=
pycam
.
Utils
.
log
.
get_logger
()
from
itertools
import
groupby
def
_check_colinearity
(
p1
,
p2
,
p3
):
def
_check_colinearity
(
p1
,
p2
,
p3
):
v1
=
p
2
.
sub
(
p1
)
.
normalized
(
)
v1
=
p
normalized
(
psub
(
p2
,
p1
)
)
v2
=
p
3
.
sub
(
p2
)
.
normalized
(
)
v2
=
p
normalized
(
psub
(
p3
,
p2
)
)
# compare if the normalized distances between p1-p2 and p2-p3 are equal
# compare if the normalized distances between p1-p2 and p2-p3 are equal
return
v1
==
v2
return
v1
==
v2
...
@@ -69,6 +72,22 @@ class Toolpath(object):
...
@@ -69,6 +72,22 @@ class Toolpath(object):
self
.
parameters
=
parameters
self
.
parameters
=
parameters
self
.
_max_safe_distance
=
2
*
parameters
.
get
(
"tool_radius"
,
0
)
self
.
_max_safe_distance
=
2
*
parameters
.
get
(
"tool_radius"
,
0
)
self
.
_feedrate
=
parameters
.
get
(
"tool_feedrate"
,
300
)
self
.
_feedrate
=
parameters
.
get
(
"tool_feedrate"
,
300
)
self
.
opengl_safety_height
=
None
self
.
_minx
=
None
self
.
_maxx
=
None
self
.
_miny
=
None
self
.
_maxy
=
None
self
.
_minz
=
None
self
.
_maxz
=
None
def
clear_cache
(
self
):
self
.
opengl_safety_height
=
None
self
.
_minx
=
None
self
.
_maxx
=
None
self
.
_miny
=
None
self
.
_maxy
=
None
self
.
_minz
=
None
self
.
_maxz
=
None
def
get_params
(
self
):
def
get_params
(
self
):
return
dict
(
self
.
parameters
)
return
dict
(
self
.
parameters
)
...
@@ -82,36 +101,48 @@ class Toolpath(object):
...
@@ -82,36 +101,48 @@ class Toolpath(object):
new_paths
.
append
(
new_path
)
new_paths
.
append
(
new_path
)
return
Toolpath
(
new_paths
,
parameters
=
self
.
get_params
())
return
Toolpath
(
new_paths
,
parameters
=
self
.
get_params
())
def
_get_limit_generic
(
self
,
attr
,
func
):
def
_get_limit_generic
(
self
,
idx
,
func
):
path_min
=
[]
path_min
=
[]
for
path
in
self
.
paths
:
for
path
in
self
.
paths
:
if
path
.
points
:
if
path
.
points
:
path_min
.
append
(
func
([
getattr
(
p
,
attr
)
for
p
in
path
.
points
]))
path_min
.
append
(
func
([
p
[
idx
]
for
p
in
path
.
points
]))
return
func
(
path_min
)
return
func
(
path_min
)
@
property
@
property
def
minx
(
self
):
def
minx
(
self
):
return
self
.
_get_limit_generic
(
"x"
,
min
)
if
self
.
_minx
==
None
:
self
.
_minx
=
self
.
_get_limit_generic
(
0
,
min
)
return
self
.
_minx
@
property
@
property
def
maxx
(
self
):
def
maxx
(
self
):
return
self
.
_get_limit_generic
(
"x"
,
max
)
if
self
.
_maxx
==
None
:
self
.
_maxx
=
self
.
_get_limit_generic
(
0
,
max
)
return
self
.
_maxx
@
property
@
property
def
miny
(
self
):
def
miny
(
self
):
return
self
.
_get_limit_generic
(
"y"
,
min
)
if
self
.
_miny
==
None
:
self
.
_miny
=
self
.
_get_limit_generic
(
1
,
min
)
return
self
.
_miny
@
property
@
property
def
maxy
(
self
):
def
maxy
(
self
):
return
self
.
_get_limit_generic
(
"y"
,
max
)
if
self
.
_maxy
==
None
:
self
.
_maxy
=
self
.
_get_limit_generic
(
1
,
max
)
return
self
.
_maxy
@
property
@
property
def
minz
(
self
):
def
minz
(
self
):
return
self
.
_get_limit_generic
(
"z"
,
min
)
if
self
.
_minz
==
None
:
self
.
_minz
=
self
.
_get_limit_generic
(
2
,
min
)
return
self
.
_minz
@
property
@
property
def
maxz
(
self
):
def
maxz
(
self
):
return
self
.
_get_limit_generic
(
"z"
,
max
)
if
self
.
_maxz
==
None
:
self
.
_maxz
=
self
.
_get_limit_generic
(
2
,
max
)
return
self
.
_maxz
def
get_meta_data
(
self
):
def
get_meta_data
(
self
):
meta
=
self
.
toolpath_settings
.
get_string
()
meta
=
self
.
toolpath_settings
.
get_string
()
...
@@ -137,12 +168,11 @@ class Toolpath(object):
...
@@ -137,12 +168,11 @@ class Toolpath(object):
self
.
last_pos
=
new_position
self
.
last_pos
=
new_position
return
True
return
True
else
:
else
:
distance
=
new_position
.
sub
(
self
.
last_pos
)
.
norm
distance
=
pnorm
(
psub
(
new_position
,
self
.
last_pos
))
if
self
.
moved_distance
+
distance
>
self
.
max_movement
:
if
self
.
moved_distance
+
distance
>
self
.
max_movement
:
partial
=
(
self
.
max_movement
-
self
.
moved_distance
)
/
\
partial
=
(
self
.
max_movement
-
self
.
moved_distance
)
/
\
distance
distance
partial_dest
=
self
.
last_pos
.
add
(
new_position
.
sub
(
partial_dest
=
padd
(
self
.
last_pos
,
pmul
(
psub
(
new_position
,
self
.
last_pos
),
partial
))
self
.
last_pos
)
.
mul
(
partial
))
self
.
moves
.
append
((
partial_dest
,
rapid
))
self
.
moves
.
append
((
partial_dest
,
rapid
))
self
.
last_pos
=
partial_dest
self
.
last_pos
=
partial_dest
# we are finished
# we are finished
...
@@ -163,21 +193,18 @@ class Toolpath(object):
...
@@ -163,21 +193,18 @@ class Toolpath(object):
continue
continue
p_next
=
path
.
points
[
0
]
p_next
=
path
.
points
[
0
]
if
p_last
is
None
:
if
p_last
is
None
:
p_last
=
Point
(
p_next
.
x
,
p_next
.
y
,
safety_height
)
p_last
=
(
p_next
[
0
],
p_next
[
1
]
,
safety_height
)
if
not
result
.
append
(
p_last
,
True
):
if
not
result
.
append
(
p_last
,
True
):
return
result
.
moves
return
result
.
moves
if
((
abs
(
p_last
.
x
-
p_next
.
x
)
>
epsilon
)
\
if
((
abs
(
p_last
[
0
]
-
p_next
[
0
])
>
epsilon
)
or
(
abs
(
p_last
[
1
]
-
p_next
[
1
])
>
epsilon
)):
or
(
abs
(
p_last
.
y
-
p_next
.
y
)
>
epsilon
)):
# Draw the connection between the last and the next path.
# Draw the connection between the last and the next path.
# Respect the safety height.
# Respect the safety height.
if
(
abs
(
p_last
.
z
-
p_next
.
z
)
>
epsilon
)
\
if
(
abs
(
p_last
[
2
]
-
p_next
[
2
])
>
epsilon
)
or
(
pnorm
(
psub
(
p_last
,
p_next
))
>
self
.
_max_safe_distance
+
epsilon
):
or
(
p_last
.
sub
(
p_next
)
.
norm
>
\
self
.
_max_safe_distance
+
epsilon
):
# The distance between these two points is too far.
# The distance between these two points is too far.
# This condition helps to prevent moves up/down for
# This condition helps to prevent moves up/down for
# adjacent lines.
# adjacent lines.
safety_last
=
Point
(
p_last
.
x
,
p_last
.
y
,
safety_height
)
safety_last
=
(
p_last
[
0
],
p_last
[
1
]
,
safety_height
)
safety_next
=
Point
(
p_next
.
x
,
p_next
.
y
,
safety_height
)
safety_next
=
(
p_next
[
0
],
p_next
[
1
]
,
safety_height
)
if
not
result
.
append
(
safety_last
,
True
):
if
not
result
.
append
(
safety_last
,
True
):
return
result
.
moves
return
result
.
moves
if
not
result
.
append
(
safety_next
,
True
):
if
not
result
.
append
(
safety_next
,
True
):
...
@@ -187,10 +214,128 @@ class Toolpath(object):
...
@@ -187,10 +214,128 @@ class Toolpath(object):
return
result
.
moves
return
result
.
moves
p_last
=
path
.
points
[
-
1
]
p_last
=
path
.
points
[
-
1
]
if
not
p_last
is
None
:
if
not
p_last
is
None
:
p_last_safety
=
Point
(
p_last
.
x
,
p_last
.
y
,
safety_height
)
p_last_safety
=
(
p_last
[
0
],
p_last
[
1
]
,
safety_height
)
result
.
append
(
p_last_safety
,
True
)
result
.
append
(
p_last_safety
,
True
)
return
result
.
moves
return
result
.
moves
def
_rotate_point
(
self
,
rp
,
sp
,
v
,
angle
):
vx
=
v
[
0
]
vy
=
v
[
1
]
vz
=
v
[
2
]
x
=
(
sp
[
0
]
*
(
vy
**
2
+
vz
**
2
)
-
vx
*
(
sp
[
1
]
*
vy
+
sp
[
2
]
*
vz
-
vx
*
rp
[
0
]
-
vy
*
rp
[
1
]
-
vz
*
rp
[
2
]))
*
(
1
-
math
.
cos
(
angle
))
+
rp
[
0
]
*
math
.
cos
(
angle
)
+
(
-
sp
[
2
]
*
vy
+
sp
[
1
]
*
vz
-
vz
*
rp
[
1
]
+
vy
*
rp
[
2
])
*
math
.
sin
(
angle
)
y
=
(
sp
[
1
]
*
(
vx
**
2
+
vz
**
2
)
-
vy
*
(
sp
[
0
]
*
vx
+
sp
[
2
]
*
vz
-
vx
*
rp
[
0
]
-
vy
*
rp
[
1
]
-
vz
*
rp
[
2
]))
*
(
1
-
math
.
cos
(
angle
))
+
rp
[
1
]
*
math
.
cos
(
angle
)
+
(
sp
[
2
]
*
vx
-
sp
[
0
]
*
vz
+
vz
*
rp
[
0
]
-
vx
*
rp
[
2
])
*
math
.
sin
(
angle
)
z
=
(
sp
[
2
]
*
(
vx
**
2
+
vy
**
2
)
-
vz
*
(
sp
[
0
]
*
vx
+
sp
[
1
]
*
vy
-
vx
*
rp
[
0
]
-
vy
*
rp
[
1
]
-
vz
*
rp
[
2
]))
*
(
1
-
math
.
cos
(
angle
))
+
rp
[
2
]
*
math
.
cos
(
angle
)
+
(
-
sp
[
1
]
*
vx
+
sp
[
0
]
*
vy
-
vy
*
rp
[
0
]
+
vx
*
rp
[
1
])
*
math
.
sin
(
angle
)
return
(
x
,
y
,
z
)
def
draw_direction_cone_mesh
(
self
,
p1
,
p2
,
position
=
0.5
,
precision
=
12
,
size
=
0.1
):
distance
=
psub
(
p2
,
p1
)
length
=
pnorm
(
distance
)
direction
=
pnormalized
(
distance
)
if
direction
is
None
or
length
<
0.5
:
# zero-length line
return
[]
cone_length
=
length
*
size
cone_radius
=
cone_length
/
3.0
bottom
=
padd
(
p1
,
pmul
(
psub
(
p2
,
p1
),
position
-
size
/
2
))
top
=
padd
(
p1
,
pmul
(
psub
(
p2
,
p1
),
position
+
size
/
2
))
#generate a a line perpendicular to this line, cross product is good at this
cross
=
pcross
(
direction
,
(
0
,
0
,
-
1
))
conepoints
=
[]
if
pnorm
(
cross
)
!=
0
:
# The line direction is not in line with the z axis.
conep1
=
padd
(
bottom
,
pmul
(
cross
,
cone_radius
))
conepoints
=
[
self
.
_rotate_point
(
conep1
,
bottom
,
direction
,
x
)
for
x
in
numpy
.
linspace
(
0
,
2
*
math
.
pi
,
precision
)]
else
:
# Z axis
# just add cone radius to the x axis and rotate the point
conep1
=
(
bottom
[
0
]
+
cone_radius
,
bottom
[
1
],
bottom
[
2
])
conepoints
=
[
self
.
_rotate_point
(
conep1
,
p1
,
direction
,
x
)
for
x
in
numpy
.
linspace
(
0
,
2
*
math
.
pi
,
precision
)]
triangles
=
[(
top
,
conepoints
[
idx
],
conepoints
[
idx
+
1
])
for
idx
in
range
(
len
(
conepoints
)
-
1
)]
return
triangles
def
get_moves_for_opengl
(
self
,
safety_height
):
if
self
.
opengl_safety_height
!=
safety_height
:
self
.
make_moves_for_opengl
(
safety_height
)
self
.
make_vbo_for_moves
()
return
(
self
.
opengl_coords
,
self
.
opengl_indices
)
# separate vertex coordinates from line definitions and convert to indices
def
make_vbo_for_moves
(
self
):
index
=
0
output
=
[]
store_vertices
=
{}
vertices
=
[]
for
path
in
self
.
opengl_lines
:
indices
=
[]
triangles
=
[]
triangle_indices
=
[]
# compress the lines into a centeral array containing all the vertices
# generate a matching index for each line
for
idx
in
range
(
len
(
path
[
0
])
-
1
):
point
=
path
[
0
][
idx
]
if
not
point
in
store_vertices
:
store_vertices
[
point
]
=
index
vertices
.
insert
(
index
,
point
)
index
+=
1
indices
.
append
(
store_vertices
[
point
])
point2
=
path
[
0
][
idx
+
1
]
if
not
point2
in
store_vertices
:
store_vertices
[
point2
]
=
index
vertices
.
insert
(
index
,
point2
)
index
+=
1
triangles
.
extend
(
self
.
draw_direction_cone_mesh
(
path
[
0
][
idx
],
path
[
0
][
idx
+
1
]))
for
t
in
triangles
:
for
p
in
t
:
if
not
p
in
store_vertices
:
store_vertices
[
p
]
=
index
vertices
.
insert
(
index
,
p
)
index
+=
1
triangle_indices
.
append
(
store_vertices
[
p
])
triangle_indices
=
array
(
triangle_indices
,
dtype
=
numpy
.
int32
)
indices
.
append
(
store_vertices
[
path
[
0
][
-
1
]])
# this list comprehension removes consecutive duplicate points.
indices
=
array
([
x
[
0
]
for
x
in
groupby
(
indices
)],
dtype
=
numpy
.
int32
)
output
.
append
((
indices
,
triangle_indices
,
path
[
1
]))
vertices
=
array
(
vertices
,
dtype
=
numpy
.
float32
)
self
.
opengl_coords
=
vbo
.
VBO
(
vertices
)
self
.
opengl_indices
=
output
#convert moves into lines for dispaly with opengl
def
make_moves_for_opengl
(
self
,
safety_height
):
working_path
=
[]
outpaths
=
[]
for
path
in
self
.
paths
:
if
not
path
:
continue
path
=
path
.
points
if
len
(
outpaths
)
!=
0
:
lastp
=
outpaths
[
-
1
][
0
][
-
1
]
working_path
.
append
((
path
[
0
][
0
],
path
[
0
][
1
],
safety_height
))
if
((
abs
(
lastp
[
0
]
-
path
[
0
][
0
])
>
epsilon
)
or
(
abs
(
lastp
[
1
]
-
path
[
0
][
1
])
>
epsilon
)):
if
(
abs
(
lastp
[
2
]
-
path
[
0
][
2
])
>
epsilon
)
or
(
pnorm
(
psub
(
lastp
,
path
[
0
]))
>
self
.
_max_safe_distance
+
epsilon
):
outpaths
.
append
((
tuple
([
x
[
0
]
for
x
in
groupby
(
working_path
)]),
True
))
else
:
working_path
.
append
((
0
,
0
,
0
))
working_path
.
append
((
path
[
0
][
0
],
path
[
0
][
1
],
safety_height
))
outpaths
.
append
((
working_path
,
True
))
# add this move to last move if last move was not rapid
if
outpaths
[
-
1
][
1
]
==
False
:
outpaths
[
-
1
]
=
(
outpaths
[
-
1
][
0
]
+
tuple
(
path
),
False
)
else
:
# last move was rapid, so add last point of rapid to beginning of path
outpaths
.
append
((
tuple
([
x
[
0
]
for
x
in
groupby
((
outpaths
[
-
1
][
0
][
-
1
],)
+
tuple
(
path
))]),
False
))
working_path
=
[]
working_path
.
append
(
path
[
-
1
])
working_path
.
append
((
path
[
-
1
][
0
],
path
[
-
1
][
1
],
safety_height
))
outpaths
.
append
((
tuple
([
x
[
0
]
for
x
in
groupby
(
working_path
)]),
True
))
self
.
opengl_safety_height
=
safety_height
self
.
opengl_lines
=
outpaths
def
get_machine_time
(
self
,
safety_height
=
0.0
):
def
get_machine_time
(
self
,
safety_height
=
0.0
):
""" calculate an estimation of the time required for processing the
""" calculate an estimation of the time required for processing the
toolpath with the machine
toolpath with the machine
...
@@ -206,7 +351,7 @@ class Toolpath(object):
...
@@ -206,7 +351,7 @@ class Toolpath(object):
# go through all points of the path
# go through all points of the path
for
new_pos
,
rapid
in
self
.
get_moves
(
safety_height
):
for
new_pos
,
rapid
in
self
.
get_moves
(
safety_height
):
if
not
current_position
is
None
:
if
not
current_position
is
None
:
result
+=
new_pos
.
sub
(
current_position
)
.
norm
/
self
.
_feedrate
result
+=
pnorm
(
psub
(
new_pos
,
current_position
))
/
self
.
_feedrate
current_position
=
new_pos
current_position
=
new_pos
return
result
return
result
...
@@ -217,7 +362,7 @@ class Toolpath(object):
...
@@ -217,7 +362,7 @@ class Toolpath(object):
# go through all points of the path
# go through all points of the path
for
new_pos
,
rapid
in
self
.
get_moves
(
safety_height
):
for
new_pos
,
rapid
in
self
.
get_moves
(
safety_height
):
if
not
current_position
is
None
:
if
not
current_position
is
None
:
result
+=
new_pos
.
sub
(
current_position
)
.
norm
result
+=
pnorm
(
psub
(
new_pos
,
current_position
))
current_position
=
new_pos
current_position
=
new_pos
return
result
return
result
...
@@ -273,6 +418,7 @@ class Toolpath(object):
...
@@ -273,6 +418,7 @@ class Toolpath(object):
if
current_path
.
points
:
if
current_path
.
points
:
new_paths
.
append
(
current_path
)
new_paths
.
append
(
current_path
)
self
.
paths
=
new_paths
self
.
paths
=
new_paths
self
.
clear_cache
()
class
Bounds
(
object
):
class
Bounds
(
object
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment