示例#1
0
def _makeNotchedEllipse(center, ellipse, start_theta, thickness, notches,
                        parent, invertNotches):
    start_theta += pi  # rotate 180 degrees to put the lid on the topside

    ell_radius = Coordinate(ellipse.x_radius, ellipse.y_radius)
    ell_radius_t = ell_radius + Coordinate(thickness, thickness)

    theta = ellipse.theta_from_dist(start_theta, notches[0])
    ell_point = center + ellipse.coordinate_at_theta(theta)
    prev_offset = ellipse.tangent(theta) * thickness

    p = svg.Path()
    p.move_to(ell_point, absolute=True)

    for n in range(len(notches) - 1):
        theta = ellipse.theta_from_dist(start_theta, notches[n + 1])
        ell_point = center + ellipse.coordinate_at_theta(theta)
        notch_offset = ellipse.tangent(theta) * thickness
        notch_point = ell_point + notch_offset

        if (n % 2 == 0) != invertNotches:
            p.arc_to(ell_radius, ell_point, absolute=True)
            prev_offset = notch_offset

        else:
            p.line_to(prev_offset)
            p.arc_to(ell_radius_t, notch_point, absolute=True)
            p.line_to(-notch_offset)

    p.path(parent)
示例#2
0
 def test_t_to_theta(self):
     #arc = EllipticArc(C10_0, C0_10, 10, 10, 45) # quarter circle, axis rotated by 45 degree
     s = Coordinate(20, 0)
     s.t += pi / 4
     e = Coordinate(0, 10)
     e.t += pi / 4
     #arc = EllipticArc(C10_0, C0_10, 10, 10, 45) # quarter circle, axis rotated by 45 degree
     arc = EllipticArc(s, e, 20, 10,
                       45)  # quarter circle, axis rotated by 45 degree
     self.assertEqual(arc.t_to_theta(0), 0)
     self.assertEqual(arc.t_to_theta(1), pi / 2)
     self.assertEqual(arc.t_to_theta(0.5), pi / 4)
示例#3
0
    def test_real_world(self):
        rx, ry = 136.87567000000001, 46.467018000000003
        rot_deg = 11.8225
        c1 = Coordinate(400.32499000000001, 546.23693000000003)
        c2 = Coordinate(256.83267000000001, 563.67507999999998)
        c3 = Coordinate(132.38073, 490.15062999999998)
        c4 = Coordinate(275.87304, 472.71246000000002)

        center = Coordinate(300, 400)
        x = 200
        y = 100
        rot_deg = 3
        rot_rad = rot_deg * pi / 180
        right = Coordinate(x, 0)
        top = Coordinate(0, y)
        left = Coordinate(-x, 0)
        bottom = Coordinate(0, -y)
        right.t += rot_rad
        top.t += rot_rad
        left.t += rot_rad
        bottom.t += rot_rad

        self.rw_tests(right, top, left, bottom, x, y, rot_deg, True)
        self.rw_tests(right, bottom, left, top, x, y, rot_deg, False)
示例#4
0
def _makeCurvedSurface(topLeft,
                       w,
                       h,
                       cutSpacing,
                       hCutCount,
                       thickness,
                       parent,
                       invertNotches=False,
                       centralRib=False):
    width = Coordinate(w, 0)
    height = Coordinate(0, h)
    wCutCount = int(floor(w / cutSpacing))
    if wCutCount % 2 == 0:
        wCutCount += 1  # make sure we have an odd number of cuts
    xCutDist = w / wCutCount
    xSpacing = Coordinate(xCutDist, 0)
    ySpacing = Coordinate(0, cutSpacing)
    cut = height / hCutCount - ySpacing
    plateThickness = Coordinate(0, thickness)
    notchEdges = []
    topHCuts = []
    bottomHCuts = []

    p = svg.Path()

    for cutIndex in range(wCutCount):
        if (cutIndex % 2 == 1) != invertNotches:  # make a notch here
            inset = plateThickness
        else:
            inset = Coordinate(0, 0)

        # A-column of cuts
        aColStart = topLeft + xSpacing * cutIndex
        notchEdges.append((aColStart - topLeft).x)

        if cutIndex > 0:  # no cuts at x == 0
            p.move_to(aColStart, True)
            p.line_to(cut / 2)

            for j in range(hCutCount - 1):
                pos = aColStart + cut / 2 + ySpacing + (cut + ySpacing) * j
                p.move_to(pos, True)
                p.line_to(cut)

            p.move_to(aColStart + height - cut / 2, True)
            p.line_to(cut / 2)

        # B-column of cuts, offset by half the cut length; these cuts run in the opposite direction
        bColStart = topLeft + xSpacing * cutIndex + xSpacing / 2
        for j in reversed(range(hCutCount)):
            end = bColStart + ySpacing / 2 + (cut + ySpacing) * j
            start = end + cut
            if centralRib and hCutCount % 2 == 0 and cutIndex % 2 == 1:
                holeTopLeft = start + (ySpacing - plateThickness -
                                       xSpacing) / 2
                if j == hCutCount // 2 - 1:
                    start -= plateThickness / 2
                    p.move_to(holeTopLeft + plateThickness + xSpacing, True)
                    p.line_to(-xSpacing)

                    p.move_to(holeTopLeft, True)
                    p.line_to(xSpacing)

                elif j == hCutCount // 2:
                    end += plateThickness / 2
            if j == 0:  # first row
                end += inset
            elif j == hCutCount - 1:  # last row
                start -= inset
            p.move_to(start, True)
            p.line_to(end, True)

        #horizontal cuts (should be done last)
        topHCuts.append((aColStart + inset, aColStart + inset + xSpacing))
        bottomHCuts.append((aColStart + height - inset,
                            aColStart + height - inset + xSpacing))

    # draw the outline
    for c in reversed(bottomHCuts):
        p.move_to(c[1], True)
        p.line_to(c[0], True)

    p.move_to(topLeft + height, True)
    p.line_to(-height)

    for c in topHCuts:
        p.move_to(c[0], True)
        p.line_to(c[1], True)

    p.move_to(topLeft + width, True)
    p.line_to(height)

    group = svg.group(parent)
    p.path(group)

    notchEdges.append(w)
    return notchEdges
