コード例 #1
0
 def test_theta_at_angle(self):
     ell = Ellipse(20, 10)
     # straight angles
     self.assertEqual(ell.theta_at_angle(0), 0, 'theta at 0')
     self.assertEqual(ell.theta_at_angle(pi / 2), pi / 2, 'theta at 90')
     self.assertAlmostEqual(ell.theta_at_angle(pi), pi, msg='theta at 180')
     self.assertEqual(ell.theta_at_angle(3 * pi / 2), 3 * pi / 2, 'theta at 270')
     # 45 degrees
     self.assertEqual(ell.theta_at_angle(pi / 4), atan(2), 'theta at 45')
コード例 #2
0
class TestEllipse(unittest.TestCase):
    def setUp(self):
        self.circle = Ellipse(10, 10)

    def test_coordinate_at_theta(self):
        ell = Ellipse(12,8)
        self.assertEqual(ell.coordinate_at_theta(0), Coordinate(12, 0), 'coordinate at angle 0')
        self.assertTrue(Coordinate(0, 8).close_enough_to(ell.coordinate_at_theta(pi/2)), 'coordinate at angle pi/2')
        self.assertTrue(Coordinate(-12, 0).close_enough_to(ell.coordinate_at_theta(pi)), 'coordinate at angle pi')
        self.assertTrue(Coordinate(0, -8).close_enough_to(ell.coordinate_at_theta(3*pi/2)), 'coordinate at angle 3*pi/2')

    def test_circle(self):
        self.assertAlmostEqual(self.circle.circumference, 20 * pi, 3, 'circumference circle')
        self.assertAlmostEqual(self.circle.dist_from_theta(0, pi), 10 * pi, 3,'arc length 0 -> pi')
        self.assertAlmostEqual(self.circle.dist_from_theta(3 * pi / 2, 0), 5 * pi, 3, 'arc length 3 * pi / 2 -> 0')
        self.assertAlmostEqual(self.circle.theta_from_dist(0, 10 * pi), pi, 5)

    def test_theta_at_angle(self):
        ell = Ellipse(20, 10)
        # straight angles
        self.assertEqual(ell.theta_at_angle(0), 0, 'theta at 0')
        self.assertEqual(ell.theta_at_angle(pi / 2), pi / 2, 'theta at 90')
        self.assertAlmostEqual(ell.theta_at_angle(pi), pi, msg='theta at 180')
        self.assertEqual(ell.theta_at_angle(3 * pi / 2), 3 * pi / 2, 'theta at 270')
        # 45 degrees
        self.assertEqual(ell.theta_at_angle(pi / 4), atan(2), 'theta at 45')

    def test_curvature(self):
        ell = Ellipse(20, 10)
        self.assertEqual(ell.curvature(0), 1/5, 'curvature at 0')
        self.assertEqual(ell.curvature(pi / 2), 1/40, 'curvature at 90')
        self.assertEqual(ell.curvature(pi), 1/5, 'curvature at 180')
        self.assertEqual(ell.curvature(3 * pi / 2), 1/40, 'curvature at 270')

    def test_dist_from_theta(self):
        pass

    def test_theta_from_dist(self):
        self.assertAlmostEqual(self.circle.theta_from_dist(0, 10 * pi), pi, places=5)
        self.assertAlmostEqual(self.circle.theta_from_dist(1, 10 * pi), pi + 1, places=1) # Accurary gets really bad here
        self.assertAlmostEqual(self.circle.theta_from_dist(pi, 10 * pi), 0, places=5)
        self.assertAlmostEqual(self.circle.theta_from_dist(2*pi, 0), 0, places=5)
