【问题标题】:How can I decompose geometry figure building in a lisp-like languages?如何以类似 lisp 的语言分解几何图形构建?
【发布时间】:2019-08-21 11:12:27
【问题描述】:

如何用类似 lisp 的语言分解这个过程?

  • 从一些几何图形开始。
  • 我们将它相乘并得到几个副本。
  • 然后我们将此副本设置在其他图形的边框上,例如副本之间的距离相等。
  • 然后我们设置每个对象在边框上的旋转 依赖于它在边界上的位置。

有哪些方法可以在函数中分解这个过程作为一个整体:制作一个对象的副本,将其副本安排在另一个对象的边界上,设置其副本的旋转?

最后一步特别有趣,还有如何与前一步组合的方法。

【问题讨论】:

  • 嗨!你能添加一个你在说什么的例子吗?这对我来说有点不清楚。您将如何使用伪代码或您选择的另一种语言来完成任务?有什么你看不到如何用 Lisp 翻译的东西吗?或者您的问题可能是关于如何设计这样的系统,而不管特定的语言?我很难想象你想要什么样的答案。
  • 谢谢,@coredump!我在询问有关系统设计的示例、提示和文章:1. 没有类(没有 OOP),2. 使用任何数字,3. 使用函数作为函数参数(一等公民),如果合适的话,4. 易于增加对图形的新操作,5.方便的语法。

标签: functional-programming lisp common-lisp decomposition


【解决方案1】:

您的问题非常广泛,让我们举一个简单的二维形状示例。

下面的代码定义为我们可以这样写:

(isomorphism (alexandria:compose (scale 10)
                                 (lift #'round)
                                 (rotate 90))
             (triangle (point 0 0)
                       (point 1 0)
                       (point 0 1)))

=> (TRIANGLE (POINT 0 0) (POINT 0 10) (POINT -10 0))

这会计算一个称为同构(保持形状)的简单变换函数,它首先是旋转,然后是计算点的舍入,然后是缩放操作。结果是描述结果形状的列表。复制形状只是与函数#'identity 的同构(但如果使用纯函数方式,它有点没用)。

注意:这里是四舍五入,例如当 cos/sin 给出非常小的浮点数时回落到零;浮点数的使用破坏了形状保持,舍入也是如此,但是当它们组合在一起时,产生的形状是一个实际的同构。根据您的需求目的,这一点正确性/准确性可能重要也可能不重要。您还可以描述应用了哪些转换,并仅“光栅化”它们以进行显示。

变换函数作用于坐标列表,并返回坐标列表:

(defun translate (dx &optional (dy dx))
  (lambda (xy) (mapcar #'+ xy (list dx dy))))

(defun scale (sx &optional (sy sx))
  (lambda (xy) (mapcar #'* xy (list sx sy))))

(defun rotate (degrees)
  (let* ((radians (* degrees pi 1/180))
         (cos (cos radians))
         (sin (sin radians)))
    (lambda (xy)
      (destructuring-bind (x y) xy
        (list (- (* x cos) (* y sin))
              (+ (* y cos) (* x sin)))))))

(defun lift (fn)
  (lambda (things)
    (mapcar fn things)))

isomorphism 函数定义如下,递归地将形状解构为类型标签(兼作构造函数)和组件,如果是点,则应用变换函数:

(defun isomorphism (transform shape)
  (flet ((isomorphism (s) (isomorphism transform s)))
    (with-shape (constructor components) shape
      (apply constructor
             (if (eq constructor 'point)
                 (funcall transform components)
                 (mapcar #'isomorphism components))))))

我将shapewith-shape 定义如下,以便对它们的表示方式进行一些抽象:

(defun shape (constructor components)
  (list* constructor components))

(defmacro with-shape ((constructor components) shape &body body)
  `(destructuring-bind (,constructor &rest ,components) ,shape
     ,@body))

我可以用简单的函数定义形状,这些函数可能会或可能不会执行一些检查和规范化:

(defun point (&rest coords)
  (shape 'point coords))

(defun triangle (a b c)
  (shape 'triangle (list a b c)))

(defun rectangle (x0 y0 x1 y1)
  (shape 'rectangle
         (list (min x0 x1)
               (min y0 y1)
               (max x0 x1)
               (max y0 y1))))

请注意构造函数总是与函数名称相同的符号。这可以通过宏强制执行,您只需要返回组件列表:

(defconstructor point (x y)
  (list x y))

您还可以从上述构造派生构造函数:

(defun rectangle-xywh (x y width height)
  (rectangle x y (+ x width) (+ y height)))

上面的形状是根据点来定义的,但是你可以想象有一些形状是由更小的形状组合而成的:

(defun group (&rest shapes)
  (shape 'group shapes))

这是一个玩具示例,但作为起点可能会很有用。

然后,如果您想制作一个形状并制作以 90° 为增量旋转的不同副本,您可以这样做:

(loop
  for angle from 0 below 360 by 90
  collect
  (isomorphism (compose (lift #'round)
                        (rotate angle)
                        (scale 2)
                        (translate 10 0))
               (group (triangle (point 0 0)
                                (point 1 0)
                                (point 0 1)))))

【讨论】:

    猜你喜欢
    • 2013-07-29
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 2013-03-18
    • 2022-06-14
    • 2013-11-02
    • 1970-01-01
    相关资源
    最近更新 更多