forked from: [sketchbook]で描けない図形があったので
drawRoundRect, drawRoundRectComplexに負の値を入れたときに、凹んだ形になるサンプル
/**
* Copyright Kay ( http://wonderfl.net/user/Kay )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/nAOx
*/
// forked from Kay's [sketchbook]で描けない図形があったので
package {
import flash.display.Sprite;
public class FlashTest extends Sprite {
public function FlashTest() {
var g:GraphicsHelper = new GraphicsHelper(graphics);
// 問題なし
g.lineStyle(0.1,0x000000,1,true);
g.drawRoundRect(50, 50, 200, 200, 50, 25);
// drawRoundRectに負の値を入れる
g.lineStyle(0.1,0xff0000,1,true);
g.drawRoundRect(110, 110, 200, 200, -50, -25);
// 問題なし
g.lineStyle(0.1, 0x000000, 1, true);
g.drawRoundRectComplex(170, 170, 200, 200, 50, 0, 0, 50);
// drawRoundRectComplexに負の値を入れる
g.lineStyle(0.1, 0xff0000, 1, true);
g.drawRoundRectComplex(230, 230, 200, 200, 50, -50, -50, 50);
}
}
}
//package sketchbook.graphics
//{
import flash.display.Graphics;
import flash.geom.Point;
import flash.geom.Matrix;
import flash.display.Bitmap;
import flash.display.BitmapData;
/**
* Graphicsクラスを操作する為のヘルパーオブジェクトです。
* <p>基本的な多角形や、ポリライン描画などをサポートします</p>
*/
/*public*/ class GraphicsHelper
{
protected var _target:Graphics
public function GraphicsHelper(_target:Graphics)
{
this._target = _target
}
public function set target(val:Graphics):void
{
_target = val;
}
public function get target():Graphics
{
return _target;
}
/*
Draws a series of lines to target graphics instance.
points:Array array that contains Point instances
close:Boolean if true, close line from the last point to tha first point.
*/
public function drawLines(points:Array, close:Boolean=false):void
{
var g:Graphics = this._target
var imax:Number = points.length
g.moveTo(points[0].x, points[0].y);
for(var i:Number=1; i<imax; i++)
g.lineTo(points[i].x, points[i].y);
if(close)
g.lineTo(points[0].x, points[0].y);
}
/*
Draws four points quad
x0:Number
y0:Number
x1:Number
y1:Number
x2:Number
y2:Number
*/
public function drawQuad(x0:Number,y0:Number, x1:Number,y1:Number, x2:Number,y2:Number, x3:Number,y3:Number):void
{
var ar:Array = getQuadPoints(x0,y0,x1,y1,x2,y2,x3,y3);
drawLines(ar, true);
}
//4点を配列化して返す
public function getQuadPoints(x0:Number,y0:Number, x1:Number,y1:Number, x2:Number,y2:Number, x3:Number,y3:Number):Array
{
return [new Point(x0,y0), new Point(x1,y1), new Point(x2,y2), new Point(x3,y3)]
}
/*
Draws three point triangle
*/
public function drawPolygon(x0:Number,y0:Number,x1:Number,y1:Number,x2:Number,y2:Number):void
{
drawLines([new Point(x0,y0), new Point(x1,y1), new Point(x2,y2)], true);
}
//弧を描く
public function drawArc(nX:Number, nY:Number, nRadius:Number, toAngle:Number, fromAngle:Number=0, closeFlg:Boolean=true):void {
var points:Array = getArcPoints(nX,nY,nRadius,toAngle,fromAngle);
if (closeFlg) _target.moveTo(points[0].x,points[0].y);
var max:int = points.length-1;
for (var i:int = 1; i < max; i+=2) {
_target.curveTo(points[i].x,points[i].y,points[i+1].x,points[i+1].y);
}
}
public function drawArcEllipse(nX:Number, nY:Number, nWidth:Number, nHeight:Number, toAngle:Number, fromAngle:Number=0, closeFlg:Boolean=true):void {
var nRadius:Number;
var xRatio:Number = 1;
var yRatio:Number = 1;
var aWidth:Number = Math.abs(nWidth);
var aHeight:Number = Math.abs(nHeight);
if (aWidth < aHeight) {
nRadius = aHeight;
xRatio = aWidth / aHeight;
} else {
nRadius = aWidth;
yRatio = aHeight / aWidth;
}
var points:Array = getArcPoints(0,0,nRadius,toAngle,fromAngle);
if (closeFlg) _target.moveTo(nX+points[0].x*xRatio,nY+points[0].y*yRatio);
var max:int = points.length-1;
for (var i:int = 1; i < max; i+=2) {
_target.curveTo(nX+points[i].x*xRatio,nY+points[i].y*yRatio,nX+points[i+1].x*xRatio,nY+points[i+1].y*yRatio);
}
}
public function drawRing(nX:Number, nY:Number, outerRadius:Number, innerRadius:Number, toAngle:Number=360, fromAngle:Number=0):void {
var points:Array = getRingPoints(nX, nY, outerRadius, innerRadius, toAngle, fromAngle);
_target.moveTo(points[0].x,points[0].y);
var max:int = (points.length/2)-1;
// outer
for (var i:int = 1; i < max; i+=2) {
_target.curveTo(points[i].x,points[i].y,points[i+1].x,points[i+1].y);
}
_target.lineTo(points[max+2].x,points[max+2].y)
// inner
for (i = 3; i < max+1; i+=2) {
_target.curveTo(points[max+i].x,points[max+i].y,points[max+i+1].x,points[max+i+1].y);
}
_target.lineTo(points[0].x, points[0].y);
}
// 円弧を描くのに必要な材料を配列として返す
public static function getArcValue(nX:Number, nY:Number, nRadius:Number, toAngle:Number, fromAngle:Number):Array {
var values:Array = new Array();
var toRadian:Number = Math.PI/180*toAngle;
var fromRadian:Number = Math.PI/180*fromAngle;
// 分割数を得る(45°未満:1)
var step:int = 1;
while (Math.abs(toRadian)/step > Math.PI/4) step++;
// 分割された角度
var stepRadian:Number = toRadian/step;
// コントロールポイントまでの距離を得る
var dist:Number = getControlRadius(nRadius,Math.abs(stepRadian));
// 配列に格納
values.toRadian = toRadian;
values.fromRadian = fromRadian;
values.step = step;
values.stepRadian = stepRadian;
values.dist = dist;
return values;
}
public static function getArcPoints(nX:Number, nY:Number, nRadius:Number, toAngle:Number, fromAngle:Number):Array {
var vals:Array = getArcValue(nX, nY, nRadius, toAngle, fromAngle);
// コントロール/アンカーポイントを取得
var points:Array = new Array();
for (var i:int = 0; i <= vals.step; i++) {
// Anchor
points.push(new Point(nX+nRadius*Math.cos(vals.fromRadian+vals.stepRadian*i),
nY+nRadius*Math.sin(vals.fromRadian+vals.stepRadian*i)));
// Control
points.push(new Point(nX+vals.dist*Math.cos(vals.fromRadian+vals.stepRadian*(i+0.5)),
nY+vals.dist*Math.sin(vals.fromRadian+vals.stepRadian*(i+0.5))));
}
return points;
}
public function getRingPoints(nX:Number, nY:Number, outerRadius:Number, innerRadius:Number, toAngle:Number=360, fromAngle:Number=0):Array
{
var vals:Array = getArcValue(nX, nY, outerRadius, toAngle, fromAngle);
var ratio:Number = innerRadius/outerRadius;
var points:Array = new Array();
var inners:Array = new Array();
for (var i:int = 0; i <= vals.step; i++) {
// Anchor
var ax:Number = outerRadius*Math.cos(vals.fromRadian+vals.stepRadian*i);
var ay:Number = outerRadius*Math.sin(vals.fromRadian+vals.stepRadian*i);
points.push(new Point(nX+ax, nY+ay));
inners.push(new Point(nX+ax*ratio, nY+ay*ratio));
// Control
var cx:Number = vals.dist*Math.cos(vals.fromRadian+vals.stepRadian*(i+0.5));
var cy:Number = vals.dist*Math.sin(vals.fromRadian+vals.stepRadian*(i+0.5));
points.push(new Point(nX+cx, nY+cy));
inners.push(new Point(nX+cx*ratio, nY+cy*ratio));
}
inners.reverse();
points = points.concat(inners);
return points;
}
// 角度からコントロールポイントの半径を得る
public static function getControlRadius(nRadius:Number, nRadian:Number):Number {
var rHalf:Number = nRadian/2;
var nHeight:Number = nRadius * Math.atan(rHalf);
var radius:Number = Math.sqrt(Math.pow(nHeight,2)+Math.pow(nRadius,2));
return radius;
}
//扇形、円弧と中心点を結んだ形状を描画する
public function drawPie(x:Number, y:Number, radius:Number, degree:Number, fromDegree:Number=0, split:Number=36):void
{
var points:Array = getPiePoints(x, y, radius, degree, fromDegree, split)
drawLines(points, true);
}
public static function getPiePoints(x:Number, y:Number, radius:Number, degree:Number, fromDegree:Number=0, split:Number=36):Array
{
var points:Array = getArcPoints(x, y, radius, degree, fromDegree)
var pt:Point
points.unshift( new Point(x, y) )
return points
}
//歯車を描画する
public function drawStar(x:Number, y:Number, outerRadius:Number, innerRadius:Number, num:Number, degreeOffset:Number=0):void
{
var ar:Array = getStarPoints(x,y,outerRadius,innerRadius,num,degreeOffset);
drawLines(ar,true);
}
//ギア状のポイント配列を取得する
public static function getStarPoints(x:Number, y:Number, outerRadius:Number, innerRadius:Number, num:Number, degreeOffset:Number=0):Array
{
var points:Array = new Array();
var drad:Number = Math.PI * 2 / num
var xOffset:Number = x
var yOffset:Number = y
var radOffset:Number = degreeOffset * Math.PI / 180
var imax:Number = num
for(var i:Number=0; i<imax; i++)
{
var rad:Number = Math.PI * 2 * i/ num + radOffset
var rad2:Number = Math.PI * 2 * (i+0.5)/ num + radOffset
var pt:Point
pt = new Point()
pt.x = Math.cos(rad)*outerRadius + xOffset
pt.y = Math.sin(rad)*outerRadius + yOffset
points.push(pt);
pt = new Point()
pt.x = Math.cos(rad2)*innerRadius + xOffset
pt.y = Math.sin(rad2)*innerRadius + yOffset
points.push(pt);
}
return points
}
/*
---------------------------------------------------------------------------------------------
Begin Fill等へのアクセス関数
本来のgraphicsにそのまま委譲します
---------------------------------------------------------------------------------------------
*/
public function beginFill(color:uint, alpha:Number=1.0):void
{
_target.beginFill(color,alpha)
}
public function clear():void
{
_target.clear()
}
public function curveTo(controlX:Number, controlY:Number, anchorX:Number, anchorY:Number):void
{
_target.curveTo(controlX, controlY, anchorX, anchorY)
}
public function drawRect(x:Number, y:Number, width:Number, height:Number):void{
_target.drawRect(x,y,width,height)
}
public function drawCircle(x:Number, y:Number, radius:Number):void
{
_target.drawCircle(x,y,radius)
}
public function drawEllipse(x:Number, y:Number, width:Number, height:Number):void
{
_target.drawEllipse(x,y,width,height)
}
public function drawRoundRect(x:Number,y:Number,width:Number,height:Number,ellipseWidth:Number=0,ellipseHeight:Number=0):void
{
// 入力値を補正
if (ellipseHeight == 0) ellipseHeight = ellipseWidth;
if (ellipseWidth * ellipseHeight < 0) ellipseHeight*=-1;
if (ellipseWidth >= 0) {
_target.drawRoundRect(x,y,width,height,ellipseWidth,ellipseHeight);
} else {
_target.moveTo(x-ellipseWidth, y);
_target.lineTo(x+width+ellipseWidth,y);
drawArcEllipse(x+width, y, ellipseWidth, ellipseHeight, -90, 180, false);
_target.lineTo(x+width, y+height+ellipseHeight);
drawArcEllipse(x+width, y+height, ellipseWidth, ellipseHeight, -90, 270, false);
_target.lineTo(x-ellipseWidth, y+height);
drawArcEllipse(x, y+height, ellipseWidth, ellipseHeight, -90, 0);
_target.lineTo(x, y-ellipseHeight);
drawArcEllipse(x, y, ellipseWidth, ellipseHeight, -90, 90, false);
}
}
public function drawRoundRectComplex(x:Number,y:Number,width:Number,height:Number, topLeftRadius:Number, topRightRadius:Number, bottomLeftRadius:Number, bottomRightRadius:Number):void
{
if (topLeftRadius > 0) {
_target.moveTo(x+topLeftRadius, y);
} else if (topLeftRadius < 0) {
_target.moveTo(x-topLeftRadius, y);
} else {
_target.moveTo(x, y);
}
if (topRightRadius > 0) {
_target.lineTo(x+width-topRightRadius,y);
drawArc(x+width-topRightRadius, y+topRightRadius, topRightRadius, 90, 270, false);
} else if (topRightRadius < 0) {
_target.lineTo(x+width+topRightRadius,y);
drawArc(x+width, y, -topRightRadius, -90, 180, false);
} else {
_target.lineTo(x+width,y);
}
if (bottomRightRadius > 0) {
_target.lineTo(x+width, y+height-bottomRightRadius);
drawArc(x+width-bottomRightRadius, y+height-bottomRightRadius, bottomRightRadius, 90, 0, false);
} else if (bottomRightRadius < 0) {
_target.lineTo(x+width, y+height+bottomRightRadius);
drawArc(x+width, y+height, -bottomRightRadius, -90, 270, false);
} else {
_target.lineTo(x+width,y+height);
}
if (bottomLeftRadius > 0) {
_target.lineTo(x+bottomLeftRadius, y+height);
drawArc(x+bottomLeftRadius, y+height-bottomLeftRadius, bottomLeftRadius, 90, 90, false);
} else if (bottomLeftRadius < 0) {
_target.lineTo(x-bottomLeftRadius, y+height);
drawArc(x, y+height, -bottomLeftRadius, -90, 0);
} else {
_target.lineTo(x,y+height);
}
if (topLeftRadius > 0) {
_target.lineTo(x, y+topLeftRadius);
drawArc(x+topLeftRadius, y+topLeftRadius, topLeftRadius, 90, 180, false);
} else if (topLeftRadius < 0) {
_target.lineTo(x, y-topLeftRadius);
drawArc(x, y, -topLeftRadius, -90, 90, false);
} else {
_target.lineTo(x,y);
}
}
public function endFill():void
{
_target.endFill()
}
public function moveTo(x:Number, y:Number):void
{
_target.moveTo(x,y)
}
public function lineTo(x:Number, y:Number):void
{
_target.lineTo(x,y)
}
public function lineStyle(thickness:Number=0,
color:uint=0,alpha:Number=1,
pixelHinting:Boolean=false,
scaleMode:String = "normal",
caps:String=null,
joints:String=null,
miterLimit:Number=3):void
{
_target.lineStyle(thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit)
}
public function beginBitmapFill(bitmap:BitmapData,matrix:Matrix=null,repeat:Boolean=true,smooth:Boolean=false):void
{
_target.beginBitmapFill(bitmap,matrix,repeat,smooth)
}
public function beginGradientFill(type:String, color:Array, alphas:Array, ratios:Array, matrix:Matrix=null, spreadMethod:String="pad", interpolationMethod:String="rgb",focalPointRation:Number=0.0):void
{
_target.beginGradientFill(type, color, alphas, ratios, matrix, spreadMethod, interpolationMethod,focalPointRation)
}
public function lineGradientStyle( type:String,colors:Array,alphas:Array,ratios:Array,matrix:Matrix=null,spreadMethod:String="pad",interpolationMethod:String="rgb",focalPointRatio:Number = 0.0):void
{
_target.lineGradientStyle(type,colors,alphas,ratios,matrix,spreadMethod,interpolationMethod,focalPointRatio)
}
}
//}