在球体表面上创建变形(使用python?)

时间:2011-02-15 00:01:04

标签: python geometry computational-geometry

嗨:) 我有以下python代码生成位于球体表面上的点

from math import sin, cos, pi

toRad = pi / 180

ox = 10
oy = -10
oz = 50

radius = 10.0
radBump = 3.0

angleMin = 0
angleMax = 360
angleOffset = angleMin * toRad
angleRange = (angleMax - angleMin) * toRad

steps = 48
angleStep = angleRange / steps
latMin = 0
latMax = 180
latOffset = latMin * toRad
if (latOffset < 0):
    latOffset = 0;

latRange = (latMax - latMin) * toRad
if (latRange > pi):
    latRange = pi - latOffset;

latSteps = 48
latAngleStep = latRange / latSteps

for lat in range(0, latSteps):
    ang = lat * latAngleStep + latOffset
    z = cos(ang) * radius + oz
    radMod = sin(ang) * radius

    for a in range(0, steps):
        x = sin(a * angleStep + angleOffset) * radMod + ox
        y = cos(a * angleStep + angleOffset) * radMod + oy
        print "%f %f %f"%(x,y,z)

之后我使用splot'datafile'

用gnuplot绘制点

你能给出关于如何在该球体上创建变形的任何提示吗? 喜欢“山”或“尖峰”吗? (类似于openbsd徽标;):https://https.openbsd.org/images/tshirt-23.gif

我知道这是一个微不足道的问题:(但感谢您的时间:)

DSP

3 个答案:

答案 0 :(得分:2)

我想到的方法,尤其是计算未明确连接的一组点的方法,是找到点在球体表面上的位置,然后将其移动一个由a确定的距离和方向。控制点集。控制点的距离越远,效果越小。例如:

# we have already computed a points position on the sphere, and
# called it x,y,z
for p in controlPoints:
    dx = p.x - x
    dy = p.y - y
    dz = p.z - z
    xDisplace += 1/(dx*dx)
    yDisplace += 1/(dy*dy)
    zDisplace += 1/(dz*dz) # using distance^2 displacement
x += xDisplace
y += yDisplace
z += zDisplace

通过更改控制点,您可以改变球体的形状 通过更改移动功能,您可以改变点形状球体的方式 你可能会变得非常棘手,并且针对不同的点有不同的功能:

# we have already computed a points position on the sphere, and
# called it x,y,z
for p in controlPoints:
    xDisplace += p.displacementFunction(x)
    yDisplace += p.displacementFunction(y)
    zDisplace += p.displacementFunction(z)
x += xDisplace
y += yDisplace
z += zDisplace

如果您不希望所有控制点影响球体中的每个点,只需将其构建到位移函数中。

答案 1 :(得分:1)

这是怎么回事?

from math import sin, cos, pi, radians, ceil
import itertools

try:
    rng = xrange    # Python 2.x
except NameError:
    rng = range     # Python 3.x

# for the following calculations,
# - all angles are in radians (unless otherwise specified)
# - latitude is in [-pi/2..pi/2]
# - longitude is in [-pi..pi)
MIN_LAT = -pi/2   # South Pole
MAX_LAT = pi/2    # North Pole
MIN_LON = -pi     # Far West
MAX_LON = pi      # Far East

def floatRange(start, end=None, step=1.0):
    "Floating-point range generator"
    start += 0.0    # cast to float
    if end is None:
        end = start
        start = 0.0
    steps = int(ceil((end-start)/step))
    return (start + k*step for k in rng(0, steps+1))

def patch2d(xmin, xmax, ymin, ymax, step=1.0):
    "2d rectangular grid generator"
    if xmin>xmax:
        xmin,xmax = xmax,xmin
    xrange = floatRange(xmin, xmax, step)

    if ymin>ymax:
        ymin,ymax = ymax,ymin
    yrange = floatRange(ymin, ymax, step)

    return itertools.product(xrange, yrange)

def patch2d_to_3d(xyIter, zFn):
    "Convert 2d field to 2.5d height-field"
    mapFn = lambda a: (a[0], a[1], zFn(a[0],a[1]))
    return itertools.imap(mapFn, xyIter)

#
# Representation conversion functions    
#

def to_spherical(lon, lat, rad):
    "Map from spherical to spherical coordinates (identity function)"
    return lon, lat, rad

def to_cylindrical(lon, lat, rad):
    "Map from spherical to cylindrical coordinates"
    # angle, z, radius
    return lon, rad*sin(lat), rad*cos(lat)

def to_cartesian(lon, lat, rad):
    "Map from spherical to Cartesian coordinates"
    # x, y, z
    cos_lat = cos(lat)
    return rad*cos_lat*cos(lon), rad*cos_lat*sin(lon), rad*sin(lat)


def bumpySphere(gridSize, radiusFn, outConv):
    lonlat = patch2d(MIN_LON, MAX_LON, MIN_LAT, MAX_LAT, gridSize)
    return list(outConv(*lonlatrad) for lonlatrad in patch2d_to_3d(lonlat, radiusFn))


# make a plain sphere of radius 10    
sphere = bumpySphere(radians(5.0), lambda x,y: 10.0, to_cartesian)    


