Merge branch 'master' into marcus7070/tangentArc
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ dist/*
|
||||
.idea/*
|
||||
cadquery.egg-info
|
||||
target/*
|
||||
.vscode
|
||||
|
100
cadquery/cq.py
100
cadquery/cq.py
@ -1557,7 +1557,10 @@ class Workplane(CQ):
|
||||
|
||||
if tangents:
|
||||
t1, t2 = tangents
|
||||
tangents = (self.plane.toWorldCoords(t1), self.plane.toWorldCoords(t2))
|
||||
tangents = (
|
||||
self.plane.toWorldCoords(t1) - self.plane.origin,
|
||||
self.plane.toWorldCoords(t2) - self.plane.origin,
|
||||
)
|
||||
|
||||
e = Edge.makeSpline(allPoints, tangents=tangents, periodic=periodic)
|
||||
|
||||
@ -1589,6 +1592,65 @@ class Workplane(CQ):
|
||||
|
||||
return self.spline(allPoints, includeCurrent=False, makeWire=True)
|
||||
|
||||
def ellipseArc(
|
||||
self,
|
||||
x_radius,
|
||||
y_radius,
|
||||
angle1=360,
|
||||
angle2=360,
|
||||
rotation_angle=0.0,
|
||||
sense=1,
|
||||
forConstruction=False,
|
||||
startAtCurrent=True,
|
||||
makeWire=False,
|
||||
):
|
||||
"""Draw an elliptical arc with x and y radiuses either with start point at current point or
|
||||
or current point being the center of the arc
|
||||
|
||||
:param x_radius: x radius of the ellipse (along the x-axis of plane the ellipse should lie in)
|
||||
:param y_radius: y radius of the ellipse (along the y-axis of plane the ellipse should lie in)
|
||||
:param angle1: start angle of arc
|
||||
:param angle2: end angle of arc (angle2 == angle1 return closed ellipse = default)
|
||||
:param rotation_angle: angle to rotate the created ellipse / arc
|
||||
:param sense: clockwise (-1) or counter clockwise (1)
|
||||
:param startAtCurrent: True: start point of arc is moved to current point; False: center of
|
||||
arc is on current point
|
||||
:param makeWire: convert the resulting arc edge to a wire
|
||||
"""
|
||||
|
||||
# Start building the ellipse with the current point as center
|
||||
center = self._findFromPoint(useLocalCoords=False)
|
||||
e = Edge.makeEllipse(
|
||||
x_radius,
|
||||
y_radius,
|
||||
center,
|
||||
self.plane.zDir,
|
||||
self.plane.xDir,
|
||||
angle1,
|
||||
angle2,
|
||||
sense == 1,
|
||||
)
|
||||
|
||||
# Rotate if necessary
|
||||
if rotation_angle != 0.0:
|
||||
e = e.rotate(center, center.add(self.plane.zDir), rotation_angle)
|
||||
|
||||
# Move the start point of the ellipse onto the last current point
|
||||
if startAtCurrent:
|
||||
startPoint = e.startPoint()
|
||||
e = e.translate(center.sub(startPoint))
|
||||
|
||||
if makeWire:
|
||||
rv = Wire.assembleEdges([e])
|
||||
if not forConstruction:
|
||||
self._addPendingWire(rv)
|
||||
else:
|
||||
rv = e
|
||||
if not forConstruction:
|
||||
self._addPendingEdge(e)
|
||||
|
||||
return self.newObject([rv])
|
||||
|
||||
def threePointArc(self, point1, point2, forConstruction=False):
|
||||
"""
|
||||
Draw an arc from the current point, through point1, and ending at point2
|
||||
@ -2073,6 +2135,42 @@ class Workplane(CQ):
|
||||
|
||||
return self.eachpoint(makeCircleWire, useLocalCoordinates=True)
|
||||
|
||||
# ellipse from current point
|
||||
def ellipse(self, x_radius, y_radius, rotation_angle=0.0, forConstruction=False):
|
||||
"""
|
||||
Make an ellipse for each item on the stack.
|
||||
:param x_radius: x radius of the ellipse (x-axis of plane the ellipse should lie in)
|
||||
:type x_radius: float > 0
|
||||
:param y_radius: y radius of the ellipse (y-axis of plane the ellipse should lie in)
|
||||
:type y_radius: float > 0
|
||||
:param rotation_angle: angle to rotate the ellipse (0 = no rotation = default)
|
||||
:type rotation_angle: float
|
||||
:param forConstruction: should the new wires be reference geometry only?
|
||||
:type forConstruction: true if the wires are for reference, false if they are creating
|
||||
part geometry
|
||||
:return: a new CQ object with the created wires on the stack
|
||||
|
||||
*NOTE* Due to a bug in opencascade (https://tracker.dev.opencascade.org/view.php?id=31290)
|
||||
the center of mass (equals center for next shape) is shifted. To create concentric ellipses
|
||||
use Workplane("XY")
|
||||
.center(10, 20).ellipse(100,10)
|
||||
.center(0, 0).ellipse(50, 5)
|
||||
"""
|
||||
|
||||
def makeEllipseWire(obj):
|
||||
elip = Wire.makeEllipse(
|
||||
x_radius,
|
||||
y_radius,
|
||||
obj,
|
||||
Vector(0, 0, 1),
|
||||
Vector(1, 0, 0),
|
||||
rotation_angle=rotation_angle,
|
||||
)
|
||||
elip.forConstruction = forConstruction
|
||||
return elip
|
||||
|
||||
return self.eachpoint(makeEllipseWire, useLocalCoordinates=True)
|
||||
|
||||
def polygon(self, nSides, diameter, forConstruction=False):
|
||||
"""
|
||||
Creates a polygon inscribed in a circle of the specified diameter for each point on
|
||||
|
@ -11,6 +11,7 @@ from OCC.Core.gp import (
|
||||
gp_Ax3,
|
||||
gp_Dir,
|
||||
gp_Circ,
|
||||
gp_Elips,
|
||||
gp_Trsf,
|
||||
gp_Pln,
|
||||
gp_GTrsf,
|
||||
@ -76,7 +77,7 @@ from OCC.Core.TopoDS import (
|
||||
|
||||
from OCC.Core.TopoDS import TopoDS_Compound, TopoDS_Builder
|
||||
|
||||
from OCC.Core.GC import GC_MakeArcOfCircle # geometry construction
|
||||
from OCC.Core.GC import GC_MakeArcOfCircle, GC_MakeArcOfEllipse # geometry construction
|
||||
from OCC.Core.GCE2d import GCE2d_MakeSegment
|
||||
from OCC.Core.GeomAPI import GeomAPI_Interpolate, GeomAPI_ProjectPointOnSurf
|
||||
|
||||
@ -751,6 +752,62 @@ class Edge(Shape, Mixin1D):
|
||||
).Value()
|
||||
return cls(BRepBuilderAPI_MakeEdge(circle_geom).Edge())
|
||||
|
||||
@classmethod
|
||||
def makeEllipse(
|
||||
cls,
|
||||
x_radius,
|
||||
y_radius,
|
||||
pnt=Vector(0, 0, 0),
|
||||
dir=Vector(0, 0, 1),
|
||||
xdir=Vector(1, 0, 0),
|
||||
angle1=360.0,
|
||||
angle2=360.0,
|
||||
sense=1,
|
||||
):
|
||||
"""
|
||||
Makes an Ellipse centered at the provided point, having normal in the provided direction
|
||||
:param cls:
|
||||
:param x_radius: x radius of the ellipse (along the x-axis of plane the ellipse should lie in)
|
||||
:param y_radius: y radius of the ellipse (along the y-axis of plane the ellipse should lie in)
|
||||
:param pnt: vector representing the center of the ellipse
|
||||
:param dir: vector representing the direction of the plane the ellipse should lie in
|
||||
:param angle1: start angle of arc
|
||||
:param angle2: end angle of arc (angle2 == angle1 return closed ellipse = default)
|
||||
:param sense: clockwise (-1) or counter clockwise (1)
|
||||
:return: an Edge
|
||||
"""
|
||||
|
||||
pnt = Vector(pnt).toPnt()
|
||||
dir = Vector(dir).toDir()
|
||||
xdir = Vector(xdir).toDir()
|
||||
|
||||
ax1 = gp_Ax1(pnt, dir)
|
||||
ax2 = gp_Ax2(pnt, dir, xdir)
|
||||
|
||||
if y_radius > x_radius:
|
||||
# swap x and y radius and rotate by 90° afterwards to create an ellipse with x_radius < y_radius
|
||||
correction_angle = 90.0 * DEG2RAD
|
||||
ellipse_gp = gp_Elips(ax2, y_radius, x_radius).Rotated(
|
||||
ax1, correction_angle
|
||||
)
|
||||
else:
|
||||
correction_angle = 0.0
|
||||
ellipse_gp = gp_Elips(ax2, x_radius, y_radius)
|
||||
|
||||
if angle1 == angle2: # full ellipse case
|
||||
ellipse = cls(BRepBuilderAPI_MakeEdge(ellipse_gp).Edge())
|
||||
else: # arc case
|
||||
# take correction_angle into account
|
||||
ellipse_geom = GC_MakeArcOfEllipse(
|
||||
ellipse_gp,
|
||||
angle1 * DEG2RAD - correction_angle,
|
||||
angle2 * DEG2RAD - correction_angle,
|
||||
sense == 1,
|
||||
).Value()
|
||||
ellipse = cls(BRepBuilderAPI_MakeEdge(ellipse_geom).Edge())
|
||||
|
||||
return ellipse
|
||||
|
||||
@classmethod
|
||||
def makeSpline(cls, listOfVector, tangents=None, periodic=False, tol=1e-6):
|
||||
"""
|
||||
@ -884,6 +941,46 @@ class Wire(Shape, Mixin1D):
|
||||
w = cls.assembleEdges([circle_edge])
|
||||
return w
|
||||
|
||||
@classmethod
|
||||
def makeEllipse(
|
||||
cls,
|
||||
x_radius,
|
||||
y_radius,
|
||||
center,
|
||||
normal,
|
||||
xDir,
|
||||
angle1=360.0,
|
||||
angle2=360.0,
|
||||
rotation_angle=0.0,
|
||||
closed=True,
|
||||
):
|
||||
"""
|
||||
Makes an Ellipse centered at the provided point, having normal in the provided direction
|
||||
:param x_radius: floating point major radius of the ellipse (x-axis), must be > 0
|
||||
:param y_radius: floating point minor radius of the ellipse (y-axis), must be > 0
|
||||
:param center: vector representing the center of the circle
|
||||
:param normal: vector representing the direction of the plane the circle should lie in
|
||||
:param angle1: start angle of arc
|
||||
:param angle2: end angle of arc
|
||||
:param rotation_angle: angle to rotate the created ellipse / arc
|
||||
:return: Wire
|
||||
"""
|
||||
|
||||
ellipse_edge = Edge.makeEllipse(
|
||||
x_radius, y_radius, center, normal, xDir, angle1, angle2
|
||||
)
|
||||
|
||||
if angle1 != angle2 and closed:
|
||||
line = Edge.makeLine(ellipse_edge.endPoint(), ellipse_edge.startPoint())
|
||||
w = cls.assembleEdges([ellipse_edge, line])
|
||||
else:
|
||||
w = cls.assembleEdges([ellipse_edge])
|
||||
|
||||
if rotation_angle != 0.0:
|
||||
w = w.rotate(center, center + normal, rotation_angle)
|
||||
|
||||
return w
|
||||
|
||||
@classmethod
|
||||
def makePolygon(cls, listOfVertices, forConstruction=False):
|
||||
# convert list of tuples into Vectors.
|
||||
|
@ -1,5 +1,5 @@
|
||||
from cadquery import *
|
||||
from OCC.gp import gp_Vec
|
||||
from OCC.Core.gp import gp_Vec
|
||||
import unittest
|
||||
import sys
|
||||
import os
|
||||
|
@ -1,18 +1,21 @@
|
||||
# system modules
|
||||
import math
|
||||
import sys
|
||||
import unittest
|
||||
from tests import BaseTest
|
||||
from OCC.gp import gp_Vec, gp_Pnt, gp_Ax2, gp_Circ, gp_DZ, gp_XYZ
|
||||
from OCC.gp import gp_Vec, gp_Pnt, gp_Ax2, gp_Circ, gp_Elips, gp_DZ, gp_XYZ
|
||||
from OCC.BRepBuilderAPI import (
|
||||
BRepBuilderAPI_MakeVertex,
|
||||
BRepBuilderAPI_MakeEdge,
|
||||
BRepBuilderAPI_MakeFace,
|
||||
)
|
||||
|
||||
from OCC.GC import GC_MakeCircle
|
||||
from OCC.Core.GC import GC_MakeCircle
|
||||
|
||||
from cadquery import *
|
||||
|
||||
DEG2RAD = 2 * math.pi / 360
|
||||
|
||||
|
||||
class TestCadObjects(BaseTest):
|
||||
def _make_circle(self):
|
||||
@ -20,6 +23,11 @@ class TestCadObjects(BaseTest):
|
||||
circle = gp_Circ(gp_Ax2(gp_Pnt(1, 2, 3), gp_DZ()), 2.0)
|
||||
return Shape.cast(BRepBuilderAPI_MakeEdge(circle).Edge())
|
||||
|
||||
def _make_ellipse(self):
|
||||
|
||||
ellipse = gp_Elips(gp_Ax2(gp_Pnt(1, 2, 3), gp_DZ()), 4.0, 2.0)
|
||||
return Shape.cast(BRepBuilderAPI_MakeEdge(ellipse).Edge())
|
||||
|
||||
def testVectorConstructors(self):
|
||||
v1 = Vector(1, 2, 3)
|
||||
v2 = Vector((1, 2, 3))
|
||||
@ -69,6 +77,13 @@ class TestCadObjects(BaseTest):
|
||||
|
||||
self.assertTupleAlmostEquals((1.0, 2.0, 3.0), e.Center().toTuple(), 3)
|
||||
|
||||
def testEdgeWrapperEllipseCenter(self):
|
||||
e = self._make_ellipse()
|
||||
w = Wire.assembleEdges([e])
|
||||
self.assertTupleAlmostEquals(
|
||||
(1.0, 2.0, 3.0), Face.makeFromWires(w).Center().toTuple(), 3
|
||||
)
|
||||
|
||||
def testEdgeWrapperMakeCircle(self):
|
||||
halfCircleEdge = Edge.makeCircle(
|
||||
radius=10, pnt=(0, 0, 0), dir=(0, 0, 1), angle1=0, angle2=180
|
||||
@ -100,6 +115,84 @@ class TestCadObjects(BaseTest):
|
||||
(0, -1, 0), tangent_arc.tangentAt(locationParam=1).toTuple(), 3
|
||||
)
|
||||
|
||||
def testEdgeWrapperMakeEllipse1(self):
|
||||
# Check x_radius > y_radius
|
||||
x_radius, y_radius = 20, 10
|
||||
angle1, angle2 = -75.0, 90.0
|
||||
arcEllipseEdge = Edge.makeEllipse(
|
||||
x_radius=x_radius,
|
||||
y_radius=y_radius,
|
||||
pnt=(0, 0, 0),
|
||||
dir=(0, 0, 1),
|
||||
angle1=angle1,
|
||||
angle2=angle2,
|
||||
)
|
||||
|
||||
start = (
|
||||
x_radius * math.cos(angle1 * DEG2RAD),
|
||||
y_radius * math.sin(angle1 * DEG2RAD),
|
||||
0.0,
|
||||
)
|
||||
end = (
|
||||
x_radius * math.cos(angle2 * DEG2RAD),
|
||||
y_radius * math.sin(angle2 * DEG2RAD),
|
||||
0.0,
|
||||
)
|
||||
self.assertTupleAlmostEquals(start, arcEllipseEdge.startPoint().toTuple(), 3)
|
||||
self.assertTupleAlmostEquals(end, arcEllipseEdge.endPoint().toTuple(), 3)
|
||||
|
||||
def testEdgeWrapperMakeEllipse2(self):
|
||||
# Check x_radius < y_radius
|
||||
x_radius, y_radius = 10, 20
|
||||
angle1, angle2 = 0.0, 45.0
|
||||
arcEllipseEdge = Edge.makeEllipse(
|
||||
x_radius=x_radius,
|
||||
y_radius=y_radius,
|
||||
pnt=(0, 0, 0),
|
||||
dir=(0, 0, 1),
|
||||
angle1=angle1,
|
||||
angle2=angle2,
|
||||
)
|
||||
|
||||
start = (
|
||||
x_radius * math.cos(angle1 * DEG2RAD),
|
||||
y_radius * math.sin(angle1 * DEG2RAD),
|
||||
0.0,
|
||||
)
|
||||
end = (
|
||||
x_radius * math.cos(angle2 * DEG2RAD),
|
||||
y_radius * math.sin(angle2 * DEG2RAD),
|
||||
0.0,
|
||||
)
|
||||
self.assertTupleAlmostEquals(start, arcEllipseEdge.startPoint().toTuple(), 3)
|
||||
self.assertTupleAlmostEquals(end, arcEllipseEdge.endPoint().toTuple(), 3)
|
||||
|
||||
def testEdgeWrapperMakeCircleWithEllipse(self):
|
||||
# Check x_radius == y_radius
|
||||
x_radius, y_radius = 20, 20
|
||||
angle1, angle2 = 15.0, 60.0
|
||||
arcEllipseEdge = Edge.makeEllipse(
|
||||
x_radius=x_radius,
|
||||
y_radius=y_radius,
|
||||
pnt=(0, 0, 0),
|
||||
dir=(0, 0, 1),
|
||||
angle1=angle1,
|
||||
angle2=angle2,
|
||||
)
|
||||
|
||||
start = (
|
||||
x_radius * math.cos(angle1 * DEG2RAD),
|
||||
y_radius * math.sin(angle1 * DEG2RAD),
|
||||
0.0,
|
||||
)
|
||||
end = (
|
||||
x_radius * math.cos(angle2 * DEG2RAD),
|
||||
y_radius * math.sin(angle2 * DEG2RAD),
|
||||
0.0,
|
||||
)
|
||||
self.assertTupleAlmostEquals(start, arcEllipseEdge.startPoint().toTuple(), 3)
|
||||
self.assertTupleAlmostEquals(end, arcEllipseEdge.endPoint().toTuple(), 3)
|
||||
|
||||
def testFaceWrapperMakePlane(self):
|
||||
mplane = Face.makePlane(10, 10)
|
||||
|
||||
|
@ -545,6 +545,206 @@ class TestCadQuery(BaseTest):
|
||||
path1 = Workplane("XZ").spline(pts[1:], includeCurrent=True).val()
|
||||
self.assertAlmostEqual(path.Length(), path1.Length())
|
||||
|
||||
# test tangents and offset plane
|
||||
pts = [(0, 0), (-1, 1), (-2, 0), (-1, 0)]
|
||||
tangents = [(0, 1), (1, 0)]
|
||||
|
||||
path2 = Workplane("XY", (0, 0, 10)).spline(pts, tangents=tangents)
|
||||
self.assertAlmostEqual(path2.val().tangentAt(0).z, 0)
|
||||
|
||||
def testRotatedEllipse(self):
|
||||
def rotatePoint(x, y, alpha):
|
||||
# rotation matrix
|
||||
a = alpha * DEG2RAD
|
||||
r = ((math.cos(a), math.sin(a)), (-math.sin(a), math.cos(a)))
|
||||
return ((x * r[0][0] + y * r[1][0]), (x * r[0][1] + y * r[1][1]))
|
||||
|
||||
def ellipsePoints(r1, r2, a):
|
||||
return (r1 * math.cos(a * DEG2RAD), r2 * math.sin(a * DEG2RAD))
|
||||
|
||||
DEG2RAD = math.pi / 180.0
|
||||
p0 = (10, 20)
|
||||
a1, a2 = 30, -60
|
||||
r1, r2 = 20, 10
|
||||
ra = 25
|
||||
|
||||
sx_rot, sy_rot = rotatePoint(*ellipsePoints(r1, r2, a1), ra)
|
||||
ex_rot, ey_rot = rotatePoint(*ellipsePoints(r1, r2, a2), ra)
|
||||
|
||||
# startAtCurrent=False, sense = 1
|
||||
ellipseArc1 = (
|
||||
Workplane("XY")
|
||||
.moveTo(*p0)
|
||||
.ellipseArc(
|
||||
r1, r2, startAtCurrent=False, angle1=a1, angle2=a2, rotation_angle=ra
|
||||
)
|
||||
)
|
||||
start = ellipseArc1.vertices().objects[0]
|
||||
end = ellipseArc1.vertices().objects[1]
|
||||
|
||||
self.assertTupleAlmostEquals(
|
||||
(start.X, start.Y), (p0[0] + sx_rot, p0[1] + sy_rot), 3
|
||||
)
|
||||
self.assertTupleAlmostEquals(
|
||||
(end.X, end.Y), (p0[0] + ex_rot, p0[1] + ey_rot), 3
|
||||
)
|
||||
|
||||
# startAtCurrent=True, sense = 1
|
||||
ellipseArc2 = (
|
||||
Workplane("XY")
|
||||
.moveTo(*p0)
|
||||
.ellipseArc(
|
||||
r1, r2, startAtCurrent=True, angle1=a1, angle2=a2, rotation_angle=ra
|
||||
)
|
||||
)
|
||||
start = ellipseArc2.vertices().objects[0]
|
||||
end = ellipseArc2.vertices().objects[1]
|
||||
|
||||
self.assertTupleAlmostEquals(
|
||||
(start.X, start.Y), (p0[0] + sx_rot - sx_rot, p0[1] + sy_rot - sy_rot), 3
|
||||
)
|
||||
self.assertTupleAlmostEquals(
|
||||
(end.X, end.Y), (p0[0] + ex_rot - sx_rot, p0[1] + ey_rot - sy_rot), 3
|
||||
)
|
||||
|
||||
# startAtCurrent=False, sense = -1
|
||||
ellipseArc3 = (
|
||||
Workplane("XY")
|
||||
.moveTo(*p0)
|
||||
.ellipseArc(
|
||||
r1,
|
||||
r2,
|
||||
startAtCurrent=False,
|
||||
angle1=a1,
|
||||
angle2=a2,
|
||||
rotation_angle=ra,
|
||||
sense=-1,
|
||||
)
|
||||
)
|
||||
start = ellipseArc3.vertices().objects[0]
|
||||
end = ellipseArc3.vertices().objects[1]
|
||||
|
||||
# swap start and end points for coparison due to different sense
|
||||
self.assertTupleAlmostEquals(
|
||||
(start.X, start.Y), (p0[0] + ex_rot, p0[1] + ey_rot), 3
|
||||
)
|
||||
self.assertTupleAlmostEquals(
|
||||
(end.X, end.Y), (p0[0] + sx_rot, p0[1] + sy_rot), 3
|
||||
)
|
||||
|
||||
# startAtCurrent=True, sense = -1
|
||||
ellipseArc4 = (
|
||||
Workplane("XY")
|
||||
.moveTo(*p0)
|
||||
.ellipseArc(
|
||||
r1,
|
||||
r2,
|
||||
startAtCurrent=True,
|
||||
angle1=a1,
|
||||
angle2=a2,
|
||||
rotation_angle=ra,
|
||||
sense=-1,
|
||||
makeWire=True,
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(len(ellipseArc4.ctx.pendingWires), 1)
|
||||
|
||||
start = ellipseArc4.vertices().objects[0]
|
||||
end = ellipseArc4.vertices().objects[1]
|
||||
|
||||
# swap start and end points for coparison due to different sense
|
||||
self.assertTupleAlmostEquals(
|
||||
(start.X, start.Y), (p0[0] + ex_rot - ex_rot, p0[1] + ey_rot - ey_rot), 3
|
||||
)
|
||||
self.assertTupleAlmostEquals(
|
||||
(end.X, end.Y), (p0[0] + sx_rot - ex_rot, p0[1] + sy_rot - ey_rot), 3
|
||||
)
|
||||
|
||||
def testEllipseArcsClockwise(self):
|
||||
ellipseArc = (
|
||||
Workplane("XY")
|
||||
.moveTo(10, 15)
|
||||
.ellipseArc(5, 4, -10, 190, 45, sense=-1, startAtCurrent=False)
|
||||
)
|
||||
sp = ellipseArc.val().startPoint()
|
||||
ep = ellipseArc.val().endPoint()
|
||||
self.assertTupleAlmostEquals(
|
||||
(sp.x, sp.y), (7.009330014275797, 11.027027582524015), 3
|
||||
)
|
||||
self.assertTupleAlmostEquals(
|
||||
(ep.x, ep.y), (13.972972417475985, 17.990669985724203), 3
|
||||
)
|
||||
|
||||
ellipseArc = (
|
||||
ellipseArc.ellipseArc(5, 4, -10, 190, 315, sense=-1)
|
||||
.ellipseArc(5, 4, -10, 190, 225, sense=-1)
|
||||
.ellipseArc(5, 4, -10, 190, 135, sense=-1)
|
||||
)
|
||||
ep = ellipseArc.val().endPoint()
|
||||
self.assertTupleAlmostEquals((sp.x, sp.y), (ep.x, ep.y), 3)
|
||||
|
||||
def testEllipseArcsCounterClockwise(self):
|
||||
ellipseArc = (
|
||||
Workplane("XY")
|
||||
.moveTo(10, 15)
|
||||
.ellipseArc(5, 4, -10, 190, 45, startAtCurrent=False)
|
||||
)
|
||||
sp = ellipseArc.val().startPoint()
|
||||
ep = ellipseArc.val().endPoint()
|
||||
self.assertTupleAlmostEquals(
|
||||
(sp.x, sp.y), (13.972972417475985, 17.990669985724203), 3
|
||||
)
|
||||
self.assertTupleAlmostEquals(
|
||||
(ep.x, ep.y), (7.009330014275797, 11.027027582524015), 3
|
||||
)
|
||||
|
||||
ellipseArc = (
|
||||
ellipseArc.ellipseArc(5, 4, -10, 190, 135)
|
||||
.ellipseArc(5, 4, -10, 190, 225)
|
||||
.ellipseArc(5, 4, -10, 190, 315)
|
||||
)
|
||||
ep = ellipseArc.val().endPoint()
|
||||
self.assertTupleAlmostEquals((sp.x, sp.y), (ep.x, ep.y), 3)
|
||||
|
||||
def testEllipseCenterAndMoveTo(self):
|
||||
# Whether we start from a center() call or a moveTo call, it should be the same ellipse Arc
|
||||
p0 = (10, 20)
|
||||
a1, a2 = 30, -60
|
||||
r1, r2 = 20, 10
|
||||
ra = 25
|
||||
|
||||
ellipseArc1 = (
|
||||
Workplane("XY")
|
||||
.moveTo(*p0)
|
||||
.ellipseArc(
|
||||
r1, r2, startAtCurrent=False, angle1=a1, angle2=a2, rotation_angle=ra
|
||||
)
|
||||
)
|
||||
sp1 = ellipseArc1.val().startPoint()
|
||||
ep1 = ellipseArc1.val().endPoint()
|
||||
|
||||
ellipseArc2 = (
|
||||
Workplane("XY")
|
||||
.moveTo(*p0)
|
||||
.ellipseArc(
|
||||
r1, r2, startAtCurrent=False, angle1=a1, angle2=a2, rotation_angle=ra
|
||||
)
|
||||
)
|
||||
sp2 = ellipseArc2.val().startPoint()
|
||||
ep2 = ellipseArc2.val().endPoint()
|
||||
|
||||
self.assertTupleAlmostEquals(sp1.toTuple(), sp2.toTuple(), 3)
|
||||
self.assertTupleAlmostEquals(ep1.toTuple(), ep2.toTuple(), 3)
|
||||
|
||||
def testMakeEllipse(self):
|
||||
el = Wire.makeEllipse(
|
||||
1, 2, Vector(0, 0, 0), Vector(0, 0, 1), Vector(1, 0, 0), 0, 90, 45, True,
|
||||
)
|
||||
|
||||
self.assertTrue(el.IsClosed())
|
||||
self.assertTrue(el.isValid())
|
||||
|
||||
def testSweep(self):
|
||||
"""
|
||||
Tests the operation of sweeping a wire(s) along a path
|
||||
@ -802,6 +1002,13 @@ class TestCadQuery(BaseTest):
|
||||
self.saveModel(s)
|
||||
self.assertEqual(14, s.faces().size())
|
||||
|
||||
def testConcentricEllipses(self):
|
||||
concentricEllipses = (
|
||||
Workplane("XY").center(10, 20).ellipse(100, 10).center(0, 0).ellipse(50, 5)
|
||||
)
|
||||
v = concentricEllipses.vertices().objects[0]
|
||||
self.assertTupleAlmostEquals((v.X, v.Y), (10 + 50, 20), 3)
|
||||
|
||||
def testLegoBrick(self):
|
||||
# test making a simple lego brick
|
||||
# which of the below
|
||||
|
Reference in New Issue
Block a user