Skip to content

Commit

Permalink
Add per-tile element drag support, simplify drag code a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
Basssiiie authored and guysv committed Jan 1, 2025
1 parent dee174f commit c510fd2
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 94 deletions.
19 changes: 10 additions & 9 deletions src/services/spacingEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as Log from "../utilities/logger";
import { getTileByCoords } from "../utilities/map";
import { abs } from "../utilities/math";
import { isNull, isUndefined } from "../utilities/type";
import { getSubpositionTranslationDistance, getTrackDistances, TrackDistances } from "./subpositionHelper";
import { getSubpositionTranslationDistance, getTrackSegmentDistances, TrackDistances } from "./subpositionHelper";


const MaxForwardIterations = 10;
Expand Down Expand Up @@ -44,8 +44,10 @@ export function getDistanceFromProgress(car: Car, trackProgress: number): number
? new ForwardIterator(trackProgress, currentProgress)
: new BackwardIterator(abs(trackProgress), currentProgress);

Log.debug("Iterating", (trackProgress >= 0)?"foward":"backward", "from progress", currentProgress, "to", trackProgress);

let trackPosition: CoordsXYZD = currentTrackLocation;
let trackDistances = getTrackDistances(iteratorSegment, subposition, trackPosition.direction);
let trackDistances = getTrackSegmentDistances(iteratorSegment, subposition, trackPosition.direction);
subpositionIterator._setInitialDistanceFromCarRemainingDistance(car.remainingDistance);

while (subpositionIterator._remainingProgress > 0 && iteratorSegment)
Expand Down Expand Up @@ -79,7 +81,7 @@ export function getDistanceFromProgress(car: Car, trackProgress: number): number
}

const nextTrackPosition = iterator.position;
const nextTrackDistance = getTrackDistances(iteratorSegment, subposition, nextTrackPosition.direction);
const nextTrackDistance = getTrackSegmentDistances(iteratorSegment, subposition, nextTrackPosition.direction);

subpositionIterator._remainingProgress--;
subpositionIterator._totalDistance += subpositionIterator._getDistanceBetweenSegments(trackPosition, trackDistances, nextTrackPosition, nextTrackDistance);
Expand Down Expand Up @@ -164,7 +166,7 @@ function calculateSpacingToPrecedingVehicle(car: Car, carInFront: Car): number |
}

const subposition = car.subposition;
let distances = getTrackDistances(iteratorSegment, subposition, currentTrackLocation.direction);
let distances = getTrackSegmentDistances(iteratorSegment, subposition, currentTrackLocation.direction);
let totalDistance = (distances._progressLength - currentProgress);
for (let i = 0; i < MaxForwardIterations; i++)
{
Expand All @@ -183,7 +185,7 @@ function calculateSpacingToPrecedingVehicle(car: Car, carInFront: Car): number |
return null;
}

distances = getTrackDistances(iteratorSegment, subposition, iteratorPosition.direction);
distances = getTrackSegmentDistances(iteratorSegment, subposition, iteratorPosition.direction);
totalDistance += distances._progressLength;
}
return null;
Expand Down Expand Up @@ -223,8 +225,7 @@ function getIndexForTrackElementAt(coords: CoordsXYZD): number | null
const element = tile.elements[i];
if (element.type === "track"
&& element.baseZ === coords.z
&& element.direction === coords.direction
&& element.sequence === 0)
&& element.direction === coords.direction)
{
return i;
}
Expand Down Expand Up @@ -304,7 +305,7 @@ class ForwardIterator extends SubpositionIterator
for (; distanceIdx < trackPieceLength && remainingProgress > 0; distanceIdx++)
{
this._totalDistance += distances[distanceIdx];
Log.debug("total +=", distances[distanceIdx], "=", this._totalDistance, "(step:", distanceIdx, ", remaining:", remainingProgress, ")");
Log.debug("total +=", distances[distanceIdx], "=", this._totalDistance, "(forward step:", distanceIdx, "/", distances.length, ", remaining:", remainingProgress, ")");
remainingProgress--;
}

Expand Down Expand Up @@ -350,7 +351,7 @@ class BackwardIterator extends SubpositionIterator
while (--distanceIdx >= 0 && remainingProgress > 0)
{
this._totalDistance += distances[distanceIdx];
Log.debug("total +=", distances[distanceIdx], "=", this._totalDistance, "(step:", distanceIdx, ", remaining:", remainingProgress, ")");
Log.debug("total +=", distances[distanceIdx], "=", this._totalDistance, "(backward step:", distanceIdx, "/", distances.length, ", remaining:", remainingProgress, ")");
remainingProgress--;
}
this._remainingProgress = remainingProgress;
Expand Down
154 changes: 146 additions & 8 deletions src/services/subpositionHelper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { abs } from "../utilities/math";


/**
* @see https://github.com/OpenRCT2/OpenRCT2/blob/develop/src/openrct2/ride/VehicleData.cpp#L801
*/
Expand All @@ -20,13 +23,35 @@ const distanceCache: Record<string, TrackDistances> = {};
/**
* Gets distance information about the current track segment.
*/
export function getTrackDistances(track: TrackSegment, subpositionType: number, direction: Direction): Readonly<TrackDistances>
export function getTrackSegmentDistances(track: TrackSegment, subpositionType: number, direction: Direction): Readonly<TrackDistances>
{
const key = createCacheKey(track.type, subpositionType, direction);
let value = distanceCache[key];
if (!value)
{
value = new TrackDistances(track.getSubpositions(subpositionType, direction));
value = new TrackDistances(track, subpositionType, direction);
distanceCache[key] = value;
}
return value;
}


