Вход

Просмотр полной версии : Области Вороного


cyber
04.12.2012, 21:44
В этой статье http://noregret.org/tutor/n/collision/#2.2 описаны Области Вороного , но как их реализовать не могу найти, может кто подскажет?
Нужно для того что бы определить к какой части многоугольника окружность находиться ближе или проще говоря в какую часть блока летит шарик.

schmetterling
05.12.2012, 10:24
Берём для примера прямоугольник. Дальше мы считаем его проекцию на Ох. Она делит эту ось координат на три части: от минус бесконечности до начала проекции, от начала проекции до конца проекции, от конца проекции до плюс бесконечности. Обозначим их, для примера, -1, 0, 1. После этого мы проверяем, какой из частей принадлежит координата X центра окружности. Тоже самое делаем с осью Oy. Итого у нас получается девять возможных комбинаций. В зависимости от каждой из этих комбинаций мы берём нужную точку прямоугольника.

schmetterling
05.12.2012, 10:55
Вот примерный код, хотя я не тестировал его.



function distance(x1, y1, x2, y2) { // считаем расстояние между двумя точками
return Math.sqrt(Math.power((x2-x1), 2) + Math.power((y2-y1), 2))
}

/*
Проверка на столкновение.
x1, y1 -- координаты левой верхней точки прямоугольника.
x2, y2 -- координаты правой нижней точки прямоугольника.
x, y -- координаты центра окружности
r -- радиус окружности.
*/
function isCollision(x1, y1, x2, y2, x, y, r) {
var compX, compY;
// выбираем точку X прямоугольника, которая ближе всего к центру окружности.
if (x <= x1) { // если X центра слева от проекции на Ox...
compX= x1;
} else if (x < x2) { // ...принадлежит проекции
compX= x;
} else { // ...справа от проекции
compX= x2;
}
// выбираем точку Y прямоугольника, которая ближе всего к центру окружности.
if (y <= y1) { // если y центра слева от проекции на Oy...
compY= y1;
} else if (y < y2) { // ...принадлежит проекции
compY= y;
} else { // ...справа от проекции
compY= y2;
}
return r <= distance(x, y, compX, compY);
}

cyber
05.12.2012, 14:35
schmetterling, спасибо, буду разбираться)

schmetterling
05.12.2012, 16:34
schmetterling, спасибо, буду разбираться)

Не за что, удачи)

cyber
06.12.2012, 18:42
schmetterling, сразу поверхностно глянул на код , а теперь сел дальше мучатся со своим арканоидом, и понял что ваш код в общем работает так же как и мой)
вот из тестового варианта
(y <= Bl_bottom && y >= block.y - ball.R) && (x >= block.x - ball.R && x <= Bl_right)
код ниже это просто черновик


<!DOCTYPE HTML>
<html>
<head> </head>
<body>
<canvas width="500" height="500"></canvas>
<script>

var canva = document.body.children[0];

var ctx = canva.getContext("2d");

var ball = {

x:20,
y:280,
R:20,

Draw: function (x, y) {

ctx.clearRect(this.x - this.R, this.y - this.R, this.R *2,this.R *2);

ctx.beginPath();
ctx.fillStyle = "red";
ctx.arc(x,y, this.R,0, (Math.PI / 180)* 360, false);
ctx.fill();

this.y = y;
this.x = x;
}


};

var block = {


width:150,
height:30,

Draw: function (x, y) {

ctx.beginPath();
ctx.fillStyle = "green";
ctx.fillRect(x,y,this.width, this.height);
this.y = y;
this.x = x;
}


};

block.Draw(150,100);

var valX = -10 , valY = -10;
var Bl_bottom = block.y + block.height + ball.R ;
var Bl_right = block.x + block.width + ball.R ;
var one = false;

