简体   繁体   English

蟒蛇。 如何从ax,y列表和偏移距离获取偏移样条的x,y坐标

[英]Python. How to get the x,y coordinates of a offset spline from a x,y list of points and offset distance

I need to make an offset parallel enclosure of an airfoil profile curve, but I cant figure out how to make all the points be equidistant to the points on the primary profile curve at desired distance. 我需要制作翼型轮廓曲线的偏移平行外壳,但我无法弄清楚如何使所有点与所需距离处的主轮廓曲线上的点等距。

this is my example airfoil profile 这是我的示例翼型轮廓 在此输入图像描述

this is my best and not good approach 这是我最好的,也不是好方法 在此输入图像描述

EDIT @Patrick Solution for distance 0.2 编辑 @Patrick解决方案距离0.2 在此输入图像描述

You'll have to special-case slopes of infinity/zero, but the basic approach is to use interpolation to calculate the slope at a point, and then find the perpendicular slope, and then calculate the point at that distance. 您将需要无限/零的特殊情况斜率,但基本方法是使用插值计算某点的斜率,然后找到垂直斜率,然后计算该距离处的点。

I have modified the example from here to add a second graph. 我已经从这里修改了示例以添加第二个图形。 It works with the data file you provided , but you might need to change the sign calculation for a different envelope. 它适用于您提供数据文件 ,但您可能需要更改其他信封的符号计算。

EDIT As per your comments about wanting the envelope to be continuous, I have added a cheesy semicircle at the end that gets really close to doing this for you. 编辑根据你关于想要信封连续的评论,我在最后添加了一个俗气的半圆, 非常接近为你做这个。 Essentially, when creating the envelope, the rounder and more convex you can make it, the better it will work. 基本上,当创建信封时,圆形和更凸的可以制作它,它会更好地工作。 Also, you need to overlap the beginning and the end, or you'll have a gap. 此外,您需要重叠开头和结尾,否则您将有差距。

Also, it could almost certainly be made more efficient -- I am not a numpy expert by any means, so this is just pure Python. 而且,它几乎可以肯定会变得更有效率 - 我不是一个笨拙的专家,所以这只是纯粹的Python。

def offset(coordinates, distance):
    coordinates = iter(coordinates)
    x1, y1 = coordinates.next()
    z = distance
    points = []
    for x2, y2 in coordinates:
        # tangential slope approximation
        try:
            slope = (y2 - y1) / (x2 - x1)
            # perpendicular slope
            pslope = -1/slope  # (might be 1/slope depending on direction of travel)
        except ZeroDivisionError:
            continue
        mid_x = (x1 + x2) / 2
        mid_y = (y1 + y2) / 2

        sign = ((pslope > 0) == (x1 > x2)) * 2 - 1

        # if z is the distance to your parallel curve,
        # then your delta-x and delta-y calculations are:
        #   z**2 = x**2 + y**2
        #   y = pslope * x
        #   z**2 = x**2 + (pslope * x)**2
        #   z**2 = x**2 + pslope**2 * x**2
        #   z**2 = (1 + pslope**2) * x**2
        #   z**2 / (1 + pslope**2) = x**2
        #   z / (1 + pslope**2)**0.5 = x

        delta_x = sign * z / ((1 + pslope**2)**0.5)
        delta_y = pslope * delta_x

        points.append((mid_x + delta_x, mid_y + delta_y))
        x1, y1 = x2, y2
    return points

def add_semicircle(x_origin, y_origin, radius, num_x = 50):
    points = []
    for index in range(num_x):
        x = radius * index / num_x
        y = (radius ** 2 - x ** 2) ** 0.5
        points.append((x, -y))
    points += [(x, -y) for x, y in reversed(points)]
    return [(x + x_origin, y + y_origin) for x, y in points]

def round_data(data):
    # Add infinitesimal rounding of the envelope
    assert data[-1] == data[0]
    x0, y0 = data[0]
    x1, y1 = data[1]
    xe, ye = data[-2]

    x = x0 - (x0 - x1) * .01
    y = y0 - (y0 - y1) * .01
    yn = (x - xe) / (x0 - xe) * (y0 - ye) + ye
    data[0] = x, y
    data[-1] = x, yn
    data.extend(add_semicircle(x, (y + yn) / 2, abs((y - yn) / 2)))
    del data[-18:]

from pylab import *

with open('ah79100c.dat', 'rb') as f:
    f.next()
    data = [[float(x) for x in line.split()] for line in f if line.strip()]

t = [x[0] for x in data]
s = [x[1] for x in data]


round_data(data)

parallel = offset(data, 0.1)
t2 = [x[0] for x in parallel]
s2 = [x[1] for x in parallel]

plot(t, s, 'g', t2, s2, 'b', lw=1)

title('Wing with envelope')
grid(True)

axes().set_aspect('equal', 'datalim')

savefig("test.png")
show()

If you are willing (and able) to install a third-party tool, I'd highly recommend the Shapely module. 如果您愿意(并且有能力)安装第三方工具,我强烈推荐使用Shapely模块。 Here's a small sample that offsets both inward and outward: 这是一个向内和向外抵消的小样本:

from StringIO import StringIO
import matplotlib.pyplot as plt
import numpy as np
import requests
import shapely.geometry as shp

# Read the points    
AFURL = 'http://m-selig.ae.illinois.edu/ads/coord_seligFmt/ah79100c.dat'
afpts = np.loadtxt(StringIO(requests.get(AFURL).content), skiprows=1)

# Create a Polygon from the nx2 array in `afpts`
afpoly = shp.Polygon(afpts)

# Create offset airfoils, both inward and outward
poffafpoly = afpoly.buffer(0.03)  # Outward offset
noffafpoly = afpoly.buffer(-0.03)  # Inward offset

# Turn polygon points into numpy arrays for plotting
afpolypts = np.array(afpoly.exterior)
poffafpolypts = np.array(poffafpoly.exterior)
noffafpolypts = np.array(noffafpoly.exterior)

# Plot points
plt.plot(*afpolypts.T, color='black')
plt.plot(*poffafpolypts.T, color='red')
plt.plot(*noffafpolypts.T, color='green')
plt.axis('equal')
plt.show()

And here's the output; 这是输出; notice how the 'bowties' (self-intersections) on the inward offset are automatically removed: 注意向内偏移的'bowties'(自交叉)是如何被自动删除的: 在此输入图像描述

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

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