我想使用Python创建以下图像模式。 为清楚起见:这些是两个独立的图像序列(一个在顶行,一个在底行)。 它们是相互关联的,因为它们是堆积四面体的投影区域。 在3D环境中,它看起来如下:
请注意,这些3D对象不会缩放,以使总对象尺寸保持不变。上面显示的投影区域就是这种情况
四级结构(未示出)顶部将有另外10个单元
C
级别的单元格总数n
为:
C = (n^3 + 3*n^2 + 2*n)/6
现在我正在手工创建模式(制作3D对象,渲染投影区域,重复)但这对于更多细分来说非常繁琐且不可行。
我设法使用以下代码创建一个多边形,但是我无法弄清楚如何循环它以使总边长保持不变,但多边形以上面可视化的方式细分。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
el = 1
dfv = 1/np.sqrt(3)*el
dfe = 1/(2*np.sqrt(3))*el
vertices1 = [(0,0),(0.5*el,-dfe),(0,dfv),(-0.5*el,-dfe)]
vertices2 = [(0.5*el,-dfe),(0,dfv),(-0.5*el,-dfe)]
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax1.add_patch(Polygon(vertices1, closed=True, fill=True))
ax1.set_xlim([-1, 1])
ax1.set_ylim([-1, 1])
ax1.set_aspect('equal')
ax2 = fig.add_subplot(122)
ax2.add_patch(Polygon(vertices2, closed=True, fill=True))
ax2.set_xlim([-1, 1])
ax2.set_ylim([-1, 1])
ax2.set_aspect('equal')
plt.show()
我使用matplotlib和包含的Polygon补丁,但我不确定这是否是最佳方法。
多边形或颜色的方向也不重要。
答案 0 :(得分:1)
助手类:
class Custom_Polygon(object):
"""docstring for Polygon"""
def __init__(self, verts):
self.verticies = np.array(verts)
self.dims = self.verticies.shape[1]
def scale(self, scaleFactor):
scaleMatrix = np.zeros((self.dims, self.dims))
np.fill_diagonal(scaleMatrix, scaleFactor)
self.verticies = np.dot(self.verticies, scaleMatrix)
def scale_with_orgin(self, scaleFactor, origin):
origin = origin.copy()
self.translate([-i for i in origin])
self.scale(scaleFactor)
self.translate([i for i in origin])
def translate(self, shiftBy):
self.verticies += shiftBy
def get_width(self):
x_min = self.verticies[:,0].min()
x_max = self.verticies[:,0].max()
return abs(x_max - x_min)
def get_height(self):
y_min = self.verticies[:,1].min()
y_max = self.verticies[:,1].max()
return abs(y_max - y_min)
制作一个辅助类,用于缩放和平移多边形以制作图案。并编写了绘制第一个模式的算法。绘制第二个模式应该不难做出类似的算法。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
def makeFirstPattern(ax, d, verticies, scale=True):
Pn = Custom_Polygon(verticies)
direction = 1
divisions = d
if scale: Pn.scale_with_orgin(2.0/(divisions+1), Pn.verticies[-1])
for i in range(divisions, 0, -2):
for _ in range(i):
ax.add_patch(Polygon(Pn.verticies, closed=True, fill=True, ec='none'))
Pn.translate([direction * Pn.get_width()/2, 0])
direction *= -1
Pn.translate([direction * Pn.get_width(), Pn.get_height()])
el = 1
dfv = 1/np.sqrt(3)*el
dfe = 1/(2*np.sqrt(3))*el
vertices1 = [(0,0),(0.5*el,-dfe),(0,dfv),(-0.5*el,-dfe)]
vertices2 = [(0.5*el,-dfe),(0,dfv),(-0.5*el,-dfe)]
fig = plt.figure()
ax1 = fig.add_subplot(111)
makeFirstPattern(ax1, 7, vertices2)
ax1.set_xlim([-1, 1])
ax1.set_ylim([-1, 1])
ax1.set_aspect('equal')
plt.show()
答案 1 :(得分:0)
对于第一个模式,您可以使用此代码:
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
nrows = 5
pat = np.array([[0,0],[0.5,np.sqrt(0.75)],[-0.5,np.sqrt(0.75)]])
fig = plt.figure()
ax = fig.add_subplot(111)
for base in range(nrows):
npat = 2*base + 1
for col in np.linspace(-base/2, base/2, npat):
pp = Polygon(pat + np.array([col, base*v]), fc='k', ec='none')
ax.add_patch(pp)
ax.autoscale_view(True,True,True)
ax.set_aspect('equal')
plt.show()
答案 2 :(得分:0)
我没有使用matplotlib,而是使用 SVG 提供解决方案,您的脚本只打印出相应的SVG命令。
注意:创建的SVG标头缺少相同的定义,这就是某些程序无法处理生成的图像的原因。 Inkscape虽然可以毫无问题地打开它并再次保存。
描述的解决方案基于您显示的“箭头”示例,即较低的一个 我将箭头编码为 SVG路径,有四个点p0,p1,p2和p3,其中p0是上尖端,p1是右下角,p3是左下角,p2是尖端下面。每个点都有一个x和y坐标(p0x,p0y ......)。
注意:SVG坐标与数学坐标不同,从左到右(x)和自上而下(y)增加,因此原点是左上角。
路径存储为字符串,其中的点为varibale。最后一个字符串是使用python的str.format()
方法创建的。
# width of the complete picture
width=600
# height of the complete picture
height=600
# desired recursion depth (>=1)
n=5
# "shape factor" of the arrow (=(p1y-p2y)/(p2y-p0y))
# a=0 would result in a triangle
a=0.3
def create_arrows(n, depth=1, width=600, height=600, refx=None, refy=None):
global a
if refx==None or refy==None:
# the first polygon instances defines it's reference point
# following instances are given a reference point by the caller
refx = (width - width/n)/2
refy = 0
if depth==1:
# the first polygon instance defines the size of all instancens
width=width/n
height=height/n
# the SVG definition of the polygon
polyg = r'<path d="M{p0x} {p0y} L{p1x} {p1y} L{p2x} {p2y} L{p3x} {p3y} Z" />'
points = {"p0x":refx+width/2, "p0y":refy, "p1x":refx+width, "p1y":refy+height, "p2x":refx+width/2, "p2y":refy+(1-a)*height, "p3x":refx, "p3y":refy+height}
# create the requested polygon
polygons = [polyg.format(**points)]
# if maximum recursion depth not reached call method recursively
if depth<n:
polygons.extend(myfunction(n, depth+1, width=width, height=height, refy=refy+(1-a)*height, refx=refx)) # down shifted
polygons.extend(myfunction(n, depth+1, width=width, height=height, refy=refy+height, refx=refx-width/2)) # bottom left
polygons.extend(myfunction(n, depth+1, width=width, height=height, refy=refy+height, refx=refx+width/2)) #bottom right
return(polygons)
print('<svg height="{height}" width="{width}">'.format(width=width, height=height))
# converting the list to a set is necessary since some polygons can be created by multiple recursion paths
print('\n'.join(set(create_arrows(4,width=width,height=height))))
print('</svg>')
箭头以递归方式创建,即您从顶部箭头开始。箭头的尺寸为width/n
和height/n
,其中n
是所需的递归级别(n> = 1)。您展示的示例包括n=1
,n=2
和n=3
。以下解释的递归模式是根据经验推导出来的,并不直接基于您的3D示例。
n = 1 :在级别n=1
中,您在创建顶部箭头后完成了。
n = 2 :在级别n=2
中,此TOP箭头分别创建另外三个,一个位于右下方,每个位于左下方。这三个箭头的尖端(p0)分别位于原始箭头的p2,p3和p1处。你已经完成了。
n = 3 :对级别n=2
中创建的每个箭头重复上述步骤,依此类推。
下面请查看级别n=6
的示例。
对于三角形,你的上层例子,这个想法很容易适应。您只需更改多边形路径和递归模式。
顺便说一句。使用给定脚本a=0
创建trianlges的旋转版本。所以如果你很懒,只需使用它并在inkscape中转换生成的SVG。