コード例 #3
0
    def effect(self):
        """
        Draws as basic elliptical box, based on provided parameters
        """

        # input sanity check
        error = False
        if min(self.options.height, self.options.width,
               self.options.depth) == 0:
            eff.errormsg('Error: Dimensions must be non zero')
            error = True

        if self.options.cut_nr < 1:
            eff.errormsg('Error: Number of cuts should be at least 1')
            error = True

        if (self.options.central_rib_lid or self.options.central_rib_body
            ) and self.options.cut_nr % 2 == 1:
            eff.errormsg(
                'Error: Central rib is only valid with an even number of cuts')
            error = True

        if self.options.unit not in self.knownUnits:
            eff.errormsg('Error: unknown unit. ' + self.options.unit)
            error = True

        if error:
            exit()

        # convert units
        unit = self.options.unit
        H = self.svg.unittouu(str(self.options.height) + unit)
        W = self.svg.unittouu(str(self.options.width) + unit)
        D = self.svg.unittouu(str(self.options.depth) + unit)
        thickness = self.svg.unittouu(str(self.options.thickness) + unit)
        cutSpacing = self.svg.unittouu(str(self.options.cut_dist) + unit)
        cutNr = self.options.cut_nr

        doc_root = self.document.getroot()
        layer = svg.layer(doc_root, 'Elliptical Box')

        ell = Ellipse(W / 2, H / 2)

        #body and lid
        lidAngleRad = self.options.lid_angle * 2 * pi / 360
        lid_start_theta = ell.theta_at_angle(pi / 2 - lidAngleRad / 2)
        lid_end_theta = ell.theta_at_angle(pi / 2 + lidAngleRad / 2)

        lidLength = ell.dist_from_theta(lid_start_theta, lid_end_theta)
        bodyLength = ell.dist_from_theta(lid_end_theta, lid_start_theta)

        # do not put elements right at the edge of the page
        xMargin = 3
        yMargin = 3

        bottom_grp = svg.group(layer)
        top_grp = svg.group(layer)

        bodyNotches = _makeCurvedSurface(Coordinate(xMargin, yMargin),
                                         bodyLength, D, cutSpacing, cutNr,
                                         thickness, bottom_grp, False,
                                         self.options.central_rib_body)
        lidNotches = _makeCurvedSurface(Coordinate(xMargin, D + 2 * yMargin),
                                        lidLength, D, cutSpacing, cutNr,
                                        thickness, top_grp,
                                        not self.options.invert_lid_notches,
                                        self.options.central_rib_lid)

        # create elliptical sides
        sidesGrp = svg.group(layer)

        elCenter = Coordinate(xMargin + thickness + W / 2,
                              2 * D + H / 2 + thickness + 3 * yMargin)

        # indicate the division between body and lid
        p = svg.Path()
        if self.options.invert_lid_notches:
            p.move_to(elCenter + ell.coordinate_at_theta(lid_start_theta + pi),
                      True)
            p.line_to(elCenter, True)
            p.line_to(elCenter + ell.coordinate_at_theta(lid_end_theta + pi),
                      True)

        else:
            angleA = ell.theta_from_dist(lid_start_theta, lidNotches[1])
            angleB = ell.theta_from_dist(lid_start_theta, lidNotches[-2])

            p.move_to(elCenter + ell.coordinate_at_theta(angleA + pi), True)
            p.line_to(elCenter, True)
            p.line_to(elCenter + ell.coordinate_at_theta(angleB + pi), True)

        _makeNotchedEllipse(elCenter, ell, lid_end_theta, thickness,
                            bodyNotches, sidesGrp, False)
        _makeNotchedEllipse(elCenter, ell, lid_start_theta, thickness,
                            lidNotches, sidesGrp,
                            not self.options.invert_lid_notches)

        p.path(sidesGrp, greenStyle)

        # ribs
        if self.options.central_rib_lid or self.options.central_rib_body:
            innerRibCenter = Coordinate(
                xMargin + thickness + W / 2,
                2 * D + 1.5 * (H + 2 * thickness) + 4 * yMargin)
            innerRibGrp = svg.group(layer)

            outerRibCenter = Coordinate(
                2 * xMargin + 1.5 * (W + 2 * thickness),
                2 * D + 1.5 * (H + 2 * thickness) + 4 * yMargin)
            outerRibGrp = svg.group(layer)

        if self.options.central_rib_lid:
            _makeNotchedEllipse(innerRibCenter, ell, lid_start_theta,
                                thickness, lidNotches, innerRibGrp, False)
            _makeNotchedEllipse(outerRibCenter, ell, lid_start_theta,
                                thickness, lidNotches, outerRibGrp, True)

        if self.options.central_rib_body:
            spacer = Coordinate(0, 10)
            _makeNotchedEllipse(innerRibCenter + spacer, ell, lid_end_theta,
                                thickness, bodyNotches, innerRibGrp, False)
            _makeNotchedEllipse(outerRibCenter + spacer, ell, lid_end_theta,
                                thickness, bodyNotches, outerRibGrp, True)

        if self.options.central_rib_lid or self.options.central_rib_body:
            svg.text(sidesGrp, elCenter, 'side (duplicate this)')
            svg.text(innerRibGrp, innerRibCenter, 'inside rib')
            svg.text(outerRibGrp, outerRibCenter, 'outside rib')
