Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Сообщения за день
 

Вернуться   Форум Flasher.ru > Flash > ActionScript 3.0

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 25.06.2013, 14:18
denver вне форума Посмотреть профиль Отправить личное сообщение для denver Найти все сообщения от denver
  № 1  
Ответить с цитированием
denver

Регистрация: Jan 2010
Сообщений: 32
Question Как описать один спрайт вокруг другого?

Доброго времечка!

Бьюсь с одной проблемой, которую визуально можно описать так:
1. картинка (см. вложение)
2. красный контур -- спрайт вокруг которого нужно описать сиреневый спрайт
3. большой серый прямоуг -- это то состояние до которого нужно довести сиреневый спрайт чтобы он описал спрайт отмеченный красным контуром
4. сиреневый спрайт может быть как угодно повернут и трансформирован

Хороший человек подсказал такой способ:
Код AS3:
var rect:Rectangle = redSprite.getBounds(purpleSprite);
Если отрисовать этот рект в системе координат purpleSprite, то он опишет redSprite.
Прим.: Ниже в лайф-демке этот прямоуг обозначен круглыми маркерами и синими соединительными линиями.

Вот заготовочка, чтобы попробовать, а главное форкнуть(!) это в живую: http://wonderfl.net/c/r6kr
Прим.: Все основные манипуляции происходят в методе test().

В итоге: нужно пропорцильно(!) увеличить/уменьшить габариты purpleSprite чтобы он описал redSprite.

С уважением и надеждой на помощь.
Изображения
 

Старый 25.06.2013, 16:21
maincode вне форума Посмотреть профиль Отправить личное сообщение для maincode Посетить домашнюю страницу maincode Найти все сообщения от maincode
  № 2  
Ответить с цитированием
maincode

Регистрация: Feb 2010
Адрес: Город суеты
Сообщений: 191
Пример testRect.swf.
Алгоритм:
Проходим циклом по всем вершинам(точнее по двум соседним) красного прямоугольника, и опускаем перпендикуляр до ближайшего ребра фиолетового прямоугольника. Длина этого перпендикуляра - это та разница на которую надо увеличить соседнее(!!!) ребро фиолетового прямоугольника, так, что бы фиолетовый прямоугольник прошел через проверяемую вершину красного. Далее находим максимальный scale и применяем его к фиолетовому прямоугольнику.

