2011-02-15 65 views
2

嗨:) 我有一個生成點,位在球體的表面產生變形(使用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「與gnuplot的繪製點下面的Python代碼數據文件'

你能給出關於如何在該球體上產生變形的提示嗎? 就像「山」或「尖刺」呢? (類似OpenBSD的標誌):https://https.openbsd.org/images/tshirt-23.gif

我知道這是一個微不足道的問題:(但您的時間謝謝:)

DSP

回答

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) 
+0

嘿人感謝很多:)這是超酷:)你擊敗了地獄 的問題! 我正在控制點(oo)的方法,所以我可以在本地變形,我會很快發佈;) 再次感謝! – ramrunner 2011-02-15 18:45:57

2

該彈簧使我想起了方法,尤其是計算一組未明確連接的點的方法是找出點在球體表面上的位置,然後將其移動一定距離並由一組控制點確定方向。控制點可以有更小的影響,他們離得越遠。例如:

# 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 

如果您不希望所有控制點影響球體中的每個點,只需將其構建到位移函數中即可。

+0

非常感謝,我工作的這個方法,我將它張貼。 似乎很好控制! :) – ramrunner 2011-02-15 18:48:50

0

所以最後創建的使用一組控制點的是「拉」的球形表面 變形。它是沉重的OO和醜陋雖然;) 感謝所有的幫助! 使用它>å文件與gnuplot的:splot「å文件」 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