コード例 #4
0
 def test_curvature(self):
     ell = Ellipse(20, 10)
     self.assertEqual(ell.curvature(0), 1/5, 'curvature at 0')
     self.assertEqual(ell.curvature(pi / 2), 1/40, 'curvature at 90')
     self.assertEqual(ell.curvature(pi), 1/5, 'curvature at 180')
     self.assertEqual(ell.curvature(3 * pi / 2), 1/40, 'curvature at 270')
コード例 #5
0
 def test_coordinate_at_theta(self):
     ell = Ellipse(12,8)
     self.assertEqual(ell.coordinate_at_theta(0), Coordinate(12, 0), 'coordinate at angle 0')
     self.assertTrue(Coordinate(0, 8).close_enough_to(ell.coordinate_at_theta(pi/2)), 'coordinate at angle pi/2')
     self.assertTrue(Coordinate(-12, 0).close_enough_to(ell.coordinate_at_theta(pi)), 'coordinate at angle pi')
     self.assertTrue(Coordinate(0, -8).close_enough_to(ell.coordinate_at_theta(3*pi/2)), 'coordinate at angle 3*pi/2')
コード例 #6
0
 def setUp(self):
     self.circle = Ellipse(10, 10)
コード例 #7
0
ファイル: EllipticArc.py プロジェクト: hasantahir/myinkspace
class EllipticArc(PathSegment):

    ell_dict = {}

    def __init__(self,
                 start,
                 end,
                 rx,
                 ry,
                 axis_rot,
                 pos_dir=True,
                 large_arc=False):
        self.rx = rx
        self.ry = ry
        # calculate ellipse center
        # the center is on two ellipses one with its center at the start point, the other at the end point
        # for simplicity take the  one ellipse at the origin and the other with offset (tx, ty),
        # find the center and translate back to the original offset at the end
        axis_rot *= pi / 180  # convert to radians
        # start and end are mutable objects, copy to avoid modifying them
        r_start = copy.copy(start)
        r_end = copy.copy(end)
        r_start.t -= axis_rot
        r_end.t -= axis_rot
        end_o = r_end - r_start  # offset end vector

        tx = end_o.x
        ty = end_o.y

        # some helper variables for the intersection points
        # used sympy to come up with the equations
        ff = (rx**2 * ty**2 + ry**2 * tx**2)
        cx = rx**2 * ry * tx * ty**2 + ry**3 * tx**3
        cy = rx * ty * ff
        sx = rx * ty * sqrt(4 * rx**4 * ry**2 * ty**2 - rx**4 * ty**4 +
                            4 * rx**2 * ry**4 * tx**2 -
                            2 * rx**2 * ry**2 * tx**2 * ty**2 - ry**4 * tx**4)
        sy = ry * tx * sqrt(
            -ff * (-4 * rx**2 * ry**2 + rx**2 * ty**2 + ry**2 * tx**2))

        # intersection points
        c1 = Coordinate((cx - sx) / (2 * ry * ff), (cy + sy) / (2 * rx * ff))
        c2 = Coordinate((cx + sx) / (2 * ry * ff), (cy - sy) / (2 * rx * ff))

        if end_o.cross_norm(c1 - r_start) < 0:  # c1 is to the left of end_o
            left = c1
            right = c2
        else:
            left = c2
            right = c1

        if pos_dir != large_arc:  #center should be on the left of end_o
            center_o = left
        else:  #center should be on the right of end_o
            center_o = right

        #re-use ellipses with same rx, ry to save some memory
        if (rx, ry) in self.ell_dict:
            self.ellipse = self.ell_dict[(rx, ry)]
        else:
            self.ellipse = Ellipse(rx, ry)
            self.ell_dict[(rx, ry)] = self.ellipse

        self.start = start
        self.end = end
        self.axis_rot = axis_rot
        self.pos_dir = pos_dir
        self.large_arc = large_arc
        self.start_theta = self.ellipse.theta_at_angle((-center_o).t)
        self.end_theta = self.ellipse.theta_at_angle((end_o - center_o).t)

        # translate center back to original offset
        center_o.t += axis_rot
        self.center = center_o + start

    @property
    def length(self):
        return self.ellipse.dist_from_theta(self.start_theta, self.end_theta)

    def t_to_theta(self, t):
        """convert t (always between 0 and 1) to angle theta"""
        start = self.start_theta
        end = self.end_theta

        if self.pos_dir and end < start:
            end += 2 * pi

        if not self.pos_dir and start < end:
            end -= 2 * pi
        arc_size = end - start

        return (start + (end - start) * t) % (2 * pi)

    def theta_to_t(self, theta):
        full_arc_size = (self.end_theta - self.start_theta + 2 * pi) % (2 * pi)
        theta_arc_size = (theta - self.start_theta + 2 * pi) % (2 * pi)
        return theta_arc_size / full_arc_size

    def curvature(self, t):
        theta = self.t_to_theta(t)
        return self.ellipse.curvature(theta)

    def tangent(self, t):
        theta = self.t_to_theta(t)
        return self.ellipse.tangent(theta)

    def t_at_length(self, length):
        """interpolated t where the curve is at the given length"""
        theta = self.ellipse.theta_from_dist(length, self.start_theta)
        return self.theta_to_t(theta)

    def length_at_t(self, t):
        return self.ellipse.dist_from_theta(self.start_theta,
                                            self.t_to_theta(t))

    def pathpoint_at_t(self, t):
        """pathpoint on the curve from t=0 to point at t."""
        centered = self.ellipse.coordinate_at_theta(self.t_to_theta(t))
        centered.t += self.axis_rot
        return PathPoint(t, centered + self.center, self.tangent(t),
                         self.curvature(t), self.length_at_t(t))

    # identical to Bezier code
    def subdivide(self, part_length, start_offset=0):
        nr_parts = int((self.length - start_offset) // part_length)
        k_o = start_offset / self.length
        k2t = lambda k: k_o + k * part_length / self.length
        points = [self.pathpoint_at_t(k2t(k)) for k in range(nr_parts + 1)]
        return (points, self.length - points[-1].c_dist)
コード例 #8
0
ファイル: EllipticArc.py プロジェクト: hasantahir/myinkspace
    def __init__(self,
                 start,
                 end,
                 rx,
                 ry,
                 axis_rot,
                 pos_dir=True,
                 large_arc=False):
        self.rx = rx
        self.ry = ry
        # calculate ellipse center
        # the center is on two ellipses one with its center at the start point, the other at the end point
        # for simplicity take the  one ellipse at the origin and the other with offset (tx, ty),
        # find the center and translate back to the original offset at the end
        axis_rot *= pi / 180  # convert to radians
        # start and end are mutable objects, copy to avoid modifying them
        r_start = copy.copy(start)
        r_end = copy.copy(end)
        r_start.t -= axis_rot
        r_end.t -= axis_rot
        end_o = r_end - r_start  # offset end vector

        tx = end_o.x
        ty = end_o.y

        # some helper variables for the intersection points
        # used sympy to come up with the equations
        ff = (rx**2 * ty**2 + ry**2 * tx**2)
        cx = rx**2 * ry * tx * ty**2 + ry**3 * tx**3
        cy = rx * ty * ff
        sx = rx * ty * sqrt(4 * rx**4 * ry**2 * ty**2 - rx**4 * ty**4 +
                            4 * rx**2 * ry**4 * tx**2 -
                            2 * rx**2 * ry**2 * tx**2 * ty**2 - ry**4 * tx**4)
        sy = ry * tx * sqrt(
            -ff * (-4 * rx**2 * ry**2 + rx**2 * ty**2 + ry**2 * tx**2))

        # intersection points
        c1 = Coordinate((cx - sx) / (2 * ry * ff), (cy + sy) / (2 * rx * ff))
        c2 = Coordinate((cx + sx) / (2 * ry * ff), (cy - sy) / (2 * rx * ff))

        if end_o.cross_norm(c1 - r_start) < 0:  # c1 is to the left of end_o
            left = c1
            right = c2
        else:
            left = c2
            right = c1

        if pos_dir != large_arc:  #center should be on the left of end_o
            center_o = left
        else:  #center should be on the right of end_o
            center_o = right

        #re-use ellipses with same rx, ry to save some memory
        if (rx, ry) in self.ell_dict:
            self.ellipse = self.ell_dict[(rx, ry)]
        else:
            self.ellipse = Ellipse(rx, ry)
            self.ell_dict[(rx, ry)] = self.ellipse

        self.start = start
        self.end = end
        self.axis_rot = axis_rot
        self.pos_dir = pos_dir
        self.large_arc = large_arc
        self.start_theta = self.ellipse.theta_at_angle((-center_o).t)
        self.end_theta = self.ellipse.theta_at_angle((end_o - center_o).t)

        # translate center back to original offset
        center_o.t += axis_rot
        self.center = center_o + start