def midLineExtended(self):
     line = self.midLine
     maxxp = max(self.treble.end.x, self.bass.start.x)
     minxp = min(self.treble.start.x, self.bass.end.x)
     return linexy(
         lineIntersection(linexy(vxy(maxxp, 0), vxy(maxxp, 1)), line).point,
         lineIntersection(linexy(vxy(minxp, 0), vxy(minxp, 1)), line).point
     )
예제 #2
0
 def calc_virt_frame():
     # String spread
     spread = (inst.bridge.stringDistanceProj - inst.nut.stringDistanceProj) / 2.0
     # Bass string length from nut to bridge (include nut offset before zero fret)
     length = inst.scale.max + inst.nut.offset
     # Side angle
     angle = math.asin(spread / length)
     bass = line(vxy(0, 0), vxy(-length, 0)).rotate(-angle)
     bass.translateTo(bass.lerpPointAt(-inst.nut.offset))
     bridge = line(bass.end, vxy(0, - inst.bridge.stringDistanceProj))
     treble = line(bridge.end, vxy(length, 0)).rotate(angle)
     nut = lineTo(treble.end, bass.start)
     return FretboardBox(bass, treble, nut, bridge)
예제 #3
0
def lineIntersection(line1, line2):
    # ! Credits: justin_c_rounds https://stackoverflow.com/a/60368757/1524027
    # if the lines intersect, the result contains the x and y of the intersection
    # (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
    result = Intersection()
    denominator = ((line2.end.y - line2.start.y) *
                   (line1.end.x - line1.start.x)) - (
                       (line2.end.x - line2.start.x) *
                       (line1.end.y - line1.start.y))
    if denominator == 0:
        return result

    a = line1.start.y - line2.start.y
    b = line1.start.x - line2.start.x
    numerator1 = ((line2.end.x - line2.start.x) * a) - (
        (line2.end.y - line2.start.y) * b)
    numerator2 = ((line1.end.x - line1.start.x) * a) - (
        (line1.end.y - line1.start.y) * b)
    a = numerator1 / denominator
    b = numerator2 / denominator

    # if we cast these lines infinitely in both directions, they intersect here:
    result.point = vxy(line1.start.x + (a * (line1.end.x - line1.start.x)),
                       line1.start.y + (a * (line1.end.y - line1.start.y)))

    # if line1 is a segment and line2 is infinite, they intersect if:
    if 0 < a < 1:
        result.onLine1 = True

    # if line2 is a segment and line1 is infinite, they intersect if:
    if 0 < b < 1:
        result.onLine2 = True

    # if line1 and line2 are segments, they intersect if both of the above are true
    return result
예제 #4
0
    def calc_neck_frame():
        x = max(frame.bass.start.x, frame.treble.end.x)
        perp = linexy(vxy(x, 0), vxy(x, 1))
        p = lineIntersection(frame.bass, perp)
        q = lineIntersection(frame.treble, perp)
        nut = linexy(p.point, q.point)

        if inst.neck.joint is NeckJoint.THROUHG:
            x = min(frame.bass.end.x, frame.treble.start.x) - inst.body.length
        else:
            x = min(frame.bass.end.x, frame.treble.start.x)
        perp = linexy(vxy(x, 0), vxy(x, 1))
        p = lineIntersection(frame.bass, perp)
        q = lineIntersection(frame.treble, perp)
        bridge = linexy(q.point, p.point)

        bass = linexy(bridge.end.clone(), nut.start.clone())
        treble = linexy(nut.end.clone(), bridge.start.clone())
        return FretboardBox(bass, treble, nut, bridge)
예제 #5
0
    def calc_fretboard_frame():

        # Bass include nut and margin
        bassRef = lineTo(fret0.start, frets[1].start)
        s = bassRef.lerpPointAt(-inst.nut.offset - inst.nut.thickness - inst.fretboard.startMargin)
        e = lineFrom(fretz.start, bassRef.vector, inst.fretboard.endMargin).end
        bass = lineTo(s, e)

        # Treble
        trebRef = lineTo(fret0.end, frets[1].end)
        if (inst.nut.position is NutPosition.PARALLEL):
            s = trebRef.lerpPointAt(-inst.nut.offset - inst.nut.thickness - inst.fretboard.startMargin)
            e = lineFrom(fretz.end, trebRef.vector, inst.fretboard.endMargin).end
            treble = lineTo(e, s)
        else:
            """if inst.nut.position is NutPosition.PERPENDICULAR"""
            tmp = lineFrom(bass.start, vxy(0, -1), 100)
            i = lineIntersection(tmp, trebRef).point or trebRef.lerpPointAt(
                -inst.nut.offset - inst.nut.thickness - inst.fretboard.startMargin)
            e = lineFrom(fretz.end, trebRef.vector, inst.fretboard.endMargin).end
            treble = lineTo(e, i)

        # Custom cut
        if (inst.fretboard.cut is FretboardCut.CUSTOM):
            bass = bass.lerpLineTo(inst.fretboard.cutBassDistance)
            treble = treble.cloneInverted().lerpLineTo(inst.fretboard.cutTrebleDistance).cloneInverted()
        elif (inst.fretboard.cut is FretboardCut.PERPENDICULAR):
            if (inst.fretboard.cutBassDistance):
                bass = bass.lerpLineTo(inst.fretboard.cutBassDistance)
            tmp = lineFrom(bass.end, vxy(0, -1), 100)
            i = lineIntersection(tmp, treble)
            if (i.point):
                treble = lineTo(i.point, treble.end)

        bridge = lineTo(bass.end, treble.start)
        nut = lineTo(treble.end, bass.start)
        return FretboardBox(bass, treble, nut, bridge)
