绘制三角形的外接圆和内接圆

已知,三角形的三个顶点坐标,求三角形的外接圆和内接圆。
三角形有重心,垂心,内心,外心,旁心。
外心即外接圆的圆心,是三角形三边垂直平分线的交点
绘制外接圆相对简单一点,

已知,两条直线方程的一般式:

a1 * x + b1 * y + c1 = 0
a2 * x + b2 * y + c2 = 0

则,交点坐标为

x = (b2 * c1 - b1 * c2) / (a2 * b1 - a1 * b2) (1)
y = (a1 * c2 - a2 * c1) / (a2 * b1 - a1 * b2) (2)

如果是两条直线方程的点斜式:

(y - y1) / (x - x1) = k1
(y - y2) / (x - x2) = k2

先把点斜式转为一般式,可得,

a1 = k1, b1 = -1, c1 = y1 - k1 * x1
a2 = k2, b2 = -1, c2 = y2 - k2 * x2

代入(1),(2) 得到,

x = (y2 - k2 * x2 - y1 + k1 * x1) / (k1 - k2)				(3)
y = (k1 * y2 - k2 * y1 - k1 * k2 * (x2 - x1)) / (k1 - k2)	(4)

有了公式(3)和(4), 就很好找到外心的坐标了。三角形边的中点坐标很容易得到吧。一条的斜率也很好得到。
设三角形,三个点的坐标为A(x1, y1), B (x2, y2), C (x3, y3)
边AB的中点坐标为( (x1 + x2)/2, (y1 + y2)/2 ), 斜率为 (y2 - y1) / (x2 - x1),
边AB的法线与AB垂直,法线的斜率为 (x1 - x2) / (y2 - y1)
外接圆的半径为圆心到顶点的距离

内心即内接圆的圆心,是三角形三角角平分线的交点,找内心的坐标相对麻烦,关键在于如找到角平分线的斜率,找到斜率后就可以应用点斜式, 公式(3)和(4) 得到内心的坐标

角平分线的斜率,可以这样来找到,比如求A角的角平分线斜率,先找到向量(A到B)与x轴的夹角,再找到
向量(A到C)与x轴的夹角,两个夹角的和除以2 就是角平分线与x轴的夹角

内接圆的半径需要用到,点到直线的距离公式:
公式描述:公式中的直线方程为Ax+By+C=0,点P的坐标为(x0,y0)。
公式描述:公式中的直线方程为Ax+By+C=0,点P的坐标为(x0,y0)。

代码说明:
function getAngleWithX_axis(v1, v2)
v1到v2的向量与x轴的夹角,返回的角度是弧度制
用反余弦函数来求夹角,因为用反余弦函数实现起来,逻辑最清晰简单,只需要判断v2.y >= v1.y

function getMiddleSlope(a, b, c)
返回角cba的角平分线的斜率, 返回的角度是弧度制

function getCrossPoint(k1, v1, k2, v2)
已知,两条直线方程的点斜率式,得到它们的交点坐标,公式(3)和(4) 的应用

function getPointToLineDistance(p, start, end)
已知,直线上的两个点start和end,线外的一点p, 返回点p到直线的距离

<html><head><title>Incircle and circumcircle</title>

</head><body><div>
	<canvas id="canvas" width="600" height="450" style="border: solid black 1px; cursor: default;"></canvas>
</div>
<div>
	<input type="button" value="clear" onclick="demo.clear();">
	<input type="button" value="generate" onclick="demo.generate(1);">
</div>

<script type="text/javascript">

function getRandom(min, max) {
  	var d = max - min;
  	return min + Math.random() * d;
}

function getDistance(v1, v2) {
	var dx = v2.x - v1.x;
	var dy = v2.y - v1.y;
	return Math.sqrt(dx * dx + dy * dy);
}

function getAngleWithX_axis(v1, v2) {
	var distance = getDistance(v1, v2);
	var dx = v2.x - v1.x;
	var cosA = dx / distance;
	if (v2.y >= v1.y) {
		return Math.acos(cosA);
	} else {
		return 2 * Math.PI - Math.acos(cosA);
	}
}

function getMiddleSlope(a, b, c) {
	var a1 = getAngleWithX_axis(b, a);
	var a2 = getAngleWithX_axis(b, c);
	var a3 = (a1 + a2) / 2;
	return Math.tan(a3);
}

function getCrossPoint(k1, v1, k2, v2) {
	var cross_x = (v2.y - k2 * v2.x - v1.y + k1 * v1.x) / (k1 - k2);
	var cross_y = (k1 * v2.y - k2 * v1.y - k1 * k2 * (v2.x - v1.x)) / (k1 - k2);
	return new Vertex(cross_x, cross_y);
}

