File:Catenary animation.gif
Catenary_animation.gif (150 × 80像素,文件大小:75 KB,MIME类型:image/gif、循环、90帧、5.1秒)
摘要
描述Catenary animation.gif |
English: Animation of a catenary curve for different seperations of the endpoints. |
日期 | |
来源 |
自己的作品 |
作者 | Geek3 |
Source Code
The image is created by the following source-code. Requirements:
- unix-like command line interface
- python
- scipy
- librsvg
- imagemagick
- lxml archive copy at the Wayback Machine
- gifsicle
python source code:
#!/usr/bin/python
# -*- coding: utf8 -*-
from lxml import etree
import os
import scipy as sc
import scipy.optimize as op
import scipy.integrate as ig
from math import *
class SvgDocument:
'''
creates a svg document structure using lxml.etree
'''
def __init__ (self, name, width=800, height=600, bgcolor='#ffffff',
center=None, unit=1.0):
self.name = name
self.width = int(width)
self.height = int(height)
self.unit = float(unit)
if center == None: self.center = [width / 2., height / 2.]
else: self.center = [float(i) for i in center]
# create document structure
self.svg = etree.Element('svg',
nsmap={None:'http://www.w3.org/2000/svg',
'xlink':'http://www.w3.org/1999/xlink'})
self.svg.set('version', '1.1')
self.svg.set('baseProfile', 'full')
self.svg.set('width', str(int(width)))
self.svg.set('height', str(int(height)))
# title
self.title = etree.SubElement(self.svg, 'title')
self.title.text = self.name
# background
if bgcolor != None:
self.background = etree.SubElement(self.svg, 'rect')
self.background.set('id', 'background')
self.background.set('x', '0')
self.background.set('y', '0')
self.background.set('width', str(width))
self.background.set('height', str(height))
self.background.set('fill', bgcolor)
# image elements
self.content = etree.SubElement(self.svg, 'g')
self.content.set('id', 'image')
self.content.set('transform',
'translate({0},{1}) scale({2},-{2})'.format(
self.center[0], self.center[1], self.unit))
def draw_object(self, name, params, group=None):
'''
Draw arbitraty svg object.
Params must be a dictionary of valid svg parameters.
'''
if group == None:
obj = etree.SubElement(self.content, name)
else:
obj = etree.SubElement(group, name)
for i, j in params.iteritems():
obj.set(str(i), str(j))
return obj
def write(self, filename=None):
# write content to file
if filename == None: filename = self.name
outfile = open(filename + '.svg', 'w')
outfile.write(etree.tostring(self.svg, xml_declaration=True,
pretty_print=True, encoding='utf-8'))
outfile.close()
print 'image written to', filename + '.svg'
# physics: calculate the catenary curve
def catenary(x, r):
# catenary curve f(x) with l=2 and horizontal distance 2r
if r == 1.0:
return 0.0
# search a-value for given length and distance
def fct(a):
if a == 0.0: return r - 1.0
return sinh(r * a) / a - 1.0
x0 = 1.0
while fct(x0) > 0.0: x0 /= 2.0
while fct(2.0 * x0) < 0.0: x0 *= 2.0
a = 1.0 / op.brentq(fct, x0, 2*x0)
return a * (cosh(x / a) - cosh(r / a))
render_mult = 8 # supersampling to improve quality
folder = 'frames'
commands = ['mkdir ' + folder]
for c in commands: print c; os.system(c)
# render frames
frames = 100
names = []
for i in range(frames):
name = 'catenary_{0:0>2}'.format(i)
names.append(name)
w, h = 150, 80
r0 = 65.0
doc = SvgDocument(name, width=w, height=h, center=[w/2, 10], unit=1)
a = 0.5 + 0.5 * cos(i * 2*pi / frames)
r = a**1.5 + 12*a**2 - 21*a**2.5 + 9*a**3
for ri in [-r, r]:
doc.draw_object('circle', {'cx':str(ri*r0), 'cy':'0', 'r':'7',
'style':'fill:#888; stroke:none'})
if r != 0.0:
x = sc.linspace(-r, r, 401)
path_data = zip(r0 * x, [r0 * catenary(xx, r) for xx in x])
else:
path_data = [[0.0, 0.0], [0.0, -r0], [0.0, 0.0]]
# append extra segment to have last point displayed
v = sc.array(path_data[-1]) - sc.array(path_data[-2])
v *= 0.1 / r0 / sqrt(v[0]**2 + v[1]**2)
path_data.append(sc.array(path_data[-1]) + v)
path = 'M ' + ' L '.join([str(xy[0]) + ',' + str(xy[1]) for xy in path_data])
doc.draw_object('path', {'d':path, 'stroke-linecap':'round',
'style':'fill:none; stroke:black; stroke-width:4',
'stroke-linejoin':'round', 'stroke-dasharray':'0,5'})
doc.write(filename=folder + '/' + name)
for name in names:
commands = ['rsvg -w{0} -h{1} {3}/{2}.svg {3}/{2}.png'.format(
w * render_mult, h * render_mult, name, folder),
'rm {1}/{0}.svg'.format(name, folder),
'convert -scale {0}x{1} {3}/{2}.png {3}/{2}.gif'.format(
w, h, name, folder),
'rm {1}/{0}.png'.format(name, folder)]
for c in commands: print c; os.system(c)
commands = ['gifsicle -d5 -l0 --colors 256 '
+ folder + '/*.gif > catenary_animation.gif',
'rm -rf ' + folder]
for c in commands: print c; os.system(c)
许可协议
我,本作品著作权人,特此采用以下许可协议发表本作品:
已授权您依据自由软件基金会发行的无固定段落及封面封底文字(Invariant Sections, Front-Cover Texts, and Back-Cover Texts)的GNU自由文件许可协议1.2版或任意后续版本的条款,复制、传播和/或修改本文件。该协议的副本请见“GNU Free Documentation License”。http://www.gnu.org/copyleft/fdl.htmlGFDLGNU Free Documentation Licensetruetrue |
本文件采用知识共享署名-相同方式共享 3.0 未本地化版本许可协议授权。
- 您可以自由地:
- 共享 – 复制、发行并传播本作品
- 修改 – 改编作品
- 惟须遵守下列条件:
- 署名 – 您必须对作品进行署名,提供授权条款的链接,并说明是否对原始内容进行了更改。您可以用任何合理的方式来署名,但不得以任何方式表明许可人认可您或您的使用。
- 相同方式共享 – 如果您再混合、转换或者基于本作品进行创作,您必须以与原先许可协议相同或相兼容的许可协议分发您贡献的作品。
您可以选择您需要的许可协议。
此文件中描述的项目
描绘内容
知识共享署名-相同方式共享3.0未本地化版本 简体中文(已转写)
GNU自由文档许可证1.2或更高版本 简体中文(已转写)
10月 2010
媒体类型 简体中文(已转写)
image/gif
数据大小 简体中文(已转写)
77,108 字节
5.099999999999992 秒
80 像素
150 像素
文件历史
点击某个日期/时间查看对应时刻的文件。
日期/时间 | 缩略图 | 大小 | 用户 | 备注 | |
---|---|---|---|---|---|
当前 | 2014年8月11日 (一) 10:26 | 150 × 80(75 KB) | Ev9n | Background converted to transparent. | |
2010年10月16日 (六) 19:27 | 150 × 80(81 KB) | Geek3 | own work |
文件用途
以下页面使用本文件:
全域文件用途
以下其他wiki使用此文件:
- de.wikipedia.org上的用途
- en.wikipedia.org上的用途
- es.wikipedia.org上的用途
- fa.wikipedia.org上的用途
- he.wikipedia.org上的用途
- hy.wikipedia.org上的用途
- it.wikipedia.org上的用途
- no.wikipedia.org上的用途
- sw.wikipedia.org上的用途
元数据
此文件中包含有扩展的信息。这些信息可能是由数码相机或扫描仪在创建或数字化过程中所添加。
如果此文件的源文件已经被修改,一些信息在修改后的文件中将不能完全反映出来。
原始文件唯一ID | xmp.did:1426D522A0236811822A9F6CF5CCF9DF |
---|---|
使用软件 | Adobe Photoshop CS6 (Macintosh) |