i trying make jigsaw pieces -
what have tried till lineto -
outside: function (ctx, s, cx, cy) { ctx.lineto(cx, cy) ctx.lineto(cx+s*.3, cy) ctx.lineto(cx+s*.5, cy+s*-.2) ctx.lineto(cx+s*.7, cy) ctx.lineto(cx+s, cy) }, inside: function (ctx, s, cx, cy) { ctx.lineto(cx, cy) ctx.lineto(cx+s*.3, cy) ctx.lineto(cx+s*.5, cy+s*+.2) ctx.lineto(cx+s*.7, cy) ctx.lineto(cx+s, cy) },
efficient jigsaw design simple , works this:
the linked code shows how efficiently assemble 1 of jigsaw pieces reusing single side design.
the piece on right side of illustration traditional (or "japanese style") piece. means sides uniform in length , interlocking. japanese style pieces easiest design because single piece of design code , reused throughout puzzle.
ironically, while japanese style puzzles easiest code, more difficult user solve since many pieces physically fit without correctly solving puzzle.
how design japanese style jigsaw puzzle
design 1 side (not more!) of jigsaw piece combining multiple cubic bezier curves.
use transforms apply 1 jigsaw design top, right, bottom or left sides needed. (or code functions automatically manipulate original bezier control points apply 1 jigsaw design 4 sides). mirror original side design give pieces variety of "inny" , "outy" sides.
assemble puzzle pieces mirroring design of each neighboring side:
- give top-left piece (0,0) random right side (either inny or outy).
- let's assume piece (0,0) assigned outy right side. next piece right (1,0) must inny left side.
- now give piece (1,0) random right side (either inny or outy), , piece (2,0) must mirrored type of side. , on...
- so in general, fill puzzle assigning random right sides pieces , mirroring assigned side on left side of next piece.
- do same vertically. fill puzzle assigning random bottom sides pieces , mirroring assigned side on top side of next piece.
designing 2 example pieces you've illustrated
i assume linked code not code because shows how design piece on right of illustration(!).
// given center point of piece (cx,cy) , side length (s) // single side "outy" design below // use single design (with transforms/mirroring) make pieces ctx.lineto(cx + s * .34, cy); ctx.beziercurveto(cx + s * .5, cy, cx + s * .4, cy + s * -.15, cx + s * .4, cy + s * -.15); ctx.beziercurveto(cx + s * .3, cy + s * -.3, cx + s * .5, cy + s * -.3, cx + s * .5, cy + s * -.3); ctx.beziercurveto(cx + s * .7, cy + s * -.3, cx + s * .6, cy + s * -.15, cx + s * .6, cy + s * -.15); ctx.beziercurveto(cx + s * .5, cy, cx + s * .65, cy, cx + s * .65, cy); ctx.lineto(cx + s, cy);
then can reuse 1 single set of bezier curves along transformations create entire puzzle. transformations==moving, rotating , mirroring 1 single design make side of puzzle piece.
the piece on left of illustration freeform style jigsaw puzzle. more complex because uses 3 different side designs. assume there additional side designs haven't shown because 3-sided design show not allow pieces interlock complete puzzle.
you have several options when creating freeform style jigsaw puzzle.
non-interlocking freeform style
in style, take image , draw lines cut non-uniform pieces can arranged form image. think of pizza that's been sliced randomly. can fit pieces reform pizza if pieces not interlock. mmmmm, pizza! :-)
interlocking freeform style
in style, design 2+ sides , create puzzle same way traditional style puzzle. create 1 design use left-right sides , second design use top-bottom sides. complexity 2 types of sides must fit meet. means side-type-1 must share mirrored pattern intersects side-type-2.
so design piece on left side of illustration, must decide if want interlocking-freeform or non-interlocking-freeform.
non-interlocking freeform easier. pull apart 3 types of sides , use them mirrored partners chop image.
for interlocking-freeform, more design work necessary on part. must create additional side designs interlock 3 designs you've created.
that's quick tour of jigsaw puzzles...good luck project!
[ additional details ]
for piece on right side of illustration, common "outside" looks "shoulders & head" silhouette.
the bezier-set create shoulders & head break down this:
- a bezier "left shoulder"
- a bezier "left neck"
- a bezier "left head"
- a bezier "right head"
- a bezier "right neck"
- a bezier "right shoulder"
a shoulder & head bezier set might this:
here's 1 specific example of control points create outside side "shoulders & head" shape:
var shouldersandheadcubicbeziercontrolpoints=[ {cx1:0, cy1:0, cx2:35,cy2:15, ex:37, ey:5}, // left shoulder {cx1:37, cy1:5, cx2:40,cy2:0, ex:38, ey:-5}, // left neck {cx1:38, cy1:-5, cx2:20,cy2:-20,ex:50, ey:-20}, // left head {cx1:50, cy1:-20,cx2:80,cy2:-20,ex:62, ey:-5}, // right head {cx1:62, cy1:-5, cx2:60,cy2:0, ex:63, ey:5}, // right neck {cx1:63, cy1:5, cx2:65,cy2:15, ex:100,ey:0}, // right shoulder ];
once have "outside" set of curves, can use canvas's context transformations flip "outside" mirrored "inside". alternatively can manually reverse "outside" array of curve control points.
illustrations: top-tab , top-slot (top-slot top-tab mirrored)
example displaying top-tab , top-slot:
var canvas=document.getelementbyid("canvas"); var ctx=canvas.getcontext("2d"); var cw=canvas.width; var ch=canvas.height; function reoffset(){ var bb=canvas.getboundingclientrect(); offsetx=bb.left; offsety=bb.top; } var offsetx,offsety; reoffset(); window.onscroll=function(e){ reoffset(); } ctx.linewidth=3; var colors=['red','green','blue','gold','purple','cyan']; var bset=makebeziers(); draw(bset,50,100); var bsetmirrored=mirror(bset,1,-1,0,0); draw(bsetmirrored,50,200); function draw(bset,transx,transy){ ctx.translate(transx,transy); ctx.scale(2,2); for(var i=0;i<bset.length;i++){ var b=bset[i]; ctx.beginpath(); ctx.beziercurveto(b.cx1,b.cy1,b.cx2,b.cy2,b.ex,b.ey); ctx.strokestyle=colors[i]; ctx.stroke(); } ctx.settransform(1,0,0,1,0,0); } function makebeziers(){ return([ {cx1:0, cy1:0, cx2:35,cy2:15, ex:37, ey:5}, // left shoulder {cx1:37, cy1:5, cx2:40,cy2:0, ex:38, ey:-5}, // left neck {cx1:38, cy1:-5, cx2:20,cy2:-20,ex:50, ey:-20}, // left head {cx1:50, cy1:-20,cx2:80,cy2:-20,ex:62, ey:-5}, // right head {cx1:62, cy1:-5, cx2:60,cy2:0, ex:63, ey:5}, // right neck {cx1:63, cy1:5, cx2:65,cy2:15, ex:100,ey:0}, // right shoulder ]); } function mirror(b,signx,signy,x,y){ var a=[]; for(var i=0;i<b.length;i++){ var bb=b[i]; a.push({ cx1: bb.cx1*signx+x, cy1: bb.cy1*signy+y, cx2: bb.cx2*signx+x, cy2: bb.cy2*signy+y, ex: bb.ex*signx+x, ey: bb.ey*signy+y }); } return(a); }
body{ background-color: ivory; } #canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>
Comments
Post a Comment