本文介绍了拼图使用贝塞尔曲线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试着做一些这样的拼图。






到目前为止,我尝试使用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)
},
(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)
},

解决方案

高效拼图设计很简单, strong>



链接的代码已经展示了如何通过重用单面设计来有效地组装您的一个拼图。



插图右侧的部分是传统(或日式)部分。这意味着其侧面长度均匀并且完全互锁。日本风格的作品是最容易设计的,因为一个单一的设计代码,并在整个拼图中重复使用。



讽刺的是,虽然日本风格的谜题是最容易的代码,



如何设计日式拼图谜题 >


  1. 通过组合多个三次贝塞尔曲线设计拼图的一边(不是更多!


  2. 使用转换将一个拼图设计应用于顶部,右侧,底部或左侧。 (或自动操作原始贝塞尔控制点以将一个拼图设计应用于4个侧面的代码函数)。


  3. 通过镜像每个部分的设计来组合一个拼图相邻侧:




    • 给左上角零件(0,0)一个随机右边(inny或outy)。

    • 让我们假设piece(0,0)被分配了一个outy右侧。

    • 现在给片(1,0)一个随机的右边(inny或outy),然后下一个右边(1,0)必须得到一个左边。 piece(2,0)必须获得镜像类型的边。

    • 因此,一般来说,通过为所有作品分配随机右侧,并将下一作品左侧的分配面镜像来填充谜题。

    • 垂直操作。


填充谜题的方法是:

设计您演示的2个示例



我假设链接的代码不是您的

  //给定中心点(cx,cy)和边长
//单边outy设计低于
//使用这个单一设计(使用转换/镜像)使所有块
ctx.lineTo(cx + s * .34,cy);
ctx.bezierCurveTo(cx + s * .5,cy,cx + s * .4,cy + s * -.15,cx + s * .4,cy + s *
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);

然后,您可以重复使用这一组贝塞尔曲线以及转换来创建整个拼图。转换==移动,旋转和镜像一个单一的设计,以组成任何一侧的任何拼图。



插图左边的一块可能是从一个自由样式七巧板。它更复杂,因为它使用3种不同的侧面设计。我假设有额外的侧面设计,你没有显示,因为你显示的3面设计不会允许所有的部分互锁完成拼图。



创建Freeform Style拼图时的几个选项。


$ b
$ b

在这种风格下,你基本上图像并绘制线条,将其切割成可以被布置成形成图像的不均匀的片。想像这样一个比萨饼是随机切片。你可以把这些块放在一起来改造比萨饼,即使这些块不互锁。 Mmmmm,披萨! : - )



联锁自由样式



+侧面,创造的难题与传统风格拼图的方式相同。通常,您将创建一个将用于所有左右侧的设计,以及将用于所有顶部和底部的第二个设计。复杂性是两种类型的边必须在它们相遇的地方适合。这意味着边类型1必须共享镜像模式,其中它与边类型2相交。



因此,要设计插图左侧的部分,必须决定是否要使用互锁自由形式或非互锁自由形式。



非联锁自由形式更容易。只需拆开3种类型的侧面,并与他们的镜像合作伙伴一起使用它们来破坏你的形象。



对于Interlocking-Freeform,你需要更多的设计工作。您必须创建额外的侧面设计,与您已经创建的3个设计互锁。



这是一个快速浏览拼图游戏...祝你好运您的专案!



在你的插图的右边,常见的外面看起来像一个肩膀和头的轮廓。



Bezier-set创造肩膀&头像如下:




  • 用于左肩的Bezier

  • 左颈

  • 左脑的贝塞尔

  • 右脑袋的贝塞尔
  • b
  • 右颈的贝济耶

  • 右肩的贝济耶



head Bezier set可能如下所示:





这里有一个具体的例子来创建一个带有肩部和头部形状的外侧:

  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, 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
];

一旦你有外部曲线集,你可以使用canvas的上下文转换来翻转外进入其镜像内部。或者,您可以手动翻转曲线控制点的外部数组。



插图:顶部标签和顶部插槽是顶部标签镜像)





显示顶部标签和顶部插槽的示例:



  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  
  body {background-color :象牙} #canvas {border:1px solid red; margin:0 auto; }  
 < canvas id =canvaswidth = 300 height = 300>< / canvas>  


I was trying to make some jigsaw pieces like this -