function action(){

if(ball.x < 0 + ball.R || ball.x > canva.width - ball.R){

valX = -valX;


};

if(ball.y < 0 + ball.R || ball.y > canva.height - ball.R){

valY = -valY;
//y = canva.height - ball.R;

}


var x = ball.x;
var y = ball.y ;


if((y <= Bl_bottom && y >= block.y - ball.R) && (x >= block.x - ball.R && x <= Bl_right)){

if(!one) drawOs(x,y);

if(!one){// запускаем еще один мячик
ball.x = 200;
ball.y = 200;
action();
one = true;
}



return;
};

x += valX;
y += valY;

ball.Draw(x,y);




setTimeout(action,1000/60);
};

action();


function drawOs(x,y){
ctx.beginPath();

ctx.moveTo(block.x - ball.R ,Bl_bottom);
ctx.lineTo(x,y);
ctx.stroke();

ctx.beginPath();
ctx.moveTo(Bl_right ,Bl_bottom);
ctx.lineTo(x,y);
ctx.stroke();

ctx.beginPath();

ctx.moveTo(block.x - ball.R,block.y - ball.R);
ctx.lineTo(x,y);
ctx.stroke();

ctx.beginPath();
ctx.moveTo(Bl_right,block.y - ball.R );
ctx.lineTo(x,y);
ctx.stroke();


};



</script>

</body>
</html>





проблема в столкновение с углом, в примере выше видно что если сталкивается не с углом все работает.

schmetterling
06.12.2012, 20:02
Вот картинка, тут понятно, что идёт не так)

http://cs305100.userapi.com/v305100005/3770/wjm_5L1nhvU.jpg

cyber
07.12.2012, 01:08
schmetterling,я и так это понял;)
и вообще уже знаю как поправить, просто показал если кто то будет писать арканоид и будет читать эту тему и мучатся)
вот так должен выглядить блок

<!DOCTYPE HTML>
<html>
<head> </head>
<body>
<canvas width="500" height="500"></canvas>
<script>

var canva = document.body.children[0];

var ctx = canva.getContext("2d");

var block = {


width:150,
height:30,

Draw: function (x, y) {

ctx.beginPath();
ctx.fillStyle = "green";
ctx.fillRect(x,y,this.width, this.height);
this.y = y;
this.x = x;

boundary();

}


};
block.Draw(150,100);

function boundary() {

var rad = 20;

ctx.beginPath();

ctx.moveTo(block.x,block.y - rad);
ctx.lineTo(block.x + block.width , block.y - rad);
ctx.stroke();

ctx.beginPath();

ctx.moveTo(block.x+ block.width + rad,block.y);
ctx.lineTo(block.x+ block.width + rad , block.y + block.height);
ctx.stroke();

ctx.beginPath();

ctx.moveTo(block.x, block.y + block.height + rad);
ctx.lineTo(block.x + block.width , block.y + block.height + rad);
ctx.stroke();


ctx.beginPath();

ctx.moveTo(block.x- rad,block.y);
ctx.lineTo(block.x - rad , block.y + block.height);
ctx.stroke();

ctx.beginPath();
ctx.fillStyle = "blue";
ctx.moveTo(block.x,block.y);
ctx.arc(block.x,block.y, rad,(Math.PI / 180)* -90, (Math.PI / 180)* -180, true);
ctx.fill();

ctx.beginPath();
ctx.fillStyle = "blue";
ctx.moveTo(block.x +block.width,block.y);
ctx.arc(block.x +block.width, block.y, rad,(Math.PI / 180)* -90, (Math.PI / 180)* 0, false);
ctx.fill();

ctx.beginPath();
ctx.fillStyle = "blue";
ctx.moveTo(block.x + block.width, block.y + block.height);
ctx.arc(block.x + block.width, block.y + block.height, rad,(Math.PI / 180)* 0, (Math.PI / 180)* 90, false);
ctx.fill();

ctx.beginPath();
ctx.fillStyle = "blue";
ctx.moveTo(block.x ,block.y + block.height);
ctx.arc(block.x ,block.y + block.height, rad,(Math.PI / 180)* 180, (Math.PI / 180)* 90, true);
ctx.fill();

}


</script>

</body>
</html>


но я так и не понял раз 15 перечитывал коммент http://javascript.ru/forum/events/33223-canvas-i-metod-arc-4.html#post216503 как правильно определить окружность ...

