Skip to main content
Inspiring
April 16, 2017
Question

Rotation of sprite on polygon edge

  • April 16, 2017
  • 1 reply
  • 416 views

Hi

I have these two functions. One positions a number of sprites in a polygon shape, the other the same but in a star. Everything works, except from the last part where I'm rotating the sprites. On some of the edges they are rotated 180 degrees wrong.

So this line in both functions are not correct:

target.rotation = 90-A/(Math.PI/180);

In this example all the triangles should point outwards.

Can anybody figure out why, and tell me how make them all rotate correctly?

Thanks,

Jakob

package

{

    import flash.display.MovieClip;

    import flash.display.Graphics;

    import flash.display.Sprite;

    import flash.geom.Point;

    import flash.events.Event;

   

    public class Polygon extends MovieClip

    {

        private var numberOfMarkers;

        private var markers:Sprite;

        private var offset:Number;

        private var numberOfSides:int;

        private var polygonAngle:Number;

        private var cornerMarginLeft:Number;

        private var cornerMarginRight:Number;

        private var sideOffset:Number;

        private var startAngle:Number;

        private var endAngle:Number;

       

        public function Polygon()

        {

            numberOfMarkers = 30;

            offset = 0;

            numberOfSides = 5;

            polygonAngle = 0;

            cornerMarginLeft = 0;

            cornerMarginRight = 0;

            sideOffset = 0;

            startAngle = 0;

            endAngle = 360;

           

            markers = new Sprite();

            addChild(markers);

           

            // draw polygon

            for(var i:int=0;i<numberOfMarkers;i++)

            {

                var markerP:Sprite = new Sprite();

                markers.addChild(markerP);

               

                markerP.graphics.beginFill(0xFF0000, .8);

                markerP.graphics.moveTo(0,-15);

                markerP.graphics.lineTo(10,10);

                markerP.graphics.lineTo(-10,10);

                markerP.graphics.lineTo(0,-15);

               

                positionInPolygon(markerP, 200, 300, numberOfSides, 200, polygonAngle, 360/numberOfMarkers*i+offset, i);

            }

           

            // draw star

            for(var k:int=0;k<numberOfMarkers;k++)

            {

                var markerS:Sprite = new Sprite();

                markers.addChild(markerS);

               

                markerS.graphics.beginFill(0xFF0000, .8);

                markerS.graphics.moveTo(0,-15);

                markerS.graphics.lineTo(10,10);

                markerS.graphics.lineTo(-10,10);

                markerS.graphics.lineTo(0,-15);

               

                positionInStar(markerS, 600, 300, numberOfSides, 100, 200, polygonAngle, 360/numberOfMarkers*k+offset);

            }

        }

       

        public function positionInStar(target:Sprite, x:Number, y:Number, spikes:uint, innerRadius:Number, outerRadius:Number, angle:Number, atAngle:Number):void

        {

            if (spikes <= 2)

            {

                throw ArgumentError("DrawingShapes.drawPolygon() - parameter 'sides' needs to be atleast 3");

                return;

            }

            if (spikes > 2)

            {

                var points:Array = [];

               

                var step:Number, halfStep:Number, start:Number, n:Number, dx:Number, dy:Number;

                step = (Math.PI * 2) / spikes;

                halfStep = step / 2;

                start = (angle / 180) * Math.PI;

                points[0] = new Point(x + (Math.cos(start) * outerRadius), y - (Math.sin(start) * outerRadius));

                for (var i:int=1;i<=spikes;++i)

                {

                    dx = x + Math.cos(start + (step * i) - halfStep) * innerRadius;

                    dy = y - Math.sin(start + (step * i) - halfStep) * innerRadius;

                    points[(i-1)*2+1] = new Point(dx, dy);

                    dx = x + Math.cos(start + (step * i)) * outerRadius;

                    dy = y - Math.sin(start + (step * i)) * outerRadius;

                    points[(i-1)*2+2] = new Point(dx, dy);

                }

               

                atAngle = atAngle%360;

                var sideLength:Number = Point.distance(points[0], points[1]);

                var cornerMarginLeftLength = sideLength*cornerMarginLeft/100;

                var cornerMarginRightLength = sideLength*cornerMarginRight/100;

                sideLength -= cornerMarginLeftLength;

                sideLength -= cornerMarginRightLength;

               

                var totalLength:Number = sideLength*spikes*2;

                var distanceFromStart:Number = totalLength*atAngle/360;

                var startPoint:int = Math.floor(distanceFromStart/sideLength);

                var endPoint:int = startPoint==spikes*2-1?0:startPoint+1;

                var distanceFromStartPoint:Number = distanceFromStart-(sideLength*startPoint)+cornerMarginRightLength+sideOffset;

                var a:Number = points[startPoint].x-points[endPoint].x;

                var b:Number = points[startPoint].y-points[endPoint].y;

                var A:Number = Math.atan(a/b);

                var na:Number = Math.sin(A)*distanceFromStartPoint*(b<0?1:-1);

                var nb:Number = Math.cos(A)*distanceFromStartPoint*(b<0?1:-1);

               

                target.x = points[startPoint].x+na;

                target.y = points[startPoint].y+nb;

                target.rotation = 90-A/(Math.PI/180);

            }

        }

       

        public function positionInPolygon(target:Sprite, x:Number, y:Number, sides:uint, radius:Number, angle:Number, atAngle:Number, index):void

        {

            if (sides <= 2)

            {

                throw ArgumentError("DrawingShapes.drawPolygon() - parameter 'sides' needs to be atleast 3");

                return;

            }

            if (sides > 2)

            {

                var points:Array = [];

                var step:Number, start:Number, dx:Number, dy:Number;

                step = (Math.PI * 2) / sides;

                start = (angle / 180) * Math.PI;

               

                points[0] = new Point(x + (Math.cos(start) * radius), y - (Math.sin(start) * radius));

                for (var i:int=1;i<=sides;++i)

                {

                    dx = x + Math.cos(start + (step * i)) * radius;

                    dy = y - Math.sin(start + (step * i)) * radius;

                    points = new Point(dx, dy);

                }

               

                var subEnd = (360-endAngle)*(1-((index+1)/numberOfMarkers));

                var subStart = startAngle*((index)/numberOfMarkers);

                atAngle = atAngle%360;

                atAngle += subEnd;

                atAngle -= subStart;

               

                var sideLength:Number = 2*radius*Math.sin(Math.PI/sides);

                var cornerMarginLeftLength = sideLength*cornerMarginLeft/100;

                var cornerMarginRightLength = sideLength*cornerMarginRight/100;

                var totalLength:Number = sideLength*sides;

                var distanceFromStart:Number = totalLength*atAngle/360;

                var startPoint:int = Math.floor(distanceFromStart/sideLength);

                var endPoint:int = startPoint==sides-1?0:startPoint+1;

               

                sideLength -= cornerMarginLeftLength;

                sideLength -= cornerMarginRightLength;

                totalLength = sideLength*sides;

                distanceFromStart = totalLength*atAngle/360;

               

                var distanceFromStartPoint:Number = distanceFromStart-(sideLength*startPoint)+cornerMarginRightLength+sideOffset;

                var a:Number = points[startPoint].x-points[endPoint].x;

                var b:Number = points[startPoint].y-points[endPoint].y;

                var A:Number = Math.atan(a/b);

                var na:Number = Math.sin(A)*distanceFromStartPoint*(b<0?1:-1);

                var nb:Number = Math.cos(A)*distanceFromStartPoint*(b<0?1:-1);

               

                target.x = points[startPoint].x+na;

                target.y = points[startPoint].y+nb;

                target.rotation = 90-A/(Math.PI/180);

            }

        }

    }

}

