PDA

Просмотр полной версии : приближённый к реалистичному drag&drop фотографии


fljot
17.07.2007, 03:17
привет. помогите пожалуйста с алгоритмом, что-то я завяз. может упёрся во что-то и ошибки в упор не вижу, бывает же такое.

отец iNils, надеюсь тебя это заинтересует и пособишь!

задача с точки зрения AS вроде незаковыристая, дело просто в алгоритме исполнения.
требуется: реализовать drag&drop приближённый к реалистичному миру. таскаем фотку(как по столу, прижав слегка и подняв мокрым пальцем=) ). берём за уголочек - "центр тяжести" на противоложном уголке и поворот осуществляется по полной программе(коэф. поворота 1). берём в центре - "центр тяжести" тут же, коэф поворота ноль(если точно в цетре схватить то типа не образуется крутящего момента). в промежуточных точках захвата - соответственно, тока коэф поворта(например) изменяется нелинейно чтоб меньше чувствовался жёсткий алгоритм.
вобщем что-то оно не так крутится как задумывалось.. главная неуверенность из-за осей x и y, которые во флеше смотрят не вправо и наверх, а вправо и вниз соотв.

вобщем буду признателен если просмотрите код и поможете найти неправильность логики.
(прим по коду: локальная ось X - из центра до точки захвата. локальная Y ей пепрендикулярна по часовой стрелке ну как и глобальные xy)

ход реализации следующий: при зажатой кнопке и движении мыши:
- записываем координаты центра фоты (center{_x,_y})
- через точку захвата и коорд. центра вычисляем "центр тяжести" (rotation_center{_x,_y})
- вычисляем коэф. поворота (нормированный, квадрат удаления от цетра фоты. K_rotation)
- через прошлое и новое положение мыши вычисляем смещение мыши (hold_dx, hold_dy)
- вычисляем вектор локальной оси Х в абс. СК(система координат)(loc_Xaxis_x, loc_Xaxis_y)
- определяем угол между абс СК и локальной СК. через скалярное произведение абс. оси x (как ветор [1,0]) и ветора локальной X (вот тут я уже начинаю сомневаться)
- вычисляем относительное смешение вдоль локальных осей(в локальной СК) (loc_dx, loc_dy)

далее такая логика: за поворот отвечает смещение вдоль локальной оси Y (плюс ещё учёт коэф. поворота). за смещение фоты отвечает остальная часть вектора смещения(т.е. смещение вдоль локальной X и ещё остаток если коэф поворта был != 1)

- вычисляем угол поворта psi. из прямоугольного треугольника: противоположный нужному углу катет - это вектор смещения курсора в проекции на локальную ось Y, прилегающий катет - расстояние от точки захвата до центра тяжести
-поворачиваем на угол. вращение вокруг центра тяжести
-теперь смещаем фоту. на смещение вдоль локальной оси X и ещё остаточек от применения коэф. поворта
-записываем новые координаты мыши

исходник: http://***********/2691216

код:

