/* This file contains proprietary software owned by Motorola Mobility, Inc.
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
*/ /////////////////////////////////////////////////////////////////////// // Class RuntimeGeomObj // Super class for all geometry classes /////////////////////////////////////////////////////////////////////// function RuntimeGeomObj() { /////////////////////////////////////////////////////////////////////// // Constants /////////////////////////////////////////////////////////////////////// this.GEOM_TYPE_RECTANGLE = 1; this.GEOM_TYPE_CIRCLE = 2; this.GEOM_TYPE_LINE = 3; this.GEOM_TYPE_PATH = 4; this.GEOM_TYPE_CUBIC_BEZIER = 5; this.GEOM_TYPE_UNDEFINED = -1; /////////////////////////////////////////////////////////////////////// // Instance variables /////////////////////////////////////////////////////////////////////// this._children; // stroke and fill colors this._strokeColor = [0,0,0,0]; this._fillColor = [0,0,0,0]; // array of materials this._materials = []; /////////////////////////////////////////////////////////////////////// // Property accessors /////////////////////////////////////////////////////////////////////// this.geomType = function() { return this.GEOM_TYPE_UNDEFINED; } this.setWorld = function(w) { this._world = w; } this.getWorld = function() { return this._world; } /////////////////////////////////////////////////////////////////////// // Methods /////////////////////////////////////////////////////////////////////// this.makeStrokeMaterial = function() { } this.makeFillMaterial = function() { } this.render = function() { } this.addChild = function( child ) { if (!this._children) this._children = []; this._children.push( child ); } this.import = function() { } this.importMaterials = function(importStr) { var nMaterials = Number( getPropertyFromString( "nMaterials: ", importStr ) ); for (var i=0; i= 0.001) { var scale = len/sum; rtnVec = []; for (var i=0; i= 0) rtnStr = rtnStr.substr(0, index); return rtnStr; } /////////////////////////////////////////////////////////////////////// // Class RuntimeRectangle /////////////////////////////////////////////////////////////////////// function RuntimeRectangle() { // inherit the members of RuntimeGeomObj this.inheritedFrom = RuntimeGeomObj; this.inheritedFrom(); this.import = function( importStr ) { this._xOffset = Number( getPropertyFromString( "xoff: ", importStr ) ); this._yOffset = Number( getPropertyFromString( "yoff: ", importStr ) ); this._width = Number( getPropertyFromString( "width: ", importStr ) ); this._height = Number( getPropertyFromString( "height: ", importStr ) ); this._strokeWidth = Number( getPropertyFromString( "strokeWidth: ", importStr ) ); this._innerRadius = Number( getPropertyFromString( "innerRadius: ", importStr ) ); this._strokeStyle = Number( getPropertyFromString( "strokeStyle: ", importStr ) ); var strokeMaterialName = getPropertyFromString( "strokeMat: ", importStr ); var fillMaterialName = getPropertyFromString( "fillMat: ", importStr ); this._strokeStyle = getPropertyFromString( "strokeStyle: ", importStr ); this._fillColor = eval( "[" + getPropertyFromString( "fillColor: ", importStr ) + "]" ); this._strokeColor = eval( "[" + getPropertyFromString( "strokeColor: ", importStr ) + "]" ); this._tlRadius = Number( getPropertyFromString( "tlRadius: ", importStr ) ); this._trRadius = Number( getPropertyFromString( "trRadius: ", importStr ) ); this._blRadius = Number( getPropertyFromString( "blRadius: ", importStr ) ); this._brRadius = Number( getPropertyFromString( "brRadius: ", importStr ) ); this.importMaterials( importStr ); } this.renderPath = function( inset, ctx ) { // various declarations var pt, rad, ctr, startPt, bPts; var width = Math.round(this._width), height = Math.round(this._height); pt = [inset, inset]; // top left corner var tlRad = this._tlRadius; //top-left radius var trRad = this._trRadius; var blRad = this._blRadius; var brRad = this._brRadius; if ((tlRad <= 0) && (blRad <= 0) && (brRad <= 0) && (trRad <= 0)) { ctx.rect(pt[0], pt[1], width - 2*inset, height - 2*inset); } else { // get the top left point rad = tlRad - inset; if (rad < 0) rad = 0; pt[1] += rad; if (Math.abs(rad) < 0.001) pt[1] = inset; ctx.moveTo( pt[0], pt[1] ); // get the bottom left point pt = [inset, height - inset]; rad = blRad - inset; if (rad < 0) rad = 0; pt[1] -= rad; ctx.lineTo( pt[0], pt[1] ); // get the bottom left curve if (rad > 0.001) ctx.quadraticCurveTo( inset, height-inset, inset+rad, height-inset ); // do the bottom of the rectangle pt = [width - inset, height - inset]; rad = brRad - inset; if (rad < 0) rad = 0; pt[0] -= rad; ctx.lineTo( pt[0], pt[1] ); // get the bottom right arc if (rad > 0.001) ctx.quadraticCurveTo( width-inset, height-inset, width-inset, height-inset-rad ); // get the right of the rectangle pt = [width - inset, inset]; rad = trRad - inset; if (rad < 0) rad = 0; pt[1] += rad; ctx.lineTo( pt[0], pt[1] ); // do the top right corner if (rad > 0.001) ctx.quadraticCurveTo( width-inset, inset, width-inset-rad, inset ); // do the top of the rectangle pt = [inset, inset] rad = tlRad - inset; if (rad < 0) rad = 0; pt[0] += rad; ctx.lineTo( pt[0], pt[1] ); // do the top left corner if (rad > 0.001) ctx.quadraticCurveTo( inset, inset, inset, inset+rad ); else ctx.lineTo( inset, 2*inset ); } } this.render = function() { // get the world var world = this.getWorld(); if (!world) throw( "null world in rectangle render" ); // get the context var ctx = world.get2DContext(); if (!ctx) return; // get some dimensions var lw = this._strokeWidth; var w = world.getViewportWidth(), h = world.getViewportHeight(); // render the fill ctx.beginPath(); if (this._fillColor) { var c = "rgba(" + 255*this._fillColor[0] + "," + 255*this._fillColor[1] + "," + 255*this._fillColor[2] + "," + this._fillColor[3] + ")"; ctx.fillStyle = c; ctx.lineWidth = lw; var inset = Math.ceil( lw ) + 0.5; this.renderPath( inset, ctx ); ctx.fill(); ctx.closePath(); } // render the stroke ctx.beginPath(); if (this._strokeColor) { var c = "rgba(" + 255*this._strokeColor[0] + "," + 255*this._strokeColor[1] + "," + 255*this._strokeColor[2] + "," + this._strokeColor[3] + ")"; ctx.strokeStyle = c; ctx.lineWidth = lw; var inset = Math.ceil( 0.5*lw ) + 0.5; this.renderPath( inset, ctx ); ctx.stroke(); ctx.closePath(); } } } /////////////////////////////////////////////////////////////////////// // Class RuntimeOval /////////////////////////////////////////////////////////////////////// function RuntimeOval() { // inherit the members of RuntimeGeomObj this.inheritedFrom = RuntimeGeomObj; this.inheritedFrom(); this.import = function( importStr ) { this._xOffset = Number( getPropertyFromString( "xoff: ", importStr ) ); this._yOffset = Number( getPropertyFromString( "yoff: ", importStr ) ); this._width = Number( getPropertyFromString( "width: ", importStr ) ); this._height = Number( getPropertyFromString( "height: ", importStr ) ); this._strokeWidth = Number( getPropertyFromString( "strokeWidth: ", importStr ) ); this._innerRadius = Number( getPropertyFromString( "innerRadius: ", importStr ) ); this._strokeStyle = getPropertyFromString( "strokeStyle: ", importStr ); var strokeMaterialName = getPropertyFromString( "strokeMat: ", importStr ); var fillMaterialName = getPropertyFromString( "fillMat: ", importStr ); this._fillColor = eval( "[" + getPropertyFromString( "fillColor: ", importStr ) + "]" ); this._strokeColor = eval( "[" + getPropertyFromString( "strokeColor: ", importStr ) + "]" ); this.importMaterials( importStr ); } this.render = function() { // get the world var world = this.getWorld(); if (!world) throw( "null world in buildBuffers" ); // get the context var ctx = world.get2DContext(); if (!ctx) return; // declare some variables var p0, p1; var x0, y1, x1, y1; // create the matrix var lineWidth = this._strokeWidth; var innerRad = this._innerRadius; var xScale = 0.5*this._width - lineWidth, yScale = 0.5*this._height - lineWidth; // translate var xCtr = 0.5*world.getViewportWidth() + this._xOffset, yCtr = 0.5*world.getViewportHeight() + this._yOffset; var mat = Matrix.create( [ [ xScale, 0.0, 0.0, xCtr], [ 0.0, yScale, 0.0, yCtr], [ 0.0, 0.0, 1.0, 0.0], [ 0.0, 0.0, 0.0, 1.0] ] ); // get a bezier representation of the circle var bezPts = this.circularArcToBezier( [0,0,0], [1,0,0], 2.0*Math.PI ); if (bezPts) { var n = bezPts.length; // set up the fill style ctx.beginPath(); ctx.lineWidth = 0; if (this._fillColor) { var c = "rgba(" + 255*this._fillColor[0] + "," + 255*this._fillColor[1] + "," + 255*this._fillColor[2] + "," + this._fillColor[3] + ")"; ctx.fillStyle = c; // draw the fill ctx.beginPath(); var p = this.transformPoint( bezPts[0], mat ); ctx.moveTo( p[0], p[1] ); var index = 1; while (index < n) { p0 = this.transformPoint( bezPts[index], mat ); p1 = this.transformPoint( bezPts[index+1], mat ); x0 = p0[0]; y0 = p0[1]; x1 = p1[0]; y1 = p1[1]; ctx.quadraticCurveTo( x0, y0, x1, y1 ); index += 2; } if ( innerRad > 0.001) { xScale = 0.5*innerRad*this._width; yScale = 0.5*innerRad*this._height; mat[0] = xScale; mat[5] = yScale; // get the bezier points var bezPts = this.circularArcToBezier( Vector.create([0,0,0]), Vector.create([1,0,0]), -2.0*Math.PI ); if (bezPts) { var n = bezPts.length; p = this.transformPoint( bezPts[0], mat ); ctx.moveTo( p[0], p[1] ); index = 1; while (index < n) { p0 = this.transformPoint( bezPts[index], mat ); p1 = this.transformPoint( bezPts[index+1], mat ); var x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1]; ctx.quadraticCurveTo( x0, y0, x1, y1 ); index += 2; } } } // fill the path ctx.fill(); } // calculate the stroke matrix xScale = 0.5*this._width - 0.5*lineWidth; yScale = 0.5*this._height - 0.5*lineWidth; mat[0] = xScale; mat[5] = yScale; // set up the stroke style ctx.beginPath(); ctx.lineWidth = lineWidth; if (this._strokeColor) { var c = "rgba(" + 255*this._strokeColor[0] + "," + 255*this._strokeColor[1] + "," + 255*this._strokeColor[2] + "," + this._strokeColor[3] + ")"; ctx.strokeStyle = c; // draw the stroke p = this.transformPoint( bezPts[0], mat ); ctx.moveTo( p[0], p[1] ); index = 1; while (index < n) { var p0 = this.transformPoint( bezPts[index], mat ); var p1 = this.transformPoint( bezPts[index+1], mat ); var x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1]; ctx.quadraticCurveTo( x0, y0, x1, y1 ); index += 2; } if (innerRad > 0.01) { // calculate the stroke matrix xScale = 0.5*innerRad*this._width - 0.5*lineWidth; yScale = 0.5*innerRad*this._height - 0.5*lineWidth; mat[0] = xScale; mat[5] = yScale; // draw the stroke p = this.transformPoint( bezPts[0], mat ); ctx.moveTo( p[0], p[1] ); index = 1; while (index < n) { var p0 = this.transformPoint( bezPts[index], mat ); var p1 = this.transformPoint( bezPts[index+1], mat ); var x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1]; ctx.quadraticCurveTo( x0, y0, x1, y1 ); index += 2; } } // render the stroke ctx.stroke(); } } } /////////////////////////////////////////////////////////////////////// // this function returns the quadratic Bezier approximation to the specified // circular arc. The input can be 2D or 3D, determined by the minimum dimension // of the center and start point. // includedAngle is in radians, can be positiveor negative this.circularArcToBezier= function( ctr_, startPt_, includedAngle ) { var dimen = 3; var ctr = ctr_.slice(); var startPt = startPt_.slice(); // make sure the start point is good var pt = this.vecSubtract(dimen, startPt, ctr); var rad = this.vecMag(dimen, pt); if ((dimen != 3) || (rad <= 0) || (includedAngle === 0)) { if (dimen != 3) console.log( "circularArcToBezier works for 3 dimensional points only. Was " + dimen ); return [ startPt.slice(0), startPt.slice(0), startPt.slice(0) ]; } // determine the number of segments. 45 degree span maximum. var nSegs = Math.ceil( Math.abs(includedAngle)/(0.25*Math.PI) ); if (nSegs <= 0) return [ startPt.slice(0), startPt.slice(0), startPt.slice(0) ]; var dAngle = includedAngle/nSegs; // determine the length of the center control point from the circle center var cs = Math.cos( 0.5*Math.abs(dAngle) ), sn = Math.sin( 0.5*Math.abs(dAngle) ); var c = rad*sn; var h = c*sn/cs; var d = rad*cs + h; var rtnPts = [ this.vecAdd(dimen, pt, ctr) ]; var rotMat = Matrix.RotationZ( dAngle ); for ( var i=0; i