cyber
07.12.2012, 01:14
просто не пойму фишки кода не увеличиваю блок на радиус шарик вроде нормально входит в угол, но наверно просто так кажется ...

<!DOCTYPE HTML>
<html>
<head> </head>
<body>
<canvas width="500" height="500"></canvas>
<script>

var canva = document.body.children[0];

var ctx = canva.getContext("2d");

var ball = {

x:20,
y:280,
R:20,

Draw: function (x, y) {

ctx.clearRect(this.x - this.R, this.y - this.R, this.R *2,this.R *2);

ctx.beginPath();
ctx.fillStyle = "red";
ctx.arc(x,y, this.R,0, (Math.PI / 180)* 360, false);
ctx.fill();

this.y = y;
this.x = x;
}


};

var block = {


width:150,
height:30,

Draw: function (x, y) {

ctx.beginPath();
ctx.fillStyle = "green";
ctx.fillRect(x,y,this.width, this.height);
this.y = y;
this.x = x;

}


};

block.Draw(150,100);

var valX = -10 , valY = -10;
var Bl_bottom = block.y + block.height ;
var Bl_right = block.x + block.width ;


!function action(){

if(ball.x < 0 + ball.R || ball.x > canva.width - ball.R){

valX = -valX;


};

if(ball.y < 0 + ball.R || ball.y > canva.height - ball.R){

valY = -valY;
//y = canva.height - ball.R;

}


var x = ball.x ;
var y = ball.y ;


if((y <= Bl_bottom && y >= block.y ) && (x >= block.x && x <= Bl_right)){
//if(isCollision(block.x ,block.y , Bl_right, Bl_bottom ,x,y, ball.R)){

drawOs(x,y);

return;
};

x = ball.x + valX;
y = ball.y + valY;

ball.Draw(x,y);





setTimeout(action,1000/60);
}();

function drawOs(x,y){
ctx.beginPath();

ctx.moveTo(block.x ,Bl_bottom);
ctx.lineTo(x,y);
ctx.stroke();

ctx.beginPath();
ctx.moveTo(Bl_right ,Bl_bottom);
ctx.lineTo(x,y);
ctx.stroke();

ctx.beginPath();

ctx.moveTo(block.x ,block.y );
ctx.lineTo(x,y);
ctx.stroke();

ctx.beginPath();
ctx.moveTo(Bl_right,block.y );
ctx.lineTo(x,y);
ctx.stroke();


};

function distance(x1,y1,x2,y2){

return Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2));

};



</script>

</body>
</html>

cyber
07.12.2012, 01:18
кажеться понял, но разберусь уже завтра)

schmetterling
07.12.2012, 12:16
cyber, в случае, если у вас шарик будет соприкасаться с углом, вам нужно считать расстояние между центром и углом) И проверять, не меньше ли оно радиуса.

cyber
07.12.2012, 20:39
нет все таки не разобрался)
если брать углы за окружность

<!DOCTYPE HTML>
<html>
<head> </head>
<body>
<canvas width="500" height="500"></canvas>
<script>

var canva = document.body.children[0];

var ctx = canva.getContext("2d");

var block = {


width:150,
height:30,

Draw: function (x, y) {

ctx.beginPath();
ctx.fillStyle = "green";
ctx.fillRect(x,y,this.width, this.height);
this.y = y;
this.x = x;

boundary();

}


};
block.Draw(150,100);

