【问题标题】:Plotting hypotrochoids using Python使用 Python 绘制下摆线
【发布时间】:2014-04-06 22:26:40
【问题描述】:

我一直在尝试使用计算机绘制一些hypotrochoids,但我遇到了一些问题。对于那些不熟悉的人,次摆线的参数方程是:

x(theta) = (R - r)cos(theta) + d*cos((R-r)/r*theta)

y(theta) = (R - r)sin(theta) - d*sin((R-r)/r*theta)

维基百科上对下摆线的定义可以进一步解释:

下摆线是一个轮盘赌,由一个连接到一个圆的点追踪 半径 r 在半径为 R 的固定圆内滚动, 其中该点距内部中心的距离为 d 圈子。

因此,值为r = d = 1R = 3 的下摆线应该如下所示:

但这肯定不是我最终使用我的计算方法的结果。我的下摆线(具有相同的值)看起来像这样:

由于 x 和 y 值是由 x 和 y 在角度 theta 的函数确定的,我假设我可以简单地循环 theta 从 0 到 2pi 的值,并在某个特定位置分别计算 x 和 y 值间隔,然后以极坐标形式绘制坐标(r**2 = x**2 + y**2),但我想我想错了。也许我的公式是错误的,但我刚刚在math stackexchange 与几个人一起检查过,但我们无法弄清楚出了什么问题。如果我的方法有误,应该使用什么方法来计算下摆线?

代码如下:

class _BaseCurve(event.EventAware):

    # This is a basic curve class from which all other curves inherit from (as
    # you will see below with the Hypotrochoid class). Basically what happens is
    # each new curve class must implement a function (relation) to calculate the
    # radius of the equation at each angle interval, then plots the equation in
    # other code elsewhere.

    def __init__(self, radius, init_angle, end_angle, speed, acceleration, *args, **kwargs):

        # Initialize geometric data...
        self.radius = radius

        # Initialize curve start and end angles...
        self.init_angle = init_angle
        self.end_angle = end_angle

        # Initialize time-based curve attributes...
        self.speed = speed
        self.accel = acceleration
        self.current_pos = 0

        # Initialize defaults...
        self.max_speed = inf
        self.min_speed = neginf

        self.args = args
        self.kwargs = kwargs

    def set_max_speed(self, speed):
        """Set the maximum speed the path can achieve."""
        if speed < self.min_speed:
            errmsg = "Max speed cannot be less than min speed."
            raise ValueError(errmsg)
        self.max_speed = speed

    def set_min_speed(self, speed):
        """Set the minimum speed the path can achieve."""
        if speed > self.max_speed:
            errmsg = "Min speed cannot be greater than max speed."
            raise ValueError(errmsg)
        self.max_speed = speed

    def set_acceleration(self, acceleration):
        """Set a new acceleration for the path."""
        self.accel = acceleration

    def move(self):
        """Progress the path forward one step.

        The amount progressed each time (curve).move is called
        depends on the path's speed parameter and the distance
        (i.e. angle_difference) it has to travel. The calculation
        is as follows:

        angle = angle_difference * current_position + init_angle

        Where current_position is the position incremented by the
        set speed in (curve).move().
        """
        self.current_pos += self.speed
        if self.accel != 1:
            new_speed = self.speed * self.accel
            self.speed = max(min(new_speed, self.max_speed), self.min_speed)

    def angle(self):
        """Return the angle of the curve at the current position."""
        return self.angle_difference * self.current_pos + self.init_angle

    def relation(self):
        """Return the relationship of the current angle to the radius.

        This is a blank function left to be filled in by subclasses of
        _BasicCurve. The return value for this function must be a function
        (or lambda expression), of which that function's return value should
        be the radius of the curve at the current position. The parameters of
        the return equation should be as follows:

        (Assuming `r` is the function representing the relation):

        radius = r(current_angle, *args, **kwargs)

        Where *args and **kwargs are the additional *args and **kwargs specified
        upon initializing the curve.
        """
        return NotImplemented

    def position(self):
        """Calculate the position on the curve at the current angle.

        The return value of this function is the coordinate in polar
        form. To view the coordinate in cartesian form, use the
        `to_cartesian` function. # Ignore the `to_cartesian` function in this code snippet, it simply converts polar to cartesian coordinates.

        NOTE: This function requires self.relation to be implemented.
        """
        r = self.relation()
        theta = self.current_angle

        args = self.args
        kwargs = self.kwargs

        radius = self.radius*r(theta, *args, **kwargs)
        return radius, theta

    @property
    def angle_difference(self):
        """The difference between the start and end angles specified."""
        return (self.end_angle - self.init_angle)

    @property
    def current_angle(self):
        """The current angle (specified by self.current_pos)."""
        return self.angle_difference * self.current_pos + self.init_angle

Curve = _BaseCurve

class Hypotrochoid(Curve):
    def relation(self):
        def _relation(theta, r, R, d):
            x = (R - r)*math.cos(theta) + d*math.cos((R - r)/r * theta)
            y = (R - r)*math.sin(theta) - d*math.sin((R - r)/r * theta)
            return (x**2 + y**2)**(1/2)
        return _relation

【问题讨论】:

    标签: python debugging plot geometry


    【解决方案1】:

    将 x,y 和 theta 转换为极坐标形式进行输出是错误的。 Theta是参数方程的参数,不是曲线点的极角(实际上是小圆心的极角)

    所以 x 和 y 可以使用笛卡尔坐标。只需绘制这一点即可。这是 Delphi 测试,它可以准确地绘制出你想要的东西(Canvas.Pixels[x, y] 用 (x,y) 坐标绘制一个点)

       R := 120;
       rr := 40;
       d:= 40;
       for i := 0 to 999 do begin
         a := i * 2 * Pi / 1000;
         y := 200 + Round((R - rr) * sin(a) - d*sin((R-rr)/rr*a));
         x := 200 + Round((R - rr) * cos(a) + d*cos((R-rr)/rr*a));
         Canvas.Pixels[x, y] := clRed;
       end;
    

    【讨论】:

    • 在计算上,当我将 (x2 + y2)**(1/2) 和 theta 转换为极坐标形式,然后返回到笛卡尔形式时会发生什么?是什么导致它具体搞砸了?
    • theta 不是 (x,y) 点的极角。该点的真实极角为 atan2(y, x) 。
    • 哦,这很有意义!谢谢!
    猜你喜欢
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    相关资源
    最近更新 更多