Implement deferred L-shaped belt drag placement
This commit is contained in:
94
src/lib/core/BeltDragPath.cpp
Normal file
94
src/lib/core/BeltDragPath.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "BeltDragPath.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace
|
||||
{
|
||||
int signOf(int value)
|
||||
{
|
||||
if (value > 0) { return 1; }
|
||||
if (value < 0) { return -1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Direction stepping from one tile to an orthogonally adjacent tile.
|
||||
Rotation directionBetween(QPoint from, QPoint to)
|
||||
{
|
||||
const QPoint delta = to - from;
|
||||
if (delta.x() > 0) { return Rotation::East; }
|
||||
if (delta.x() < 0) { return Rotation::West; }
|
||||
if (delta.y() > 0) { return Rotation::South; }
|
||||
return Rotation::North;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<BeltPathTile> computeBeltDragPath(QPoint anchor, QPoint cursor,
|
||||
Rotation orientation)
|
||||
{
|
||||
const bool horizontalFirst =
|
||||
(orientation == Rotation::East || orientation == Rotation::West);
|
||||
|
||||
// Build the ordered tile coordinates: first leg along the primary axis to the
|
||||
// corner, then the orthogonal leg to the cursor (no duplicated corner tile).
|
||||
std::vector<QPoint> coords;
|
||||
if (horizontalFirst)
|
||||
{
|
||||
const int stepX = signOf(cursor.x() - anchor.x());
|
||||
for (int x = anchor.x(); ; x += stepX)
|
||||
{
|
||||
coords.push_back(QPoint(x, anchor.y()));
|
||||
if (x == cursor.x() || stepX == 0) { break; }
|
||||
}
|
||||
const int stepY = signOf(cursor.y() - anchor.y());
|
||||
if (stepY != 0)
|
||||
{
|
||||
for (int y = anchor.y() + stepY; ; y += stepY)
|
||||
{
|
||||
coords.push_back(QPoint(cursor.x(), y));
|
||||
if (y == cursor.y()) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int stepY = signOf(cursor.y() - anchor.y());
|
||||
for (int y = anchor.y(); ; y += stepY)
|
||||
{
|
||||
coords.push_back(QPoint(anchor.x(), y));
|
||||
if (y == cursor.y() || stepY == 0) { break; }
|
||||
}
|
||||
const int stepX = signOf(cursor.x() - anchor.x());
|
||||
if (stepX != 0)
|
||||
{
|
||||
for (int x = anchor.x() + stepX; ; x += stepX)
|
||||
{
|
||||
coords.push_back(QPoint(x, cursor.y()));
|
||||
if (x == cursor.x()) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assign each tile the direction toward the next tile; the last tile keeps its
|
||||
// incoming step direction, and a single-tile path keeps the belt orientation.
|
||||
std::vector<BeltPathTile> path;
|
||||
path.reserve(coords.size());
|
||||
const std::size_t count = coords.size();
|
||||
for (std::size_t index = 0; index < count; ++index)
|
||||
{
|
||||
Rotation rotation;
|
||||
if (count == 1)
|
||||
{
|
||||
rotation = orientation;
|
||||
}
|
||||
else if (index + 1 < count)
|
||||
{
|
||||
rotation = directionBetween(coords[index], coords[index + 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rotation = directionBetween(coords[index - 1], coords[index]);
|
||||
}
|
||||
path.push_back(BeltPathTile{ coords[index], rotation });
|
||||
}
|
||||
return path;
|
||||
}
|
||||
27
src/lib/core/BeltDragPath.h
Normal file
27
src/lib/core/BeltDragPath.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QPoint>
|
||||
|
||||
#include "Rotation.h"
|
||||
|
||||
// One tile of a belt drag-placement path: the tile coordinate and the belt
|
||||
// orientation it should be given (REQ-BLD-BELT-DRAG).
|
||||
struct BeltPathTile
|
||||
{
|
||||
QPoint tile;
|
||||
Rotation rotation;
|
||||
};
|
||||
|
||||
// Computes the rectilinear (L-shaped) belt path from `anchor` to `cursor` for a
|
||||
// belt whose current orientation is `orientation` (REQ-BLD-BELT-DRAG). The path
|
||||
// first runs along the axis parallel to `orientation` (horizontal for East/West,
|
||||
// vertical for North/South), stepping toward the cursor's coordinate on that axis
|
||||
// to the corner tile, then runs along the orthogonal axis to the cursor tile. Each
|
||||
// tile is oriented to point toward the next tile along the path; the final tile
|
||||
// keeps the direction of its incoming step, and a single-tile path keeps
|
||||
// `orientation`. Returned tiles are ordered from anchor to cursor with no duplicate
|
||||
// corner tile.
|
||||
std::vector<BeltPathTile> computeBeltDragPath(QPoint anchor, QPoint cursor,
|
||||
Rotation orientation);
|
||||
@@ -11,6 +11,7 @@ SET(HDRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Port.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SchematicChoiceOption.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/DisplayName.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BeltDragPath.h
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -19,6 +20,7 @@ SET(SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingType.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/EntityAdmin.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/DisplayName.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BeltDragPath.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user