예제 #6
0
def makeTenon(fbd, neckAngleRad, posXY, h, tenonThickness, tenonLength,
              tenonOffset, joint):
    if tenonThickness > 0 \
        and tenonLength > 0 \
            and joint is NeckJoint.SETIN:

        naLineDir = linexy(vxy(0, 0),
                           angleVxy(math.pi + neckAngleRad, tenonLength))
        naAp = geom.vecxz(naLineDir.start)
        naBp = geom.vecxz(naLineDir.end)
        refp = geom.vec(posXY, tenonOffset - h + tenonThickness)
        naSidePs = [
            naAp,
            Vector(naAp.x, naAp.y, naAp.z - tenonThickness),
            Vector(naBp.x, naBp.y, naBp.z - tenonThickness), naBp, naAp
        ]
        naSidePs = [v.add(refp) for v in naSidePs]
        naSide = Part.Face(Part.makePolygon(naSidePs)).extrude(
            Vector(0, fbd.neckFrame.bridge.length, 0))
        return naSide
예제 #7
0
def buildFretboardData(inst):
    """
    Create Fretboard reference constructions
    """

    # Virtual String Frame (String projection)
    def calc_virt_frame():
        # String spread
        spread = (inst.bridge.stringDistanceProj - inst.nut.stringDistanceProj) / 2.0
        # Bass string length from nut to bridge (include nut offset before zero fret)
        length = inst.scale.max + inst.nut.offset
        # Side angle
        angle = math.asin(spread / length)
        bass = line(vxy(0, 0), vxy(-length, 0)).rotate(-angle)
        bass.translateTo(bass.lerpPointAt(-inst.nut.offset))
        bridge = line(bass.end, vxy(0, - inst.bridge.stringDistanceProj))
        treble = line(bridge.end, vxy(length, 0)).rotate(angle)
        nut = lineTo(treble.end, bass.start)
        return FretboardBox(bass, treble, nut, bridge)

    virtStrFrame = calc_virt_frame()

    # Scale Frame
    def calc_scale_frame():
        s = virtStrFrame.bass.lerpPointAt(inst.nut.offset)
        bass = lineTo(s, virtStrFrame.bass.end)
        bassPF = fret(inst.fretboard.perpendicularFret, inst.scale.bass)
        trebPF = fret(inst.fretboard.perpendicularFret, inst.scale.treble)
        scaleOffset = bassPF - trebPF
        vtreb = virtStrFrame.treble.cloneInverted()
        nut = lineTo(vtreb.lerpPointAt(scaleOffset + inst.nut.offset), bass.start)
        treble = lineTo(vtreb.lerpPointAt(scaleOffset + inst.nut.offset + inst.scale.treble), nut.start)
        bridge = lineTo(bass.end, treble.start)
        return FretboardBox(bass, treble, nut, bridge)

    scaleFrame = calc_scale_frame()
    bassSideMargin = inst.fretboard.sideMargin + inst.stringSet.last / 2.0
    trebSideMargin = inst.fretboard.sideMargin + inst.stringSet.first / 2.0

    # Frets
    def calc_frets():
        frets = []
        vtreb = scaleFrame.treble.cloneInverted()
        for i in range(inst.fretboard.frets + 1):
            s = fret(i, inst.scale.bass)
            e = fret(i, inst.scale.treble)
            ps = scaleFrame.bass.lerpPointAt(s)
            pe = vtreb.lerpPointAt(e)
            bfret = lineTo(ps, pe)
            bassMargin = bassSideMargin / math.sin(-bfret.vector.angle())
            trebleMargin = trebSideMargin / math.sin(-bfret.vector.angle())
            ps = bfret.lerpPointAt(-bassMargin)
            pe = bfret.lerpPointAt(bfret.vector.length + bassMargin + trebleMargin)
            frets.append(lineTo(ps, pe))
        return frets

    frets = calc_frets()
    fret0 = frets[0]
    fretz = frets[-1]

    # Fretboard Frame
    def calc_fretboard_frame():

        # Bass include nut and margin
        bassRef = lineTo(fret0.start, frets[1].start)
        s = bassRef.lerpPointAt(-inst.nut.offset - inst.nut.thickness - inst.fretboard.startMargin)
        e = lineFrom(fretz.start, bassRef.vector, inst.fretboard.endMargin).end
        bass = lineTo(s, e)

        # Treble
        trebRef = lineTo(fret0.end, frets[1].end)
        if (inst.nut.position is NutPosition.PARALLEL):
            s = trebRef.lerpPointAt(-inst.nut.offset - inst.nut.thickness - inst.fretboard.startMargin)
            e = lineFrom(fretz.end, trebRef.vector, inst.fretboard.endMargin).end
            treble = lineTo(e, s)
        else:
            """if inst.nut.position is NutPosition.PERPENDICULAR"""
            tmp = lineFrom(bass.start, vxy(0, -1), 100)
            i = lineIntersection(tmp, trebRef).point or trebRef.lerpPointAt(
                -inst.nut.offset - inst.nut.thickness - inst.fretboard.startMargin)
            e = lineFrom(fretz.end, trebRef.vector, inst.fretboard.endMargin).end
            treble = lineTo(e, i)

        # Custom cut
        if (inst.fretboard.cut is FretboardCut.CUSTOM):
            bass = bass.lerpLineTo(inst.fretboard.cutBassDistance)
            treble = treble.cloneInverted().lerpLineTo(inst.fretboard.cutTrebleDistance).cloneInverted()
        elif (inst.fretboard.cut is FretboardCut.PERPENDICULAR):
            if (inst.fretboard.cutBassDistance):
                bass = bass.lerpLineTo(inst.fretboard.cutBassDistance)
            tmp = lineFrom(bass.end, vxy(0, -1), 100)
            i = lineIntersection(tmp, treble)
            if (i.point):
                treble = lineTo(i.point, treble.end)

        bridge = lineTo(bass.end, treble.start)
        nut = lineTo(treble.end, bass.start)
        return FretboardBox(bass, treble, nut, bridge)

    frame = calc_fretboard_frame()

    # Nut Frame
    def calc_nut_frame():
        vtreb = frame.treble.cloneInverted()
        s = frame.bass.lerpPointAt(inst.fretboard.startMargin)
        bass = lineFrom(s, frame.bass.vector, inst.nut.thickness)
        s = vtreb.lerpPointAt(inst.fretboard.startMargin)
        treble = lineFrom(s, vtreb.vector, inst.nut.thickness).flipDirection()
        return FretboardBox(bass, treble, lineTo(treble.end, bass.start), lineTo(bass.end, treble.start))

    nutFrame = calc_nut_frame()

    # Adjust ScaleFrame ans virtStrFrame (Center in Fretboard)
    def adjust_scale_frame():
        diff = frets[0].mid().sub(scaleFrame.nut.mid())
        return (scaleFrame.translate(diff), virtStrFrame.translate(diff))

    (scaleFrame, virtStrFrame) = adjust_scale_frame()

    # Bridge position line with compensation
    def cal_bridge_pos():
        a = scaleFrame.treble.lerpPointAt(-inst.bridge.trebleCompensation)
        b = scaleFrame.bass.lerpPointAt(scaleFrame.bass.length + inst.bridge.bassCompensation)
        return linexy(a, b)

    bridgePos = cal_bridge_pos()

    # Neck Frame
    def calc_neck_frame():
        x = max(frame.bass.start.x, frame.treble.end.x)
        perp = linexy(vxy(x, 0), vxy(x, 1))
        p = lineIntersection(frame.bass, perp)
        q = lineIntersection(frame.treble, perp)
        nut = linexy(p.point, q.point)

        if inst.neck.joint is NeckJoint.THROUHG:
            x = min(frame.bass.end.x, frame.treble.start.x) - inst.body.length
        else:
            x = min(frame.bass.end.x, frame.treble.start.x)
        perp = linexy(vxy(x, 0), vxy(x, 1))
        p = lineIntersection(frame.bass, perp)
        q = lineIntersection(frame.treble, perp)
        bridge = linexy(q.point, p.point)

        bass = linexy(bridge.end.clone(), nut.start.clone())
        treble = linexy(nut.end.clone(), bridge.start.clone())
        return FretboardBox(bass, treble, nut, bridge)

    neckFrame = calc_neck_frame()

    fbd = FretboardData(frame, virtStrFrame, scaleFrame, nutFrame, frets, bridgePos, neckFrame)
    fbd = fbd.translate(vxy(0, 0).sub(neckFrame.nut.mid()))

    return fbd