What I have tried till now with 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)
    },

Fiddle Link

解决方案

Efficient Jigsaw design is simple and it works like this:

The linked code already shows how to efficiently assemble one of your jigsaw pieces by reusing a single side design.

The piece on the right side of you illustration is a traditional (or "Japanese Style") piece. This means its sides are uniform in length and fully interlocking. Japanese style pieces are the easiest to design because a single piece of design code and be reused throughout the puzzle.

Ironically, While Japanese Style puzzles are the easiest to code, they are more difficult for the user to solve since many pieces will physically fit together without correctly solving the puzzle.

How to design a Japanese Style jigsaw puzzle

  1. Design one side (not more!) of a jigsaw piece by combining multiple cubic Bezier curves.

  2. Use transforms to apply that one jigsaw design to the top, right, bottom or left sides as needed. (or code functions that automatically manipulate the original Bezier control points to apply that one jigsaw design to the 4 sides). Mirror the original side design to give your pieces a variety of "inny" and "outy" sides.

  3. Assemble a puzzle from pieces by mirroring the design of each neighboring side:

    • Give the top-left piece (0,0) a random right side (either inny or outy).
    • Let's assume piece (0,0) was assigned an outy right side. Then the next piece to the right (1,0) must get an inny left side.
    • Now give piece (1,0) a random right side (either inny or outy), and piece (2,0) must get the mirrored type of side. And so on...
    • So in general, fill the puzzle by assigning random right sides to all the pieces and mirroring the assigned side on the left side of the next piece.
    • Do the same vertically. fill the puzzle by assigning random bottom sides to all the pieces and mirroring the assigned side on the top side of the next piece.

Designing the 2 example pieces you've illustrated

I assume the linked code is not your code because it already shows how to design that piece on the right of your illustration(!).

// Given the center point of the piece (cx,cy) and the side length (s)
// The single side "outy" design is below
// Use this single design (with transforms/mirroring) to make all 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 you can reuse this one single set of Bezier curves along with transformations to create your entire puzzle. Transformations==moving, rotating and mirroring the one single design to make up any side of any puzzle piece.

The piece on the left of your illustration is probably from a Freeform Style jigsaw puzzle. It is more complex because it uses 3 different side designs. I assume there are additional side designs which you haven't shown because the 3-sided design you show would not allow all pieces to interlock to complete the puzzle.

You have several options when creating a Freeform Style jigsaw puzzle.

Non-interlocking Freeform Style

In this style, you basically take an image and draw lines that cut it into non-uniform pieces that can be arranged to form the image. Think of this like a pizza that's been sliced randomly. You can fit the pieces together to reform the pizza even if the pieces do not interlock. Mmmmm, pizza! :-)

Interlocking Freeform Style

In this style, you design 2+ sides and create the puzzle much the same way as the traditional style puzzle. Usually you create one design that you will use for all left-right sides and a second design that you will use for all top-bottom sides. The complexity is that the 2 types of sides must fit together where they meet. This means that side-type-1 must share a mirrored pattern where it intersects side-type-2.

So to design the piece on the left side of your illustration, you must decide if you want it to be Interlocking-Freeform or Non-interlocking-Freeform.

Non-interlocking Freeform is the easier. Just pull apart the 3 types of sides and use them with their mirrored partners to chop up your image.

For Interlocking-Freeform, more design work is necessary on your part. You must create additional side designs that will interlock with the 3 designs you've already created.

That's a quick tour of jigsaw puzzles...Good luck with your project!

[ Additional details ]

For the piece on the right side of your illustration, the common "outside" looks like a "shoulders & head" silhouette.

The Bezier-set to create the shoulders & head break down like this:

  • A Bezier for the "left shoulder"
  • A Bezier for the "left neck"
  • A Bezier for the "left head"
  • A Bezier for the "right head"
  • A Bezier for the "right neck"
  • A Bezier for the "right shoulder"

A shoulder & head Bezier set might look like this:

Here's one specific example of the control points to create an outside side with a "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 you have the "outside" set of curves, you can use canvas's context transformations to flip the "outside" into its mirrored "inside". Alternatively you can manually reverse the "outside" array of curve control points.

Illustrations: top-tab and top-slot (top-slot is top-tab mirrored)

Example displaying top-tab and 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>

这篇关于拼图使用贝塞尔曲线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-17 21:56
查看更多