Archived
forked from RDTKEditor/RDTKEditor
添加对 Core 的直接引用
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
using RhythmBase.Components;
|
||||
using RhythmBase.Events;
|
||||
using RhythmBase.Extensions;
|
||||
namespace RhythmBase.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Beat calculator.
|
||||
/// </summary>
|
||||
public class BeatCalculator
|
||||
{
|
||||
internal BeatCalculator(RDLevel level)
|
||||
{
|
||||
Collection = level;
|
||||
Refresh();
|
||||
}
|
||||
/// <summary>
|
||||
/// Refresh the cache.
|
||||
/// </summary>
|
||||
public void Refresh()
|
||||
{
|
||||
_BPMList = Collection.Where<BaseBeatsPerMinute>()
|
||||
.ToList();
|
||||
_CPBList = Collection.Where<SetCrotchetsPerBar>()
|
||||
.ToList();
|
||||
}
|
||||
/// <summary>
|
||||
/// Convert beat data.
|
||||
/// </summary>
|
||||
/// <param name="bar">The 1-based bar.</param>
|
||||
/// <param name="beat">The 1-based beat of the bar.</param>
|
||||
/// <returns>Total 1-based beats.</returns>
|
||||
public float BarBeatToBeatOnly(uint bar, float beat) => BarBeatToBeatOnly(bar, beat, _CPBList);
|
||||
/// <summary>
|
||||
/// Convert beat data.
|
||||
/// </summary>
|
||||
/// <param name="bar">The 1-based bar.</param>
|
||||
/// <param name="beat">The 1-based beat of the bar.</param>
|
||||
/// <returns>Total time span.</returns>
|
||||
public TimeSpan BarBeatToTimeSpan(uint bar, float beat) => BeatOnlyToTimeSpan(BarBeatToBeatOnly(bar, beat));
|
||||
/// <summary>
|
||||
/// Convert beat data.
|
||||
/// </summary>
|
||||
/// <param name="beat">Total 1-based beats.</param>
|
||||
/// <returns>The 1-based bar and the 1-based beat of bar.</returns>
|
||||
public (uint bar, float beat) BeatOnlyToBarBeat(float beat) => BeatOnlyToBarBeat(beat, _CPBList);
|
||||
/// <summary>
|
||||
/// Convert beat data.
|
||||
/// </summary>
|
||||
/// <param name="beat">Total 1-based beats.</param>
|
||||
/// <returns>Total time span.</returns>
|
||||
public TimeSpan BeatOnlyToTimeSpan(float beat) => BeatOnlyToTimeSpan(beat, _BPMList);
|
||||
/// <summary>
|
||||
/// Convert beat data.
|
||||
/// </summary>
|
||||
/// <param name="timeSpan">Total time span.</param>
|
||||
/// <returns>Total 1-based beats.</returns>
|
||||
public float TimeSpanToBeatOnly(TimeSpan timeSpan) => TimeSpanToBeatOnly(timeSpan, _BPMList);
|
||||
/// <summary>
|
||||
/// Convert beat data.
|
||||
/// </summary>
|
||||
/// <param name="timeSpan">Total time span.</param>
|
||||
/// <returns>The 1-based bar and the 1-based beat of bar.</returns>
|
||||
public (uint bar, float beat) TimeSpanToBarBeat(TimeSpan timeSpan) => BeatOnlyToBarBeat(TimeSpanToBeatOnly(timeSpan));
|
||||
private static float BarBeatToBeatOnly(uint bar, float beat, IEnumerable<SetCrotchetsPerBar> Collection)
|
||||
{
|
||||
(float BeatOnly, uint Bar, uint CPB) foreCPB = new(1f, 1U, 8U);
|
||||
SetCrotchetsPerBar? LastCPB = Collection.LastOrDefault((SetCrotchetsPerBar i) => i.Active && i.Beat.BarBeat.bar < bar);
|
||||
if (LastCPB != null)
|
||||
foreCPB = new(LastCPB.Beat.BeatOnly, LastCPB.Beat.BarBeat.bar, LastCPB.CrotchetsPerBar);
|
||||
return foreCPB.BeatOnly + (bar - foreCPB.Bar) * foreCPB.CPB + beat - 1f;
|
||||
}
|
||||
private static (uint bar, float beat) BeatOnlyToBarBeat(float beat, IEnumerable<SetCrotchetsPerBar> Collection)
|
||||
{
|
||||
(float BeatOnly, uint Bar, uint CPB) foreCPB = new(1f, 1U, 8U);
|
||||
SetCrotchetsPerBar? LastCPB = Collection.LastOrDefault((SetCrotchetsPerBar i) => i.Active && i.Beat.BeatOnly < beat);
|
||||
if (LastCPB != null)
|
||||
foreCPB = new(LastCPB.Beat.BeatOnly, LastCPB.Beat.BarBeat.bar, LastCPB.CrotchetsPerBar);
|
||||
(uint bar, float beat) result = ((uint)Math.Round(foreCPB.Bar + Math.Floor((double)((beat - foreCPB.BeatOnly) / foreCPB.CPB))), ((beat - foreCPB.BeatOnly) % foreCPB.CPB) + 1f);
|
||||
return result;
|
||||
}
|
||||
private static TimeSpan BeatOnlyToTimeSpan(float beatOnly, IEnumerable<BaseBeatsPerMinute> BPMCollection)
|
||||
{
|
||||
ValueTuple<float, float> fore = new(1f, Utils.DefaultBPM);
|
||||
BaseBeatsPerMinute? foreBPM = BPMCollection.FirstOrDefault();
|
||||
if (foreBPM != null)
|
||||
fore = new ValueTuple<float, float>(foreBPM.Beat.BeatOnly, foreBPM.BeatsPerMinute);
|
||||
float resultMinute = 0f;
|
||||
foreach (BaseBeatsPerMinute item in BPMCollection)
|
||||
if (beatOnly > item.Beat.BeatOnly)
|
||||
{
|
||||
resultMinute += (item.Beat.BeatOnly - fore.Item1) / fore.Item2;
|
||||
fore = new ValueTuple<float, float>(item.Beat.BeatOnly, item.BeatsPerMinute);
|
||||
}
|
||||
resultMinute += (beatOnly - fore.Item1) / fore.Item2;
|
||||
return TimeSpan.FromMinutes((double)resultMinute);
|
||||
}
|
||||
private static float TimeSpanToBeatOnly(TimeSpan timeSpan, IEnumerable<BaseBeatsPerMinute> BPMCollection)
|
||||
{
|
||||
ValueTuple<float, float> fore = new(1f, Utils.DefaultBPM);
|
||||
BaseBeatsPerMinute? foreBPM = BPMCollection.FirstOrDefault();
|
||||
if (foreBPM != null)
|
||||
fore = new ValueTuple<float, float>(foreBPM.Beat.BeatOnly, foreBPM.BeatsPerMinute);
|
||||
float beatOnly = 1f;
|
||||
foreach (BaseBeatsPerMinute item in BPMCollection)
|
||||
if (timeSpan > BeatOnlyToTimeSpan(item.Beat.BeatOnly, BPMCollection))
|
||||
beatOnly = (float)((double)beatOnly + (BeatOnlyToTimeSpan(item.Beat.BeatOnly, BPMCollection) - BeatOnlyToTimeSpan(fore.Item1, BPMCollection)).TotalMinutes * (double)fore.Item2);
|
||||
beatOnly = (float)((double)beatOnly + (timeSpan - BeatOnlyToTimeSpan(fore.Item1, BPMCollection)).TotalMinutes * (double)fore.Item2);
|
||||
return beatOnly;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a beat instance.
|
||||
/// </summary>
|
||||
public RDBeat BeatOf(float beatOnly) => new(this, beatOnly);
|
||||
/// <summary>
|
||||
/// Creates a beat instance.
|
||||
/// </summary>
|
||||
public RDBeat BeatOf(uint bar, float beat) => new(this, bar, beat);
|
||||
/// <summary>
|
||||
/// Creates a beat instance.
|
||||
/// </summary>
|
||||
public RDBeat BeatOf(TimeSpan timeSpan) => new(this, timeSpan);
|
||||
/// <summary>
|
||||
/// Creates an interval between two beats.
|
||||
/// </summary>
|
||||
/// <param name="beat1">The first beat.</param>
|
||||
/// <param name="beat2">The second beat.</param>
|
||||
/// <returns>An RDRange representing the interval between the two beats.</returns>
|
||||
public RDRange IntervalOf(RDBeat beat1, RDBeat beat2) => new(new(this, beat1), new(this, beat2));
|
||||
/// <summary>
|
||||
/// Creates an interval between two beats specified by bar and beat.
|
||||
/// </summary>
|
||||
/// <param name="beat1">The first beat specified by bar and beat.</param>
|
||||
/// <param name="beat2">The second beat specified by bar and beat.</param>
|
||||
/// <returns>An RDRange representing the interval between the two beats.</returns>
|
||||
public RDRange IntervalOf((uint bar, float beat) beat1, (uint bar, float beat) beat2) => IntervalOf(BeatOf(beat1.bar, beat1.beat), BeatOf(beat2.bar, beat2.beat));
|
||||
/// <summary>
|
||||
/// Creates an interval between two beats specified by time spans.
|
||||
/// </summary>
|
||||
/// <param name="timeSpan1">The first time span.</param>
|
||||
/// <param name="timeSpan2">The second time span.</param>
|
||||
/// <returns>An RDRange representing the interval between the two time spans.</returns>
|
||||
public RDRange IntervalOf(TimeSpan timeSpan1, TimeSpan timeSpan2) => IntervalOf(BeatOf(timeSpan1), BeatOf(timeSpan2));
|
||||
/// <summary>
|
||||
/// Calculate the BPM of the moment in which the beat is.
|
||||
/// </summary>
|
||||
public float BeatsPerMinuteOf(RDBeat beat) => _BPMList.LastOrDefault((BaseBeatsPerMinute i) => i.Beat < beat)?.BeatsPerMinute ?? Utils.DefaultBPM;
|
||||
/// <summary>
|
||||
/// Calculate the CPB of the moment in which the beat is.
|
||||
/// </summary>
|
||||
public float CrotchetsPerBarOf(RDBeat beat) => _CPBList.LastOrDefault((SetCrotchetsPerBar i) => i.Beat < beat)?.CrotchetsPerBar ?? 8;
|
||||
internal readonly RDLevel Collection;
|
||||
private List<BaseBeatsPerMinute> _BPMList = [];
|
||||
private List<SetCrotchetsPerBar> _CPBList = [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
using RhythmBase.Events;
|
||||
using RhythmBase.Exceptions;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace RhythmBase.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class for converting between event types and enumerations.
|
||||
/// </summary>
|
||||
public static class EventTypeUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a type to its corresponding EventType enumeration.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to convert.</param>
|
||||
/// <returns>The corresponding EventType enumeration.</returns>
|
||||
/// <exception cref="IllegalEventTypeException">Thrown when no matching EventType is found or multiple matching EventTypes are found.</exception>
|
||||
public static EventType ToEnum(Type type)
|
||||
{
|
||||
EventType ConvertToEnum;
|
||||
if (EventType_Enums == null)
|
||||
{
|
||||
string name = type.Name;
|
||||
if (!Enum.TryParse(name, out EventType result))
|
||||
{
|
||||
throw new IllegalEventTypeException(type, "Unable to find a matching EventType.");
|
||||
}
|
||||
ConvertToEnum = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ConvertToEnum = EventType_Enums[type].Single();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new IllegalEventTypeException(type, "Multiple matching EventTypes were found. Please check if the type is an abstract class type.", new ArgumentException("Multiple matching EventTypes were found. Please check if the type is an abstract class type.", nameof(type)));
|
||||
}
|
||||
}
|
||||
return ConvertToEnum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a generic event type to its corresponding EventType enumeration.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEvent">The generic event type to convert.</typeparam>
|
||||
/// <returns>The corresponding EventType enumeration.</returns>
|
||||
public static EventType ToEnum<TEvent>() where TEvent : IBaseEvent, new() => ToEnum(typeof(TEvent));
|
||||
|
||||
/// <summary>
|
||||
/// Converts a type to an array of corresponding EventType enumerations.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to convert.</param>
|
||||
/// <returns>An array of corresponding EventType enumerations.</returns>
|
||||
/// <exception cref="IllegalEventTypeException">Thrown when an unexpected exception occurs.</exception>
|
||||
public static EventType[] ToEnums(Type type)
|
||||
{
|
||||
EventType[] ConvertToEnums;
|
||||
try
|
||||
{
|
||||
ConvertToEnums = EventType_Enums[type];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new IllegalEventTypeException(type, "This exception is not expected. Please contact the developer to handle this exception.", ex);
|
||||
}
|
||||
return ConvertToEnums;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a generic event type to an array of corresponding EventType enumerations.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEvent">The generic event type to convert.</typeparam>
|
||||
/// <returns>An array of corresponding EventType enumerations.</returns>
|
||||
public static EventType[] ToEnums<TEvent>() where TEvent : IBaseEvent => ToEnums(typeof(TEvent));
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string representation of an event type to its corresponding Type.
|
||||
/// </summary>
|
||||
/// <param name="type">The string representation of the event type.</param>
|
||||
/// <returns>The corresponding Type.</returns>
|
||||
public static Type ToType(string type)
|
||||
{
|
||||
Type ConvertToType;
|
||||
if (Enum.TryParse(type, out EventType result))
|
||||
{
|
||||
ConvertToType = result.ToType();
|
||||
}
|
||||
else
|
||||
{
|
||||
ConvertToType = EventType.CustomEvent.ToType();
|
||||
}
|
||||
return ConvertToType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an EventType enumeration to its corresponding Type.
|
||||
/// </summary>
|
||||
/// <param name="type">The EventType enumeration to convert.</param>
|
||||
/// <returns>The corresponding Type.</returns>
|
||||
/// <exception cref="IllegalEventTypeException">Thrown when the value does not exist in the EventType enumeration.</exception>
|
||||
public static Type ToType(this EventType type)
|
||||
{
|
||||
Type ConvertToType;
|
||||
if (Enum_EventType == null)
|
||||
{
|
||||
return Type.GetType($"{typeof(IBaseEvent).Namespace}.{type}") ?? throw new RhythmBaseException(string.Format("Illegal Type: {0}.", type));
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ConvertToType = Enum_EventType[type];
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new IllegalEventTypeException(type.ToString(), "This value does not exist in the EventType enumeration.");
|
||||
}
|
||||
}
|
||||
return ConvertToType;
|
||||
}
|
||||
|
||||
private static readonly ReadOnlyCollection<Type> EventTypes = (from i in typeof(IBaseEvent).Assembly.GetTypes()
|
||||
where i.IsAssignableTo(typeof(IBaseEvent))
|
||||
select i)
|
||||
.ToList()
|
||||
.AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary that records the correspondence of event types inheriting from <see cref="T:RhythmBase.Events.IBaseEvent" /> to <see cref="T:RhythmBase.Events.EventType" />.
|
||||
/// </summary>
|
||||
private static readonly ReadOnlyDictionary<Type, EventType[]> EventType_Enums = EventTypes.ToDictionary((Type i) => i, (Type i) => (from j in EventTypes
|
||||
where (j == i || j.IsAssignableTo(i)) && !j.IsAbstract
|
||||
select j)
|
||||
.Select((Type j) => ToEnum(j))
|
||||
.ToArray())
|
||||
.AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary that records the correspondence of <see cref="T:RhythmBase.Events.EventType" /> to event types inheriting from <see cref="T:RhythmBase.Events.IBaseEvent" />.
|
||||
/// </summary>
|
||||
private static readonly ReadOnlyDictionary<EventType, Type> Enum_EventType = Enum.GetValues<EventType>().ToDictionary((EventType i) => i, (EventType i) => i.ToType()).AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Event types that inherit from <see cref="T:RhythmBase.Events.BaseRowAction" />.
|
||||
/// </summary>
|
||||
public static readonly ReadOnlyCollection<EventType> RowTypes = ToEnums<BaseRowAction>().AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Event types that inherit from <see cref="T:RhythmBase.Events.BaseDecorationAction" />.
|
||||
/// </summary>
|
||||
public static readonly ReadOnlyCollection<EventType> DecorationTypes = ToEnums<BaseDecorationAction>().AsReadOnly();
|
||||
/// <summary>
|
||||
/// Custom event types.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<EventType> CustomTypes => new(
|
||||
[
|
||||
EventType.CustomEvent,
|
||||
EventType.CustomRowEvent,
|
||||
EventType.CustomDecorationEvent,
|
||||
]);
|
||||
/// <summary>
|
||||
/// Event types for gameplay.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<EventType> EventTypeEnumsForGameplay => new(
|
||||
[
|
||||
EventType.HideRow,
|
||||
EventType.ChangePlayersRows,
|
||||
EventType.FinishLevel,
|
||||
EventType.ShowHands,
|
||||
EventType.SetHandOwner,
|
||||
EventType.SetPlayStyle
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Event types for environment.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<EventType> EventTypeEnumsForEnvironment => new(
|
||||
[
|
||||
EventType.SetTheme,
|
||||
EventType.SetBackgroundColor,
|
||||
EventType.SetForeground,
|
||||
EventType.SetSpeed,
|
||||
EventType.Flash,
|
||||
EventType.CustomFlash
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Event types for row effects.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<EventType> EventTypeEnumsForRowFX => new(
|
||||
[
|
||||
EventType.HideRow,
|
||||
EventType.MoveRow,
|
||||
EventType.PlayExpression,
|
||||
EventType.TintRows
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Event types for camera effects.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<EventType> EventTypeEnumsForCameraFX => new(
|
||||
[
|
||||
EventType.MoveCamera,
|
||||
EventType.ShakeScreen,
|
||||
EventType.FlipScreen,
|
||||
EventType.PulseCamera
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Event types for visual effects.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<EventType> EventTypeEnumsForVisualFX => new(
|
||||
[
|
||||
EventType.SetVFXPreset,
|
||||
EventType.SetSpeed,
|
||||
EventType.Flash,
|
||||
EventType.CustomFlash,
|
||||
EventType.BassDrop,
|
||||
EventType.InvertColors,
|
||||
EventType.Stutter,
|
||||
EventType.PaintHands,
|
||||
EventType.NewWindowDance
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Event types for text effects.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<EventType> EventTypeEnumsForText => new(
|
||||
[
|
||||
EventType.TextExplosion,
|
||||
EventType.ShowDialogue,
|
||||
EventType.ShowStatusSign,
|
||||
EventType.FloatingText,
|
||||
EventType.AdvanceText
|
||||
]);
|
||||
|
||||
/// <summary>
|
||||
/// Event types for utility actions.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<EventType> EventTypeEnumsForUtility => new(
|
||||
[
|
||||
EventType.Comment,
|
||||
EventType.TagAction,
|
||||
EventType.CallCustomMethod
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using RhythmBase.Components;
|
||||
using RhythmBase.Converters;
|
||||
using RhythmBase.Events;
|
||||
using RhythmBase.Exceptions;
|
||||
using RhythmBase.Settings;
|
||||
namespace RhythmBase.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class providing utility methods.
|
||||
/// </summary>
|
||||
public static class Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts Xs patterns to string form.
|
||||
/// </summary>
|
||||
/// <param name="pattern">List of patterns.</param>
|
||||
/// <returns>String representation of patterns.</returns>
|
||||
public static string GetPatternString(Patterns[] pattern) => string.Join("",
|
||||
pattern?.Select(p => p switch
|
||||
{
|
||||
Patterns.None => "-",
|
||||
Patterns.X => "x",
|
||||
Patterns.Up => "u",
|
||||
Patterns.Down => "d",
|
||||
Patterns.Banana => "b",
|
||||
Patterns.Return => "r",
|
||||
_ => throw new ConvertingException($"Invalid pattern: {p}")
|
||||
|
||||
}) ?? throw new ConvertingException($"Cannot write pattern."));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the JSON serializer settings for the specified level and settings.
|
||||
/// </summary>
|
||||
/// <param name="rdlevel">The level to serialize.</param>
|
||||
/// <param name="settings">The settings for reading or writing the level.</param>
|
||||
/// <returns>JSON serializer settings.</returns>
|
||||
public static JsonSerializerSettings GetSerializer(this RDLevel rdlevel, LevelReadOrWriteSettings settings)
|
||||
{
|
||||
JsonSerializerSettings EventsSerializer = new()
|
||||
{
|
||||
ContractResolver = new RDContractResolver()
|
||||
};
|
||||
IList<JsonConverter> converters = EventsSerializer.Converters;
|
||||
converters.Add(new PanelColorConverter(rdlevel.ColorPalette));
|
||||
converters.Add(new ColorConverter());
|
||||
converters.Add(new ConditionalConverter());
|
||||
converters.Add(new CharacterConverter());
|
||||
converters.Add(new ConditionConverter(rdlevel.Conditionals));
|
||||
converters.Add(new TagActionConverter(rdlevel, settings));
|
||||
converters.Add(new CustomDecorationEventConverter(rdlevel, settings));
|
||||
converters.Add(new CustomRowEventConverter(rdlevel, settings));
|
||||
converters.Add(new CustomEventConverter(rdlevel, settings));
|
||||
converters.Add(new BaseRowActionConverter<BaseRowAction>(rdlevel, settings));
|
||||
converters.Add(new BaseDecorationActionConverter<BaseDecorationAction>(rdlevel, settings));
|
||||
converters.Add(new BaseEventConverter<IBaseEvent>(rdlevel, settings));
|
||||
converters.Add(new BookmarkConverter(rdlevel.Calculator));
|
||||
converters.Add(new StringEnumConverter());
|
||||
return EventsSerializer;
|
||||
}
|
||||
/// <summary>
|
||||
/// The default beats per minute.
|
||||
/// </summary>
|
||||
public const float DefaultBPM = 100f;
|
||||
/// <summary>
|
||||
/// The default crotchets per bar.
|
||||
/// </summary>
|
||||
public const int DefaultCPB = 8;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using RhythmBase.Components;
|
||||
|
||||
namespace RhythmBase.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Visual utils.
|
||||
/// </summary>
|
||||
public static class VisualUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts percentage point to pixel point with default screen size (352 * 198).
|
||||
/// </summary>
|
||||
public static RDPointE PercentToPixel(RDPointE point) => PercentToPixel(point, RDSizeNI.Screen);
|
||||
|
||||
/// <summary>
|
||||
/// Converts percentage point to pixel point with specified size.
|
||||
/// </summary>
|
||||
/// <param name="point">The percentage point.</param>
|
||||
/// <param name="size">Specified size.</param>
|
||||
/// <returns>The pixel point.</returns>
|
||||
public static RDPointE PercentToPixel(RDPointE point, RDSizeE size)
|
||||
{
|
||||
RDPointE PercentToPixel = new(point.X * size.Width / 100f, point.Y * size.Height / 100f);
|
||||
return PercentToPixel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts pixel point to percentage point with default screen size (352 * 198).
|
||||
/// </summary>
|
||||
/// <param name="point">The pixel point.</param>
|
||||
/// <returns>The percentage point.</returns>
|
||||
public static (float? X, float? Y) PixelToPercent((float X, float Y) point) => PixelToPercent(point, (352f, 198f));
|
||||
|
||||
/// <summary>
|
||||
/// Converts pixel point to percentage point with specified size.
|
||||
/// </summary>
|
||||
/// <param name="point">The pixel point.</param>
|
||||
/// <param name="size">Specified size.</param>
|
||||
/// <returns>The percentage point.</returns>
|
||||
public static (float? X, float? Y) PixelToPercent((float? X, float? Y) point, (float? X, float? Y) size)
|
||||
{
|
||||
(float? X, float? Y) PixelToPercent = (point.X * 100f / size.X, point.Y * 100f / size.Y);
|
||||
return PixelToPercent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates a point in room perspective.
|
||||
/// </summary>
|
||||
/// <param name="p">The point to translate.</param>
|
||||
/// <param name="rect">The rectangle defining the room perspective.</param>
|
||||
/// <returns>The translated point.</returns>
|
||||
public static RDPointN RoomPerspectiveTranslate(this RDPointN p, RDRectN rect)
|
||||
{
|
||||
RDPointN plb = rect.LeftBottom;
|
||||
RDPointN prb = rect.RightBottom;
|
||||
RDPointN plt = rect.LeftTop;
|
||||
RDPointN prt = rect.RightTop;
|
||||
p = new(p.X, p.Y);
|
||||
RDPointN p1p2 = prb - (RDSizeN)plb;
|
||||
RDPointN p1p4 = plt - (RDSizeN)plb;
|
||||
RDPointN p1p3 = prt - (RDSizeN)plb;
|
||||
RDPointN pr = plb + new RDSizeN(p1p2.X * p.X, p1p2.Y * p.X) +
|
||||
new RDSizeN((p1p3.X - p1p2.X - p1p4.X) * p.X * p.Y, (p1p3.Y - p1p2.Y - p1p4.Y) * p.X * p.Y) +
|
||||
new RDSizeN(p1p4.X * p.Y, p1p4.Y * p.Y);
|
||||
return pr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts degrees to radians.
|
||||
/// </summary>
|
||||
/// <param name="degree">The angle in degrees.</param>
|
||||
/// <returns>The angle in radians.</returns>
|
||||
public static float DegreeToRadius(float degree) => float.Pi * degree / 180f;
|
||||
|
||||
/// <summary>
|
||||
/// Converts radians to degrees.
|
||||
/// </summary>
|
||||
/// <param name="radius">The angle in radians.</param>
|
||||
/// <returns>The angle in degrees.</returns>
|
||||
public static float RadiusToDegree(float radius) => radius * 180f / float.Pi;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user