function boundary() {

var rad = 20;

ctx.beginPath();

ctx.moveTo(block.x,block.y - rad);
ctx.lineTo(block.x + block.width , block.y - rad);
ctx.stroke();

ctx.beginPath();

ctx.moveTo(block.x+ block.width + rad,block.y);
ctx.lineTo(block.x+ block.width + rad , block.y + block.height);
ctx.stroke();

ctx.beginPath();

ctx.moveTo(block.x, block.y + block.height + rad);
ctx.lineTo(block.x + block.width , block.y + block.height + rad);
ctx.stroke();


ctx.beginPath();

ctx.moveTo(block.x- rad,block.y);
ctx.lineTo(block.x - rad , block.y + block.height);
ctx.stroke();

ctx.beginPath();
ctx.fillStyle = "blue";
ctx.moveTo(block.x,block.y);
ctx.arc(block.x,block.y, rad,(Math.PI / 180)* -90, (Math.PI / 180)* -180, true);
ctx.fill();

ctx.beginPath();
ctx.fillStyle = "blue";
ctx.moveTo(block.x +block.width,block.y);
ctx.arc(block.x +block.width, block.y, rad,(Math.PI / 180)* -90, (Math.PI / 180)* 0, false);
ctx.fill();

ctx.beginPath();
ctx.fillStyle = "blue";
ctx.moveTo(block.x + block.width, block.y + block.height);
ctx.arc(block.x + block.width, block.y + block.height, rad,(Math.PI / 180)* 0, (Math.PI / 180)* 90, false);
ctx.fill();

ctx.beginPath();
ctx.fillStyle = "blue";
ctx.moveTo(block.x ,block.y + block.height);
ctx.arc(block.x ,block.y + block.height, rad,(Math.PI / 180)* 180, (Math.PI / 180)* 90, true);
ctx.fill();

}


</script>

</body>
</html>


расчитывать пересечение двух окружностей , то возникает проблема когда шарик на шаге n не пересекается с окружностью , а на шаге n+1 он нужен дальше окружности..
проверял так

var d = (x - block.x)*(x - block.x) + (y - block.y + block.height) * (y - block.y + block.height);
if(d < (ball.R + ball.R ) * (ball.R + ball.R) && d > (ball.R - ball.R) * (ball.R - ball.R))

и блин не как не могу понять как автор этой (http://noregret.org/tutor/n/collision/#2.2) статьи так просто расчитывает пересечения с углами

cyber
07.12.2012, 20:49
cyber, в случае, если у вас шарик будет соприкасаться с углом, вам нужно считать расстояние между центром и углом) И проверять, не меньше ли оно радиуса.
если бы прочитал бы этот коммент на пол часа раньше, то не ломал бы голову пол часа, но в итоге сам дошел)
Кстати арканоид хороший способ подучить геометрию))
П.с сор что туплю, понимаю что достал уже)

schmetterling
08.12.2012, 00:19
П.с сор что туплю, понимаю что достал уже)

Да всё норм)

cyber
10.12.2012, 21:37
schmetterling,хм, запутался.
Так как расчитываю координаты следущие, то если шарик залетает на блок нужно уменьшать растояние до того на котором он только столкнется , а не пересечет и не могу найти как определить ту точку в которой он будет сталкиваться а не пересекать(проблема только с углами)?

schmetterling
10.12.2012, 23:06
cyber, ну вы же координаты последующие как-то вычисляете? Вот и проверяете каждый раз пересечение круга и блока для вычисленных координат. Если пересеклись -- значит, текущая точка и есть точка столкновения.

cyber
10.12.2012, 23:18
schmetterling,можно на ты ?
я делаю так:
что бы найти растояние до нужной точки я от радиуса отнимаю растояние между точками В и А и прибавляю его к А.
https://lh3.googleusercontent.com/-8p56xj9-2QI/UMYwi-mR1DI/AAAAAAAAAJk/frKG5rQWpxw/s300/2.jpg
но работает как то не так...

schmetterling
11.12.2012, 01:12
schmetterling,можно на ты ?

Да, конечно)

что бы найти растояние до нужной точки
Это можно, но сложно. Зачем? Просто проверяй вычисленные координаты на столкновение.

cyber
11.12.2012, 02:50
schmetterling, не совсем понял.
Если новые координаты внутри блока, а если отразить раньше то сильно заметно..

