Skip to content

Commit

Permalink
heuristics for reconnecting cells in constructors improved (yields le…
Browse files Browse the repository at this point in the history
…ss defective offspring)
  • Loading branch information
chrxh committed Jan 3, 2025
1 parent 18bca14 commit 98d7e2c
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 42 deletions.
117 changes: 79 additions & 38 deletions source/EngineGpuKernels/CellConnectionProcessor.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ __inline__ __device__ bool CellConnectionProcessor::tryAddConnectionOneWay(
float desiredAngleOnCell1,
ConstructorAngleAlignment angleAlignment)
{
if (cell1->numConnections == MAX_CELL_BONDS) {
return false;
}
if (ConstructorAngleAlignment_None != angleAlignment && cell1->numConnections >= angleAlignment + 1) {
return false;
}

if (wouldResultInOverlappingConnection(cell1, cell2->pos)) {
return false;
}
Expand All @@ -290,13 +297,20 @@ __inline__ __device__ bool CellConnectionProcessor::tryAddConnectionOneWay(
desiredDistance = Math::length(posDelta);
}

// *****
// special case: cell1 has no connections
// *****
if (0 == cell1->numConnections) {
cell1->numConnections++;
cell1->connections[0].cell = cell2;
cell1->connections[0].distance = desiredDistance;
cell1->connections[0].angleFromPrevious = 360.0f;
return true;
}

// *****
// special case: cell1 has one connection
// *****
if (1 == cell1->numConnections) {
auto connectedCellDelta = cell1->connections[0].cell->pos - cell1->pos;
data.cellMap.correctDirection(connectedCellDelta);
Expand All @@ -323,72 +337,99 @@ __inline__ __device__ bool CellConnectionProcessor::tryAddConnectionOneWay(
return true;
}

//find appropriate index for new connection
// *****
// process general case
// *****

// find appropriate index for new connection
int index = 0;
float prevAngle = 0;
float nextAngle = 0;
for (; index < cell1->numConnections; ++index) {
auto prevIndex = (index + cell1->numConnections - 1) % cell1->numConnections;
prevAngle = Math::angleOfVector(data.cellMap.getCorrectedDirection(cell1->connections[prevIndex].cell->pos - cell1->pos));
nextAngle = Math::angleOfVector(data.cellMap.getCorrectedDirection(cell1->connections[index].cell->pos - cell1->pos));
if (Math::isAngleInBetween(prevAngle, nextAngle, newAngle)) {
if (Math::isAngleInBetween(prevAngle, nextAngle, newAngle) || prevIndex == index) {
break;
}
}

//create connection object
// create new connection object
CellConnection newConnection;
newConnection.cell = cell2;
newConnection.distance = desiredDistance;
auto angleFromPrevious = 0.0f;

float angleFromPrevious;
auto refAngle = cell1->connections[index].angleFromPrevious;
if (Math::isAngleInBetween(prevAngle, nextAngle, newAngle)) {
if (0 == desiredAngleOnCell1) {
auto angleDiff1 = Math::subtractAngle(newAngle, prevAngle);
auto angleDiff2 = Math::subtractAngle(nextAngle, prevAngle);
auto factor = angleDiff2 != 0 ? angleDiff1 / angleDiff2 : 0.5f;
if (0 == desiredAngleOnCell1) {
angleFromPrevious = refAngle * factor;
} else {
angleFromPrevious = desiredAngleOnCell1;
}
angleFromPrevious = min(angleFromPrevious, refAngle);

angleFromPrevious = Math::alignAngle(angleFromPrevious, angleAlignment);
angleFromPrevious = Math::alignAngleOnBoundaries(angleFromPrevious, refAngle, angleAlignment);
auto newAngleFraction = angleDiff2 != 0 ? angleDiff1 / angleDiff2 : 0.5f;
angleFromPrevious = refAngle * newAngleFraction;
} else {
angleFromPrevious = desiredAngleOnCell1;
}
angleFromPrevious = min(angleFromPrevious, refAngle);

if (angleFromPrevious < NEAR_ZERO) {
return false;
}
newConnection.angleFromPrevious = angleFromPrevious;

//adjust reference angle of next connection
auto nextAngleFromPrevious = refAngle - angleFromPrevious;
auto nextAngleFromPreviousAligned = Math::alignAngle(nextAngleFromPrevious, angleAlignment);
auto angleDiff = nextAngleFromPreviousAligned - nextAngleFromPrevious;

auto nextIndex = index % cell1->numConnections;
auto nextNextIndex = (index + 1) % cell1->numConnections;
auto nextNextAngleFromPrevious = cell1->connections[nextNextIndex].angleFromPrevious;
if (nextNextAngleFromPrevious - angleDiff >= 0.0f && nextNextAngleFromPrevious - angleDiff <= 360.0f) {
if (nextAngleFromPreviousAligned < NEAR_ZERO || nextNextAngleFromPrevious - angleDiff < NEAR_ZERO) {
return false;
// insert new connection to a clone of the existing connection array
CellConnection newConnections[MAX_CELL_BONDS];
for (int i = 0; i < cell1->numConnections; ++i) {
newConnections[i] = cell1->connections[i];
}
if (index == 0) {
index = cell1->numConnections; // connection at index 0 should be an invariant
}
for (int j = cell1->numConnections; j > index; --j) {
newConnections[j] = newConnections[j - 1];
}
newConnections[index] = newConnection;
newConnections[(index + 1) % (cell1->numConnections + 1)].angleFromPrevious = refAngle - angleFromPrevious;

// align angles
if (angleAlignment != ConstructorAngleAlignment_None) {
auto const angleUnit = 360.0f / (angleAlignment + 1);
for (int i = 0; i < cell1->numConnections + 1; ++i) {
newConnections[i].angleFromPrevious = Math::alignAngle(newConnections[i].angleFromPrevious, angleAlignment);
if (abs(newConnections[i].angleFromPrevious) < NEAR_ZERO) {
newConnections[i].angleFromPrevious = angleUnit;
}
}
cell1->connections[nextIndex].angleFromPrevious = nextAngleFromPreviousAligned;
cell1->connections[nextNextIndex].angleFromPrevious = nextNextAngleFromPrevious - angleDiff;
} else {
if (nextAngleFromPrevious < NEAR_ZERO) {
return false;

for (int i = 0; i < MAX_CELL_BONDS; ++i) {
float sumAngle = 0;
for (int i = 0; i < cell1->numConnections + 1; ++i) {
sumAngle += newConnections[i].angleFromPrevious;
}
if (sumAngle > 360.0f + NEAR_ZERO || sumAngle < 360.0f - NEAR_ZERO) {
int indexWithMaxAngle = -1;
float maxAngle = 0;
for (int j = 0; j < cell1->numConnections + 1; ++j) {
if (newConnections[j].angleFromPrevious > maxAngle) {
maxAngle = newConnections[j].angleFromPrevious;
indexWithMaxAngle = j;
}
}
if (sumAngle > 360.0f + NEAR_ZERO) {
newConnections[indexWithMaxAngle].angleFromPrevious -= angleUnit;
} else {
newConnections[indexWithMaxAngle].angleFromPrevious += angleUnit;
}
} else {
break;
}
}
cell1->connections[nextIndex].angleFromPrevious = nextAngleFromPrevious;
}

//add connection
for (int j = cell1->numConnections; j > index; --j) {
cell1->connections[j] = cell1->connections[j - 1];
// adopt new connections
cell1->numConnections++;
for (int i = 0; i < cell1->numConnections; ++i) {
cell1->connections[i] = newConnections[i];
}
cell1->connections[index] = newConnection;
++cell1->numConnections;

return true;
}

Expand Down
35 changes: 31 additions & 4 deletions source/EngineGpuKernels/ConstructorProcessor.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,21 @@ __inline__ __device__ Cell* ConstructorProcessor::continueConstruction(

auto newCellPos = hostCell->pos + posDelta;

//get surrounding cells
float angleFromPrevious1;
float angleFromPrevious2;
auto const& lastConstructionCell = constructionData.lastConstructionCell;

for (int i = 0; i < lastConstructionCell->numConnections; ++i) {
if (lastConstructionCell->connections[i].cell == hostCell) {
angleFromPrevious1 = lastConstructionCell->connections[i].angleFromPrevious;
angleFromPrevious2 = lastConstructionCell->connections[(i + 1) % lastConstructionCell->numConnections].angleFromPrevious;
break;
}
}
auto n = Math::normalized(hostCell->pos - lastConstructionCell->pos);
Math::rotateQuarterClockwise(n);

// assemble surrounding cell candidates
Cell* otherCellCandidates[MAX_CELL_BONDS * 2];
int numOtherCellCandidates = 0;
data.cellMap.getMatchingCells(
Expand All @@ -426,14 +440,27 @@ __inline__ __device__ Cell* ConstructorProcessor::continueConstruction(
hostCell->detached,
[&](Cell* const& otherCell) {
if (otherCell == constructionData.lastConstructionCell || otherCell == hostCell
|| (otherCell->livingState != LivingState_UnderConstruction
&& otherCell->activationTime == 0) || otherCell->creatureId != hostCell->cellFunctionData.constructor.offspringCreatureId) {
|| (otherCell->livingState != LivingState_UnderConstruction && otherCell->activationTime == 0)
|| otherCell->creatureId != hostCell->cellFunctionData.constructor.offspringCreatureId) {
return false;
}

// discard cells that are not on the correct side
auto delta = data.cellMap.getCorrectedDirection(otherCell->pos - lastConstructionCell->pos);
if (angleFromPrevious2 < angleFromPrevious1) {
if (Math::dot(delta, n) < 0) {
return false;
}
}
if (angleFromPrevious2 > angleFromPrevious1) {
if (Math::dot(delta, n) > 0) {
return false;
}
}
return true;
});

//assemble surrounding cell candidates
// evaluate candidates
Cell* otherCells[MAX_CELL_BONDS];
int numOtherCells = 0;
for (int i = 0; i < numOtherCellCandidates; ++i) {
Expand Down

0 comments on commit 98d7e2c

Please sign in to comment.