offset a parallel line to a given line python
Asked Answered
C

2

0

I want to draw parallel line to given X,Y coordinate below code helps to draw ,

import numpy as np
import matplotlib.pyplot as plt

x = [187, 879, 722, 322]

y = [341, 344, 112, 112]


newX = []
newY = []

def findIntesection(p1x, p1y, p2x, p2y, p3x,p3y, p4x, p4y):
    dx12 = p2x - p1x
    dy12 = p2y - p1y
    dx34 = p4x - p3x
    dy34 = p4y - p3y

    denominator = (dy12*dx34-dx12*dy34)

    t1 = ((p1x - p3x) * dy34 + (p3y - p1y) * dx34)/ denominator

    t2 = ((p3x - p1x) * dy12 + (p1y - p3y) * dx12)/ -denominator;
    
    intersectX = p1x + dx12 * t1
    intersectY = p1y + dy12 * t1

    if (t1 < 0): t1 = 0
    elif (t1 > 1): t1 = 1
    if (t2 < 0): t2 = 0
    elif (t2 > 1): t2 = 1
    
    return intersectX,intersectY

def normalizeVec(x,y):
    distance = np.sqrt(x*x+y*y)
    return x/distance, y/distance

def getEnlarged(oldX, oldY, offset):
    num_points = len(oldX)
    
    for j in range(num_points):
        i = j - 1
        if i < 0:
            i += num_points
        k = (j + 1) % num_points

        vec1X =  oldX[j] - oldX[i]
        vec1Y =  oldY[j] - oldY[i]
        v1normX, v1normY = normalizeVec(vec1X,vec1Y)
        v1normX *= offset
        v1normY *= offset
        n1X = -v1normY
        n1Y = v1normX
        pij1X = oldX[i] + n1X
        pij1Y = oldY[i] + n1Y
        pij2X = oldX[j] + n1X
        pij2Y = oldY[j] + n1Y

        vec2X =  oldX[k] - oldX[j]
        vec2Y =  oldY[k] - oldY[j]
        v2normX, v2normY = normalizeVec(vec2X,vec2Y)
        v2normX *= offset
        v2normY *= offset
        n2X = -v2normY
        n2Y = v2normX
        pjk1X = oldX[j] + n2X
        pjk1Y = oldY[j] + n2Y
        pjk2X = oldX[k] + n2X
        pjk2Y = oldY[k] + n2Y
        
        intersectX,intersetY = findIntesection(pij1X,pij1Y,pij2X,pij2Y,pjk1X,pjk1Y,pjk2X,pjk2Y)
        
        #print(intersectX,intersetY)
        
        newX.append(intersectX)
        newY.append(intersetY)

getEnlarged(x, y, 20)

plt.plot(x, y)
plt.plot(newX, newY)
plt.show()

This gives result as below

enter image description here

Here it is giving good result by drawing parallel line to each line of our trapezoidal shaped , but i want it to be a closed shape in place of open shape i want to join the 1st and last coordinate so that it should form a closed shape. Any help will be appreciated .

Cithara answered 23/6, 2021 at 17:56 Comment(0)
M
4

Using approach from here

outer_ccw parameters combines vertex order and desired offset direction. For CCW order and outer polygon it is 1, for inner polygon it should be -1.

def makeOffsetPoly(oldX, oldY, offset, outer_ccw = 1):
    num_points = len(oldX)

    for curr in range(num_points):
        prev = (curr + num_points - 1) % num_points
        next = (curr + 1) % num_points

        vnX =  oldX[next] - oldX[curr]
        vnY =  oldY[next] - oldY[curr]
        vnnX, vnnY = normalizeVec(vnX,vnY)
        nnnX = vnnY
        nnnY = -vnnX

        vpX =  oldX[curr] - oldX[prev]
        vpY =  oldY[curr] - oldY[prev]
        vpnX, vpnY = normalizeVec(vpX,vpY)
        npnX = vpnY * outer_ccw
        npnY = -vpnX * outer_ccw

        bisX = (nnnX + npnX) * outer_ccw
        bisY = (nnnY + npnY) * outer_ccw

        bisnX, bisnY = normalizeVec(bisX,  bisY)
        bislen = offset /  np.sqrt((1 + nnnX*npnX + nnnY*npnY)/2)

        newX.append(oldX[curr] + bislen * bisnX)
        newY.append(oldY[curr] + bislen * bisnY)

x = [0, 100, 60, 40]
y = [0, 0, 50, 50]
makeOffsetPoly(x, y, 20)
print(newX, newY)

>>>[-29.424478775259594, 129.4244787752596, 66.79706177729007, 33.202938222709925] 
   [-14.14213562373095, -14.14213562373095, 64.14213562373095, 64.14213562373095]

enter image description here

Murial answered 24/6, 2021 at 3:29 Comment(4)
what if our any edge has non-straight line can we still make such outer shapeCithara
Defining offset line for curves is very hard problem in general (except for circle arcs). You can approximate curve by small line segments.Murial
any example can you show for curved edge at your free time ..i have tried to approximate using cv2.approxPolyDPCithara
approxPolyDP assumes you already have vertex array (with too many vertices). After simplification just apply described approach.Murial
S
0

Just append the first coordinates to the end of your lists.

x.append(x[0])
y.append(y[0])
newX.append(newX[0])
newY.append(newY[0])

Place this right before you plot. Here's my output

Sackcloth answered 23/6, 2021 at 19:9 Comment(3)
i have tried this manually but offset line is not giving proper result .Cithara
@Sackcloth can u illustrate with example/ or making changes in the code according to your thoughtSemipostal
@Cithara see edit. I'm not sure what you mean by offset lineSackcloth

© 2022 - 2024 — McMap. All rights reserved.