Дзен-трансгуманист
11.12.2012, 16:27
В общем набросал кое-что, но сюда код не помещается, поэтому кладу на дропбокс: Collisions (http://dl.dropbox.com/u/19390559/lab/Collisions.html).
Управление:
стрелочки - перемещение шарика
WSAD - поворот и изменение длины вектора движения

Иногда шарик проходит углы насквозь. Иногда даже зависает.
Писать красиво и модульно мне было некогда, поэтому говнокод.

В данный момент только статическая трассировка, может в другой раз заставлю картинку двигаться самостоятельно.

cyber
11.12.2012, 18:53
Дзен-трансгуманист, спасибо, буду разбираться

cyber
11.12.2012, 19:55
вот пока то что у меня есть http://learn.javascript.ru/play/8nu3s

<!DOCTYPE HTML>
<html>
<head> </head>
<body>
<canvas width="500" height="500"></canvas>
<script>

var canva = document.body.children[0];

var ctx = canva.getContext("2d");

var ball = {

// x:20,
// y:280,
x:50,
y:40,
R:20,

Draw: function (x, y) {

ctx.clearRect(this.x - this.R, this.y - this.R, this.R *2,this.R *2);

ctx.beginPath();
ctx.fillStyle = "red";
ctx.arc(x,y, this.R,0, (Math.PI / 180)* 360, false);
ctx.fill();

this.y = y;
this.x = x;
}


};

var block = {


width:150,
height:30,

Draw: function (x, y) {

ctx.beginPath();
ctx.fillStyle = "green";
ctx.fillRect(x,y,this.width, this.height);
this.y = y;
this.x = x;

}


};

block.Draw(150,100);

var valX = -10 , valY = -10;
var Bl_bottom = block.y + block.height + ball.R ;
var Bl_right = block.x + block.width + ball.R ;

var stop = false;
!function action(){

if(ball.x < 0 + ball.R || ball.x > canva.width - ball.R){

valX = -valX;


};

if(ball.y < 0 + ball.R || ball.y > canva.height - ball.R){

valY = -valY;


}


var x = ball.x + valX;
var y = ball.y + valY;


if((y <= Bl_bottom && y >= block.y - ball.R) && (x >= block.x - ball.R && x <= Bl_right)){

var pos = getPosit();



if(pos == "angle") {

// проверка на столкновение с одним из 4х углов
if(distance(x,y,block.x, block.y + block.height) <= ball.R ||
distance(x,y,block.x, block.y ) <= ball.R
|| distance(x,y,block.x + block.width, block.y + block.height) <= ball.R||
distance(x,y,block.x+ block.width, block.y) <= ball.R){


valY = - valY;
valX = - valX;
return;
}



}

if(pos == "x") {

valX = - valX;
}

if(pos == "y") {

valY = - valY;
}

// return;
};



ball.Draw(x,y);





setTimeout(action,1000/60);
}();

function getPosit() {

var x,y;

if(ball.x <= block.x){

x = "left";
}

else if(ball.x >= block.x + block.width){

x = "right";
}


else x = "on";



if(ball.y >= block.y + block.height){

y = "bottom";
}

else if(ball.y <= block.y){

y = "top";
}
else y = "on";


if((x == "right" || x == "left") && (y == "on")) {

return "x";
}

else if((y == "bottom" || y == "top") && x == "on"){

return "y";
}

else return "angle";

}



function distance(x1,y1,x2,y2){

return Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2));

};




</script>

</body>
</html>


сделал остановку когда новые координаты шарика будут равны углу или внутри угла.

cyber
11.12.2012, 20:59
Дзен-трансгуманист, я понимаю что это уже наглость, но не могу разобраться в твоем коде, какой метод отвечает за рисование шариков которые рисуются на векторе?

Дзен-трансгуманист
11.12.2012, 21:48
cyber,
drawPath в области видимости TracerView, строчки 489-500 (потом рисуются линии). Это типа как приватная функция, только вместо контекста this я передаю экземпляр класса явно в аргументе object.

Дзен-трансгуманист
11.12.2012, 22:01
Я сейчас понял, что трейсер возвращает только путь в виде набора точек, но не возвращает новый вектор движения после всех столкновений. Без этого, конечно, шарик самостоятельно никуда не полетит.

И наверное я неправильно поступил, что мастер-объектом движения сделал вектор [x,y]. Так теряется некоторая точность преобразований, причем, чем больше столкновений за один ход - тем больше потери точности. Надо было хранить и обрабатывать его как [длина,азимут].


