Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ KAD - Keyboard Automated Design

KAD is the SVG CAD engine which powers the mechanical keyboard CAD generation site [builder.swillkb.com](http://builder.swillkb.com/). If you are going to use this library, you should probably review the documentation site for the published builder in order to understand what all the different features are. The documentation site is available and kept up to date at [builder-docs.swillkb.com](http://builder-docs.swillkb.com/).

KAD is a Golang library to aid in the design of mechanical keyboard plates and cases. The keyboard layout uses the standard format developed by the [www.keyboard-layout-editor.com](http://www.keyboard-layout-editor.com/) project. KAD is designed to produce SVG files which can be taken to a laser or water cutting fabrication shop to be cut. KAD supports a huge number of features, including but not limited it; 4 switch types, 4 stabilizer types, 3 case types, rounded corners, padding, mount holes, usb cutouts, etc...
KAD is a Golang library to aid in the design of mechanical keyboard plates and cases. The keyboard layout uses the standard format developed by the [www.keyboard-layout-editor.com](http://www.keyboard-layout-editor.com/) project. KAD is designed to produce SVG files which can be taken to a laser or water cutting fabrication shop to be cut. KAD supports a huge number of features, including but not limited it; 4 switch types, 5 stabilizer types, 3 case types, rounded corners, padding, mount holes, usb cutouts, etc...


## Get Started
Expand Down
165 changes: 155 additions & 10 deletions key.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ import (
)

const (
SWITCHMX = 1
SWITCHMXALPS = 2
SWITCHMXH = 3
SWITCHALPS = 4
STABREMOVE = 0
STABCHERRYCOSTAR = 1
STABCHERRY = 2
STABCOSTAR = 3
STABALPS = 4
SWITCHMX = 1
SWITCHMXALPS = 2
SWITCHMXH = 3
SWITCHALPS = 4
STABREMOVE = 0
STABCHERRYCOSTAR = 1
STABCHERRY = 2
STABCOSTAR = 3
STABALPS = 4
STABKAILHCHOCSOCKETED = 5
STABKAILHCHOCSEATED = 6
)

type Key struct {
Expand Down Expand Up @@ -95,13 +97,38 @@ func GetAlpsStabOffset(size float64) (float64, error) {
}
}

func GetKailhChocStabOffset(size float64) (float64, error) {
switch size {
case 1.75: // 1.75u
return 11.975, nil
case 2.0: // 2.0u
return 11.975, nil
case 2.25: // 2.25u
return 11.975, nil
case 2.50: // 2.5u
return 11.975, nil
case 2.75: // 2.75u
return 11.975, nil
case 5.5: // 5.5u
return 37.95, nil
case 5.75: // 5.75u
return 37.95, nil
case 6: // 6u
return 37.95, nil
case 6.25: // 6.25u
return 37.95, nil
default:
return 0, errors.New(fmt.Sprintf("No kailh choc stabilizer offset defined for a %fu key.", size))
}
}

// Draw an individual switch/stabilizer opening.
func (key *Key) Draw(k *KAD, c Point, ctx Key, init bool) {
// set the key defaults and update items like kerf to the functional value
if !in_ints(key.Type, []int{SWITCHMX, SWITCHMXALPS, SWITCHMXH, SWITCHALPS}) {
key.Type = k.SwitchType
}
if !in_ints(key.Stab, []int{STABREMOVE, STABCHERRYCOSTAR, STABCHERRY, STABCOSTAR, STABALPS}) {
if !in_ints(key.Stab, []int{STABREMOVE, STABCHERRYCOSTAR, STABCHERRY, STABCOSTAR, STABALPS, STABKAILHCHOCSOCKETED}) {
key.Stab = k.StabType
}
if key.Kerf != 0 {
Expand Down Expand Up @@ -220,6 +247,10 @@ func (key *Key) Draw(k *KAD, c Point, ctx Key, init bool) {
key.DrawCostarStab(k, c, ctx, vertical, flip_stab)
case STABALPS:
key.DrawAlpsStab(k, c, ctx, vertical, flip_stab)
case STABKAILHCHOCSOCKETED: // kailh choc stabiliser full cutout for placing into switchplate
key.DrawKailhChocSocketedStab(k, c, ctx, vertical, flip_stab)
case STABKAILHCHOCSEATED: // kailh choc stabiliser partial cutout for placing on top of switchplate.
key.DrawKailhChocSeatedStab(k, c, ctx, vertical, flip_stab)
}

if key.Width == 6 || (vertical && key.Height == 6) { // adjust for offcenter stem switch
Expand Down Expand Up @@ -406,3 +437,117 @@ func (key *Key) DrawAlpsStab(k *KAD, c Point, ctx Key, vertical, flip_stab bool)
key.DrawCostarStab(k, c, ctx, vertical, flip_stab)
}
}

// draw the Kailh Choc stabilizer socketed into the switch plate
func (key *Key) DrawKailhChocSocketedStab(k *KAD, c Point, ctx Key, vertical, flip_stab bool) {
// special case where 'union' will never be applied, so 'stab_path' is not used
var stab_path_l Path
var stab_path_r Path
size := key.Width
if vertical {
size = key.Height
}

s, err := GetKailhChocStabOffset(size)

// if we don't know the offset, abort as no other shapes will fit our stabiliser properly
if err != nil {
return
}

// kerf is an additional amount to allow for when drawing lines
// kerf operator is the inverse of the preceeding number (- for +number, + for -number)
// points are x,y relative the center point of the key shape. S is used to modify that for left and right
stab_path_l = Path{
{-s - 3.15 + key.Kerf, 2.3 - key.Kerf}, {-s + 3.15 - key.Kerf, 2.3 - key.Kerf},
{-s + 3.15 - key.Kerf, -4.3 + key.Kerf}, {-s + 1.55 - key.Kerf, -4.3 + key.Kerf},
{-s + 1.55 - key.Kerf, -7.6 + key.Kerf}, {-s - 1.55 + key.Kerf, -7.6 + key.Kerf},
{-s - 1.55 + key.Kerf, -4.3 + key.Kerf}, {-s - 3.15 + key.Kerf, -4.3 + key.Kerf},
}

stab_path_r = Path{
{s - 3.15 + key.Kerf, 2.3 - key.Kerf}, {s + 3.15 - key.Kerf, 2.3 - key.Kerf},
{s + 3.15 - key.Kerf, -4.3 + key.Kerf}, {s + 1.55 - key.Kerf, -4.3 + key.Kerf},
{s + 1.55 - key.Kerf, -7.6 + key.Kerf}, {s - 1.55 + key.Kerf, -7.6 + key.Kerf},
{s - 1.55 + key.Kerf, -4.3 + key.Kerf}, {s - 3.15 + key.Kerf, -4.3 + key.Kerf},
}
if vertical {
stab_path_l.RotatePath(90, Point{0, 0})
stab_path_r.RotatePath(90, Point{0, 0})
}
if flip_stab {
stab_path_l.RotatePath(180, Point{0, 0})
stab_path_r.RotatePath(180, Point{0, 0})
}
if key.RotateStab != 0 {
stab_path_l.RotatePath(key.RotateStab, Point{0, 0})
stab_path_r.RotatePath(key.RotateStab, Point{0, 0})
}
// draw each shape relative to the given origin point
stab_path_l.Rel(c)
stab_path_r.Rel(c)
if ctx.RotateCluster != 0 {
stab_path_l.RotatePath(ctx.RotateCluster, Point{ctx.Xabs*k.U1 + k.DMZ + k.LeftPad, ctx.Yabs*k.U1 + k.DMZ + k.TopPad})
stab_path_r.RotatePath(ctx.RotateCluster, Point{ctx.Xabs*k.U1 + k.DMZ + k.LeftPad, ctx.Yabs*k.U1 + k.DMZ + k.TopPad})
}
// add the created shapes to the visible layers to be cut
k.Layers[SWITCHLAYER].CutPolys = append(k.Layers[SWITCHLAYER].CutPolys, stab_path_l)
k.Layers[SWITCHLAYER].CutPolys = append(k.Layers[SWITCHLAYER].CutPolys, stab_path_r)
}

// draw the Kailh Choc stabilizer seated on top of the switchplate
func (key *Key) DrawKailhChocSeatedStab(k *KAD, c Point, ctx Key, vertical, flip_stab bool) {
// special case where 'union' will never be applied, so 'stab_path' is not used
var stab_path_l Path
var stab_path_r Path
size := key.Width
if vertical {
size = key.Height
}

s, err := GetKailhChocStabOffset(size)

// if we don't know the offset, abort as no other shapes will fit our stabiliser properly
if err != nil {
return
}

// kerf is an additional amount to allow for when drawing lines
// kerf operator is the inverse of the preceeding number (- for +number, + for -number)
// points are x,y relative the center point of the key shape. S is used to modify that for left and right
stab_path_l = Path{
{-s - 2.35 + key.Kerf, 2.35 - key.Kerf}, {-s + 2.35 - key.Kerf, 2.35 - key.Kerf},
{-s + 2.35 - key.Kerf, -2.65 + key.Kerf}, {-s + 1.60 - key.Kerf, -2.65 + key.Kerf},
{-s + 1.60 - key.Kerf, -8.85 + key.Kerf}, {-s - 1.60 + key.Kerf, -8.85 + key.Kerf},
{-s - 1.60 + key.Kerf, -2.65 + key.Kerf}, {-s - 2.35 + key.Kerf, -2.65 + key.Kerf},
}

stab_path_r = Path{
{s - 2.35 + key.Kerf, 2.35 - key.Kerf}, {s + 2.35 - key.Kerf, 2.35 - key.Kerf},
{s + 2.35 - key.Kerf, -2.65 + key.Kerf}, {s + 1.60 - key.Kerf, -2.65 + key.Kerf},
{s + 1.60 - key.Kerf, -8.85 + key.Kerf}, {s - 1.60 + key.Kerf, -8.85 + key.Kerf},
{s - 1.60 + key.Kerf, -2.65 + key.Kerf}, {s - 2.35 + key.Kerf, -2.65 + key.Kerf},
}
if vertical {
stab_path_l.RotatePath(90, Point{0, 0})
stab_path_r.RotatePath(90, Point{0, 0})
}
if flip_stab {
stab_path_l.RotatePath(180, Point{0, 0})
stab_path_r.RotatePath(180, Point{0, 0})
}
if key.RotateStab != 0 {
stab_path_l.RotatePath(key.RotateStab, Point{0, 0})
stab_path_r.RotatePath(key.RotateStab, Point{0, 0})
}
// draw each shape relative to the given origin point
stab_path_l.Rel(c)
stab_path_r.Rel(c)
if ctx.RotateCluster != 0 {
stab_path_l.RotatePath(ctx.RotateCluster, Point{ctx.Xabs*k.U1 + k.DMZ + k.LeftPad, ctx.Yabs*k.U1 + k.DMZ + k.TopPad})
stab_path_r.RotatePath(ctx.RotateCluster, Point{ctx.Xabs*k.U1 + k.DMZ + k.LeftPad, ctx.Yabs*k.U1 + k.DMZ + k.TopPad})
}
// add the created shapes to the visible layers to be cut
k.Layers[SWITCHLAYER].CutPolys = append(k.Layers[SWITCHLAYER].CutPolys, stab_path_l)
k.Layers[SWITCHLAYER].CutPolys = append(k.Layers[SWITCHLAYER].CutPolys, stab_path_r)
}
31 changes: 31 additions & 0 deletions test/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,34 @@ func TestStabAlpsSize(t *testing.T) {
return
}
}

func TestStabKailhChocSize(t *testing.T) {
json_str := `{
"layout":[
[{"w":2},"", {"w":6.25},""]
]}`

cad := kad.New()

// populate the kad object with the request POST json, oh and get the hash...
decoder := json.NewDecoder(strings.NewReader(json_str))
err := decoder.Decode(cad)
if err != nil {
t.Errorf("TestStabKailhChocSize: failed to parse json data into KAD file")
return
}

cad.Hash = "stab_kailh_choc_size"
cad.FileStore = kad.STORE_LOCAL
cad.FileDirectory = "./output/"
cad.FileServePath = "/test/output/"

cad.SwitchType = kad.SWITCHMX
cad.StabType = kad.STABKAILHCHOCSOCKETED

err = cad.Draw()
if err != nil {
t.Errorf("TestStabKailhChocSize: failed to Draw the KAD file")
return
}
}
28 changes: 11 additions & 17 deletions test/output/stab_alps_size_switch.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading