繪製三角形的外接圓和內接圓

已知,三角形的三個頂點座標,求三角形的外接圓和內接圓。
三角形有重心,垂心,內心,外心,旁心。
外心即外接圓的圓心,是三角形三邊垂直平分線的交點
繪製外接圓相對簡單一點,

已知,兩條直線方程的一般式:

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>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章