placementScore function
double
placementScore({
- required Offset candidate,
- required Offset previous,
- required Offset outward,
- Offset? connectorStart,
- Offset? connectorEnd,
- Rect? candidateRect,
- List<
Rect> slots = const [], - List<
Rect> obstacles = const [], - double previousWeight = 0.65,
- double originWeight = 0.2,
- double directionWeight = 16.0,
- double lengthWeight = 0.18,
- double clearanceWeight = 8.0,
- double coverageWeight = 16.0,
- double slotCenterWeight = 18.0,
- double connectorIntersectWeight = 160.0,
- double connectorProximityWeight = 24.0,
- double connectorAvoidDistance = 10.0,
Implementation
double placementScore({
required Offset candidate,
required Offset previous,
required Offset outward,
Offset? connectorStart,
Offset? connectorEnd,
Rect? candidateRect,
List<Rect> slots = const [],
List<Rect> obstacles = const [],
double previousWeight = 0.65,
double originWeight = 0.2,
double directionWeight = 16.0,
double lengthWeight = 0.18,
double clearanceWeight = 8.0,
double coverageWeight = 16.0,
double slotCenterWeight = 18.0,
double connectorIntersectWeight = 160.0,
double connectorProximityWeight = 24.0,
double connectorAvoidDistance = 10.0,
}) {
final prevDistance = (candidate - previous).distance;
final originDistance = candidate.distance;
final connectorLength = candidate.distance;
final preferredDir = dirOrFallback(previous, outward);
final preferredNorm = preferredDir.distance > 1e-6
? preferredDir / preferredDir.distance
: const Offset(1, 0);
final candidateNorm =
candidate.distance > 1e-6 ? candidate / candidate.distance : Offset.zero;
final directionPenalty = (1 -
(candidateNorm.dx * preferredNorm.dx +
candidateNorm.dy * preferredNorm.dy)) *
directionWeight;
final clearancePenalty = switch (candidateRect) {
final Rect rect when slots.isNotEmpty =>
math.max(0.0, _kClearanceTarget - bestSlotClearance(rect, slots)) *
clearanceWeight,
_ => 0.0,
};
final coveragePenalty = switch (candidateRect) {
final Rect rect when slots.isNotEmpty =>
(1 - slotCoverageRatio(rect, slots)) * coverageWeight,
_ => 0.0,
};
final slotCenterPenalty = switch (candidateRect) {
final Rect rect when slots.isNotEmpty =>
bestSlotCenterDistanceRatio(rect, slots) * slotCenterWeight,
_ => 0.0,
};
final connectorPenalty = switch ((connectorStart, connectorEnd)) {
(final Offset start, final Offset end) when obstacles.isNotEmpty =>
connectorObstaclePenalty(
start,
end,
obstacles,
avoidDistance: connectorAvoidDistance,
intersectWeight: connectorIntersectWeight,
proximityWeight: connectorProximityWeight,
),
_ => 0.0,
};
return prevDistance * previousWeight +
originDistance * originWeight +
connectorLength * lengthWeight +
directionPenalty +
clearancePenalty +
coveragePenalty +
slotCenterPenalty +
connectorPenalty;
}