示例#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 __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
示例#7
0
 def test_pathpoint_at_t(self):
     arc = EllipticArc(C10_0, Coordinate(-10, 0), 10, 20, 0)
     self.assertTrue(
         arc.pathpoint_at_t(0.5).coord.close_enough_to(Coordinate(0, 20)),
         'coordinate at 90')
     self.assertAlmostEqual(arc.tangent(0.5).t, pi / 2)
示例#8
0
 def test_eq(self):
     self.assertEqual(Coordinate(1, 2), Coordinate(1, 2))
示例#9
0
import unittest

from inkscape_helper.Effect import Effect
from inkscape_helper.EllipticArc import EllipticArc
from inkscape_helper.Coordinate import Coordinate

from math import pi

C00 = Coordinate(0, 0)
C20_0 = Coordinate(20, 0)
C0_10 = Coordinate(0, 10)
C10_0 = Coordinate(10, 0)
C20_10 = Coordinate(20, 10)


def between(mid, end1, end2):
    small = min(end1, end2)
    large = max(end1, end2)
    return small < mid < large


class TestEllipticArc(unittest.TestCase, Effect):
    def test_elliptic_arc_center(self):
        arc = EllipticArc(C20_0, C0_10, 20, 10, 0)
        self.assertTrue(arc.center.close_enough_to(C00), 'ellipse center')
        large_arc = EllipticArc(C20_0, C0_10, 20, 10, 0, large_arc=True)
        self.assertEqual(large_arc.center, C20_10, 'ellipse center large arc')
        neg_arc = EllipticArc(C20_0, C0_10, 20, 10, 0, pos_dir=False)
        self.assertEqual(neg_arc.center, C20_10, 'ellipse center neg dir')

    def test_t_to_theta(self):
示例#10
0
 def coordinate_at_theta(self, theta):
     """Coordinate of the point at theta."""
     return Coordinate(self.x_radius * cos(theta),
                       self.y_radius * sin(theta))
示例#11
0
 def tangent(self, theta):
     angle = self.theta_at_angle(theta)
     return Coordinate(cos(angle), sin(angle))
示例#12
0
 def test_div(self):
     quot = C11 / 2
     self.assertEqual(quot, Coordinate(.5, .5))
示例#13
0
 def test_rmul(self):
     prod = 2 * C11
     self.assertEqual(prod, Coordinate(2, 2))
示例#14
0
 def test_mul(self):
     prod = C11 * 2
     self.assertEqual(prod, Coordinate(2, 2))
示例#15
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')
示例#16
0
import unittest

from inkscape_helper.Effect import Effect
from inkscape_helper.PathSegment import PathSegment
from inkscape_helper.BezierCurve import BezierCurve
from inkscape_helper.Line import Line
from inkscape_helper.Coordinate import Coordinate

from math import sqrt

C00 = Coordinate(0, 0)
C10 = Coordinate(1, 0)
C01 = Coordinate(0, 1)
C11 = Coordinate(1, 1)

class TestPathSegment(unittest.TestCase, Effect):
    #def setUp(self):

    def test_quadratic_bezier(self):
        quadratic = BezierCurve([C10, C11, C01])
        self.assertEqual(quadratic.pathpoint_at_t(0).coord, C10, 'start point')
        self.assertEqual(quadratic.pathpoint_at_t(1).coord, C01, 'end point')

    def test_cubic_bezier(self):
        cubic = BezierCurve([C10, C11, C00, C01])
        self.assertEqual(cubic.pathpoint_at_t(0).coord, C10, 'start point')
        self.assertEqual(cubic.pathpoint_at_t(1).coord, C01, 'end point')

    def test_bezier_length(self):
        line = BezierCurve([C00, C10, C10 * 2])
        self.assertEqual(line.pathpoint_at_t(0.5).coord, C10, 'midpoint by t')
示例#17
0
 def setUp(self):
     self.CX = Coordinate(1, 0)
     self.CY = Coordinate(0, 1)