# spiky-star-function maker
def starFnMaker(xWidth, xOffset, yWidth, yOffset, minRad, maxRad):
    # make a spiky-star function:
    #   longitudinal and latitudinal triangular waveforms,
    #   joined as boolean intersection,
    #   resulting in a grid of positive square pyramids
    def starFn(x, y, xWidth=xWidth, xOffset=xOffset, yWidth=yWidth, yOffset=yOffset, minRad=minRad, maxRad=maxRad):
        xo = ((x-xOffset)/float(xWidth)) % 1.0   # xo in [0.0..1.0), progress across a single pattern-repetition
        xh = 2 * min(xo, 1.0-xo)                 # height at xo in [0.0..1.0]
        xHeight = minRad + xh*(maxRad-minRad)

        yo = ((y-yOffset)/float(yWidth)) % 1.0
        yh = 2 * min(yo, 1.0-yo)
        yHeight = minRad + yh*(maxRad-minRad)

        return min(xHeight, yHeight)
    return starFn

# parameters to spike-star-function maker    
width = 2*pi
horDivs = 20    # number of waveforms longitudinally
horShift = 0.0  # longitudinal offset in [0.0..1.0) of a wave

height = pi
verDivs = 10
verShift = 0.5      # leave spikes at the poles

minRad = 10.0
maxRad = 15.0

deathstarFn = starFnMaker(width/horDivs, width*horShift/horDivs, height/verDivs, height*verShift/verDivs, minRad, maxRad)

deathstar = bumpySphere(radians(2.0), deathstarFn, to_cartesian)

答案 2 :(得分:0)

所以我最终使用一组“拉”球形的控制点来创建变形 表面。它虽然很重,但很难看;) 谢谢你的帮助!!! 使用它&gt; afile和gnuplot:splot'afile'w l

DSP

from math import sin, cos, pi ,sqrt,exp
class Point:
    """a 3d point class"""
    def __init__(self,x,y,z):
            self.x = x
            self.y = y
            self.z = z
    def __repr__(self):
            return "%f %f %f\n"%(self.x,self.y,self.z)
    def __str__(self):
            return "point centered: %f %f %f\n"%(self.x,self.y,self.z)
    def distance(self,b):
            return sqrt((self.x - b.x)**2 +(self.y - b.y)**2 +(self.z -b.z)**2)
    def displaceTowards(self,b):
            self.x

class ControlPoint(Point):
    """a control point that deforms positions of other points"""
    def __init__(self,p):
            Point.__init__(self,p.x,p.y,p.z)
            self.deformspoints=[]

    def deforms(self,p):
            self.deformspoints.append(p)
    def deformothers(self):
            self.deformspoints.sort()
            #print self.deformspoints
            for i in range(0,len(self.deformspoints)):
                    self.deformspoints[i].x +=  (self.x - self.deformspoints[i].x)/2
                    self.deformspoints[i].y +=  (self.y - self.deformspoints[i].y)/2
                    self.deformspoints[i].z +=  (self.z - self.deformspoints[i].z)/2
class Sphere:
    """returns points on a sphere"""
    def __init__(self,radius,angleMin,angleMax,latMin,latMax,discrStep,ox,oy,oz):
            toRad = pi/180
            self.ox=ox
            self.oy=oy
            self.oz=oz
            self.radius=radius
            self.angleMin=angleMin
            self.angleMax=angleMax
            self.latMin=latMin
            self.latMax=latMax
            self.discrStep=discrStep
            self.angleRange = (self.angleMax - self.angleMin)*toRad
            self.angleOffset = self.angleMin*toRad
            self.angleStep = self.angleRange / self.discrStep
            self.latOffset = self.latMin*toRad
            self.latRange = (self.latMax - self.latMin) * toRad
            self.latAngleStep = self.latRange / self.discrStep
            if(self.latOffset <0):
                    self.latOffset = 0
            if(self.latRange > pi):
                    self.latRange = pi - latOffset

    def CartesianPoints(self):
            PointList = []
            for lat in range(0,self.discrStep):
                    ang = lat * self.latAngleStep + self.latOffset
                    z = cos(ang) * self.radius + self.oz

                    radMod = sin(ang)*self.radius

                    for a in range(0,self.discrStep):
                            x = sin(a*self.angleStep+self.angleOffset)*radMod+self.ox
                            y = cos(a*self.angleStep+self.angleOffset)*radMod+self.oy
                            PointList.append(Point(x,y,z))
            return PointList
mysphere = Sphere(10.0,0,360,0,180,50,10,10,10)
mylist = mysphere.CartesianPoints()
cpoints = [ControlPoint(Point(0.0,0.0,0.0)),ControlPoint(Point(20.0,0.0,0.0))]
deforpoints=[]
for cp in cpoints:
    for p in mylist:
            if(p.distance(cp) < 15.0):
                    cp.deforms(p)
    """print "cp ",cp,"deforms:"
    for dp in cp.deformspoints:
            print dp ,"at distance", dp.distance(cp)"""
    cp.deformothers()
out= mylist.__repr__()
s = out.replace(","," ")
print s