Не знаю, дойдут ли у меня руки править это, но, честно говоря, не очень-то хочется, поскольку не люблю поддерживать код, написанный второпях буквально за один день. Такие вещи надо продумывать и делать основательно, а не на коленке. ;)

cyber
11.12.2012, 22:05
Дзен-трансгуманист,хм, не совсем понял как ты расчитываешь расстояние от угла до центра шарика?

cyber
11.12.2012, 22:12
Дзен-трансгуманист,да вообщем я понимаю как все работает, но у меня проблемы с реализацией из за пробелов в школьной геометрии пофигизм выходит боком , если тот пример ты для меня лепил, то спасибо, но все таки не нужно, я в общем разобрался с колизиями и отражением, но только не могу правильно найти расстояние на которое нужно сместить шарик по вектору движения так что бы он не оказался внутри блока.
Допустим по формуле
Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2));
я определил что на шаге n+1 шарик будет внутри блока, то нужно установить такие координаты при которых шарик не пересечет угол.
Вроде просто, а не фига не получается .

Дзен-трансгуманист
11.12.2012, 22:13
как ты расчитываешь расстояние от угла до центра шарика?
Функция vertexCollision. Я даже не уверен, что она полностью правильная. ;) Там решается квадратное уравнение чтобы найти точки пересечения прямой и окружности. А нормаль столкновения это не что иное как вектор, проложенный от угла к центру шарика в сам момент столкновения.

Дзен-трансгуманист
11.12.2012, 22:14
из за пробелов в школьной геометрии
Я вообще троечник был. Думаешь мне легко?

cyber
11.12.2012, 22:19
Я вообще троечник был. Думаешь мне легко?
Неа)
Значить не я один вместо повторение учу что то новое из школьной программы)))
П.с я тоже троечником был)

cyber
11.12.2012, 22:31
Дзен-трансгуманист, хм, а если найти угол падения, а через него угол отражения?

Дзен-трансгуманист
11.12.2012, 22:39
cyber,
Все равно нужна нормаль. На отрезках она во всех точках одинакова, а на углах зависит от направления удара.

cyber
11.12.2012, 22:51
Дзен-трансгуманист, как то так http://habrahabr.ru/post/105882/ там есть под раздел "Вычисление отражённого луча" ?

Дзен-трансгуманист
11.12.2012, 23:00
cyber,
Хороший пост. И?

cyber
11.12.2012, 23:08
Дзен-трансгуманист,мне он тоже показался хорошим:)
но я не совсем понял как получить новые координаты из градуса угла
http://habrastorage.org/storage/436a45df/f727f4f8/2f748788/54ace04f.png

Дзен-трансгуманист
11.12.2012, 23:18
cyber,
Где ты там видишь градус?) Это пост об алгебре, нет там никаких градусов.)
Точка в формуле - это скалярное произведение, если че.

cyber
11.12.2012, 23:22
Дзен-трансгуманист, wtf , ну меня и лагануло)
прочитал статью на хабре, потом начал читать эту http://www.ecto.ru/details/reflex_drop/ и получился бред в голове)

Дзен-трансгуманист
11.12.2012, 23:24
cyber,
Если смотреть на мой код с такой точки зрения, то у меня там действительно много избыточных вычислений. Это еще одна причина, почему я не хочу его править, ибо проще написать новый с нуля.

cyber
11.12.2012, 23:25
вроде тут все понятно http://www.ecto.ru/details/reflex_drop/, но как найти нормаль я так и не понял..

cyber
11.12.2012, 23:27
Дзен-трансгуманист, смысел писать целый скрипт, что бы только показать что делать с углами?

Дзен-трансгуманист
11.12.2012, 23:35
cyber,
Ты не понял, я говорю о том, что векторной алгеброй можно было бы многое сократить и ускорить в моем примере. А писать что-то или переписывать я уже не буду, надоело.

Дзен-трансгуманист
11.12.2012, 23:36
но как найти нормаль я так и не понял..
Кстати, я не рассказал, как её определить. Если прямая задана двумя точками (x1,y1) и (x2,y2), то вектор нормали (ненормированый) легко определяется вот так:
http://habrastorage.org/storage/19f690e2/c9bbb888/57ab0761/58072d9d.png