예제 #8
0
def makeHeel(neckd, line, angle, joint, backThickness, topThickness, topOffset,
             neckPocketDepth, neckPocketLength, jointFret, transitionLength,
             transitionTension, bodyLength, tenonThickness, tenonLength,
             tenonOffset, forPocket):
    """
    Create heel shape.

    Args:
        fbd   : FredboardData
        line  : linexy, reference line
    """
    fbd = neckd.fbd
    neckAngleRad = deg(angle)
    if joint is NeckJoint.THROUHG:
        h = backThickness + topThickness + topOffset
    else:
        h = neckPocketDepth + topOffset

    if forPocket:
        jointFret = 0

    start_p = lineIntersection(fbd.frets[jointFret], line).point
    start_d = linexy(line.start, start_p).length

    # Curved Part
    if not forPocket:
        transitionJob = Task.execute(heelTransition, neckd, line, start_d, h,
                                     transitionLength, transitionTension)

    xperp = line.lerpLineTo(
        start_d + transitionLength).perpendicularCounterClockwiseEnd()
    a = lineIntersection(xperp, fbd.neckFrame.treble).point
    b = lineIntersection(xperp, fbd.neckFrame.bass).point
    c = fbd.neckFrame.bridge.end
    d = fbd.neckFrame.bridge.start

    # Rect Part
    def heelBase():
        segments = [
            Part.LineSegment(geom.vec(b), geom.vec(c)),
            Part.LineSegment(geom.vec(c), geom.vec(d)),
            Part.LineSegment(geom.vec(d), geom.vec(a)),
            Part.LineSegment(geom.vec(a), geom.vec(b)),
        ]
        part = Part.Face(Part.Wire(Part.Shape(segments).Edges)).extrude(
            Vector(0, 0, -100))
        return part

    partJob = Task.execute(heelBase)

    if not forPocket:
        transition = transitionJob.get()
    else:
        transition = None

    part = partJob.get()

    if transition:
        part = transition.fuse(part)

    # Neck Angle Cut (Bottom)
    extrusionDepth = 100
    lengthDelta = max(neckPocketLength,
                      (fbd.neckFrame.midLine.length -
                       start_d))  #- inst.neck.transitionLength/2
    naLineDir = linexy(vxy(0, 0), angleVxy(neckAngleRad, lengthDelta))
    naLineDir = naLineDir.flipDirection().lerpLineTo(naLineDir.length +
                                                     30).flipDirection()
    naAp = geom.vecxz(naLineDir.start)
    naBp = geom.vecxz(naLineDir.end)
    refp = geom.vec(fbd.frame.bridge.end,
                    -h).add(Vector(0, -fbd.neckFrame.bridge.length / 2, 0))

    if joint is NeckJoint.THROUHG:
        refp = refp.add(
            Vector(-bodyLength * math.cos(neckAngleRad), 0,
                   -bodyLength * math.sin(neckAngleRad)))

    naSidePs = [
        naAp,
        Vector(naAp.x, naAp.y, naAp.z - extrusionDepth),
        Vector(naBp.x, naBp.y, naBp.z - extrusionDepth), naBp, naAp
    ]
    naSidePs = [v.add(refp) for v in naSidePs]
    naSide = Part.Face(Part.makePolygon(naSidePs)).extrude(
        Vector(0, fbd.neckFrame.bridge.length * 2, 0))

    # Cut bottom
    part = part.cut(naSide)

    # Then move and cut top (Remove Top thickness)
    cutThickness = extrusionDepth * math.cos(neckAngleRad)
    naSide.translate(
        Vector((backThickness + cutThickness) * math.sin(neckAngleRad), 0,
               (backThickness + cutThickness) * math.cos(neckAngleRad)))
    naSide.translate(
        Vector((bodyLength - lengthDelta) * math.cos(neckAngleRad), 0,
               (bodyLength - lengthDelta) * math.sin(neckAngleRad)))

    part = part.cut(naSide)

    # Tenon
    tenon = makeTenon(fbd, neckAngleRad, d, h,
                      tenonThickness + 100 if forPocket else tenonThickness,
                      tenonLength, tenonOffset, joint)
    if tenon:
        part = part.fuse(tenon)

    return part.removeSplitter()
예제 #9
0
 def lerp(self, alpha):
     return vxy().lerpVectors(self.v1, self.v2, alpha)
예제 #10
0
 def vector(self):
     return vxy().subVectors(self.v2, self.v1)
예제 #11
0
def line(start, vector):
    return linexy(start.clone(), vxy().addVectors(start, vector))