From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Alex Kost Newsgroups: gmane.lisp.guile.user Subject: Re: Solid modeling in Guile Date: Fri, 19 Aug 2016 12:29:46 +0300 Message-ID: <87tweh3y45.fsf@gmail.com> References: NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Trace: blaine.gmane.org 1471599025 18096 195.159.176.226 (19 Aug 2016 09:30:25 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Fri, 19 Aug 2016 09:30:25 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) Cc: guile-user@gnu.org To: Matthew Keeter Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Fri Aug 19 11:30:17 2016 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bag80-0004EL-7k for guile-user@m.gmane.org; Fri, 19 Aug 2016 11:30:16 +0200 Original-Received: from localhost ([::1]:56395 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bag7x-0006TP-CJ for guile-user@m.gmane.org; Fri, 19 Aug 2016 05:30:13 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:43643) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bag7b-0006T7-8G for guile-user@gnu.org; Fri, 19 Aug 2016 05:29:52 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bag7W-0003gs-61 for guile-user@gnu.org; Fri, 19 Aug 2016 05:29:50 -0400 Original-Received: from mail-lf0-x22d.google.com ([2a00:1450:4010:c07::22d]:35583) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bag7V-0003gl-Ow for guile-user@gnu.org; Fri, 19 Aug 2016 05:29:46 -0400 Original-Received: by mail-lf0-x22d.google.com with SMTP id f93so28841016lfi.2 for ; Fri, 19 Aug 2016 02:29:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version:content-transfer-encoding; bh=stNIWXYDCkivQps2EPRH0pQfOUPjIpjSe9R0NShQ29I=; b=evRBeXxmV5KAnZSf4WktyDn21i+WDYiGUZW8fA+QDEEoPrmgzBoResGxTVmnLnwFDC oqkC4T7xZgD3W61D+0G8RHS2IQj9QeIHNZB+/SZTFEXzgCR8fevWiBfxThsmBswrOFNF 0o1IHXrfTAb1b/HF+WOTu8RW5PLDwvPPNyrVMaDhx7a/yY3RFjtUSiALoOtroTtbM1/M cwIdfLWoipqMB2Ezw2HWqB8VITKeo/Nx4FmDjv4mBZjH54uOSMbgqfh2kCSS7MIkkXhu gjcTjdTsZVxMWQyfR5lCMzU71HpTaHiRhkrP3KMaYDZex+D4RtKgFFaiU/0Z83t90nzc LkgA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version:content-transfer-encoding; bh=stNIWXYDCkivQps2EPRH0pQfOUPjIpjSe9R0NShQ29I=; b=Wq9YiuW+IUsERaNHqShmLtGwPwFoIGJrfhsrPr8zv0jJQ4ekXiPHXJxNUyb60nvLmf mJ29ntzzmQFJR5Gp8ZCmhnxJx+1IBXDBCy5pU7vqgAhHmQ0vJ1gEU2Qf+sRciyevYBRj qBKdECaSy6K8NvHHPNJfVpoU5klcO40g+1hvWDT42bPgCV5daytACfmo/8v8GdG9DaHA odzQk6mpjateXda8R+tp9QQhQJkTTfiwBkX5YE39kLXN/4YxMVRwtjYhbFPCrRH/LY7h Em+djfdMsL361Uc9e8z/s+xDEhXgskeIFqAqDnM3pVwH4tAa1yA0mTA25/KPl3YSfFad k+Dg== X-Gm-Message-State: AEkoouuEEK4IvhE/dod5NLEMFzdxikNHhJ4G9ICe+uSBAVNiHEPznLHkBYQYH4briYZ7qw== X-Received: by 10.46.33.5 with SMTP id h5mr1775862ljh.43.1471598984153; Fri, 19 Aug 2016 02:29:44 -0700 (PDT) Original-Received: from leviafan ([217.107.192.156]) by smtp.gmail.com with ESMTPSA id 20sm1066723lja.34.2016.08.19.02.29.43 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 19 Aug 2016 02:29:43 -0700 (PDT) In-Reply-To: (Matthew Keeter's message of "Thu, 18 Aug 2016 17:44:46 -0400") X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:4010:c07::22d X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane.org@gnu.org Original-Sender: "guile-user" Xref: news.gmane.org gmane.lisp.guile.user:12845 Archived-At: Matthew Keeter (2016-08-19 00:44 +0300) wrote: > Hi Guile-folks, > > I wrote a computer-aided design (CAD) tool that you may find interesting. > > It=E2=80=99s a solid modeling tool that uses Guile scripts to define obje= cts (and > constructive solid geometry + functional representations under the hood). > > Project page: http://www.mattkeeter.com/projects/ao/ > Source: https://github.com/mkeeter/ao Wow, this looks very impressive, and you have so many great projects! > I=E2=80=99d love feedback =E2=80=93 Scheme is relatively new to me, so I= =E2=80=99m sure there are > more elegant ways to accomplish a lot of what the code implements. You use =E2=80=98(- (inf))=E2=80=99 several times, it can be replaced with = =E2=80=98-inf.0=E2=80=99. >From "bind/guile/ao/bind.scm": --8<---------------cut here---------------start------------->8--- (define-module (ao bind)) (use-modules (srfi srfi-1)) (use-modules (ice-9 i18n)) (use-modules (system foreign)) --8<---------------cut here---------------end--------------->8--- Usually modules are defined like this: --8<---------------cut here---------------start------------->8--- (define-module (ao bind) #:use-modules (srfi srfi-1) #:use-modules (ice-9 i18n) #:use-modules (system foreign)) --8<---------------cut here---------------end--------------->8--- >From "bind/guile/ao/bounds.scm": --8<---------------cut here---------------start------------->8--- (define-public (bounds-intersection bs) "bounds-intersection bs bs should be a list of '((xmin ymin zmin) (xmax ymax zmax)) lists Finds the intersection along each dimension If bounds are disjoint, returns empty interval (0, 0)" (let* ((lower (map car bs)) (upper (map cadr bs)) (xmin (apply max (map (lambda (b) (car b)) lower))) (ymin (apply max (map (lambda (b) (cadr b)) lower))) (zmin (apply max (map (lambda (b) (caddr b)) lower))) (xmax (apply min (map (lambda (b) (car b)) upper))) (ymax (apply min (map (lambda (b) (cadr b)) upper))) (zmax (apply min (map (lambda (b) (caddr b)) upper)))) ;; Clamp intervals to empty (0,0) if bounds are disjoint (if (< xmax xmin) (begin (set! xmin 0) (set! xmax 0))) (if (< ymax ymin) (begin (set! ymin 0) (set! ymax 0))) (if (< zmax zmin) (begin (set! zmin 0) (set! zmax 0))) (list (list xmin ymin zmin) (list xmax ymax zmax)))) --8<---------------cut here---------------end--------------->8--- All these cadr, caddr are hard to understand. I would rather make some level of abstraction for coordinates and bounds. (if I understand it right) the simplest would be: --8<---------------cut here---------------start------------->8--- (define make-coordinates list) (define x first) (define y second) (define z third) (define make-bound cons) ; bound of lower and upper coordinates (define lower-coordinates car) (define upper-coordinates cdr) (define (extremum min-or-max coordinate coordinates) "Return minimal or maximal coordinate from COORDINATES. MIN-OR-MAX is 'min' or 'max' procedure. COORDINATE is either 'x', 'y' or 'z' procedure." (apply min-or-max (map coordinate coordinates))) --8<---------------cut here---------------end--------------->8--- And now this 'bounds-intersection' can be written like this: --8<---------------cut here---------------start------------->8--- (define-public (bounds-intersection bounds) "Finds the intersection along each dimension of BOUNDS. If bounds are disjoint, returns empty interval (0, 0)." (let* ((lower (map lower-coordinates bounds)) (upper (map upper-coordinates bounds)) (xmin (extremum max x lower)) (ymin (extremum max y lower)) (zmin (extremum max z lower)) (xmax (extremum min x upper)) (ymax (extremum min y upper)) (zmax (extremum min z upper))) ;; Clamp intervals to empty (0,0) if bounds are disjoint (when (< xmax xmin) (set! xmin 0) (set! xmax 0)) (when (< ymax ymin) (set! ymin 0) (set! ymax 0)) (when (< zmax zmin) (set! zmin 0) (set! zmax 0)) (make-bound (make-coordinates xmin ymin zmin) (make-coordinates xmax ymax zmax)))) --8<---------------cut here---------------end--------------->8--- Actually using 'set!' for local variables is not considered a good style, but, well, who cares :-) Note that those 'first', 'second', 'third' procedures come from (srfi srfi-1) module. I'm not an expert, so do not consider this is the best (or even a good) way. I just wanted to point that instead of using lists, cars and cdrs directly, it is better to have some higher-level procedures. BTW, the indentation in .scm files is *very* unusual :-) --=20 Alex