Вот как выглядит код:
Код AS3:
package
{
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.MouseEvent;
 
	import ru.flashpress.geom.line.FPGLine2d;
	import ru.flashpress.geom.line.math.FPGLineToPoint2dMath;
	import ru.flashpress.geom.point.FPGPoint2d;
	import ru.flashpress.geom.polygon.FPGEdge2d;
	import ru.flashpress.geom.polygon.FPGPolygon2d;
	import ru.flashpress.geom.polygon.FPGVertex2d;
 
	[SWF(width="600", height="600")]
	public class testRect extends Sprite
	{
		private var redRect:Sprite;
		private var purpleRect:Sprite;
		private var grayRect:Sprite;
		private var polygonRed:FPGPolygon2d;
		private var polygonPurp:FPGPolygon2d;
		public function testRect()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			//
			var cx:Number = 300;
			var cy:Number = 300;
			var wRed:Number = 100;
			var hRed:Number = 200;
			var wPur:Number = 100;
			var hPur:Number = 150;
			//
			redRect = new Sprite();
			redRect.graphics.lineStyle(1, 0xff0000, 1);
			redRect.graphics.drawRect(-wRed/2, -hRed/2, wRed, hRed);
			redRect.graphics.endFill();
			this.addChild(redRect);
			redRect.x = cx;
			redRect.y = cy;
			//
			purpleRect = new Sprite();
			purpleRect.graphics.lineStyle(1, 0xff00ff, 1);
			purpleRect.graphics.drawRect(-wPur/2, -hPur/2, wPur, hPur);
			purpleRect.graphics.endFill();
			this.addChild(purpleRect);
			purpleRect.x = cx;
			purpleRect.y = cy;
			//
			grayRect = new Sprite();
			grayRect.graphics.lineStyle(1, 0x999999, 1);
			grayRect.graphics.drawRect(-wPur/2, -hPur/2, wPur, hPur);
			grayRect.graphics.endFill();
			this.addChild(grayRect);
			grayRect.x = cx;
			grayRect.y = cy;
			//
			var redPoints:Vector.<FPGPoint2d> = new Vector.<FPGPoint2d>();
			redPoints.push(new FPGPoint2d(cx-wRed/2, cy-hRed/2));
			redPoints.push(new FPGPoint2d(cx+wRed/2, cy-hRed/2));
			redPoints.push(new FPGPoint2d(cx+wRed/2, cy+hRed/2));
			redPoints.push(new FPGPoint2d(cx-wRed/2, cy+hRed/2));
			polygonRed = new FPGPolygon2d(redPoints);
			//
			var purpPoints:Vector.<FPGPoint2d> = new Vector.<FPGPoint2d>();
			purpPoints.push(new FPGPoint2d(cx-wPur/2, cy-hPur/2));
			purpPoints.push(new FPGPoint2d(cx+wPur/2, cy-hPur/2));
			purpPoints.push(new FPGPoint2d(cx+wPur/2, cy+hPur/2));
			purpPoints.push(new FPGPoint2d(cx-wPur/2, cy+hPur/2));
			polygonPurp = new FPGPolygon2d(purpPoints);
			//
			this.stage.addEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
			rotate(0);
			calculate();
		}
 
 
		private function moveHandler(event:MouseEvent):void
		{
			event.updateAfterEvent();
			var dx:Number = this.mouseX-purpleRect.x;
			var dy:Number = this.mouseY-purpleRect.y;
			var radians:Number = Math.atan2(dy, dx);
			rotate(radians);
			calculate();
		}
 
		private var oldRotate:Number = 0;
		private function rotate(radians:Number):void
		{
			grayRect.rotation = purpleRect.rotation = radians*180/Math.PI;
			polygonPurp.rotation(radians-oldRotate, new FPGPoint2d(purpleRect.x, purpleRect.y));
			oldRotate = radians;
		}
 
		private function calculate():void
		{
			var i:int;
			var j:int;
			var vertex:FPGVertex2d;
			var edge:FPGEdge2d;
			var heightLine:FPGLine2d;
			//
			var leftPoint:FPGVertex2d;
			var leftEdge:FPGEdge2d;
			var maxScale:Number = 1;
			for (i=0; i<polygonRed.vertexes.length; i++) {
				vertex = polygonRed.vertexes[i];
				for (j=0; j<polygonPurp.edges.length; j++) {
					edge = polygonPurp.edges[j];
					if (edge.valueFromPoint(vertex) <= 0) continue;
					heightLine = FPGLineToPoint2dMath.lineHeight(edge, vertex);
					//
					leftPoint = edge.p1 as FPGVertex2d;
					leftEdge = leftPoint.leftEdge;
					maxScale = Math.max(maxScale, (leftEdge.length+heightLine.length*2)/leftEdge.length);
				}
			}
			grayRect.scaleX = grayRect.scaleY = maxScale;
		}
	}
}
Для математических расчетов на плоскости использовал библиотеку FPGeometry2d.swc
__________________
FlashPress.ru | Blog


Последний раз редактировалось maincode; 25.06.2013 в 16:42.
Старый 25.06.2013, 18:15
denver вне форума Посмотреть профиль Отправить личное сообщение для denver Найти все сообщения от denver
  № 3  
Ответить с цитированием
denver

