在两条直线之间画弧线 & 通过两个点画曲线。

3

框架: fabricjs

我的第一个问题是如何在两条线之间画角度。我的代码可以运行,但我对结果不满意。

我的第二个问题是在两个点之间画一条曲线。

关于第一个问题的代码。 我有三个点: A,B,C

2条线: AB,BC

利用这些信息,我计算出距离为10的距离点。

let angle = this.calcAngle(A,B,C);
let distanceAB  = this.calcCornerPoint(A, B, 10);
let distanceBC = this.calcCornerPoint(C, B, 10);

计算角度:

  calcAngle(A, B, C, final, finalAddon = "°") {

    var nx1 = A.x - B.x;
    var ny1 = A.y - B.y;
    var nx2 = C.x - B.x;
    var ny2 = C.y - B.y;

    this.lineAngle1 = Math.atan2(ny1, nx1);
    this.lineAngle2 = Math.atan2(ny2, nx2);

    if (nx1 * ny2 - ny1 * nx2 < 0) { 
      const t = lineAngle2;
      this.lineAngle2 = this.lineAngle1;
      this.lineAngle1 = t;
    }

    // if angle 1 is behind then move ahead
    if (lineAngle1 < lineAngle2) {
      this.lineAngle1 += Math.PI * 2;
    }

  }

使用以下步骤绘制路径:

this.drawAngleTrapez(distanceAB, distanceBC, B);

drawAngleTrapez(AB, BC, B) {
    let points = [AB, BC, B];
    let path = "";
    if (this.trapezObjs[this.iterator]) {
      this.canvas.remove(this.trapezObjs[this.iterator]);
    }
    path += "M " + Math.round(points[0].x) + " " + Math.round(points[0].y) + "";
    for (let i = 1; i < points.length; i++) {
      path += " L " + Math.round(points[i].x) + " " + Math.round(points[i].y) + "";
    }

    this.currentTrapez = this.trapezObjs[this.iterator] = new fabric.Path(path, {
      selectable: false,
      hasControls: false,
      hasBorders: false,
      hoverCursor: 'default',
      fill: '#ccc',
      strokeWidth: this.strokeWidth,
    });
    this.canvas.add(this.trapezObjs[this.iterator]);
  }

然后我画了一个圆形:
drawAnglePoint(B,d = 10) {
    this.currentCorner = new fabric.Circle({
      left: B.x,
      top: B.y,
      startAngle: this.lineAngle1,
      endAngle: this.lineAngle2,
      radius: 10,
      fill: '#ccc',
      selectable: false,
      hasControls: false,
      hasBorders: false,
      hoverCursor: 'default',
    });
    this.canvas.add(this.currentCorner);
  }

但是结果并不美观:

输入图像描述

并且蓝点不在线的末端,或许还需要一些修正。

this.startPoint.set({ left: C.x, top: C.y });

第二个问题已解决:我的计算有误。
问题是,这不是一个漂亮的曲线: enter image description here

在第一个问题中,"the result is not beautiful" 的确切意思是什么?您能否更好地描述一下您的期望? Translated text: 在第一个问题中,“the result is not beautiful”的确切含义是什么?您能否更好地描述一下您的期望? - Freeman Lambda
在两个对象之间添加空格。 - joe69
1个回答

0

不要将中心的“楔形”绘制为两个形状 - 三角形和部分圆形,而应该将其绘制为它所代表的双面图形。

圆是通过提供原点来绘制的。因此,要在线的末端绘制蓝色点,您应该为线段的末点指定与圆心相同的坐标。

以下代码将重新创建您的第一张图像,但不包括文本。虽然我已经透明地绘制了扫描角度指示器,放在了线条上方,但您可能想要更改绘制顺序、颜色和不透明度。

(I used 0x88/0xFF = 136/255 = 53.3%),

"use strict";
function newEl(tag){return document.createElement(tag)}
function byId(id){return document.getElementById(id)}

