Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   [Алгоритмы] Отрисовка кривой со стрелочкой на конце (http://www.flasher.ru/forum/showthread.php?t=210795)

Alex626 06.05.2015 17:31

Отрисовка кривой со стрелочкой на конце
 
Добрый день!

У меня возникла необходимость отрисовывать в программе кривые линии методом curveTo, и нужно чтобы на конце каждая такая линия оканчивалась стрелочкой. Как в иллюстраторе. С прямыми линиями lineTo всё было проще - можно узнать градус наклона линии, и соответственно, отрисовать на конце стрелку под определённым углом. А вот с кривыми проблема - контрольная точка вносит неясность, и непонятно, как определять угол касательной на конце этой кривой. А нужно очень точно определять, чтобы работало с любым искривлением.

Есть материал, но он для прямых линий: http://stackoverflow.com/questions/8...ing-line-slope

Вопрос: можно ли как-то математически вычислить этот угол наклона, и как это сделать? Можно ли придумать какой-то иной способ для реализации задуманного?

Спасибо большое за внимание!

undefined 06.05.2015 18:04

Глядя сюда,можно предположить что можно использовать алгоритм рисования стрелочки для прямой.Только в качестве прямой будет касательная в конце курвы(от controlX;controlY до anchorX;anchorY)

OlmerDale 06.05.2015 18:57

Цитата:

Глядя сюда можно предположить что можно использовать алгоритм рисования стрелочки для прямой.
Смотря какие требования к точности. Правильную стрелку можно нарисовать отложив точку на кривой образующую прямую (равную длине стрелки) с конечной точкой кривой. И вот от этой точки отложить две перпендикулярные прямые равные половине основания стрелки.
Если так не сделать, то будет ощущение, что кривая не в центр входит.

undefined 06.05.2015 19:38

Насколько я понял проблема не в том как нарисовать стрелку,а в том,как найти угол,на который надо повернуть изображение стрелки.
Цитата:

Если так не сделать, то будет ощущение, что кривая не в центр входит.
ничего не будет направление стрелки должно совпадать с касательной на конце

OlmerDale 06.05.2015 19:39

Вложений: 1
Ну так откладываемый на кривой отрезок и будет угол относительно точки конца..

Я вот о чем, F это опорная точка -

Хотя так тоже некрасиво. Лучше искать ещё одну точку и саму стрелку изгибать относительно кривой.

Wolsh 06.05.2015 21:43

В направлении контрольной точки рисуете прямой штришок на длину стрелки (корень стрелки) и кривую приводите к нему. Тоесть рисуете короткую прямую стрелку и присоединяете к ней кривую.

Alex626 06.05.2015 23:16

Цитата:

Сообщение от Wolsh (Сообщение 1182088)
В направлении контрольной точки рисуете прямой штришок на длину стрелки (корень стрелки) и кривую приводите к нему. Тоесть рисуете короткую прямую стрелку и присоединяете к ней кривую.

Я пробовал, но это выглядит не так надёжно. К тому же, если контрольная точка находится близко к краю, и у кривой сильный изгиб в конце, то это не будет работать.

Цитата:

Сообщение от OlmerDale (Сообщение 1182078)
Лучше искать ещё одну точку и саму стрелку изгибать относительно кривой.

Как это сделать в коде? Я имею в виду, какую именно точку - как её найти?

OlmerDale 07.05.2015 15:43

Цитата:

Как это сделать в коде? Я имею в виду, какую именно точку - как её найти?
Найти нужно точку G, а как это сделать, знаю лишь приблизительно, опробовать время нет.
Но на словах - найти длину кривой и узнать процентное соотношение длины наконечника к кривой.
А дальше с помощью аппроксимации найти координаты этой точки. И так наверное даже лучше будет,
так как если сильно загнуть и приблизить опорную точку к концу кривой, то сама стрелка будет визуально немного меньше из-за того, что нахождение описанное выше предполагает, что искомый отрезок в точности совпадает с кривой.

OlmerDale 07.05.2015 20:54

Вложений: 1
Качаете bezier. которая Вам покажет и координаты точки и угол наклона в этой точке и длину все кривой. Этой информации хватит чтобы любую стрелку отрисовать.
Код AS3:

package
{
        import flash.display.DisplayObject;
        import flash.display.Graphics;
        import flash.display.Shape;
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.MouseEvent;
        import flash.geom.Bezier;
        import flash.geom.Point;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
 
 
        public class Main extends Sprite
        {
                private var _allCircles:Vector.<DisplayObject> = new Vector.<DisplayObject>();
 
                private var _currentPivotPoint:DisplayObject;
                private var _bezier:Bezier;
                private var _map:Object;
                private var _pivot:DisplayObject;
                private var _textField:TextField;
 
                public function Main()
                {
                        if (stage) init();
                        else addEventListener(Event.ADDED_TO_STAGE, init);
                }
 
                private function init(e:Event = null):void
                {
                        removeEventListener(Event.ADDED_TO_STAGE, init);
 
                        stage.color = 0x232323;
 
                        _textField = new TextField();
                        _textField.textColor = 0x595959;
                        _textField.autoSize = TextFieldAutoSize.LEFT;
                        super.addChild(_textField);
 
                        var start:Point = new Point(100, 100);
                        var end:Point = new Point(300, 100);
                        var control:Point = new Point(200, 50);
 
                        _bezier = new Bezier(start, control, end);
 
                        var a:DisplayObject = this.createCircle();
                        var b:DisplayObject = this.createCircle();
                        var c:DisplayObject = this.createCircle();
 
                        a.name = 'start';
                        b.name = 'end';
                        c.name = 'control';
 
                        _map = { };
                        _map[a.name] = _bezier.start;
                        _map[b.name] = _bezier.end;
                        _map[c.name] = _bezier.control;
 
                        this._allCircles.push(a);
                        this._allCircles.push(b);
                        this._allCircles.push(c);
 
                        a.x = start.x;
                        a.y = start.y;
 
                        b.x = end.x;
                        b.y = end.y;
 
                        c.x = control.x;
                        c.y = control.y;
 
                        super.addChild(a);
                        super.addChild(b);
                        super.addChild(c);
 
                        _pivot = this.createCircle(1, 0xEB0101);
 
                        super.addChild(_pivot);
 
                        this.drawCurve();
 
                        stage.addEventListener(MouseEvent.MOUSE_DOWN, stage_mouseDownHandler);
                        stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler);
                }
 
                private function stage_mouseUpHandler(event:MouseEvent):void
                {
                        super.removeEventListener(Event.ENTER_FRAME, super_enterFrameHandler);
                }
 
                private function stage_mouseDownHandler(event:MouseEvent):void
                {
                        if (this._allCircles.length == 3)
                        {
                                var length:int = this._allCircles.length;
 
                                while (length-- > 0)
                                {
                                        if (this._allCircles[length].hitTestPoint(event.stageX, event.stageY, true))
                                        {
                                                this._currentPivotPoint = this._allCircles[length];
                                                super.addEventListener(Event.ENTER_FRAME, super_enterFrameHandler);
                                        }
                                }
                        }
                }
 
                private function super_enterFrameHandler(event:Event):void
                {
                        var point:Point = this._map[this._currentPivotPoint.name];
 
                        point.x = this._currentPivotPoint.x = super.stage.mouseX
                        point.y = this._currentPivotPoint.y = super.stage.mouseY;
 
                        this.drawCurve();
                }
 
                private function createCircle(radius:Number = 4, color:uint = 0x67CDD6, lineSize:Number = 1, lineColor:uint = 0xFFFFFF):DisplayObject
                {
                        var circle:Shape = new Shape();
                        var graphics:Graphics = circle.graphics;
 
                        graphics.beginFill(color);
                        graphics.lineStyle(lineSize, lineColor);
                        graphics.drawCircle(0, 0, radius);
                        graphics.endFill();
 
                        return circle;
                }
 
                private function drawCurve():void
                {
                        var point:Point =  _bezier.getPoint(.9);
 
                        this._textField.text = 'point x: ' + point.x + '\n' + 'point y: ' + point.y + '\n' + 'angle: ' + _bezier.getTangentAngle(.9) + '\n' + 'length: ' + _bezier.length;
 
                        trace(point, _bezier.getTangentAngle(.9));
                        _pivot.x = point.x;
                        _pivot.y = point.y;
 
                        super.graphics.clear();
                        super.graphics.lineStyle(1);
                        super.graphics.moveTo(this._bezier.start.x, this._bezier.start.y);
                        super.graphics.curveTo(this._bezier.control.x, this._bezier.control.y, this._bezier.end.x, this._bezier.end.y);
                }
 
        }
 
}


Голосуем за редактор! Если Вы уже голосовали, то голосуйте ещё раз, при смене ip это становится возможным!
Не дадим haxe одержать победу на as3.

bezier.swf   (19.5 Кб)

Alex626 07.05.2015 20:58

Просто великолепно! Спасибо огромное!


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

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