function phys_drag() {
hold_x = _root._xmouse; //координата x точки захвата
hold_y = _root._ymouse; //координата y точки захвата

this.onMouseMove = function() {

//коориднаты центра объекта
center = {_x: this._x, _y: this._y};

//точка захвата: _root._xmouse, _root._ymouse

//координаты цетра тяжести
rotation_center = {_x: 2*center._x - _root._xmouse, _y: 2*center._y - _root._ymouse};

//удаление от центра фоты (относительно 1/2 диагонали)
d_from_center = Math.sqrt(((Math.pow((_root._xmouse - center._x),2) + Math.pow((_root._ymouse - center._y),2))) / _global.diagonal_length);

//коэф поворота
K_rotation = Math.pow(d_from_center, 2);

//смещение мыши(=точки захвата) в абс СК (система координат)
_global.hold_dx = _root._xmouse - hold_x; _global.hold_dy = _root._ymouse - hold_y;

//вектор локальной оси X (в абс координатах)
loc_Xaxis_x = hold_x - center._x; loc_Xaxis_y = hold_y - center._y;

//определяем угол между абс СК и локальной СК. через скалярное произведение [1,0](=ось X) и локальной оси x
cos_fi = loc_Xaxis_x/(Math.sqrt(loc_Xaxis_x*loc_Xaxis_x + loc_Xaxis_y*loc_Xaxis_y));
fi = Math.acos(cos_fi); if (loc_Xaxis_y < 0) fi = 2*Math.PI - fi;

//вычисляем относительное смешение вдоль локальных осей(в локальной СК)
//т.е. переводим смещение hold_dx и hold_dy в локальную СК
loc_dx = hold_dx*Math.cos(fi) - hold_dy*Math.sin(fi); //смещение по x в локальной
loc_dy = hold_dx*Math.sin(fi) + hold_dy*Math.cos(fi); //смещение по y в локальной


//вычисляем угол поворта. из прямоугольного треугольника,
//противоположный нужному углу катет - это вектор смещения курсора в проекции на локальную ось Y
//прилегающий катет - расстояние от точки захвата до центра тяжести
//С УЧЁТОМ КОЭФ ПОВОРОТА
rel_dy_x = loc_dy*Math.sin(-fi); //x-компонента проекции вектора смещения на локальную ось Y
rel_dy_x_rot = rel_dy_x*K_rotation; //x-компонента проекции вектора смещения на локальную ось Y С УЧЁТОМ КОЭФ ПОВОРОТА
rel_dy_y = loc_dy*Math.cos(-fi); //y-компонента проекции вектора смещения на локальную ось Y
rel_dy_y_rot = rel_dy_y*K_rotation; //y-компонента проекции вектора смещения на локальную ось Y С УЧЁТОМ КОЭФ ПОВОРОТА
tan_psi = Math.sqrt(Math.pow(rel_dy_x_rot,2) + Math.pow(rel_dy_y_rot,2))/(2*Math.sqrt(Math.pow(loc_Xaxis_x,2) + Math.pow(loc_Xaxis_y,2)));
psi = Math.atan(tan_psi);
if (loc_dy < 0) psi = -psi;

//поворачиваем на угол. вращение вокруг центра тяжести
this.rotation(psi, rotation_center._x, rotation_center._y);

//вычисляем как надо сместить центр(переводим смещение в абс СК)
//сместить его надо на смещение вдоль локальной оси X и на остаток от смещения вдоль локальной Y (из-за коэф поворота)
//смещаем центр
this._x += loc_dx*Math.cos(-fi) - loc_dy*(1-K_rotation)*Math.sin(-fi);
this._y += loc_dx*Math.sin(-fi) + loc_dy*(1-K_rotation)*Math.cos(-fi);


//записываем новые координаты мыши для вычисления
//вектора смещения в следующей ветви
hold_x = _root._xmouse;
hold_y = _root._ymouse;

updateAfterEvent();

if (!this.hitTest(_root._xmouse, _root._ymouse, true))
{
this.onMouseMove = null;
//trace('out!');
}

}
}

//поворачивает мувик относительно точки (pointx, pointy) на угол angle
//(положительное направление поворота по часовой)
MovieClip.prototype.rotation = function (angle, pointx, pointy) {
var vector_x = this._x - pointx;
var vector_y = this._y - pointy;
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var vector_rotate_x = (vector_x*cos - vector_y*sin);
var vector_rotate_y = (vector_x*sin + vector_y*cos);
this._x = vector_rotate_x + pointx;
this._y = vector_rotate_y + pointy;
this._rotation += angle*180/Math.PI;
};

iNils
17.07.2007, 04:05
У меня нет детей, я точно помню :)
Немудрено, что вы запутались. Реализовать такой код линейно не лучший способ, а уж разбираться в нем совсем сложно. Поэтому лишь дам пару советов:
1. Логически отдельные операции лучше вынести в отдельные методы, спрятав ненужные хвосты.
2. Математическую модель отделить от мувиклипа вобще.
3. Вместо фото на этапе моделирования надо выводить вектора направлений. Это поможет лучше ориентироваться.

