-
Notifications
You must be signed in to change notification settings - Fork 0
/
Profile.cs
197 lines (163 loc) · 6.15 KB
/
Profile.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
using System;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using System.Globalization;
namespace NacaProfile
{
class Probe
{
private int index;
private VectorF normalVector;
public int Index
{ get { return index; } }
public VectorF NormalVector
{ get { return normalVector; } }
public Probe(int index, VectorF normalVector)
{
this.index = index;
this.normalVector = normalVector;
}
}
class Profile
{
private List<PointF> points;
private List<Probe> probes;
private IFormatProvider format = CultureInfo.GetCultureInfo("en-US").NumberFormat;
private float maxX, maxY, minX, minY;
private PointF centroid;
private float area;
public List<PointF> Points
{ get { return points; } }
public List<Probe> Probes
{ get { return probes; } }
public float MaximumX
{ get { return maxX; } }
public float MaximumY
{ get { return maxY; } }
public float MinimumX
{ get { return minX; } }
public float MinimumY
{ get { return minY; } }
public PointF Centroid
{ get { return centroid; } }
public float Area
{ get { return area; } }
public Profile(string profileFile, string probeFile)
{
points = ReadPointsFromFile(profileFile);
probes = ReadProbesFromFile(probeFile);
FindMinMax();
CalculateAreaAndCentroid();
}
public void CalculateAreaAndCentroid()
{
if (points.Count < 1)
throw new InvalidOperationException("Found no points!");
float sumX = 0, sumY = 0, a = 0;
for (int i = 0; i < points.Count - 1; i++)
{
float tmp = points[i].X * points[i + 1].Y - points[i + 1].X * points[i].Y;
sumX += (points[i].X + points[i + 1].X) * tmp;
sumY += (points[i].Y + points[i + 1].Y) * tmp;
a += tmp;
}
area *= 0.5f;
float factor = 1 / (6 * a);
centroid = new PointF(sumX * factor, sumY * factor);
}
private List<PointF> ReadPointsFromFile(string file)
{
List<PointF> points = new List<PointF>();
string[] lines = File.ReadAllLines(file);
foreach (string line in lines)
{
if (line.StartsWith("#")) continue;
string[] splitted = line.Split(' ');
if (splitted.Length != 2) continue;
double x, y;
if (!Double.TryParse(splitted[0], NumberStyles.Any, format, out x)) continue;
if (!Double.TryParse(splitted[1], NumberStyles.Any, format, out y)) continue;
points.Add(new PointF((float)x, (float)y));
}
return points;
}
private List<Probe> ReadProbesFromFile(string file)
{
List<Probe> probes = new List<Probe>();
string[] lines = File.ReadAllLines(file);
foreach (string line in lines)
{
if (line.StartsWith("#")) continue;
int index;
if (!Int32.TryParse(line, out index)) continue;
if (index < 0 || index >= points.Count) continue;
VectorF normalVector = EstimateNormalVector(index).Norm();
probes.Add(new Probe(index, normalVector));
}
return probes;
}
private void FindMinMax()
{
if (points.Count < 1)
throw new InvalidOperationException("Found no points!");
minX = maxX = points[0].X;
minY = maxY = points[0].Y;
for (int i = 1; i < points.Count; i++)
{
if (points[i].X > maxX) maxX = points[i].X;
if (points[i].Y > maxY) maxY = points[i].Y;
if (points[i].X < minX) minX = points[i].X;
if (points[i].Y < minY) minY = points[i].Y;
}
}
private PointF GetRelativePoint(int index, int offset)
{
int pos = index + offset;
while (pos >= points.Count) pos -= points.Count;
while (pos < 0) pos += points.Count;
return points[pos];
}
private VectorF EstimateNormalVector(int index)
{
if (index < 0 || index >= points.Count)
throw new IndexOutOfRangeException();
PointF p1 = GetRelativePoint(index, +1);
PointF p2 = GetRelativePoint(index, -1);
return VectorF.CalculateNormalVector(p1, p2);
}
public PointF InterpolateBetweenPoints(int indexBefore, int indexAfter, float ratio)
{
if (indexAfter != indexBefore + 1)
throw new ArgumentException("The two points must be adjacent!");
VectorF vector = VectorF.Vector(points[indexBefore], points[indexAfter]);
float length = vector.Length();
return points[indexBefore] + vector * ratio;
}
public PointF InterpolateNewPoint(int index1, int index2, float ratio)
{
if (index2 <= index1)
throw new ArgumentException("index2 must be greater than index1!");
PointF p1 = points[index1];
PointF p2 = points[index2];
float sum = 0;
for (int i = index1; i < index2; i++)
sum += VectorF.Vector(points[i], points[i + 1]).Length();
float pos = sum * ratio;
int j = index1;
sum = 0;
while (true)
{
float tmp = VectorF.Vector(points[j], points[j + 1]).Length();
if (sum + tmp > pos) break;
else sum += tmp;
j++;
}
int indexBefore = j;
int indexAfter = j + 1;
float rest = pos - sum;
float length = VectorF.Vector(points[indexBefore], points[indexAfter]).Length();
return InterpolateBetweenPoints(indexBefore, indexAfter, rest / length);
}
}
}