Make regions from the Delaunay triangulation
authorJavier Sancho <jsf@jsancho.org>
Fri, 2 Aug 2019 16:59:23 +0000 (18:59 +0200)
committerJavier Sancho <jsf@jsancho.org>
Fri, 2 Aug 2019 16:59:23 +0000 (18:59 +0200)
dungeon-master/generators/town.scm
dungeon-master/geom.scm [new file with mode: 0644]
dungeon-master/geom/voronoi.scm

index e8e6d95b73ad6528105b08a3bb63881ddad031d6..cefa138308d0a3dbe8854b12edc52b5563e50460 100644 (file)
@@ -17,7 +17,7 @@
 
 (define (build-patches n-patches)
   (define* (get-points n seed #:optional (l '()))
-    (cond ((> n 0)
+    (cond ((>= n 0)
            (let* ((a (+ seed (* (sqrt n) 5)))
                   (r (if (= n 0)
                          0
diff --git a/dungeon-master/geom.scm b/dungeon-master/geom.scm
new file mode 100644 (file)
index 0000000..96cc378
--- /dev/null
@@ -0,0 +1,20 @@
+(define-module (dungeon-master geom)
+  #:use-module (dungeon-master geom point)
+  #:export (angle-sign))
+
+
+(define (angle-sign center a b)
+  "Return the sign of (- (atan (- a center))
+                         (atan (- b center)))"
+  (let ((x1 (- (point-x a) (point-x center)))
+        (y1 (- (point-y a) (point-y center)))
+        (x2 (- (point-x b) (point-x center)))
+        (y2 (- (point-y b) (point-y center))))
+    (cond ((and (>= x1 0) (< x2 0))
+             1)
+          ((and (>= x2 0) (< x1 0))
+             -1)
+          ((and (= x1 0) (= x2 0))
+           (if (> y2 y1) 1 -1))
+          (else
+           (if (> (- (* x2 y1) (* x1 y2)) 0) 1 -1)))))
index 3f55946fbc8ade891e8e8b2ef2fcd52711f92b02..9217285ad97c2295dd539acd6cba191284526801 100644 (file)
@@ -1,7 +1,9 @@
 (define-module (dungeon-master geom voronoi)
   #:use-module (ice-9 receive)
+  #:use-module (rnrs sorting)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-9)
+  #:use-module (dungeon-master geom)
   #:use-module (dungeon-master geom point)
   #:use-module (dungeon-master geom triangle)
   #:use-module (dungeon-master geom bowyer-watson)
 ;;; Voronoi mesh region
 
 (define-record-type <voronoi-region>
-  (make-voronoi-region seed vertices)
+  (make-raw-voronoi-region seed vertices)
   voronoi-region?
   (seed voronoi-region-seed)
   (vertices voronoi-region-vertices))
 
+(define (make-voronoi-region seed vertices)
+  (define (compare-angles triangle1 triangle2)
+    (let ((c1 (triangle-center triangle1))
+          (c2 (triangle-center triangle2)))
+      (> (angle-sign seed c1 c2) 0)))
+  (make-raw-voronoi-region seed (list-sort compare-angles vertices)))
 
 ;;; Voronoi mesh
 
@@ -35,7 +43,7 @@
   (regions voronoi-mesh-regions))
 
 (define* (make-voronoi-mesh vertices #:optional (relax-steps 3))
-  ; Delaunay triangulation
+  ;; Delaunay triangulation
   (receive (triangles points frame)
       (bowyer-watson vertices)
     (make-raw-voronoi-mesh
      frame
      (make-regions points triangles))))
 
+(define (partitioning voronoi)
+  (define (is-real-triangle triangle)
+    ;; real triangle points cannot be frame points
+    (let ((frame (voronoi-mesh-frame voronoi)))
+      (let check-points ((points (triangle-points triangle)))
+        (cond ((null? points)
+               #t)  ; triangle is real
+              (else
+               (and (not (member (car points) frame))
+                    (check-points (cdr points))))))))
+
+  (define (is-real-region region)
+    ;; real region points cannot be frame points
+    (let check-vertices ((vertices (voronoi-region-vertices region)))
+      (cond ((null? vertices)
+             #t)  ; region is real
+            (else
+             (and (is-real-triangle (car vertices))
+                  (check-vertices (cdr vertices)))))))
+
+  (let* ((points (voronoi-mesh-points voronoi))
+         (regions (voronoi-mesh-regions voronoi))
+         ;; we need the regions in the same order as points are
+         (ordered-regions
+          (map-in-order
+           (lambda (p)
+             (assoc-ref regions p))
+           points))
+         ;; only real regions without frame points
+         (filtered-regions
+          (filter (lambda (r) (is-real-region r))
+                  ordered-regions)))
+    filtered-regions))
+
 (define* (voronoi-mesh-relax voronoi #:optional (to-relax '()))
-  voronoi)
-
-(define* (make-regions points triangles #:optional (regions '()))
-  (cond ((null? points)
-         regions)
-        (else
-         (let* ((p (car points))
-                (vertices (filter
-                           (lambda (tr) (member p (triangle-points tr)))
-                           triangles))
-                (region (make-voronoi-region p vertices)))
-           (make-regions (cdr points)
-                         triangles
-                         (alist-cons p region regions))))))
+  (let ((regions (partitioning voronoi)))
+    voronoi))
+
+(define (make-regions points triangles)
+  (map-in-order
+   (lambda (p)
+     (let ((vertices
+            (filter
+             (lambda (tr) (member p (triangle-points tr)))
+             triangles)))
+       (cons p (make-voronoi-region p vertices))))
+   points))