Отличие моего кода в том, что у меня нормали левосторонние, так как фигуры у меня определяются по часовой стрелке.

cyber
11.12.2012, 23:39
Дзен-трансгуманист, видел, но не понял.
мне нужно y1-y2 / (x2-x1)?

Дзен-трансгуманист
11.12.2012, 23:51
cyber,
Круглые скобки там - это просто описание компонент вектора. Так еще матрицы описываются.
x = y1-y2
y = x2-x1

Лучше пойди выспись и перечитай тот пост с утра на свежую голову, а то я всю ночь тут тебе объяснять буду... Всё, умаялся я уже.

cyber
12.12.2012, 15:21
Дзен-трансгуманист, да, чет по вечерам у меня включается режим тормоз))
Зная х и у , можно получить угол нормали через теорему косинусов...

Дзен-трансгуманист
12.12.2012, 15:33
cyber,
Если угол все-таки нужен, то Math.atan2 (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/atan2).

cyber
12.12.2012, 15:37
Дзен-трансгуманист, вот блин, как я мог пропустить такую полезную функцию....

cyber
12.12.2012, 15:56
ну вот как то так)

function reflect(dx,dy){

var power = Math.sqrt(dx*dx + dy*dy); // сила=корень из (dx*dx + dy*dy)

var sinDrop = dy/power; //sin(угла падения) = dy / сила
var cosDrop = dx/power; //cos(угла падения) = dx / сила


var normal = Math.atan2(wall.x - ball.x, ball.y - wall.y);

var sinL = Math.sin(normal) * cosDrop - Math.cos(normal) * sinDrop; //sin(L)=sin(Нормали)*cos(падения)-cos(Нормали)*sin(падения);

var cosL = Math.cos(normal) * cosDrop + Math.sin(normal) * sinDrop; //cos(L)=cos(Нормали)*cos(падения)+sin (Нормали)*sin(падения);

var reflSin = sinL * Math.cos(normal) + cosL * Math.sin(normal); //sin(отражения)=sin(L)*cos(Нормали) +cos(L)*sin(Нормали);
var reflCos = cosL * Math.cos(normal) - sinL * Math.sin(normal); //cos(отражения)=cos(L)*cos(Нормали)-sin(L)*sin(Нормали);

dx = Math.cos(reflCos) * power; //dx = cos(угол)*сила
dy = Math.sin(reflSin) * power; //dy = sin(угол)*сила

return {
dx:dx,
dy:dy
}
};



<!DOCTYPE HTML>
<html>
<head> </head>
<body>
<canvas width="500" height="500"></canvas>
<script>
var canv = document.body.children[0];
var ctx = canv.getContext("2d");

var ball = {
x:80,
y:170,
R:20,
Draw: function (x,y){

ctx.clearRect(this.x - this.R, this.y - this.R, this.R *2,this.R *2);

ctx.beginPath();
ctx.fillStyle = "red";

ctx.arc(x,y,ball.R,0, (Math.PI/180)* 360, false);
ctx.fill();
}


};

var wall = {

x:100,
y:100,
width:100,
height:50,
Draw:function() {



ctx.beginPath();
ctx.fillStyle = "green";
ctx.fillRect(wall.x,wall.y,wall.width,wall.height) ;

}
};


ball.Draw(ball.x, ball.y, false);
wall.Draw();

var dx = 10, dy = 10;

var ref = reflect(dx,dy);


ball.Draw(ball.x + ref.dx,ball.y + ref.dy);

function distance(x1,y1,x2,y2){

return Math.sqrt(Math.pow(x2-x1,2) + Math.pow(y2-y1,2));

};