fljot
17.07.2007, 04:12
iNils,
векторами тогда буду бить охъ.. пункт2 поясни пожалуйста, что здесь от чего отделить можно?

Kikasso
17.07.2007, 04:19
У вас центр точно по центру?

iNils
17.07.2007, 04:27
iNils,
векторами тогда буду бить охъ.. пункт2 поясни пожалуйста, что здесь от чего отделить можно?
В самом начале снять необходимые данные с "физического" объекта, передать их математической модели, обсчитать все, а потом применить обратно к объекту, тогда мыслей
главная неуверенность из-за осей x и y, которые во флеше смотрят не вправо и наверх, а вправо и вниз соотв. точно не возникнет

etc
17.07.2007, 10:15
http://etcs.ru/pre/Core/picture.swf
:D

(Какой-то треш давний, даже не доделан)

iNils
17.07.2007, 11:19
Не реалистично, если взять картинку и начать крутить ее в пределах площади самой картинки, то возникает ощущение, что к ней моторчик пределан. Да и поворчивается она в сторону где разница между вектором "тяжести" и направления меньше, а не по ходу движения.

etc
17.07.2007, 11:34
Это просто потому что ты её в центре хватаешь. А в центре у неё центр тяжести, я не сделал мертвую зону…

fljot
17.07.2007, 13:28
http://etcs.ru/pre/Core/picture.swf
:D

(Какой-то треш давний, даже не доделан)

вау супер! к этому тока фишку с коэф. поворота надо добавить!

могу я вас просить о коде касаемо этой части флешки? в личку отправил для чего)

etc
17.07.2007, 13:52
Пожалуй, в данном случае я вам помочь ничем не могу.

fljot
17.07.2007, 13:56
не осталось или ..?

etc
17.07.2007, 13:59
Просто не хочу этим заниматься, извините.

fljot
17.07.2007, 14:04
да я как бы сам) от вас только прошу код если не жалко. потом выложу что получилось

etc
17.07.2007, 14:08
Честно говоря, я не знаю, где лежат исходники. Тем более, я на работе.
Вообще говоря, там какой-то ужас с физикой, поэтому лучше сделать на трезвую голову самостоятельно.

iNils
18.07.2007, 00:27
Это просто потому что ты её в центре хватаешь. А в центре у неё центр тяжести, я не сделал мертвую зону…
Не в центре, а с краю, и точкой вращения при движении должна быть точка в которую я ткнул мышью, а у тебя она вращается относительно центра фото + мышь сползает с точки захвата.

etc
18.07.2007, 00:44
Гы, а у меня не сползает :)
Да я особо и не стремился сделать реальную физику, главное эффект получить, а ньюансы не каждый заметит :D

fljot
18.07.2007, 16:40
помурыжил алгорит, сделал. всё-таки беда была из-за непоняток с осями. неправильные декартовые они) и поврот теперь относительно точки захвата что из-за всяких погрешностей она оставалась реально там же, где и курсор.

вот пример http://inreflected.com/fljot/test/#gallery_id=085
дальш всякие инерции можно приделывать, мне вроде не надо

код функции, отвечающей за таскание:

