
Задача: Определить количество общих точек двух отрезков: нуль, одна или бесконечное множество.
Описание работы программы:
По щелчку левой кнопки мыши считываются координаты четырех точек (концов отрезков AB и CD) и, переведенные из экранной системы координат в декартову, добавляются в массив points. Для уменьшения количества проверок координаты сортируются таким образом, чтобы A была левее B, а C левее D.
После этого запускается функция draw, отрисовывающая отрезки и их концы. В случае, если пользователь щелкнул на одну и ту же точку дважды, на экран выводится сообщение о том, что отрезок вырожденный.
Затем запускается функция chek, подробное описание работы которой можно увидеть в комментариях в коде.
Для вычисления косого произведения векторов используется функция PseudoScalar.
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>Количесвто общих точек двух отрезков</title> <canvas id="canvas" width="500" height="500" style="border: 1px solid grey"></canvas> <script> var x, y; let points = []; //массив для хранения точек A, B, C, D var canvas = document.getElementById("canvas"); var ctx = canvas.getContext('2d'); //по нажатию левой кнопки мыши ставятся точки: window.onload=function(){ canvas.addEventListener('click', (e) => { //заполняем массив точками с декартовыми координатами: if (points.length < 4) points.push({x: e.pageX - 250, y: 250 - e.pageY}); //делаем А всегда левее В и С всегда левее D для уменьшения количества проверок: if (points.length === 4) { if (points[0].x > points[1].x) [points[0], points[1]] = [points[1], points[0]]; if (points[2].x > points[3].x) [points[2], points[3]] = [points[3], points[2]]; if (points[0].x === points[1].x && points[0].y > points[1].y) [points[0], points[1]] = [points[1], points[0]]; if (points[2].x === points[3].x && points[2].y > points[3].y) [points[2], points[3]] = [points[3], points[2]]; } draw(); }); } function draw() { ctx.strokeStyle = "#000"; ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, 500, 500); ctx.fillStyle = "#000"; //отрисовка точек (возврат к экранной системе координат): for (var i = 0; i < points.length; i++) { ctx.beginPath(); ctx.arc(250 + points[i].x, 250 - points[i].y, 2, 0, 2*Math.PI, false); ctx.stroke(); ctx.fill(); } //при щелчке мышью в одном и том же месте: if (points.length > 1) { if (points.length === 2 && points[0].x === points[1].x && points[0].y === points[1].y) { alert("Вы построили вырожденный отрезок. После перезагрузки страницы попробуйте еще раз."); } //отрисовка отрезка АВ (возврат к экранной системе координат): else { ctx.beginPath(); ctx.moveTo(250 + points[0].x, 250 - points[0].y); ctx.lineTo(250 + points[1].x, 250 - points[1].y); ctx.stroke(); ctx.closePath(); } } //при щелчке мышью в одном и том же месте: if (points.length > 3) { if (points.length === 4 && points[2].x === points[3].x && points[2].y === points[3].y) { alert("Вы построили вырожденный отрезок. После перезагрузки страницы попробуйте еще раз."); } //отрисовка отрезка CD (возврат к экранной системе координат): else { ctx.beginPath(); ctx.moveTo(250 + points[2].x, 250 - points[2].y); ctx.lineTo(250 + points[3].x, 250 - points[3].y); ctx.stroke(); ctx.closePath(); check(); } } } function check() { console.log(points); //считаем определители, полученные из условия равенства уравнений прямых, содержащих наши отрезки, для проверки их пересечения/наложения: var det = (points[1].x - points[0].x) * (points[2].y - points[3].y) - (points[2].x - points[3].x) * (points[1].y - points[0].y); var detl = (points[2].x - points[0].x) * (points[2].y - points[3].y) - (points[2].y - points[0].y) * (points[2].x - points[3].x); var detm = (points[1].x - points[0].x) * (points[2].y - points[0].y) - (points[1].y - points[0].y) * (points[2].x - points[0].x); var X, Y; //случай, когда отрезки имеют общий конец (A=D): if (points[0].x === points[3].x && points[0].y === points[3].y) { alert('Отрезки имеют одну общую точку ('+points[0].x+'; '+points[0].y+')'); } //случай, когда отрезки имеют общий конец (В=С): else if (points[1].x === points[2].x && points[1].y === points[2].y) { alert('Отрезки имеют одну общую точку ('+points[1].x+'; '+points[1].y+')'); } else { if (det === 0) { if (detl === 0 && detm === 0) { //случай равенства всех определителей нулю означает расположение отрезков на одной прямой (они либо имеют общий сегмент, либо не имеют общих точек). if (points[0].x === points[1].x) { if ((points[0].y < points[2].y && points[2].y < points[1].y) || (points[2].y < points[0].y && points[0].y < points[3].y) || (points[0].y === points[2].y || points[1].y === points[3].y)) { alert('Отрезки имеют бесконечное множество общих точек'); } } else if ((points[0].x < points[2].x && points[2].x < points[1].x) || (points[2].x < points[0].x && points[0].x < points[3].x) || (points[0].x === points[2].x || points[1].x === points[3].x)) { alert('Отрезки имеют бесконечное множество общих точек'); } else alert('Отрезки не имеют общих точек'); } else alert('Отрезки не имеют общих точек'); } //случай, когда концы отрезка АВ расположены по разные стороны от отрезка CD и концы отрезка CD расположены по разные стороны от отрезка АВ (пересечение): else if (Math.sign(PseudoScalar(points[2], points[3], points[2], points[0])) != Math.sign(PseudoScalar(points[2], points[3], points[2], points[1])) && Math.sign(PseudoScalar(points[0], points[1], points[0], points[3])) != Math.sign(PseudoScalar(points[0], points[1], points[0], points[2]))) { //вычисление координат точки пересечения: X = points[0].x + (detl / det) * (points[1].x - points[0].x); Y = points[0].y + (detl / det) * (points[1].y - points[0].y); alert('Отрезки имеют одну общую точку ('+X+'; '+Y+')'); } else alert('Отрезки не имеют общих точек'); } } //функция для вычисления косого произведения векторов АВ и CD: function PseudoScalar(A, B, C, D) { return (B.x - A.x) * (D.y - C.y) - (D.x - C.x) * (B.y - A.y); } </script> </head> <body> </body> </html>
Прикрепленный файл | Размер |
---|---|
memetova_common_points_source.zip | 2.2 кб |