Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:48:51

0001 #!/usr/bin/env python
0002 #
0003 # Copyright (c) 2019 Opticks Team. All Rights Reserved.
0004 #
0005 # This file is part of Opticks
0006 # (see https://bitbucket.org/simoncblyth/opticks).
0007 #
0008 # Licensed under the Apache License, Version 2.0 (the "License"); 
0009 # you may not use this file except in compliance with the License.  
0010 # You may obtain a copy of the License at
0011 #
0012 #   http://www.apache.org/licenses/LICENSE-2.0
0013 #
0014 # Unless required by applicable law or agreed to in writing, software 
0015 # distributed under the License is distributed on an "AS IS" BASIS, 
0016 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
0017 # See the License for the specific language governing permissions and 
0018 # limitations under the License.
0019 #
0020 
0021 """
0022 
0023 Cubic Bezier polynomial interpolating from P0 to P3 as u 
0024 goes from 0 to 1 controlled by P1, P2::
0025 
0026     B(u) = P0*(1-u)**3 + P1*3*u*(1-u)**2 + P2*3*u**2*(1-u) + P3*u**3   
0027 
0028 To apply to surface of revolution (rr,z) in range z1 to z2, equate 
0029 
0030          (z - z1)
0031     u =  --------         u = 0 at z=z1  u = 1 at z=z2
0032           (z2 - z1)
0033 
0034 Or more in spirit of Bezier decide on begin/end points and 
0035 control points
0036 
0037 ::
0038 
0039     (z1, rr1) 
0040     (cz1, crr1)
0041     (cz2, crr2)
0042     (z2, rr2) 
0043 
0044 
0045 * https://stackoverflow.com/questions/246525/how-can-i-draw-a-bezier-curve-using-pythons-pil
0046 
0047 
0048 ::
0049 
0050     In [6]: bezier([0,1])
0051     Out[6]: [(50, 100), (100, 50)]
0052 
0053     In [7]: bezier([0,0.5,1])
0054     Out[7]: [(50, 100), (77.5, 77.5), (100, 50)]
0055 
0056     In [8]: bezier([0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1])
0057     Out[8]: 
0058     [(50, 100),
0059      (55.900000000000006, 95.9),
0060      (61.60000000000001, 91.60000000000002),
0061      (67.1, 87.1),
0062      (72.4, 82.4),
0063      (77.5, 77.5),
0064      (82.4, 72.4),
0065      (87.1, 67.1),
0066      (91.60000000000001, 61.6),
0067      (95.89999999999999, 55.9),
0068      (100, 50)]
0069 
0070 
0071 """
0072 
0073 
0074 
0075 def pascal_row(n):
0076     # This returns the nth row of Pascal's Triangle
0077     result = [1]
0078     x, numerator = 1, n
0079     for denominator in range(1, n//2+1):
0080         # print(numerator,denominator,x)
0081         x *= numerator
0082         x /= denominator
0083         result.append(x)
0084         numerator -= 1
0085     if n&1 == 0:
0086         # n is even
0087         result.extend(reversed(result[:-1]))
0088     else:
0089         result.extend(reversed(result)) 
0090     return result
0091 
0092 
0093 def make_bezier(xys):
0094     """
0095     :param xys: sequence of 2-tuples (Bezier control points)
0096     :return func: call it over t parameter iterable
0097     
0098     Uses the generalized formula for bezier curves
0099     http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Generalization
0100 
0101     For cubic bezier with 4 points combinations is just (1,3,3,1)
0102     """
0103     n = len(xys)
0104     combinations = pascal_row(n-1)   
0105 
0106     def bezier(ts):
0107         result = []
0108         for t in ts:
0109             tpowers = (t**i for i in range(n))
0110             upowers = reversed([(1-t)**i for i in range(n)])
0111             coefs = [c*a*b for c, a, b in zip(combinations, tpowers, upowers)]
0112             result.append(
0113                 tuple(sum([coef*p for coef, p in zip(coefs, ps)]) for ps in zip(*xys)))
0114         return result
0115     pass
0116     return bezier
0117 
0118 
0119 
0120 
0121 from PIL import Image
0122 from PIL import ImageDraw
0123 
0124 
0125 def bezier_heart():
0126     im = Image.new('RGBA', (100, 100), (0, 0, 0, 0)) 
0127     draw = ImageDraw.Draw(im)
0128     ts = [t/100.0 for t in range(101)]
0129 
0130     xys = [(50, 100), (80, 80), (100, 50)]
0131     bezier = make_bezier(xys)
0132     points = bezier(ts)
0133 
0134     xys = [(100, 50), (100, 0), (50, 0), (50, 35)]
0135     bezier = make_bezier(xys)
0136     points.extend(bezier(ts))
0137 
0138     xys = [(50, 35), (50, 0), (0, 0), (0, 50)]
0139     bezier = make_bezier(xys)
0140     points.extend(bezier(ts))
0141 
0142     xys = [(0, 50), (20, 80), (50, 100)]
0143     bezier = make_bezier(xys)
0144     points.extend(bezier(ts))
0145 
0146     draw.polygon(points, fill = 'red')
0147     im.save('out.png')
0148 
0149 
0150 
0151 if __name__ == '__main__':
0152 
0153     xys = [(50,100), (80,80), (100,50) ]
0154     bezier =  make_bezier(xys)
0155 
0156