1#include "Library/Rail/Rail.h"
2
3#include "Library/Math/MathUtil.h"
4#include "Library/Placement/PlacementFunction.h"
5#include "Library/Placement/PlacementInfo.h"
6#include "Library/Rail/RailPart.h"
7
8namespace al {
9
10Rail::Rail() = default;
11
12// NON_MATCHING: mismatch during `mRailPart`-array creation
13void Rail::init(const PlacementInfo& info) {
14 mIsClosed = false;
15 tryGetArg(arg: &mIsClosed, placementInfo: info, key: "IsClosed");
16 PlacementInfo railPointsInfo;
17 tryGetPlacementInfoByKey(outPlacementInfo: &railPointsInfo, placementInfo: info, key: "RailPoints");
18 mRailPointsCount = getCountPlacementInfo(placementInfo: railPointsInfo);
19 if (mRailPointsCount <= 0)
20 return;
21
22 mRailPoints = new PlacementInfo*[mRailPointsCount];
23 for (s32 i = 0; i < mRailPointsCount; i++) {
24 mRailPoints[i] = new PlacementInfo();
25 tryGetPlacementInfoByIndex(outPlacementInfo: mRailPoints[i], placementInfo: railPointsInfo, index: i);
26 }
27
28 if (mRailPointsCount == 1) {
29 mRailPartCount = 1;
30 mRailPart = new RailPart[1];
31 PlacementInfo partInfo;
32 tryGetPlacementInfoByIndex(outPlacementInfo: &partInfo, placementInfo: railPointsInfo, index: 0);
33 sead::Vector3f pos = sead::Vector3f::zero;
34 tryGetRailPointPos(railPoint: &pos, placementInfo: partInfo);
35 mRailPart->init(pos, pos, pos, pos);
36 return;
37 }
38
39 mRailPartCount = (mIsClosed ? 1 : 0) + mRailPointsCount - 1;
40 mRailPart = new RailPart[mRailPartCount];
41
42 f32 totalLength = 0;
43 for (s32 i = 0; i < mRailPartCount; i++) {
44 PlacementInfo startInfo, endInfo;
45 tryGetPlacementInfoByIndex(outPlacementInfo: &startInfo, placementInfo: railPointsInfo, index: i);
46 tryGetPlacementInfoByIndex(outPlacementInfo: &endInfo, placementInfo: railPointsInfo, index: (i + 1) % mRailPointsCount);
47
48 sead::Vector3f start = sead::Vector3f::zero;
49 sead::Vector3f startHandle = sead::Vector3f::zero;
50 sead::Vector3f endHandle = sead::Vector3f::zero;
51 sead::Vector3f end = sead::Vector3f::zero;
52 tryGetRailPointPos(railPoint: &start, placementInfo: startInfo);
53 getRailPointHandleNext(railPoint: &startHandle, placementInfo: startInfo);
54 getRailPointHandlePrev(railPoint: &endHandle, placementInfo: endInfo);
55 tryGetRailPointPos(railPoint: &end, placementInfo: endInfo);
56
57 mRailPart[i].init(start, startHandle, endHandle, end);
58 totalLength += mRailPart[i].getPartLength();
59 mRailPart[i].setTotalDistance(totalLength);
60 }
61}
62
63void Rail::calcPos(sead::Vector3f* pos, f32 distance) const {
64 const RailPart* part = nullptr;
65 f32 partDistance = 0;
66 getIncludedSection(&part, &partDistance, distance);
67 part->calcPos(pos, part->calcCurveParam(partDistance));
68}
69
70// NON_MATCHING: minor reorderings
71s32 Rail::getIncludedSection(const RailPart** part, f32* partDistance, f32 distance) const {
72 f32 distanceOnRail = normalizeLength(distance);
73 f32 startDistanceOnRail = 0.0;
74 s32 maxRailPart = -1;
75 s64 longI = -0x100000000;
76 for (s32 i = 0; i < mRailPartCount; i++) {
77 if (distanceOnRail <= mRailPart[i].getTotalDistance()) {
78 if (i <= 0)
79 startDistanceOnRail = distanceOnRail;
80 else
81 startDistanceOnRail = distanceOnRail - mRailPart[longI >> 32].getTotalDistance();
82 maxRailPart = i;
83 break;
84 }
85 longI += 0x100000000;
86 }
87
88 if (part)
89 *part = &mRailPart[maxRailPart];
90 if (partDistance)
91 *partDistance = sead::Mathf::clamp(value: startDistanceOnRail, low: 0.0, high: (*part)->getPartLength());
92
93 return maxRailPart;
94}
95
96void Rail::calcDirection(sead::Vector3f* direction, f32 distance) const {
97 const RailPart* part = nullptr;
98 f32 partDistance = 0;
99 getIncludedSection(part: &part, partDistance: &partDistance, distance);
100 part->calcDir(direction, part->calcCurveParam(partDistance));
101}
102
103void Rail::calcPosDir(sead::Vector3f* position, sead::Vector3f* direction, f32 distance) const {
104 const RailPart* part = nullptr;
105 f32 partDistance = 0;
106 getIncludedSection(part: &part, partDistance: &partDistance, distance);
107 f32 curveParam = part->calcCurveParam(partDistance);
108 part->calcPos(position, curveParam);
109 part->calcDir(direction, curveParam);
110}
111
112f32 Rail::getTotalLength() const {
113 return mRailPart[mRailPartCount - 1].getTotalDistance();
114}
115
116f32 Rail::getPartLength(s32 index) const {
117 return mRailPart[index].getPartLength();
118}
119
120f32 Rail::getLengthToPoint(s32 index) const {
121 if (index == 0)
122 return 0;
123 return mRailPart[index - 1].getTotalDistance();
124}
125
126void Rail::calcRailPointPos(sead::Vector3f* pos, s32 index) const {
127 if (mIsClosed || index != mRailPointsCount - 1)
128 return mRailPart[index].calcStartPos(pos);
129
130 return mRailPart[index - 1].calcEndPos(pos);
131}
132
133void Rail::calcNearestRailPointPosFast(sead::Vector3f* rail_pos, u32* index,
134 const sead::Vector3f& pos) const {
135 u32 rail_points_count = mRailPointsCount;
136
137 sead::Vector3f tmp;
138 mRailPart[0].calcStartPos(&tmp);
139 *rail_pos = tmp;
140 *index = 0;
141
142 f32 best_distance = (tmp - pos).squaredLength();
143 u32 curr_index = 0;
144 for (u32 i = 1; i < rail_points_count; i++) {
145 mRailPart[curr_index].calcEndPos(&tmp);
146 if ((tmp - pos).squaredLength() < best_distance) {
147 best_distance = (tmp - pos).squaredLength();
148 *rail_pos = tmp;
149 *index = i;
150 }
151 curr_index += (i & 1); // only increases every second iteration
152 }
153}
154
155void Rail::calcNearestRailPointNo(s32* index, const sead::Vector3f& pos) const {
156 sead::Vector3f tmp = sead::Vector3f::zero;
157 calcRailPointPos(pos: &tmp, index: 0);
158 f32 best_distance = (pos - tmp).squaredLength();
159 *index = 0;
160
161 s32 curr_index = 1;
162 for (s64 i = 1; i < mRailPointsCount; i++) {
163 calcRailPointPos(pos: &tmp, index: curr_index);
164 if ((pos - tmp).squaredLength() < best_distance) {
165 best_distance = (pos - tmp).squaredLength();
166 *index = i;
167 }
168 curr_index++;
169 }
170}
171
172// NON_MATCHING: mismatch in storing *rail_pos = tmp; (stp instead of two strs)
173void Rail::calcNearestRailPointPos(sead::Vector3f* rail_pos, const sead::Vector3f& pos) const {
174 if (mRailPointsCount == 0)
175 return;
176
177 sead::Vector3f tmp = sead::Vector3f::zero;
178 calcRailPointPos(pos: &tmp, index: 0);
179 f32 best_distance = (pos - tmp).squaredLength();
180
181 s32 curr_index = 1;
182 for (s64 i = 1; i < mRailPointsCount; i++) {
183 calcRailPointPos(pos: &tmp, index: curr_index);
184 if ((pos - tmp).squaredLength() < best_distance) {
185 best_distance = (pos - tmp).squaredLength();
186 *rail_pos = tmp;
187 }
188 curr_index++;
189 }
190}
191
192f32 Rail::normalizeLength(f32 distance) const {
193 if (mIsClosed) {
194 f32 distanceOnRail = modf(a: distance, b: getTotalLength());
195 if (distanceOnRail < 0.0)
196 distanceOnRail += getTotalLength();
197 return distanceOnRail;
198 }
199
200 return sead::Mathf::clamp(value: distance, low: 0.0, high: getTotalLength());
201}
202
203// NON_MATCHING: diff issue due to bug in tools/check
204f32 Rail::calcNearestRailPosCoord(const sead::Vector3f& pos, f32 interval) const {
205 f32 tmp;
206 return calcNearestRailPosCoord(pos, interval, &tmp);
207}
208
209// NON_MATCHING: diff issue due to bug in tools/check
210f32 Rail::calcNearestRailPosCoord(const sead::Vector3f& pos, f32 interval, f32* distance) const {
211 *distance = sead::Mathf::maxNumber();
212 f32 bestParam = sead::Mathf::maxNumber();
213
214 s32 curr_index = 0LL;
215 s32 bestIndex = 0;
216 for (s64 i = 0; i < mRailPartCount; i++) {
217 RailPart* part = &mRailPart[curr_index];
218 f32 param;
219 f32 length = part->calcNearestLength(&param, pos, part->getPartLength(), interval);
220 if (length < *distance) {
221 *distance = length;
222 bestParam = param;
223 bestIndex = i;
224 }
225 ++curr_index;
226 }
227
228 if (bestIndex > 0)
229 bestParam = bestParam + mRailPart[bestIndex - 1].getTotalDistance();
230 return bestParam;
231}
232
233// NON_MATCHING: diff issue due to bug in tools/check
234f32 Rail::calcNearestRailPos(sead::Vector3f* rail_pos, const sead::Vector3f& pos,
235 f32 interval) const {
236 f32 coord = calcNearestRailPosCoord(pos, interval);
237 const RailPart* part = nullptr;
238 f32 partDistance = 0;
239 getIncludedSection(part: &part, partDistance: &partDistance, distance: coord);
240 part->calcPos(rail_pos, part->calcCurveParam(partDistance));
241 return coord;
242}
243
244bool Rail::isNearRailPoint(f32 distance, f32 epsilon) const {
245 const RailPart* part = nullptr;
246 f32 partDistance;
247 getIncludedSection(part: &part, partDistance: &partDistance, distance);
248
249 return (partDistance < epsilon) || ((part->getPartLength() - partDistance) < epsilon);
250}
251
252s32 Rail::calcRailPointNum(f32 distance1, f32 distance2) const {
253 if ((distance2 - distance1) < 0.01f)
254 return 0;
255 const RailPart* part1 = nullptr;
256 const RailPart* part2 = nullptr;
257 f32 partDistance1, partDistance2;
258 s32 sec1 = getIncludedSection(part: &part1, partDistance: &partDistance1, distance: distance1);
259 s32 sec2 = getIncludedSection(part: &part2, partDistance: &partDistance2, distance: distance2);
260
261 return ((sec2 - sec1) + (partDistance1 < 0.01f)) +
262 ((part2->getPartLength() - partDistance2) < 0.01f);
263}
264
265// NON_MATCHING: regalloc in length calculation
266f32 Rail::getIncludedSectionLength(f32* partDistance, f32* length, f32 distance) const {
267 const RailPart* part = nullptr;
268 getIncludedSection(part: &part, partDistance, distance);
269 f32 partLength = part->getPartLength();
270 if (partDistance && length)
271 *length = partLength - *partDistance;
272 return partLength;
273}
274
275s32 Rail::getIncludedSectionIndex(f32 distance) const {
276 return getIncludedSection(part: nullptr, partDistance: nullptr, distance);
277}
278
279bool Rail::isIncludeBezierRailPart() const {
280 for (s32 i = 0; i < mRailPartCount; i++)
281 if (isBezierRailPart(i))
282 return true;
283 return false;
284}
285
286bool Rail::isBezierRailPart(s32 index) const {
287 return mRailPart[index].isBezierCurve();
288}
289
290} // namespace al
291