# 【螺旋线】
螺旋线应用十分广泛。
- 螺旋
- 漩涡
- 蚊香
- 卷轴
- 内卷
以下是直线扭曲成螺旋线可视化:
module vp
{
/** 卷轴螺旋线组件 */
export class ComponentScroll extends Phaser.GameObjects.Container
{
// 原点
public oriX: number = 370;
public oriY: number = 370;
// 开始旋转半径
public minRadiu:number = 10;
// 结束旋转半径
public maxRadiu:number = 40;
// 总旋转弧度
public scrollRadin:number = 2 * Math.PI * 2;
/** 步进长度,控制螺旋线的顺滑程度,越小越顺滑,性能消耗越大 */
// public stepLen:number = 5;
public stepCount = 600;
// 线条粗细
public lineThickness:number = 2;
// 线条颜色
public lineColor:number = 0x6e789e;
private spiralGraphics:Phaser.GameObjects.Graphics;
private centerGraphics:Phaser.GameObjects.Graphics;
constructor(scene: Phaser.Scene)
{
super(scene);
this.spiralGraphics = new Phaser.GameObjects.Graphics(this.scene);
this.centerGraphics = new Phaser.GameObjects.Graphics(this.scene);
this.centerGraphics.fillStyle(0xff0000,1.0);
this.centerGraphics.fillCircle(0,0,3);
this.centerGraphics.fill();
this.add(this.spiralGraphics);
this.add(this.centerGraphics);
this.updateSpiralGraphics();
}
/** 0为直线 1为完全螺旋线 */
public scrollPos:number = 1;
/** 圆上的切线方向 */
public normalizeTangentVector(ax, ay)
{
// 计算点a到圆心的距离
var dist = Math.sqrt(ax * ax + ay * ay);
// 计算连线向量
var vector = {x: ax/dist, y: ay/dist};
// 计算切线向量
var tangentVector = {x: -vector.y, y: vector.x};
// 归一化切线向量
var normalizedTangentVector = {x: tangentVector.x/dist, y: tangentVector.y/dist};
return normalizedTangentVector;
}
/** 刷新图形的显示 */
public updateSpiralGraphics():void
{
this.spiralGraphics.clear();
this.spiralGraphics.lineStyle(this.lineThickness,this.lineColor,1.0);
// 螺旋线长度
let spiralLength = this.calculateSpiralLength(this.minRadiu,this.maxRadiu,this.scrollRadin);
let stepLen = spiralLength/this.stepCount;
for (let i = 0; i < this.stepCount; i++) {
let spLen = (i+1) * stepLen;
// 进度 0~1,0代表直线,1代表全漩涡
let bi = spLen/spiralLength;
if(bi > this.scrollPos){
// 螺旋线结束,显示直线
// 直线长度
let straightLineLen = (1-bi) * spiralLength;
if(straightLineLen > 0){
// 螺旋切线方向
let radin = this.scrollRadin * bi;
let radiu = this.minRadiu + (this.maxRadiu - this.minRadiu) * bi;
let posX = Math.cos(radin) * radiu;
let posY = Math.sin(radin) * radiu;
this.centerGraphics.x = posX;
this.centerGraphics.y = posY;
let dirObj = this.normalizeTangentVector(Math.cos(radin),Math.sin(radin));
let dirX = dirObj.x;
let dirY = dirObj.y;
let endX = posX + dirX * straightLineLen;
let endY = posY + dirY * straightLineLen;
this.spiralGraphics.lineTo(endX,endY);
break;
}
}else{
let xyObj = this.calculateSpiralXY(this.minRadiu,this.maxRadiu,this.scrollRadin,spLen);
if(i == 0){
if(xyObj){
this.spiralGraphics.moveTo(xyObj.x,xyObj.y);
}
}else{
if(xyObj){
this.spiralGraphics.lineTo(xyObj.x,xyObj.y);
}
}
}
}
this.spiralGraphics.stroke();
}
private _spiralLength:number = -1;
/**
* 计算螺旋线长度
*/
public calculateSpiralLength(startRadius:number, endRadius:number, totalRotation:number):number
{
if(this._spiralLength != -1)return this._spiralLength;
// 螺旋线的总旋转圈数
var totalRevolutions = totalRotation / (2 * Math.PI);
// 螺旋线的半径差
var radiusDiff = endRadius - startRadius;
// 螺旋线的长度
var length = 0;
// 每计算一小段弧长的长度
var delta = 0.0001;
// 通过积分计算螺旋线的长度
let temp1 = totalRevolutions * 2 * Math.PI;
for (var t = 0; t < temp1; t += delta) {
var radius = startRadius + (radiusDiff * t) / temp1;
var dS = Math.sqrt(1 + radius * radius) * delta;
length += dS;
}
// 返回螺旋线的长度
this._spiralLength = length;
return length;
}
/** 计算螺旋线上的坐标点 */
public calculateSpiralXY(startRadius:number, endRadius:number, totalRotation:number, desiredLength:number)
{
const totalLength = this.calculateSpiralLength(startRadius, endRadius, totalRotation);
const numTurns = totalRotation / (2 * Math.PI); // 总旋转弧度除以2π,得到螺旋线的圈数
const rateOfIncrease = (endRadius - startRadius) / numTurns; // 螺旋线半径的增加率
// 计算指定长度时的旋转弧度
const desiredRotation = (desiredLength / totalLength) * totalRotation;
// 计算指定长度时的螺旋线半径
const desiredRadius = startRadius + (desiredRotation / (2 * Math.PI)) * rateOfIncrease;
// 根据指定长度时的螺旋线半径计算坐标点xy
const x = desiredRadius * Math.cos(desiredRotation);
const y = desiredRadius * Math.sin(desiredRotation);
return { x, y };
}
}
}