This topic has been closed for replies.

1 reply

kglad
Community Expert
Community Expert
April 16, 2017

that code isn't the way i would encode that.

first, i could make the number of sides variable, so you class is really a general Polygon_Star class not a Pentagon_5PointedStar class like you have now.  2nd i would move the perimeter maker creation to a private function  (all appear to be red triangles).  and 3rd your rotations do look screwy.  they should each probably be rotated towards the center of the pentagon/star.

Inspiring
April 17, 2017

Hi Kglad

Thank you for answering. Maybe I asked in a weird way. My problem is exactly that rotations are wrong. All triangles should be pointing outwards, as some of them already are.

So this line is the problem: target.rotation = 90-A/(Math.PI/180);

I'm looking for help to fix this line so that all triangles are pointing outwards.

Other than that, I totally agree with you structure wise.

- Jakob

Colin Holgate
Inspiring
April 17, 2017

There are a few things wrong, and the different wrongnesses compensate for each other, but not quite making it all work.

I managed to get your code going and could fix the easy things, but didn't quite figure out how the main polygon angles are done. So, I'll tell you the two most important things, and then perhaps you'll see how to make the rest work.

1. When drawing an arrow or pointed triangle that you intend to rotate to a particular direction, make the original point to the right, not upwards. Zero rotation is to the right.

2. The two parameter version of atan() need the Y difference first. Like, Math.atan(dy,dx); You're doing Math.atan(dx,dy);

Between those two things you should get a lot closer, but you'll need to take out your work-arounds such as 90-A/(Math.PI/180)