110 lines
4.6 KiB
C#
110 lines
4.6 KiB
C#
using System;
|
|||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Collections.ObjectModel;
|
||
|
|
|
||
|
|
namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.Visualization;
|
||
|
|
|
||
|
|
/// <summary>单张 SVG/PNG 共享的不可变绘图视图。</summary>
|
||
|
|
public sealed class SmoothingFigureDefinition
|
||
|
|
{
|
||
|
|
internal SmoothingFigureDefinition(
|
||
|
|
SmoothingFigureKind kind,
|
||
|
|
string fileStem,
|
||
|
|
string title,
|
||
|
|
SmoothingFigureModel model,
|
||
|
|
bool showsMapContext,
|
||
|
|
IReadOnlyList<SmoothingFigureSeriesView> series,
|
||
|
|
double worldXMinMeters,
|
||
|
|
double worldXMaxMeters,
|
||
|
|
double worldYMinMeters,
|
||
|
|
double worldYMaxMeters,
|
||
|
|
IReadOnlyList<double> xTicks,
|
||
|
|
IReadOnlyList<double> yTicks,
|
||
|
|
double curvatureArcLengthMaximumMeters,
|
||
|
|
double curvatureMinimumPerMeter,
|
||
|
|
double curvatureMaximumPerMeter,
|
||
|
|
IReadOnlyList<double> curvatureArcLengthTicks,
|
||
|
|
IReadOnlyList<double> curvatureTicks)
|
||
|
|
{
|
||
|
|
Kind = kind;
|
||
|
|
FileStem = fileStem ?? string.Empty;
|
||
|
|
Title = title ?? string.Empty;
|
||
|
|
Model = model ?? throw new ArgumentNullException(nameof(model));
|
||
|
|
ShowsMapContext = showsMapContext;
|
||
|
|
Series = Copy(series);
|
||
|
|
WorldXMinMeters = worldXMinMeters;
|
||
|
|
WorldXMaxMeters = worldXMaxMeters;
|
||
|
|
WorldYMinMeters = worldYMinMeters;
|
||
|
|
WorldYMaxMeters = worldYMaxMeters;
|
||
|
|
XTicks = Copy(xTicks);
|
||
|
|
YTicks = Copy(yTicks);
|
||
|
|
CurvatureArcLengthMaximumMeters = curvatureArcLengthMaximumMeters;
|
||
|
|
CurvatureMinimumPerMeter = curvatureMinimumPerMeter;
|
||
|
|
CurvatureMaximumPerMeter = curvatureMaximumPerMeter;
|
||
|
|
CurvatureArcLengthTicks = Copy(curvatureArcLengthTicks);
|
||
|
|
CurvatureTicks = Copy(curvatureTicks);
|
||
|
|
}
|
||
|
|
|
||
|
|
public SmoothingFigureKind Kind { get; }
|
||
|
|
public string FileStem { get; }
|
||
|
|
public string Title { get; }
|
||
|
|
public SmoothingFigureModel Model { get; }
|
||
|
|
public bool ShowsMapContext { get; }
|
||
|
|
public bool IsCurvatureFigure => Kind == SmoothingFigureKind.CurvatureComparison;
|
||
|
|
public double FigureWidthPoints => Model.FigureWidthPoints;
|
||
|
|
public double FigureHeightPoints => Model.FigureHeightPoints;
|
||
|
|
public double PlotXPoints => 68d;
|
||
|
|
public double PlotYPoints => 44d;
|
||
|
|
public double PlotWidthPoints => 400d;
|
||
|
|
public double PlotHeightPoints => 245d;
|
||
|
|
public double LegendYPoints => 340d;
|
||
|
|
public IReadOnlyList<SmoothingFigureSeriesView> Series { get; }
|
||
|
|
public IReadOnlyList<SmoothingFigureLegendEntry> LegendEntries => BuildLegend(Series);
|
||
|
|
public double WorldXMinMeters { get; }
|
||
|
|
public double WorldXMaxMeters { get; }
|
||
|
|
public double WorldYMinMeters { get; }
|
||
|
|
public double WorldYMaxMeters { get; }
|
||
|
|
public double WorldScalePointsPerMeter => Math.Min(PlotWidthPoints / (WorldXMaxMeters - WorldXMinMeters), PlotHeightPoints / (WorldYMaxMeters - WorldYMinMeters));
|
||
|
|
public IReadOnlyList<double> XTicks { get; }
|
||
|
|
public IReadOnlyList<double> YTicks { get; }
|
||
|
|
public double CurvatureArcLengthMaximumMeters { get; }
|
||
|
|
public double CurvatureMinimumPerMeter { get; }
|
||
|
|
public double CurvatureMaximumPerMeter { get; }
|
||
|
|
public IReadOnlyList<double> CurvatureArcLengthTicks { get; }
|
||
|
|
public IReadOnlyList<double> CurvatureTicks { get; }
|
||
|
|
|
||
|
|
private static IReadOnlyList<T> Copy<T>(IReadOnlyList<T> source)
|
||
|
|
{
|
||
|
|
var copy = new List<T>(source == null ? 0 : source.Count);
|
||
|
|
if (source != null) for (int index = 0; index < source.Count; index++) copy.Add(source[index]);
|
||
|
|
return new ReadOnlyCollection<T>(copy);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static IReadOnlyList<SmoothingFigureLegendEntry> BuildLegend(IReadOnlyList<SmoothingFigureSeriesView> views)
|
||
|
|
{
|
||
|
|
var entries = new List<SmoothingFigureLegendEntry>(views == null ? 0 : views.Count);
|
||
|
|
if (views != null)
|
||
|
|
{
|
||
|
|
for (int index = 0; index < views.Count; index++)
|
||
|
|
{
|
||
|
|
SmoothingFigureSeries series = views[index].Series;
|
||
|
|
entries.Add(new SmoothingFigureLegendEntry(series.Label + " (" + series.Status + ")", series.Color, string.Empty));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return new ReadOnlyCollection<SmoothingFigureLegendEntry>(entries);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>某条路径在特定图中的显示透明度。</summary>
|
||
|
|
public sealed class SmoothingFigureSeriesView
|
||
|
|
{
|
||
|
|
internal SmoothingFigureSeriesView(SmoothingFigureSeries series, double opacity)
|
||
|
|
{
|
||
|
|
Series = series ?? throw new ArgumentNullException(nameof(series));
|
||
|
|
Opacity = opacity < 0d ? 0d : (opacity > 1d ? 1d : opacity);
|
||
|
|
}
|
||
|
|
|
||
|
|
public SmoothingFigureSeries Series { get; }
|
||
|
|
public double Opacity { get; }
|
||
|
|
}
|