function getPointToLineDistance(p, start, end) {
	var a = end.y - start.y;
	var b = start.x - end.x;
	var c = end.x * start.y - start.x * end.y;
	var d = Math.abs(a * p.x + b * p.y + c) / Math.sqrt(a*a + b*b);
	return d;
}

function Demo() {
    var vertices = [];
	var circumcircleCenter;
	var circumcircleRadius;

	var incircleCenter;
	var incircleRadius;
	var barycenter;

    this.generate = function(n) {
		var v1 = new Vertex(getRandom(100, 200), getRandom(100, 400));
		var v2 = new Vertex(getRandom(200, 400), getRandom(100, 400));
		var v3 = new Vertex(getRandom(150, 350), getRandom(100, 400));
		vertices.push(v1, v2, v3);
		// var kv1 = (v1.y - v2.y) / (v1.x - v2.x);
		// var kv2 = (v2.y - v3.y) / (v2.x - v3.x);
		var k12 = (v2.x - v1.x) / (v1.y - v2.y);
		var k23 = (v3.x - v2.x) / (v2.y - v3.y);
		var m12 = new Vertex((v1.x + v2.x)/2, (v1.y + v2.y)/2);
		var m23 = new Vertex((v2.x + v3.x)/2, (v2.y + v3.y)/2);
		// var circumcircle_x = (m23.y - k23 * m23.x - m12.y + k12 * m12.x) / (k12 - k23);
		// var circumcircle_y = (k12 * m23.y - k23 * m12.y - k12 * k23 * (m23.x - m12.x)) / (k12 - k23);
		// circumcircleCenter = new Vertex(circumcircle_x, circumcircle_y);
		circumcircleCenter = getCrossPoint(k12, m12, k23, m23);
		circumcircleRadius = getDistance(circumcircleCenter, v1);

		var k213_m = getMiddleSlope(v2, v1, v3);
		var k123_m = getMiddleSlope(v1, v2, v3);
		incircleCenter = getCrossPoint(k213_m, v1, k123_m, v2);
		incircleRadius = getPointToLineDistance(incircleCenter, v1, v2);

		var centroid = new Vertex(0,0);
		centroid.x = (v1.x + v2.x + v3.x)/3;
		centroid.y = (v1.y + v2.y + v3.y)/3;
		var a123 = getAngleWithX_axis(v1, m23);
		var a312 = getAngleWithX_axis(v3, m12);
		var k123 = Math.tan(a123), k312 = Math.tan(a312);
		barycenter = getCrossPoint(k123, v1, k312, v3);
		console.log("centroid: " + centroid + ", barycenter: " + barycenter + ", incircleCenter: " + incircleCenter);

		this.render();
		vertices = [];
    };

    this.clear = function() {
      vertices = [];
      this.render();
    }

// function render() {
    this.render = function() {
    	var canvas = document.getElementById('canvas');
	    if (!canvas.getContext)
	    	return;
	    var context = canvas.getContext('2d');
	    context.clearRect(0, 0, Number(canvas.width), Number(canvas.height));
	    if (vertices.length <= 0) {
	    	return;
	    }
	    vertices.forEach(function(vertex) {
	    	context.beginPath();
			context.arc(vertex.x, vertex.y, 5, 0, Math.PI * 2, true);
			context.closePath();

			context.fillStyle = "#0000ff";
			context.fill();
      	});

		context.beginPath();
		context.moveTo(vertices[0].x, vertices[0].y);
      	for (var i = 1; i < vertices.length; i++) {
      		context.lineTo(vertices[i].x, vertices[i].y);
      	}
      	context.lineTo(vertices[0].x, vertices[0].y);
      	context.closePath();
        context.strokeStyle = "#ff0000";
        context.stroke();

        //draw circumcircle
        drawCircle(context, circumcircleCenter, circumcircleRadius, "#006600");

        //draw incircle
        drawCircle(context, incircleCenter, incircleRadius, "#990066");
    }
  };

  function drawCircle(ctx, center, radius, centerColor) {
  	ctx.beginPath();
	ctx.arc(center.x, center.y, 5, 0, Math.PI * 2, true);
	ctx.closePath();
	ctx.fillStyle = centerColor;
	ctx.fill();
	ctx.beginPath();
  	ctx.arc(center.x, center.y, radius, 0, Math.PI * 2, true);
  	ctx.closePath();
  	ctx.strokeStyle = "#ff0000";
    ctx.stroke();
  }

  function Vertex(x, y) {
	    this.x = x;
	    this.y = y;
	}
  
  var demo = new Demo();

  window.onload = function() {
    document.getElementById("canvas").onclick = function(e) {
      e = e ? e : window.event;
      var rect = this.getBoundingClientRect();
      demo.addAt(e.clientX - rect.left, e.clientY - rect.top);
    }
  };

</script>

</body></html>

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值