【问题标题】:Python to Plot Graphics and Output Vector XY PairsPython 绘制图形和输出向量 XY 对
【发布时间】:2014-02-06 04:51:08
【问题描述】:

我需要画一些矢量图,这对我来说是新的。

寻找可以绘制矢量形状并将其输出为一系列 XY 移动的 Python 模块的一些建议。这些形状通常是圆形和线条以及其他简单的形状,但会使用算法修饰符来加粗、摆动或“加深”线条。

我看到了一些绘图库(MathGL、matplotlib、pyplot),它们似乎都可以创建图形。最终,我希望它将输出分解为一系列由许多小直线组成的 XY 指令。

(我正在使用 Python 向数模转换器输出指令,以控制激光的 XY 运动。)

请原谅我的问题。我会更新问题,因为我能够更好地表述它。

编辑:另一方面,对于那些在数学方面得心应手的人来说,也许这太简单了,也许 PyModule 是矫枉过正的。接受将曲线切割成直线的建议。

EDIT2:最后,我自己进行了计算,但使用 pyglet 进行矢量图形输出。

【问题讨论】:

  • 这绝对有助于减少结果。但是用于创建原始 SVG 的 Python 模块怎么样?
  • pysvg?或者 svg 是 xml .. 你可以自己写。用sax得到一条线,画一条线,得到一条曲线画一堆线?或者看看pycairo?甚至是附言(虽然这有点过时了)。是否已经存在适用于该特定应用程序的软件? wiki.linuxcnc.org/cgi-bin/…

标签: python graphics vector python-module


【解决方案1】:

我最终使用 pyglet 进行矢量图形输出,并在 NYU 的cubicSpline 代码的帮助下自己计算绘制圆和线。

#!/usr/bin/env python

# core modules
from itertools import chain

# installed modules
import pyglet
import numpy

# local modules
import config

# constants
CURVE_SEGS = config.curve_segments  # number of line segs in a curve

# bezier curves courtesy of NYU

def fac( k ):
    '''
    Returns k!.
    '''

    if k == 0: return 1
    else: return reduce(lambda i,j : i*j, range(1,k+1))

def binom( n, k ):
    '''
    Returns n choose k.
    '''

    if k < 0 or k > n: return 0

    return fac( n ) / ( fac( k ) * fac( n - k ) )

def B( P, t ):
    '''
    Evaluates the bezier curve of degree len(P) - 1, using control points 'P',
    at parameter value 't' in [0,1].
    '''
    n = len( P ) - 1
    assert n > 0

    from numpy import zeros
    result = zeros( len( P[0] ) )
    for i in xrange( n + 1 ):
        result += binom( n, i ) * P[i] * (1 - t)**(n-i) * t**i

    return result

def B_n( P, n, t ):
    '''
    Evaluates the bezier curve of degree 'n', using control points 'P',
    at parameter value 't' in [0,1].
    '''

    ## clamp t to the range [0,1]
    t = min( 1., max( 0., t ) )

    num_segments = 1 + (len( P ) - (n+1) + n-1) // n
    assert num_segments > 0
    from math import floor
    segment_offset = min( int( floor( t * num_segments ) ), num_segments-1 )

    P_offset = segment_offset * n

    return B( P[ P_offset : P_offset + n+1 ], ( t - segment_offset/float(num_segments) ) * num_segments )

def Bezier_Curve( P ):
    '''
    Returns a function object that can be called with parameters between 0 and 1
    to evaluate the Bezier Curve with control points 'P' and degree len(P)-1.
    '''
    return lambda t: B( P, t )

def Bezier_Curve_n( P, n ):
    '''
    Returns a function object that can be called with parameters between 0 and 1
    to evaluate the Bezier Curve strip with control points 'P' and degree n.
    '''
    return lambda t: B_n( P, n, t )

def cubicSpline(p0, p1, p2, p3, nSteps):
    """Returns a list of line segments and an index to make the full curve.

    Cubics are defined as a start point (p0) and end point (p3) and
    control points (p1 & p2) and a parameter t that goes from 0.0 to 1.0.
    """
    points = numpy.array([p0, p1, p2, p3])
    bez = bezier.Bezier_Curve( points )
    lineSegments = []
    for val in numpy.linspace( 0, 1, nSteps ):
        #print '%s: %s' % (val, bez( val ))
        # the definition of the spline means the parameter t goes
        # from 0.0 to 1.0
        (x,y) = bez(val)
        lineSegments.append((int(x),int(y)))
    #lineSegments.append(p2)
    cubicIndex = [0] + [int(x * 0.5) for x in range(2, (nSteps-1)*2)] + [nSteps-1]
    #print "lineSegments = ",lineSegments
    #print "cubicIndex = ",cubicIndex
    return (lineSegments,cubicIndex)