function reflect(dx,dy){

var power = Math.sqrt(dx*dx + dy*dy); // сила=корень из (dx*dx + dy*dy)

var sinDrop = dy/power; //sin(угла падения) = dy / сила
var cosDrop = dx/power; //cos(угла падения) = dx / сила

var nx = wall.x - ball.x;
var ny = ball.y - wall.y;

var normal = Math.atan2(nx,ny);

var sinL = Math.sin(normal) * cosDrop - Math.cos(normal) * sinDrop; //sin(L)=sin(Нормали)*cos(падения)-cos(Нормали)*sin(падения);

var cosL = Math.cos(normal) * cosDrop + Math.sin(normal) * sinDrop; //cos(L)=cos(Нормали)*cos(падения)+sin (Нормали)*sin(падения);

var reflSin = sinL * Math.cos(normal) + cosL * Math.sin(normal); //sin(отражения)=sin(L)*cos(Нормали) +cos(L)*sin(Нормали);
var reflCos = cosL * Math.cos(normal) - sinL * Math.sin(normal); //cos(отражения)=cos(L)*cos(Нормали)-sin(L)*sin(Нормали);

dx = Math.cos(reflCos) * power; //dx = cos(угол)*сила
dy = Math.sin(reflSin) * power; //dy = sin(угол)*сила

return {
dx:dx,
dy:dy
}
}
</script>

</body>
</html>

Дзен-трансгуманист
12.12.2012, 15:58
cyber,
Там в статье написано, что углы отсчитываются против часовой стрелки, но здесь имеется ввиду традиционное представление координат, как на обычных графиках, когда игрек направлен вверх. В экранных же координатах, как и на канвасе, игрек направлен вниз, поэтому угол тут возрастает по часовой стрелке.

cyber
12.12.2012, 16:20
Там в статье написано,
чет не могу найти такого , но не важно , я вроде понял к чему ты клонишь.
В экранных же координатах, как и на канвасе, игрек направлен вниз, поэтому тут угол возрастает по часовой стрелке.
т.е y нужно отнимать , а не прибавлять?

Дзен-трансгуманист
12.12.2012, 16:24
т.е y нужно отнимать , а не прибавлять?
Я просто прокомментировал то, о чем написано в статье про Math.atan2, уточнил на всякий случай.
Алгоритмов это никак не касается.
Ладно, как-нибудь сам разберешься... ;)

cyber
12.12.2012, 16:41
Дзен-трансгуманист, тьфу блин, запутал :)
Я думал ты про статью с алгоритмом , перечетал ее еще раз 5, после твоего коммента.
Прочитав описание Math.atan2 , понял к чему ты
This is the counterclockwise angle, measured in radians,
кстати нужно было сразу описание читать, так как результат возвращает в радианах, значить нужно перевести его в градусы ?!

var normal = (Math.atan2(nx,ny)) * 180/ Math.PI;

Дзен-трансгуманист
12.12.2012, 16:43
cyber,
Зачем тебе градусы? Градусы не нужны.

var normal = (Math.atan2(nx,ny)) * 180/ Math.PI;
ЩИТО? О_о

cyber
12.12.2012, 16:48
Зачем тебе градусы? Градусы не нужны.
да ты прав, там нужен угол, про градусы нечего не сказано
ЩИТО? О_о
var normal = Math.atan2(nx,ny) * 180/ Math.PI

Rad:=Grad*Pi/180;//перевод градусов (Grad) в радианы (Rad)
Grad:=Rad*180/Pi;//обратный перевод

Дзен-трансгуманист
12.12.2012, 16:48
cyber,
Нормаль - это вектор, а ты что думал? :lol: иди еще раз перечитывай статью на хабре.

Дзен-трансгуманист
12.12.2012, 16:51
Math.atan2(nx,ny)
Опять же твоя невнимательность. В этой функции сначала Y, потом X.

Ну всё, я снимаю подписку с этой темы, а то это будет бесконечно длиться, а у меня еще работы дохера. :)
Успехов!

cyber
12.12.2012, 16:59
Нормаль - это вектор, а ты что думал? иди еще раз перечитывай статью на хабре.
пора завязывать с травкой:lol:
Опять же твоя невнимательность. В этой функции сначала Y, потом X.
блин, ну вот нет что бы сделать по нормальному сначала х потом у,не нужно выпендрится )
Ну всё, я снимаю подписку с этой темы, а то это будет бесконечно длиться, а у меня еще работы дохера.
Успехов!
Огромное спасибо.:thanks:
Удачи!