【问题标题】:creating deformations on a sphere surface (using python?)在球体表面上创建变形(使用 python?)
【发布时间】:2015-03-14 10:24:38
【问题描述】:

嗨 :) 我有以下 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

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

DP

【问题讨论】:

    标签: python geometry computational-geometry


    【解决方案1】:

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

    # 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
    

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

    【讨论】:

    • 非常感谢,我正在研究这种方法,我会发布它。似乎很好控制! :)
    【解决方案2】:

    怎么样?

    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)
    

    【讨论】:

    • 嘿,非常感谢 :) 这太酷了 :) 你解决了这个问题!我正在研究控制点(oo)方法,所以我可以在局部变形,我会尽快发布;)再次感谢!
    【解决方案3】:

    所以我最终使用一组“拉”球形的控制点创建了变形 表面。虽然它是严重的 OO 和丑陋的 ;) 感谢所有的帮助! 使用它 > afile 和 gnuplot : splot 'afile' w l

    DP

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 2010-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-24
      • 1970-01-01
      相关资源
      最近更新 更多