Python OR-工具点之间的距离
Python OR-Tools Distance between points
我正在使用 or-tools 约束求解器来查找房间中物品的工作位置。我正在使用 CP 求解器而不是背包求解器,因为我需要添加额外的约束。
我将每个项目表示为 x 区间和 y 区间并添加如下约束:
model.AddNoOverlap2D(x_intervals, y_intervals)
这有助于放置对象,使它们不重叠,但我需要添加另一个约束以确保对象之间有一定距离。这应该是对象之间的基本 2D 距离,但此公式需要 sqrt 和 pow 函数,这些函数似乎不适用于 IntVar 项目。
我考虑过使用另一个以每个主要对象为中心的“spacer 对象”,并添加另一个 NoOverlap2D
约束,但这会导致 space 当距离公式是一个更精确的距离时,不会在房间里浪费那么多 space。
编辑 - 下面的代码现在可以对项目设置距离限制。
根据 Laurent 的建议,我尝试制作许多中间变量来处理这个问题,但我坚持乘以或除以定义形状位置间隔的 IntVars:
# Now lets make all possible combinations and make a distance between them
combos = list(combinations(range(len(rects_data)), 2))
print(combos)
currentDistanceId = 0
distanceVariables = []
for listSet in combos:
leftItem = all_vars[listSet[0]]
rightItem = all_vars[listSet[1]]
if leftItem.holderType == HolderType.Person and rightItem.holderType == HolderType.Person:
print(f"Adding distances between {listSet[0]} and {listSet[1]} because both are people")
currentDistanceId = currentDistanceId + 1
# Add an intermediate variable to store the sum of x for the center of left object
leftCenterXSum = model.NewIntVar(0, horizon.x*2, f"leftCenterXSum{currentDistanceId}")
# Add constraint to it
model.Add(leftCenterXSum == leftItem.x2 + leftItem.x1)
# Add an intermediate variable to store the center of x of the left object
leftCenterX = model.NewIntVar(0, horizon.x, f"leftCenterX{currentDistanceId}")
# Add a constraint to divide it by 2 to make it te center
model.AddDivisionEquality(leftCenterX, leftCenterXSum, 2)
## Repeat for x and y for left and right objects
leftCenterYSum = model.NewIntVar(0, horizon.y*2, f"leftCenterYSum{currentDistanceId}")
model.Add(leftCenterYSum == leftItem.y2 + leftItem.y1)
leftCenterY = model.NewIntVar(0, horizon.y, f"leftCenterY{currentDistanceId}")
model.AddDivisionEquality(leftCenterY, leftCenterYSum, 2)
rightCenterXSum = model.NewIntVar(0, horizon.x*2, f"rightCenterXSum{currentDistanceId}")
model.Add(rightCenterXSum == rightItem.x2 + rightItem.x1)
rightCenterX = model.NewIntVar(0, horizon.x, f"rightCenterX{currentDistanceId}")
model.AddDivisionEquality(rightCenterX, rightCenterXSum, 2)
rightCenterYSum = model.NewIntVar(0, horizon.y*2, f"rightCenterYSum{currentDistanceId}")
model.Add(rightCenterYSum == rightItem.y2 + rightItem.y1)
rightCenterY = model.NewIntVar(0, horizon.y, f"rightCenterY{currentDistanceId}")
model.AddDivisionEquality(rightCenterY, rightCenterYSum, 2)
# Create variable for difference of x
xDiff = model.NewIntVar(-horizon.x, horizon.x, f"xDiff{currentDistanceId}")
# Create constraint for difference of x
model.Add(xDiff == rightCenterX - leftCenterX)
# Create variable for difference of y
yDiff = model.NewIntVar(-horizon.y, horizon.y, f"yDiff{currentDistanceId}")
# Create constraint for difference for y
model.Add(yDiff == rightCenterY - leftCenterY)
# Create variables for x and y squared
xDiffSquared = model.NewIntVar(0, horizon.x**2, f"xDiffSquared{currentDistanceId}")
yDiffSquared = model.NewIntVar(0, horizon.y**2, f"yDiffSquared{currentDistanceId}")
# Add constraint to multiply them
model.AddMultiplicationEquality(xDiffSquared, [xDiff, xDiff])
model.AddMultiplicationEquality(yDiffSquared, [yDiff, yDiff])
totalDistance = model.NewIntVar(0, horizon.x**2 + horizon.y**2, f"totalDistance{currentDistanceId}")
model.Add(totalDistance == xDiffSquared + yDiffSquared)
distanceVariables.append(totalDistance)
model.Add( totalDistance >= distanceSquared )
else:
print(f"Skipping distances between {listSet[0]} and {listSet[1]} because one is furniture")
而不是
Sqrt((x1-x2)^2 + (y1-y2)^2) >= d
为什么不写
(x1-x2)^2 + (y1-y2)^2 >= d^2
支持。您将需要编写(伪代码)
IntVar t_x
Add(t_x == x1 - x2)
IntVar t_sx
AddMultiplicationEquality(t_sx, [t_x, t_x])
IntVar t_y
Add(t_y == y1 - y2)
IntVar t_sy
AddMultiplicationEquality(t_sy, [t_y, t_y])
Add(t_sx + t_sy >= d * d)
我正在使用 or-tools 约束求解器来查找房间中物品的工作位置。我正在使用 CP 求解器而不是背包求解器,因为我需要添加额外的约束。
我将每个项目表示为 x 区间和 y 区间并添加如下约束:
model.AddNoOverlap2D(x_intervals, y_intervals)
这有助于放置对象,使它们不重叠,但我需要添加另一个约束以确保对象之间有一定距离。这应该是对象之间的基本 2D 距离,但此公式需要 sqrt 和 pow 函数,这些函数似乎不适用于 IntVar 项目。
我考虑过使用另一个以每个主要对象为中心的“spacer 对象”,并添加另一个 NoOverlap2D
约束,但这会导致 space 当距离公式是一个更精确的距离时,不会在房间里浪费那么多 space。
编辑 - 下面的代码现在可以对项目设置距离限制。
根据 Laurent 的建议,我尝试制作许多中间变量来处理这个问题,但我坚持乘以或除以定义形状位置间隔的 IntVars:
# Now lets make all possible combinations and make a distance between them
combos = list(combinations(range(len(rects_data)), 2))
print(combos)
currentDistanceId = 0
distanceVariables = []
for listSet in combos:
leftItem = all_vars[listSet[0]]
rightItem = all_vars[listSet[1]]
if leftItem.holderType == HolderType.Person and rightItem.holderType == HolderType.Person:
print(f"Adding distances between {listSet[0]} and {listSet[1]} because both are people")
currentDistanceId = currentDistanceId + 1
# Add an intermediate variable to store the sum of x for the center of left object
leftCenterXSum = model.NewIntVar(0, horizon.x*2, f"leftCenterXSum{currentDistanceId}")
# Add constraint to it
model.Add(leftCenterXSum == leftItem.x2 + leftItem.x1)
# Add an intermediate variable to store the center of x of the left object
leftCenterX = model.NewIntVar(0, horizon.x, f"leftCenterX{currentDistanceId}")
# Add a constraint to divide it by 2 to make it te center
model.AddDivisionEquality(leftCenterX, leftCenterXSum, 2)
## Repeat for x and y for left and right objects
leftCenterYSum = model.NewIntVar(0, horizon.y*2, f"leftCenterYSum{currentDistanceId}")
model.Add(leftCenterYSum == leftItem.y2 + leftItem.y1)
leftCenterY = model.NewIntVar(0, horizon.y, f"leftCenterY{currentDistanceId}")
model.AddDivisionEquality(leftCenterY, leftCenterYSum, 2)
rightCenterXSum = model.NewIntVar(0, horizon.x*2, f"rightCenterXSum{currentDistanceId}")
model.Add(rightCenterXSum == rightItem.x2 + rightItem.x1)
rightCenterX = model.NewIntVar(0, horizon.x, f"rightCenterX{currentDistanceId}")
model.AddDivisionEquality(rightCenterX, rightCenterXSum, 2)
rightCenterYSum = model.NewIntVar(0, horizon.y*2, f"rightCenterYSum{currentDistanceId}")
model.Add(rightCenterYSum == rightItem.y2 + rightItem.y1)
rightCenterY = model.NewIntVar(0, horizon.y, f"rightCenterY{currentDistanceId}")
model.AddDivisionEquality(rightCenterY, rightCenterYSum, 2)
# Create variable for difference of x
xDiff = model.NewIntVar(-horizon.x, horizon.x, f"xDiff{currentDistanceId}")
# Create constraint for difference of x
model.Add(xDiff == rightCenterX - leftCenterX)
# Create variable for difference of y
yDiff = model.NewIntVar(-horizon.y, horizon.y, f"yDiff{currentDistanceId}")
# Create constraint for difference for y
model.Add(yDiff == rightCenterY - leftCenterY)
# Create variables for x and y squared
xDiffSquared = model.NewIntVar(0, horizon.x**2, f"xDiffSquared{currentDistanceId}")
yDiffSquared = model.NewIntVar(0, horizon.y**2, f"yDiffSquared{currentDistanceId}")
# Add constraint to multiply them
model.AddMultiplicationEquality(xDiffSquared, [xDiff, xDiff])
model.AddMultiplicationEquality(yDiffSquared, [yDiff, yDiff])
totalDistance = model.NewIntVar(0, horizon.x**2 + horizon.y**2, f"totalDistance{currentDistanceId}")
model.Add(totalDistance == xDiffSquared + yDiffSquared)
distanceVariables.append(totalDistance)
model.Add( totalDistance >= distanceSquared )
else:
print(f"Skipping distances between {listSet[0]} and {listSet[1]} because one is furniture")
而不是
Sqrt((x1-x2)^2 + (y1-y2)^2) >= d
为什么不写
(x1-x2)^2 + (y1-y2)^2 >= d^2
支持。您将需要编写(伪代码)
IntVar t_x
Add(t_x == x1 - x2)
IntVar t_sx
AddMultiplicationEquality(t_sx, [t_x, t_x])
IntVar t_y
Add(t_y == y1 - y2)
IntVar t_sy
AddMultiplicationEquality(t_sy, [t_y, t_y])
Add(t_sx + t_sy >= d * d)