Регистрация: Jan 2010
Сообщений: 32
В версии swc которая доступна для скачивания (http://flashpress.ru/projects/geom/2d/FPGeometry2d.swc), нет например класса FPGPolygon2d используемого в коде примера.

И повлияет ли на результат если "точка регистрации" спрайта будет не в центре, как в Вашем коде, а в левом верхнем углу?

Старый 25.06.2013, 18:20
maincode вне форума Посмотреть профиль Отправить личное сообщение для maincode Посетить домашнюю страницу maincode Найти все сообщения от maincode
  № 4  
Ответить с цитированием
maincode

Регистрация: Feb 2010
Адрес: Город суеты
Сообщений: 191
Последняя версия (ru.flashpress.geom.FPAbout.VERSION = 0.1) лежит здесь http://flashpress.ru/blog/libs/ .
Если точка регистрации будет лежать не в центре, то мой пример работать не будет, надо поэкспериментировать, как будет время - допишу

Добавлено через 21 час 53 минуты
Дописал код так, что бы можно было вертеть объекты с точкой регистрации в левом верхнем углу:
Код AS3:
package
{
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.MouseEvent;
 
	import ru.flashpress.geom.line.FPGLine2d;
	import ru.flashpress.geom.line.math.FPGLineToPoint2dMath;
	import ru.flashpress.geom.point.FPGPoint2d;
	import ru.flashpress.geom.polygon.FPGEdge2d;
	import ru.flashpress.geom.polygon.FPGPolygon2d;
	import ru.flashpress.geom.polygon.FPGVertex2d;
 
	[SWF(width="600", height="600")]
	public class testRect2 extends Sprite
	{
		private static const CENTER_X:Number = 300;
		private static const CENTER_Y:Number = 300;
		//
		private var redRect:Sprite;
		private var purpleRect:Sprite;
		private var grayRect:Sprite;
		private var polygonRed:FPGPolygon2d;
		private var polygonPurp:FPGPolygon2d;
		public function testRect2()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			//
			var wRed:Number = 100;
			var hRed:Number = 200;
			var wPur:Number = 100;
			var hPur:Number = 150;
			//
			redRect = new Sprite();
			redRect.graphics.lineStyle(1, 0xff0000, 1);
			redRect.graphics.drawRect(0, 0, wRed, hRed);
			redRect.graphics.endFill();
			this.addChild(redRect);
			redRect.x = CENTER_X-wRed/2;
			redRect.y = CENTER_Y-hRed/2;
			//
			purpleRect = new Sprite();
			purpleRect.graphics.lineStyle(1, 0xff00ff, 1);
			purpleRect.graphics.drawRect(0, 0, wPur, hPur);
			purpleRect.graphics.endFill();
			this.addChild(purpleRect);
			purpleRect.x = redRect.x + (redRect.width-purpleRect.width)/2;
			purpleRect.y = redRect.y + (redRect.height-purpleRect.height)/2;
			//
			grayRect = new Sprite();
			grayRect.graphics.lineStyle(1, 0x999999, 1);
			grayRect.graphics.drawRect(0, 0, wPur, hPur);
			grayRect.graphics.endFill();
			this.addChild(grayRect);
			//
			// создаем полигон красного прямоугольника
			var redPoints:Vector.<FPGPoint2d> = new Vector.<FPGPoint2d>();
			redPoints.push(new FPGPoint2d(CENTER_X-wRed/2, CENTER_Y-hRed/2));
			redPoints.push(new FPGPoint2d(CENTER_X+wRed/2, CENTER_Y-hRed/2));
			redPoints.push(new FPGPoint2d(CENTER_X+wRed/2, CENTER_Y+hRed/2));
			redPoints.push(new FPGPoint2d(CENTER_X-wRed/2, CENTER_Y+hRed/2));
			polygonRed = new FPGPolygon2d(redPoints);
			//
			// создаем полигон фиолетового прямоугольника
			var purpPoints:Vector.<FPGPoint2d> = new Vector.<FPGPoint2d>();
			purpPoints.push(new FPGPoint2d(CENTER_X-wPur/2, CENTER_Y-hPur/2));
			purpPoints.push(new FPGPoint2d(CENTER_X+wPur/2, CENTER_Y-hPur/2));
			purpPoints.push(new FPGPoint2d(CENTER_X+wPur/2, CENTER_Y+hPur/2));
			purpPoints.push(new FPGPoint2d(CENTER_X-wPur/2, CENTER_Y+hPur/2));
			polygonPurp = new FPGPolygon2d(purpPoints);
			//
			this.stage.addEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
			rotate(0);
			calculate();
		}
 
 
		private function moveHandler(event:MouseEvent):void
		{
			event.updateAfterEvent();
			var dx:Number = this.mouseX-purpleRect.x;
			var dy:Number = this.mouseY-purpleRect.y;
			var radians:Number = Math.atan2(dy, dx);
			rotate(radians);
			calculate();
		}
 
		private var oldRotate:Number = 0;
		private function rotate(radians:Number):void
		{
			// поворачиваем филотетовый полигон относительно центральной точки CENTER_X-CENTER_Y
			// на угол равный разнице между текущим значением и предыдущим
			polygonPurp.rotation(radians-oldRotate, new FPGPoint2d(CENTER_X, CENTER_Y));
			oldRotate = radians;
			//
			//
			// поворачиваем Displayobject-ы
			grayRect.rotation = purpleRect.rotation = radians*180/Math.PI;
			// задаем фиолетовому спрайту координаты смещения
			purpleRect.x = polygonPurp.vertexes[0].x;
			purpleRect.y = polygonPurp.vertexes[0].y;
		}
 
		private function calculate():void
		{
			var i:int;
			var j:int;
			var vertex:FPGVertex2d;
			var edge:FPGEdge2d;
			var heightLine:FPGLine2d;
			//
			var leftPoint:FPGVertex2d;
			var leftEdge:FPGEdge2d;
			var maxScale:Number = 1;
			for (i=0; i<polygonRed.vertexes.length; i++) {
				// текущая вершина красного полигона
				vertex = polygonRed.vertexes[i];
				for (j=0; j<polygonPurp.edges.length; j++) {
					// текущее ребро фиолетового полигона
					edge = polygonPurp.edges[j];
					// если вершина лежит "слева" от ребра, то пропускаем проверку
					// в случае прямоугольников если вершина лежит "слева" -
					// это значит что данное ребро не является наиближайщим к данной вершине
					if (edge.valueFromPoint(vertex) <= 0) continue;
					// получаем отрезок прямой опущенной из вершины на ребро 
					heightLine = FPGLineToPoint2dMath.lineHeight(edge, vertex);
					//
					// определяем левую вершину ребра
					leftPoint = edge.p1 as FPGVertex2d;
					// определяем левое ребро
					// в итоге leftEdge будет ссылаться на ребро соседнее с edge
					leftEdge = leftPoint.leftEdge;
					// определяем максимальный scale
					// длина перпендикуляра heightLine умноженная на 2 - это то значение,
					// на которое надо увеличить соседнее ребро,
					// что бы фиолетовый прямоугольник прошел через текущую вершину
					maxScale = Math.max(maxScale, (leftEdge.length+heightLine.length*2)/leftEdge.length);
				}
			}
			//
			grayRect.scaleX = grayRect.scaleY = maxScale;
			// создаем копию фиолетового полигона
			var polygonClone:FPGPolygon2d = polygonPurp.clone();
			// применяем к этому полигону scale относительно центральной точки
			polygonClone.scale(maxScale, maxScale, new FPGPoint2d(CENTER_X, CENTER_Y));
			// и задаем увеличенному спрайту координаты смещения
			grayRect.x = polygonClone.vertexes[0].x;
			grayRect.y = polygonClone.vertexes[0].y;
		}
	}
}
Дописал библиотеку FPGeometry2d - обновил метод scale(sx, sy) так, что бы можно было передать в него точку, относительно которой происходит растяжение (Текущая версия ru.flashpress.geom.FPAbout.VERSION = 0.1.1)
__________________
FlashPress.ru | Blog

Старый 27.06.2013, 10:54
denver вне форума Посмотреть профиль Отправить личное сообщение для denver Найти все сообщения от denver
  № 5  
Ответить с цитированием
denver

Регистрация: Jan 2010
Сообщений: 32
to maincode: Спасибо за наводку, которая помогла форкнуть мой же пример и получить требуемый результат http://wonderfl.net/c/37hj

Проблема решена, спасибо!

Создать новую тему Ответ Часовой пояс GMT +4, время: 13:50.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


Часовой пояс GMT +4, время: 13:50.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.