如何绘制恒定长度的贝塞尔曲线?

时间:2019-07-19 22:04:46

标签: python graph bezier codeskulptor

我正在创建一个绘制二次Bezier曲线的程序,该曲线的点随程序运行而移动。我通过沿其绘制40个点来绘制曲线,以使其看起来有些实心。但是,我希望绘制的曲线截面始终具有相同的长度,即200个单位。我要做的是从X单位长的曲线中最多绘制200个单位。这样做的问题是,随着曲线变大,绘制的截面在视觉上会缩小。无论曲线多长,我都希望它总是一样,但是我不知道如何去做。

这是它的样子。我还将发布必须在CodeSkulptor 3中运行才能获得这些结果的代码(这是一个Web IDE,我无法在此处发布链接,如果您搜索它,它将显示出来)。

curve1

蓝色部分是绘制的曲线,当总曲线长度较短时,此处显示较长

curve2

总曲线越长,曲线越短。当您延伸总曲线时,它会变得更短。

这是代码

import simplegui
import math

def DrawPointsOnTail(canvas):
    global tailSegments, centerPoint, endPoint, midPoint, tailLength
    currentBezierLength = BezierLength(centerPoint.position,
                                       midPoint.position, 
                                       endPoint.position,
                                       100)
    print (currentBezierLength)
    if (currentBezierLength < tailLength):
        distanceBetweenPoints = currentBezierLength / tailSegments
    else:
        distanceBetweenPoints = tailLength / tailSegments

    for i in range(0, tailSegments):
        currentSegment = Point(BezierCurve(centerPoint.position,
                                           midPoint.position,
                                           endPoint.position,
                                           (i * distanceBetweenPoints) / currentBezierLength),
                               3, "Blue")
        currentSegment.draw(canvas)


def Distance(p1, p2):
    dist = math.sqrt(math.pow(p2[0] - p1[0], 2) + math.pow(p2[1] - p1[1], 2))
    return dist

def Lerp(p1, p2, t):
    newPos = [p1[0] + (p2[0] - p1[0]) * t, p1[1] + (p2[1] - p1[1]) * t]
    return newPos

def BezierCurve(p1, p2, p3, t):
    seg1Point = Lerp(p1, p2, t)
    seg2Point = Lerp(p2, p3, t)
    bezPoint = Lerp(seg1Point, seg2Point, t)
    return bezPoint

def BezierLength(p1, p2, p3, segments):
    totalLength = 0
    prevPoint = p1
    for i in range(1, segments + 1):
        currentPoint = BezierCurve(p1, p2, p3, i / segments)
        totalLength += Distance(prevPoint, currentPoint)
        prevPoint = currentPoint
    return totalLength


class Point:
    def __init__(self, position, radius = 1, color = "Black"):
        self.position = position
        self.radius = radius
        self.color = color

    def draw(self, canvas):
        canvas.draw_circle(self.position, self.radius, 1, self.color, self.color) 


tailSegments = 40         
centerPoint = Point([250, 250], 5)
midPoint = Point([350, 250], 5)
endPoint = Point([450, 250], 5)
tailLength = 200

# Handler to draw on canvas, called 60 times a second
def draw_handler(canvas):
    global lerpPointStep, lerpPointSpeed, lerpPointDirection
    centerPoint.draw(canvas)
    midPoint.draw(canvas)
    endPoint.position[1] -= 1
    endPoint.draw(canvas)

    DrawPointsOnTail(canvas)


# Create a frame and assign callbacks to event handlers
frame = simplegui.create_frame("Rope Thing", 500, 500)

frame.set_canvas_background("White")
frame.set_draw_handler(draw_handler)

# Start the frame animation
frame.start()

1 个答案:

答案 0 :(得分:0)

如果仅使用

$("[contenteditable=true]").removeAttr('contenteditable')

没有distanceBetweenPoints = currentBezierLength / tailSegments ,则可以正确绘制。

if/else

Code on codeskulptor