class vec2
{
 constructor(x,y){this.x = x;this.y = y;}
 get x(){ return this._x; }
 set x(newVal){ this._x = newVal; }
 get y(){ return this._y; }
 set y(newVal){ this._y = newVal; }
 get length(){return Math.hypot(this.x,this.y);}
 set length(len){var invLen = len/this.length; this.timesEquals(invLen);}
 add(other){return new vec2(this.x+other.x, this.y+other.y);}
 sub(other){return new vec2(this.x-other.x, this.y-other.y);}
 plusEquals(other){this.x+=other.x;this.y+=other.y;return this;}
 minusEquals(other){this.x-=other.x;this.y-=other.y;return this;}
 timesEquals(scalar){this.x*=scalar;this.y*=scalar;return this;}
 divByEquals(scalar){this.x/=scalar;this.y/=scalar;return this;}
 setTo(other){this.x=other.x;this.y=other.y;}
 toString(){return `vec2 {x: ${this.x}, y: ${this.y}}` }
 toStringN(n){ return `vec2 {x: ${this.x.toFixed(n)}, y: ${this.y.toFixed(n)}}` }
 dotProd(other){return this.x*other.x + this.y*other.y;}
 timesEquals(scalar){this.x *= scalar;this.y *= scalar;return this;}
 normalize(){let len = this.length;this.x /= len;this.y /= len;return this;}
 static clone(other){let result = new vec2(other.x, other.y);return result;}
 clone(){return vec2.clone(this);}
};

window.addEventListener('load', onWindowLoaded, false);

function onWindowLoaded(evt)
{
 var can = byId('output');
 let A = new vec2(172,602), B = new vec2(734,602), C = new vec2(847,194);
 myTest(can, [A,B,C]);
}

function circle(canvas, x, y, radius)
{
 let ctx = canvas.getContext('2d');
 ctx.moveTo(x,y);
 ctx.beginPath();
 ctx.ellipse(x,y, radius,radius, 0, 0, 2*Math.PI);
 ctx.closePath();
 ctx.fill();
}

function getAngle(origin, pt)
{
 let delta = pt.sub(origin);
 let angle = Math.atan2( delta.y, delta.x );
 return angle;
}

function myTest(canvas, points)
{
 let ctx = canvas.getContext('2d');
 
 // background colour
 //
 ctx.fillStyle = '#ebedf0';
 ctx.fillRect(0,0,canvas.width,canvas.height);

 
 // white square grid
 //
 //60,33 = intersection of first
 //115 = square-size
 ctx.strokeStyle = '#FFFFFF';
 ctx.lineWidth = 12;
 for (let x=60; x<canvas.width; x+=112)
 {
  ctx.beginPath();
  ctx.moveTo(x, 0);
  ctx.lineTo(x, canvas.height);
  ctx.stroke();
  ctx.closePath();
 }
 for (let y=33; y<canvas.height; y+=112)
 {
  ctx.beginPath();
  ctx.moveTo(0, y);
  ctx.lineTo(canvas.width, y);
  ctx.stroke();
  ctx.closePath();
 }
 
 
 // wedge indicating swept angle
 let angle1 = getAngle(points[1], points[2]);
 let angle2 = getAngle(points[1], points[0]);
 ctx.beginPath();
 ctx.moveTo(points[1].x,points[1].y);
 ctx.arc(points[1].x,points[1].y, 70, angle1,angle2, true);
 ctx.fillStyle = '#cccccc88';
 ctx.fill();
 console.log(angle1, angle2);

 // lines
 //
 ctx.lineWidth = 9;
 ctx.strokeStyle = '#c3874c';
 ctx.beginPath();
 ctx.moveTo(points[0].x, points[0].y);
 ctx.lineTo(points[1].x, points[1].y);
 ctx.lineTo(points[2].x, points[2].y);
 ctx.stroke();
 ctx.closePath();

 // points
 //
 ctx.fillStyle = '#3b89c9';
 ctx.beginPath();
 points.forEach( function(pt){circle(canvas, pt.x,pt.y, 10);} );
 ctx.closePath();
}
canvas
{
 zoom: 67%;
}
<canvas id='output' width='996' height='730'></canvas>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接