@@ -12,11 +12,6 @@ use super::{
1212use std:: vec;
1313use std:: vec:: Vec ;
1414
15- /// An `f64` wrapper implementing `Ord` and `Eq`.
16- ///
17- /// This is only used as part of bulk loading.
18- /// All input coordinates are checked with `validate_coordinate` before they are used, hence
19- /// `Ord` and `Eq` should always be well-defined.
2015#[ derive( Debug , PartialEq , PartialOrd , Clone , Copy ) ]
2116struct FloatOrd < S > ( S ) ;
2217
3227
3328impl < S > Eq for FloatOrd < S > where S : PartialOrd { }
3429
35- /// Implements a circle-sweep bulk loading algorithm for efficient initialization of Delaunay
36- /// triangulations.
37- ///
38- /// The algorithm is motivated by:
39- ///
40- /// A faster circle-sweep Delaunay triangulation algorithm
41- /// Ahmad Biniaz, Gholamhossein Dastghaibyfard
42- /// Advances in Engineering Software,
43- /// Volume 43, Issue 1,
44- /// 2012,
45- /// <https://doi.org/10.1016/j.advengsoft.2011.09.003>
46- ///
47- /// Or alternatively: <http://cglab.ca/~biniaz/papers/Sweep%20Circle.pdf>
48- ///
49- /// # Overview
50- ///
51- /// The major reason for the algorithm's good performance lies in an efficient lookup structure
52- /// for finding *hull edges* at a certain *angle*.
53- /// "angle" always refers to the angle of a vertex to a center point which is calculated first.
54- /// The lookup structure is implemented by the `Hull` struct. It has a `get` and `insert` method
55- /// which can quickly find and update the edges of the hull at a given angle.
56- ///
57- /// The algorithm is roughly compromised of these steps:
58- ///
59- /// 1. Calculate the median position of all vertices. We call this position `initial_center`.
60- /// 2. Sort all vertices along their distance to this center.
61- /// 3. Build a seed triangulation by inserting vertices (beginning with the closest vertex) into an
62- /// empty triangulation. Stop once the triangulation has at least one inner face.
63- /// 4. Calculate the final center. The final center is some point inside the seed triangulation (e.g.
64- /// the average its vertices)
65- /// 5. Initiate the `Hull` lookup structure with the seed triangulation.
66- /// 6. Insert all remaining vertices, beginning with the vertex closest to `initial_center`.
67- /// This can be done efficiently as the edge "closest" to the new vertex can be identified quickly
68- /// with `Hull.get`. After each insertion, the hull is partially patched to be more convex
69- /// 7. After all vertices have been inserted: The hull is not necessarily convex. Fill any "hole"
70- /// in the hull by a process comparable to the graham scan algorithm.
71- ///
72- /// # Some details
73- ///
74- /// "angle" does not refer to an actual angle in radians but rather to an approximation that doesn't
75- /// require trigonometry for calculation. See method `pseudo_angle` for more information.
7630pub fn bulk_load < V , T > ( mut elements : Vec < V > ) -> Result < T , InsertionError >
7731where
7832 V : HasPosition ,
@@ -611,7 +565,6 @@ where
611565 Ok ( ( ) )
612566}
613567
614- /// Makes the outer hull convex. Similar to a graham scan.
615568fn fix_convexity < TR > ( triangulation : & mut TR )
616569where
617570 TR : Triangulation ,
@@ -671,9 +624,6 @@ impl Segment {
671624 Self { from, to }
672625 }
673626
674- /// Returns `true` if this segment does not contain the angle 0.0.
675- ///
676- /// Pseudo angles wrap back to 0.0 after a full rotation.
677627 fn is_non_wrapping_segment ( & self ) -> bool {
678628 self . from < self . to
679629 }
@@ -689,42 +639,21 @@ impl Segment {
689639
690640#[ derive( Clone , Copy , Debug ) ]
691641struct Node {
692- /// Pseudo-angle of this hull entry
693642 angle : FloatOrd < f64 > ,
694643
695- /// An edge leaving at this hull entry.
696644 edge : FixedDirectedEdgeHandle ,
697645
698- /// Neighbors (indexes into the hull)
699646 left : usize ,
700647 right : usize ,
701648}
702649
703- /// Implements an efficient angle-to-edge lookup for edges of the hull of a triangulation.
704- ///
705- /// Refer to `bulk_load` (in `bulk_load.rs`) for more background on how this structure is being used.
706- ///
707- /// It implements an efficient mapping of (pseudo-)angles to edges. To do so, it stores all inserted
708- /// edges in a linked list backed by a vec. Finding an edge belonging to a given angle can always
709- /// be done by iterating through this list until the target angle is found.
710- /// The entries are stored in a consistent order (either clockwise or counterclockwise)
711- ///
712- /// This naive sequential search is very slow as it needs to traverse half of the list on average.
713- /// To speed things up, the space of valid angles (the half open interval [0, 1) )
714- /// is partitioned into `n` equally sized buckets.
715- /// For each bucket, `Hull` stores a reference to the list entry with the *biggest angle* that
716- /// still belongs into that bucket. A sequential search will begin at this bucket and has to traverse
717- /// only a few elements before finding the target angle.
718- /// Since the number of buckets is re-adjusted depending on the number of hull entries, this mapping
719- /// will now be in O(1) for reasonably evenly distributed triangulations.
720650#[ derive( Debug ) ]
721651pub struct Hull {
722652 buckets : Vec < usize > ,
723653 data : Vec < Node > ,
724654
725655 center : Point2 < f64 > ,
726656
727- /// Unused indices in data which might be reclaimed later
728657 empty : Vec < usize > ,
729658}
730659
@@ -817,23 +746,6 @@ impl Hull {
817746 }
818747 }
819748
820- /// Updates the hull after the insertion of a vertex.
821- ///
822- /// This method should be called after a vertex `v` has been inserted into the outer face of the
823- /// triangulation under construction.
824- ///
825- /// Such a vertex is guaranteed to have two outgoing edges that are adjacent to the convex hull,
826- /// e.g. `e0 -> v -> e1`
827- ///
828- /// In these scenarios, the parameters should be set as follows:
829- /// * `left_angle`: `pseudo_angle(e0.from())`
830- /// * `middle_angle`: `pseudo_angle(v.position())`
831- /// * `right_angle`: `pseudo_angle(e1.to())`
832- /// * `left_edge`: `e0.fix()`
833- /// * `right_edge`: `e1.fix()`
834- ///
835- /// Note that `left_angle` and `right_angle` must already be present in the hull. Otherwise,
836- /// calling this method will result in an endless loop.
837749 fn insert (
838750 & mut self ,
839751 left_angle : FloatOrd < f64 > ,
@@ -949,10 +861,6 @@ impl Hull {
949861 }
950862 }
951863
952- /// Gets an edge of the hull which covers a given input angle.
953- ///
954- /// An edge is considered to cover an input angle if the input angle is contained in the angle
955- /// segment spanned by `pseudo_angle(edge.from()) .. pseudo_angle(edge.from())`
956864 fn get ( & self , angle : FloatOrd < f64 > ) -> FixedDirectedEdgeHandle {
957865 let mut current_handle = self . buckets [ self . floored_bucket ( angle) ] ;
958866 loop {
@@ -968,7 +876,6 @@ impl Hull {
968876 }
969877 }
970878
971- /// Looks up what bucket a given pseudo-angle will fall into.
972879 fn floored_bucket ( & self , angle : FloatOrd < f64 > ) -> usize {
973880 ( ( angle. 0 * self . buckets . len ( ) as f64 ) . floor ( ) as usize ) % self . buckets . len ( )
974881 }
@@ -999,22 +906,6 @@ impl Hull {
999906 }
1000907}
1001908
1002- /// Returns a pseudo-angle in the 0-1 range, without expensive trigonometry functions
1003- ///
1004- /// The angle has the following shape:
1005- /// ```text
1006- /// 0.25
1007- /// ^ y
1008- /// |
1009- /// |
1010- /// 0 | x
1011- /// <-----------o-----------> 0.5
1012- /// 1 |
1013- /// |
1014- /// |
1015- /// v
1016- /// 0.75
1017- /// ```
1018909#[ inline]
1019910fn pseudo_angle ( a : Point2 < f64 > , center : Point2 < f64 > ) -> FloatOrd < f64 > {
1020911 let diff = a. sub ( center) ;
0 commit comments