# graphic primatives

class GraphicObject(object):

    """Basic graphic object primative"""

    def __init__(self, field, points, index, color):
        """Graphic object constructor.

            Args:
                arcpoints - list of points that define the graphic object
                arcindex - list of indicies to arcpoints
                color - list of colors of each arc
        """
        self.m_field = field
        self.m_arcpoints = points
        self.m_arcindex = index
        self.m_color = color
        # each arc is broken down into a list of points and indecies
        # these are gathered into lists of lists
        # TODO: possibly these could be melded into single dim lists
        self.m_points = []
        self.m_index = []

class Circle(GraphicObject):

    """Define circle object."""

    def __init__(self, field, p, r, color,solid=False):
        """Circle constructor.

        Args:
            p - center point
            r - radius of circle
            c - color
        """
        self.m_center = p
        self.m_radius = r
        self.m_solid = solid
        k = 0.5522847498307935  # 4/3 (sqrt(2)-1)
        kr = int(r*k)
        (x,y)=p
        arcpoints=[(x+r,y),(x+r,y+kr), (x+kr,y+r), (x,y+r),
                           (x-kr,y+r), (x-r,y+kr), (x-r,y),
                           (x-r,y-kr), (x-kr,y-r), (x,y-r),
                            (x+kr,y-r), (x+r,y-kr)]
        arcindex=[(0, 1, 2, 3), (3, 4, 5, 6), (6, 7, 8, 9), (9, 10, 11, 0)]
        GraphicObject.__init__(self,field,arcpoints,arcindex,color)

    def render(self):
        # e.g., self.m_arcpoints = [(10,5),(15,5),(15,10),(15,15),(10,15),(5,15),(5,10)]
        # e.g., self.m_arcindex = [(0,1,2,3),(3,4,5,6)]
        for i in range(len(self.m_arcindex)):
            # e.g., self.m_arcindex[i] = (0,1,2)
            p0 = self.m_arcpoints[self.m_arcindex[i][0]]
            p1 = self.m_arcpoints[self.m_arcindex[i][1]]
            p2 = self.m_arcpoints[self.m_arcindex[i][2]]
            p3 = self.m_arcpoints[self.m_arcindex[i][3]]
            (points,index) = cubicSpline(p0,p1,p2,p3,CURVE_SEGS)
            if self.m_solid:
                points.append(self.m_center)
                nxlast_pt = len(points)-2
                last_pt = len(points)-1
                xtra_index = [nxlast_pt,last_pt,last_pt,0]
                index = index + xtra_index
            self.m_points.append(points)
            self.m_index.append(index)

    def draw(self):
        for i in range(len(self.m_index)):
            points = self.m_points[i]
            index = self.m_index[i]
            pyglet.gl.glColor3f(self.m_color[0],self.m_color[1],self.m_color[2])
            if not self.m_solid:
                pyglet.graphics.draw_indexed(len(points), pyglet.gl.GL_LINES,
                    index,
                    ('v2i',self.m_field.scale2out(tuple(chain(*points)))),
                )
            else:
                pyglet.graphics.draw_indexed(len(points), pyglet.gl.GL_POLYGON,
                    index,
                    ('v2i',self.m_field.scale2out(tuple(chain(*points)))),
                )

这不是可运行的代码,因为您缺少一些常量和类,但如果您遇到困难,它可能对理论有所帮助。

每个图形对象,包括圆和线,都由圆弧组成,每个圆弧都有四个控制点。由点列表和这些点的索引组成。

类似但不同的是,pyglet 想要由两个点组成的直线段,并带有指向这些点的索引。所以涉及到一些翻译。

编辑:早些时候,我实现了贝塞尔二次样条(本质上是抛物线),它制作了非常有趣的非圆。上面的代码使用了贝塞尔三次样条来渲染真实的圆。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 2017-03-30
    • 1970-01-01
    • 2021-04-29
    • 1970-01-01
    • 2018-11-19
    • 1970-01-01
    相关资源
    最近更新 更多