Simple Flower Petal Geometry

I recently wanted to make a She Loves Me, She Loves Me Not Game using JavaScript and SVG. My requirements were: 1) Support a random number of petals. 2) The petals should be clickable. Turns out these two requirements make for some fun JavaScript and Geometry.

Here is an image of what I was going for.

Screen Shot 2013-02-13 at 8.22.15 PM

The first thing I tackled was the basic infrastructure of the flower. The following Flower function handles generating a random number of petals and the state of the game messages.

// by Jason Rowe - jasonrowe.com @jsonrow
function Flower(thee, numberOfPetals) {
    var petals = numberOfPetals;

    if(!petals && petals !== 0){
        petals = Math.floor(Math.random()* 5) + 5;
    }

    var originalTotalNumberOfPetals = petals;

    this.totalPetals = function () {
        return originalTotalNumberOfPetals;
    }

    this.removePetal = function(){
        if(petals > 0){
            petals = petals - 1;
        }
        
        return petals;
    };

    this.petals = function(){
        return petals;
    };

    var love = false;

    this.toggleLove = function(){
        love = !love;
        return love;
    };

    this.isItLove = function(){
        return love;
    };

    this.result = function(){
        var message;

        if(this.toggleLove()){
            message = thee + " loves me";
        }
        else{
            message = thee + " loves me not";
        }

        return message;
    };
}
The next thing was to get the actual drawing of the flower. The first challenge I ran into was creating a random number of petals equally distributed around the center of the flower. To do this I used the polar coordinate system.
 var totalPetals = flowerData.petals();
 for(var i = 0; i < totalPetals; i++){
     log("creating petal");

     // Creates Circle Polar Coordinate System

     var radius = 83;
     var centerX = 170;
     var centerY = 160;

     // get x, y position of the petals
     var xPosition = radius * Math.cos(2 * Math.PI * i / totalPetals) + centerX;
     var yPosition = radius * Math.sin(2 * Math.PI * i / totalPetals) + centerY;
        ....

It quickly became apparent that I needed more Geometry to point the petals in the right direction.

Screen Shot 2013-02-22 at 11.22.56 PM

So to help find the correct rotation, I created a TrianglePointsToDegrees function which would solve the angles I needed.

//by Jason Rowe - jasonrowe.com @jsonrow 2013
//Given a triangle with points (x1, y1, x2, y2, x3, y3),
// calculates angles A,B,C and edges a,b,c
//
//
//     lower case a,b,c are the edges
//     upper case A,B,C are angles
//            (x1, y1)
//               /\
//            b / C\ a
//             /    \
//            /      \
//    (x2,y2)/A______B\(x3, y3)
//               c
function TrianglePointsToDegrees(x1, y1, x2, y2, x3, y3){
	
    //distance formula to find lengths between points
	function lineDistance( point1, point2 ){
		var xs = 0;
		var ys = 0;

		xs = point2.x - point1.x;
		xs = xs * xs;

		ys = point2.y - point1.y;
		ys = ys * ys;

		return Math.sqrt( xs + ys );
	};

	log("create points");

	var point1 = {"x": x1, "y": y1};
	var point2 = {"x": x2, "y": y2};
	var point3 = {"x": x3, "y": y3};

	log("create triangle edges");

	var edgeA = {};
	edgeA.points = [point3, point1];
	edgeA.distance = lineDistance(point3, point1);

	this.edgeA = function(){
		return edgeA;
	};

	var edgeB = {};
	edgeB.points = [point1, point2];
	edgeB.distance = lineDistance(point1, point2);

	this.edgeB = function(){
		return edgeB;
	};

	var edgeC = {};
	edgeC.points = [point2, point3];
	edgeC.distance = lineDistance(point2, point3);

	this.edgeC = function(){
		return edgeC;
	};

    var sidea = edgeA.distance;
    var sideb = edgeB.distance;
    var sidec = edgeC.distance;

   log("calc angles");

	var anga = Math.acos((-sidea*sidea+sideb*sideb+sidec*sidec)/(2*sideb*sidec));
	var angb = Math.acos((-sideb*sideb+sidea*sidea+sidec*sidec)/(2*sidea*sidec));
	var angc = Math.acos((-sidec*sidec+sidea*sidea+sideb*sideb)/(2*sidea*sideb));

	this.aDegree = function(){
		return anga*180/Math.PI;
	};

	this.bDegree = function(){
		return angb*180/Math.PI;
	};

	this.cDegree = function(){
		return angc*180/Math.PI;
	};
}

Then after creating my x, y coordinates, I found the angle I needed, and completed the ellipse rotation

Screen Shot 2013-02-22 at 11.23.34 PM
var totalPetals = flowerData.petals();
for(var i = 0; i < totalPetals; i++){
    log("creating petal");

    // Creates Circle Polar Coordinate System

    var radius = 83;
    var centerX = 170;
    var centerY = 160;

    // get x, y position of the petals
    var xPosition = radius * Math.cos(2 * Math.PI * i / totalPetals) + centerX;
    var yPosition = radius * Math.sin(2 * Math.PI * i / totalPetals) + centerY;

    var ellipseHeight = 70;
    var petalEllipse = this.paper.ellipse(xPosition, yPosition, 30, ellipseHeight);

    var angle = null;

    if(xPosition !== centerX){

        var triangle = new TrianglePointsToDegrees(xPosition, yPosition, centerX, centerY, xPosition, yPosition + ellipseHeight)
        
        if(xPosition > centerX){
            angle = triangle.cDegree();
         }
         else{
            angle = -triangle.cDegree();
         }
     }

    //rotate ellipse around center
    if(angle){
        petalEllipse.transform("r" + angle);
    }

The final fun Geometry was the stem which is a quadratic B├ęzier curve. I mostly just used trial and error to get the intermediate points Q “M 150 150, Q 210 227 150 300 Q 70 400 150 450″. The other points are just the start, middle, and end of the line.

    var stem = this.paper.path("M 150 150, Q 210 227 150 300 Q 70 400 150 450")
    stem.attr({stroke:'#47D147',"stroke-width":5});

    stem.attr("width", 5);