function phys_drag() {
hold_x = _root._xmouse; //координата x точки захвата
hold_y = _root._ymouse; //координата y точки захвата

this.onMouseMove = function() {

//коориднаты центра объекта
center = {_x: this._x, _y: this._y};

//точка захвата: _root._xmouse, _root._ymouse

//координаты цетра тяжести
rotation_center = {_x: 2*center._x - _root._xmouse, _y: 2*center._y - _root._ymouse};

//удаление от центра фоты (относительно 1/2 диагонали)
d_from_center = Math.sqrt(((Math.pow((_root._xmouse - center._x),2) + Math.pow((_root._ymouse - center._y),2))) / _global.diagonal_length);

//коэф поворота
K_rotation = Math.pow(d_from_center, 2);

//смещение мыши(=точки захвата) в абс СК (система координат)
_global.hold_dx = _root._xmouse - hold_x; _global.hold_dy = _root._ymouse - hold_y;

//вектор локальной оси X (в абс координатах)
loc_Xaxis_x = hold_x - center._x; loc_Xaxis_y = hold_y - center._y;


//определяем угол между абс СК и локальной СК. через скалярное произведение [1,0](=ось X) и локальной оси x
cos_fi = loc_Xaxis_x/(Math.sqrt(loc_Xaxis_x*loc_Xaxis_x + loc_Xaxis_y*loc_Xaxis_y));
fi = Math.acos(cos_fi);
if (loc_Xaxis_y > 0) fi = - fi; //от -pi до pi

//вычисляем относительное смешение вдоль локальных осей(в локальной СК)
//т.е. переводим смещение hold_dx и hold_dy в локальную СК
loc_dx = hold_dx*Math.cos(fi) - hold_dy*Math.sin(fi); //смещение по x в локальной
loc_dy = hold_dx*Math.sin(fi) + hold_dy*Math.cos(fi); //смещение по y в локальной


//вычисляем угол поворта. из прямоугольного треугольника,
//противоположный нужному углу катет - это вектор смещения курсора в проекции на локальную ось Y
//прилегающий катет - расстояние от точки захвата до центра тяжести
//С УЧЁТОМ КОЭФ ПОВОРОТА
rel_dy_x = loc_dy*Math.sin(fi); //x-компонента проекции вектора смещения на локальную ось Y
rel_dy_x_rot = rel_dy_x*K_rotation; //x-компонента проекции вектора смещения на локальную ось Y С УЧЁТОМ КОЭФ ПОВОРОТА
rel_dy_y = loc_dy*Math.cos(fi); //y-компонента проекции вектора смещения на локальную ось Y
rel_dy_y_rot = rel_dy_y*K_rotation; //y-компонента проекции вектора смещения на локальную ось Y С УЧЁТОМ КОЭФ ПОВОРОТА
tan_psi = Math.sqrt(Math.pow(rel_dy_x_rot,2) + Math.pow(rel_dy_y_rot,2))/(2*Math.sqrt(Math.pow(loc_Xaxis_x,2) + Math.pow(loc_Xaxis_y,2)));
psi = Math.atan(tan_psi);
if (loc_dy < 0) psi = -psi;

//поворачиваем на угол. вращение вокруг точки захвата
this.rotation(psi, this._parent._xmouse, this._parent._ymouse);

//вычисляем как надо сместить центр(переводим смещение в абс СК)
//сместить его надо на смещение вдоль локальной оси X и на остаток от смещения вдоль локальной Y (из-за коэф поворота)
//смещаем центр
//fi = 2*Math.PI - fi;
this._x += _global.hold_dx;
this._y += _global.hold_dy;

//записываем новые координаты мыши для вычисления
//вектора смещения в следующей ветви
hold_x = _root._xmouse;
hold_y = _root._ymouse;

updateAfterEvent();

}
}

etc
18.07.2007, 16:51
А функциональная нагрузка сего действа какая?

fljot
18.07.2007, 16:59
1) люди любят вертеть фоты по-своему
2) создавать атмосферу чего-то реального, лежащего на плоскости моника

наверное так

etc
18.07.2007, 17:00
Тогда где тень от фотографии на «столе»?

fljot
18.07.2007, 17:01
собственно потому и почти везде для появления\убирания\смены использую движение, а не что-то абстрактное. а там где через альфу - ну там по-другому не было мыслей(

Тогда где тень от фотографии на «столе»?

ну если лежит плоская тонкая - то зачем тень?

etc
18.07.2007, 17:08
Толком не видно реальных границ фото.

fljot
18.07.2007, 17:12
Толком не видно реальных границ фото.
а надо?

etc
18.07.2007, 17:26
Думаю, что да.