mirror of
https://github.com/MewoLab/AquaDX.git
synced 2026-02-12 09:37:27 +08:00
[+] Slide code support & split multiple patches (#77)
* 功能拆分 将不同的功能分拆到不同文件 * Slide code notation support This is part of Maimai DX 2077 patch set. New MA2 commands: NMSSS, BRSSS, EXSSS, BXSSS, CNSSS
This commit is contained in:
132
AquaMai/MaimaiDX2077/SlidePathGenerator.cs
Normal file
132
AquaMai/MaimaiDX2077/SlidePathGenerator.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace AquaMai.MaimaiDX2077;
|
||||
|
||||
public class SlidePathGenerator
|
||||
{
|
||||
public List<ParametricSlidePath.PathSegment> PathSegments = new List<ParametricSlidePath.PathSegment>();
|
||||
public Complex CurrentEndPoint = Complex.Zero;
|
||||
|
||||
public static SlidePathGenerator BeginAt(Complex point)
|
||||
{
|
||||
var obj = new SlidePathGenerator();
|
||||
obj.CurrentEndPoint = point;
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static double CalcTangentAngle(Complex point, MaiGeometry.CircleStruct circle, bool isCcw)
|
||||
{
|
||||
var hypot = point - circle.Center;
|
||||
var angleDelta = Math.Acos(circle.Radius / hypot.Magnitude);
|
||||
var tanAngle = hypot.Phase + (isCcw ? angleDelta : -angleDelta);
|
||||
return Math.IEEERemainder(tanAngle, Math.PI * 2.0);
|
||||
}
|
||||
|
||||
public void TrySetLastParseMarker(ParametricSlidePath.ParseMarker marker)
|
||||
{
|
||||
if (PathSegments.Count <= 0) return;
|
||||
PathSegments[PathSegments.Count - 1].SetParseMarker(marker);
|
||||
}
|
||||
|
||||
public void LineToPoint(Complex point)
|
||||
{
|
||||
PathSegments.Add(new ParametricSlidePath.LineSegment(CurrentEndPoint, point));
|
||||
CurrentEndPoint = point;
|
||||
}
|
||||
|
||||
public void TangentToCircle(MaiGeometry.CircleStruct circle, bool isCcw)
|
||||
{
|
||||
var inAngle = CalcTangentAngle(CurrentEndPoint, circle, isCcw);
|
||||
var inPoint = Complex.FromPolarCoordinates(circle.Radius, inAngle) + circle.Center;
|
||||
LineToPoint(inPoint);
|
||||
}
|
||||
|
||||
/// <summary>Note: endAngle should be in range [-PI, PI]</summary>
|
||||
public void ArcToAngle(Complex center, double endAngle, bool isCcw, bool skipIfZero)
|
||||
{
|
||||
var diff = CurrentEndPoint - center;
|
||||
var circle = new MaiGeometry.CircleStruct(center, diff.Magnitude);
|
||||
var startAngle = diff.Phase;
|
||||
// startAngle and endAngle in range [-PI, PI]
|
||||
if (isCcw)
|
||||
{
|
||||
if (startAngle > endAngle)
|
||||
{
|
||||
startAngle -= 2 * Math.PI;
|
||||
}
|
||||
|
||||
if (Math.Abs(endAngle - startAngle) < 0.001)
|
||||
{
|
||||
if (skipIfZero) return;
|
||||
endAngle += 2 * Math.PI;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startAngle < endAngle)
|
||||
{
|
||||
startAngle += 2 * Math.PI;
|
||||
}
|
||||
|
||||
if (Math.Abs(endAngle - startAngle) < 0.001)
|
||||
{
|
||||
if (skipIfZero) return;
|
||||
endAngle -= 2 * Math.PI;
|
||||
}
|
||||
}
|
||||
|
||||
var seg = new ParametricSlidePath.ArcSegment(circle, startAngle, endAngle);
|
||||
PathSegments.Add(seg);
|
||||
CurrentEndPoint = seg.GetPointAt(1f);
|
||||
}
|
||||
|
||||
public void ArcToTangentTowards(Complex target, Complex center, bool isCcw)
|
||||
{
|
||||
var diff = CurrentEndPoint - center;
|
||||
var endAngle = CalcTangentAngle(target, new MaiGeometry.CircleStruct(center, diff.Magnitude), !isCcw);
|
||||
ArcToAngle(center, endAngle, isCcw, false);
|
||||
}
|
||||
|
||||
public void FullCircle(Complex center, bool isCcw)
|
||||
{
|
||||
var diff = CurrentEndPoint - center;
|
||||
var circle = new MaiGeometry.CircleStruct(center, diff.Magnitude);
|
||||
PathSegments.Add(new ParametricSlidePath.CircleSegment(circle, diff.Phase, isCcw));
|
||||
// CurrentEndPoint not changed
|
||||
}
|
||||
|
||||
public void ExternTangentTransfer(Complex currentCenter, MaiGeometry.CircleStruct targetCircle, bool isCcw)
|
||||
{
|
||||
var diff = CurrentEndPoint - currentCenter;
|
||||
double endAngle;
|
||||
if (Math.Abs(diff.Magnitude - targetCircle.Radius) < 0.001)
|
||||
{
|
||||
// two circles are approximately same radius
|
||||
var vector = targetCircle.Center - currentCenter;
|
||||
vector *= isCcw ? -Complex.ImaginaryOne : Complex.ImaginaryOne;
|
||||
endAngle = vector.Phase;
|
||||
}
|
||||
else if (targetCircle.Radius > diff.Magnitude)
|
||||
{
|
||||
// target circle larger
|
||||
var helperCircle = new MaiGeometry.CircleStruct(targetCircle.Center, targetCircle.Radius - diff.Magnitude);
|
||||
endAngle = CalcTangentAngle(currentCenter, helperCircle, isCcw);
|
||||
}
|
||||
else
|
||||
{
|
||||
var helperCircle = new MaiGeometry.CircleStruct(currentCenter, diff.Magnitude - targetCircle.Radius);
|
||||
endAngle = CalcTangentAngle(targetCircle.Center, helperCircle, !isCcw);
|
||||
}
|
||||
ArcToAngle(currentCenter, endAngle, isCcw, false);
|
||||
var inPoint = Complex.FromPolarCoordinates(targetCircle.Radius, endAngle) + targetCircle.Center;
|
||||
LineToPoint(inPoint);
|
||||
}
|
||||
|
||||
public ParametricSlidePath GeneratePath()
|
||||
{
|
||||
return new ParametricSlidePath(PathSegments);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user