/**
* Gets distance information about the specified track type.
*/
export function getTrackTypeDistances(trackType: number, subpositionType: number, direction: Direction): Readonly<TrackDistances>
{
const key = createCacheKey(trackType, subpositionType, direction);
let value = distanceCache[key];
if (!value)
{
const segment = context.getTrackSegment(trackType);
if (!segment)
{
throw Error("Unknown track piece");
}

value = new TrackDistances(segment, subpositionType, direction);
distanceCache[key] = value;
}
return value;
Expand Down Expand Up @@ -54,35 +79,99 @@ function createCacheKey(trackType: number, subposition: number, direction: Direc
}


/**
* Gets the non-square root distance between two positions.
*/
function distance(start: Readonly<CoordsXYZ>, end: Readonly<CoordsXYZ>): number
{
const deltaX = (start.x - end.x);
const deltaY = (start.y - end.y);
const deltaZ = (start.z - end.z);
return abs(deltaX * deltaX + deltaY * deltaY + deltaZ + deltaZ);
}


/**
* Rotates the coordinates by 90 degrees a specified amount of times.
*/
function rotate(coordinates: CoordsXY, by: number): void
{
const rotation = (by & 3);
const x = coordinates.x;
const y = coordinates.y;

if (rotation == 1)
{
coordinates.x = y;
coordinates.y = -x;
}
else if (rotation == 2)
{
coordinates.x = -x;
coordinates.y = -y;
}
else if (rotation == 3)
{
coordinates.x = -y;
coordinates.y = x;
}
}


/**
* A single sequence in a multi-tile track-piece.
*/
interface TrackSequence extends CoordsXYZ
{
// Progress' values closest to the center of that sequence element.
progress: number | null;
}


/**
* The positional data for a specific track element.
*/
export class TrackDistances
{
// Offsets of the starting subposition.
_startX: number;
_startY: number;
_startZ: number;
// Offsets of the ending subposition.
_endX: number;
_endY: number;
_endZ: number;
// Direction of the track piece.
_direction: Direction;
// Distances between each of the subpositions.
_distances: Uint16Array;
// All the sequences in a potentially multi-part track piece.
_sequences: TrackSequence[];
// Total length of the track segment/piece.
_progressLength: number;
// Total distance of all subpositions on the track segment/piece.
_totalDistance: number;

constructor(subpositions: TrackSubposition[])
constructor(track: TrackSegment, subpositionType: number, direction: Direction)
{
const length = subpositions.length;
// Note: optimized to reduce external Duktape calls.
const subpositions = track.getSubpositions(subpositionType, direction);
const subpositionsLength = subpositions.length;
const elements = track.elements;
const elementsLength = elements.length;
const start = subpositions[0];
const distances = new Uint16Array(length - 1);
const distances = new Uint16Array(subpositionsLength - 1);
const sequences = new Array<TrackSequence>(elementsLength);
let totalDistance = 0;
let idx = 1;

// Note: optimized to reduce external Duktape calls.
let { x, y, z } = start;
this._startX = x;
this._startY = y;
this._startZ = z;

for (let idx = 1; idx < length; idx++)
// Get the distance between each of the subpositions.
for (; idx < subpositionsLength; idx++)
{
const next = subpositions[idx];
const distance = getSubpositionTranslationDistance(x, y, z, next.x, next.y, next.z);
Expand All @@ -94,11 +183,60 @@ export class TrackDistances
y = next.y;
z = next.z;
}

// Check if current subposition is closest to any sequence center.
for (idx = 0; idx < elementsLength; idx++)
{
const element = elements[idx];
const center = <TrackSequence>{ x: element.x, y: element.y, z: element.z };
let subposition = 0;
let closestSubposition: number | null = null;
let closestDistance = 10_000; // About max. 3 tiles away (100*100 units, non-square rooted).
let currentDistance;

rotate(center, direction);
center.x += 16;
center.y += 16;

for (; subposition < subpositionsLength; subposition++)
{
currentDistance = distance(center, subpositions[subposition]);
if (currentDistance < closestDistance)
{
closestDistance = currentDistance;
closestSubposition = subposition;
}
}

// Reuse allocated center object for storing the sequence.
center.x -= 16;
center.y -= 16;
center.progress = closestSubposition;

sequences[idx] = center;
}

this._endX = x;
this._endY = y;
this._endZ = z;
this._direction = direction;
this._distances = distances;
this._sequences = sequences;
this._progressLength = distances.length;
this._totalDistance = totalDistance;
}
}

/**
* Get the origin of a track piece in world coordinates.
*/
_origin(x: number, y: number, z: number, sequence: number): CoordsXYZD
{
const element = this._sequences[sequence];
return {
x: x - element.x,
y: y - element.y,
z: z - element.z,
direction: this._direction
};
}
}
Loading

0 comments on commit c510fd2

Please sign in to comment.