简体   繁体   English

Python OR-工具 点间距离

[英]Python OR-Tools Distance between points

I am using the or-tools constraint solver to find working positions of items in a room.我正在使用 or-tools 约束求解器来查找房间中物品的工作位置。 I am using the CP solver instead of the knapsack solver because I need to add additional constraints.我使用 CP 求解器而不是背包求解器,因为我需要添加额外的约束。

I am representing each item as an x interval and y interval and adding a constraint like this:我将每个项目表示为 x 间隔和 y 间隔,并添加如下约束:

model.AddNoOverlap2D(x_intervals, y_intervals)

This helps to place the objects such that they do not overlap, but I need to add another constraint to ensure there is some distance between the objects.这有助于放置对象,使它们不重叠,但我需要添加另一个约束以确保对象之间有一定距离。 This should be a basic 2D distance between the objects, but this formula requires sqrt and pow functions which do not seem usable by IntVar items.这应该是对象之间的基本 2D 距离,但此公式需要 IntVar 项似乎无法使用的 sqrt 和 pow 函数。

I have considered using another "spacer object" that is centered on each primary object, and adding another NoOverlap2D constraint, but this would result in blocking out an entire square of space when the distance formula would be a more precise distance that doesn't waste as much space in the room.我考虑过使用另一个以每个主要 object 为中心的“间隔对象”,并添加另一个NoOverlap2D约束,但是当距离公式将是更精确的距离且不会浪费时,这将导致整个正方形空间被遮挡房间里的空间。

Edit - The code below is now working for putting a distance constraint on items.编辑- 下面的代码现在用于对项目施加距离限制。

After the suggestion from Laurent I have tried to make many intermediate variables to handle this, but am stuck on multiplying or dividing the IntVars defining the intervals of the shape locations:在 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")

Instead of代替

Sqrt((x1-x2)^2 + (y1-y2)^2) >= d

Why don't you write你为什么不写

(x1-x2)^2 + (y1-y2)^2 >= d^2

Which is supported.支持哪个。 You will need to write (in pseudo code)您将需要编写(在伪代码中)

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM