Skip to main content

physdes/
vlsi_ops.rs

1//! VLSI-specific geometric operations
2//!
3//! This module provides operations commonly used in VLSI physical design and layout.
4
5use crate::{Point, Polygon};
6
7/// Represents a rectangle in 2D space defined by its minimum (bottom-left)
8/// and maximum (top-right) corner points.
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct Rectangle<T> {
11    /// The minimum (bottom-left) corner point
12    pub min: Point<T, T>,
13    /// The maximum (top-right) corner point
14    pub max: Point<T, T>,
15}
16
17impl<T: Clone + Ord + Copy + std::ops::Add<Output = T>> Rectangle<T> {
18    /// Creates a new rectangle from min and max points
19    ///
20    /// # Arguments
21    ///
22    /// * `min` - The minimum (bottom-left) corner
23    /// * `max` - The maximum (top-right) corner
24    ///
25    /// # Examples
26    ///
27    /// ```
28    /// use physdes::{Point, vlsi_ops::Rectangle};
29    ///
30    /// let rect = Rectangle::new(
31    ///     Point::new(0, 0),
32    ///     Point::new(10, 20)
33    /// );
34    /// ```
35    pub fn new(min: Point<T, T>, max: Point<T, T>) -> Self {
36        assert!(min.xcoord <= max.xcoord && min.ycoord <= max.ycoord);
37        Rectangle { min, max }
38    }
39
40    /// Creates a rectangle from origin, width, and height
41    pub fn from_dimensions(origin: Point<T, T>, width: T, height: T) -> Self {
42        Rectangle::new(
43            origin,
44            Point::new(origin.xcoord + width, origin.ycoord + height),
45        )
46    }
47
48    /// Checks if this rectangle overlaps with another
49    ///
50    /// Two rectangles overlap iff their projections on both axes overlap:
51    ///
52    /// $$\[a_x,b_x\] \cap \[c_x,d_x\] \neq \varnothing \land \[a_y,b_y\] \cap \[c_y,d_y\] \neq \varnothing$$
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use physdes::{Point, vlsi_ops::Rectangle};
58    ///
59    /// let rect1 = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
60    /// let rect2 = Rectangle::new(Point::new(5, 5), Point::new(15, 15));
61    /// assert!(rect1.overlaps(&rect2));
62    ///
63    /// let rect3 = Rectangle::new(Point::new(20, 20), Point::new(30, 30));
64    /// assert!(!rect1.overlaps(&rect3));
65    /// ```
66    pub fn overlaps(&self, other: &Self) -> bool {
67        self.min.xcoord <= other.max.xcoord
68            && self.max.xcoord >= other.min.xcoord
69            && self.min.ycoord <= other.max.ycoord
70            && self.max.ycoord >= other.min.ycoord
71    }
72
73    /// Checks if this rectangle contains another rectangle
74    ///
75    /// $$A \supseteq B \iff A_{\min x} \le B_{\min x} \land A_{\max x} \ge B_{\max x}$$
76    pub fn contains(&self, other: &Self) -> bool {
77        self.min.xcoord <= other.min.xcoord
78            && self.max.xcoord >= other.max.xcoord
79            && self.min.ycoord <= other.min.ycoord
80            && self.max.ycoord >= other.max.ycoord
81    }
82
83    /// Checks if this rectangle contains a point
84    ///
85    /// $$P \in R \iff x_{\min} \le x \le x_{\max} \land y_{\min} \le y \le y_{\max}$$
86    pub fn contains_point(&self, point: &Point<T, T>) -> bool {
87        point.xcoord >= self.min.xcoord
88            && point.xcoord <= self.max.xcoord
89            && point.ycoord >= self.min.ycoord
90            && point.ycoord <= self.max.ycoord
91    }
92
93    /// Computes the intersection with another rectangle
94    ///
95    /// $$A \cap B = \[\\max(x_{A\\min}, x_{B\\min}),\; \\min(x_{A\\max}, x_{B\\max})\] \times \[\\max(y_{A\\min}, y_{B\\min}),\; \\min(y_{A\\max}, y_{B\\max})\]$$
96    ///
97    /// Returns `None` if the rectangles don't overlap
98    pub fn intersect(&self, other: &Self) -> Option<Self>
99    where
100        T: std::ops::Add<Output = T>,
101    {
102        if !self.overlaps(other) {
103            return None;
104        }
105
106        Some(Rectangle::new(
107            Point::new(
108                self.min.xcoord.max(other.min.xcoord),
109                self.min.ycoord.max(other.min.ycoord),
110            ),
111            Point::new(
112                self.max.xcoord.min(other.max.xcoord),
113                self.max.ycoord.min(other.max.ycoord),
114            ),
115        ))
116    }
117
118    /// Computes the area of the rectangle
119    ///
120    /// $$A = w \times h = (x_{\max} - x_{\min}) \times (y_{\max} - y_{\min})$$
121    pub fn area(&self) -> T
122    where
123        T: std::ops::Sub<Output = T> + std::ops::Mul<Output = T>,
124    {
125        let width = self.max.xcoord - self.min.xcoord;
126        let height = self.max.ycoord - self.min.ycoord;
127        width * height
128    }
129
130    /// Computes the bounding rectangle of two rectangles
131    ///
132    /// $$\text{bbox}(A,B) = \[\\min(x_{A\\min}, x_{B\\min}),\; \\max(x_{A\\max}, x_{B\\max})\] \times \[\\min(y_{A\\min}, y_{B\\min}),\; \\max(y_{A\\max}, y_{B\\max})\]$$
133    pub fn bounding_rect(&self, other: &Self) -> Self {
134        Rectangle::new(
135            Point::new(
136                self.min.xcoord.min(other.min.xcoord),
137                self.min.ycoord.min(other.min.ycoord),
138            ),
139            Point::new(
140                self.max.xcoord.max(other.max.xcoord),
141                self.max.ycoord.max(other.max.ycoord),
142            ),
143        )
144    }
145
146    /// Converts to a Polygon
147    pub fn to_polygon(&self) -> Polygon<T>
148    where
149        T: Clone + std::ops::Add<Output = T> + num_traits::Num + std::ops::AddAssign + Ord,
150    {
151        Polygon::new(&[
152            self.min,
153            Point::new(self.max.xcoord, self.min.ycoord),
154            self.max,
155            Point::new(self.min.xcoord, self.max.ycoord),
156        ])
157    }
158}
159
160/// Detects if any pair of rectangles overlap using the line sweep algorithm.
161///
162/// The algorithm uses a sweep line approach:
163/// 1. Create events for left and right edges of each rectangle
164/// 2. Sort events by x-coordinate
165/// 3. Sweep from left to right, maintaining active rectangles
166/// 4. Check y-overlap when a new rectangle becomes active
167///
168/// Two active rectangles overlap in y iff:
169///
170/// $$y_{\min}^{(1)} \le y_{\max}^{(2)} \land y_{\min}^{(2)} \le y_{\max}^{(1)}$$
171///
172/// # Arguments
173///
174/// * `rectangles` - A slice of rectangles to check for overlaps
175///
176/// # Returns
177///
178/// The indices of two overlapping rectangles if found, otherwise `None`
179///
180/// # Examples
181///
182/// ```
183/// use physdes::{Point, vlsi_ops::{Rectangle, detect_overlap}};
184///
185/// let rects = vec![
186///     Rectangle::new(Point::new(0, 0), Point::new(10, 10)),
187///     Rectangle::new(Point::new(5, 5), Point::new(15, 15)),
188///     Rectangle::new(Point::new(20, 20), Point::new(30, 30)),
189/// ];
190/// let result = detect_overlap(&rects);
191/// assert!(result.is_some());
192/// assert_eq!(result.unwrap(), (0, 1));
193/// ```
194pub fn detect_overlap<T>(rectangles: &[Rectangle<T>]) -> Option<(usize, usize)>
195where
196    T: Copy + Ord,
197{
198    if rectangles.len() < 2 {
199        return None;
200    }
201
202    // Create events: (x_coord, is_start, rect_index)
203    let mut events: Vec<(T, bool, usize)> = Vec::with_capacity(rectangles.len() * 2);
204    for (idx, rect) in rectangles.iter().enumerate() {
205        events.push((rect.min.xcoord, true, idx));
206        events.push((rect.max.xcoord, false, idx));
207    }
208
209    events.sort_by_key(|a| a.0);
210
211    // Active rectangles: (rect_index, y_min, y_max)
212    let mut active: Vec<(usize, T, T)> = Vec::new();
213
214    for &(_x, is_start, idx) in &events {
215        let rect = &rectangles[idx];
216
217        if is_start {
218            // Check y-overlap with all active rectangles
219            for &(other_idx, other_y_min, other_y_max) in &active {
220                if rect.min.ycoord <= other_y_max && other_y_min <= rect.max.ycoord {
221                    return Some((other_idx, idx));
222                }
223            }
224            active.push((idx, rect.min.ycoord, rect.max.ycoord));
225        } else {
226            // O(1) removal: swap with back and pop
227            for i in 0..active.len() {
228                if active[i].0 == idx {
229                    active.swap_remove(i);
230                    break;
231                }
232            }
233        }
234    }
235
236    None
237}
238
239/// Calculates Manhattan distance between two points
240///
241/// $$d = |x_1 - x_2| + |y_1 - y_2|$$
242///
243/// The Manhattan distance is the sum of the absolute differences of coordinates.
244/// This is commonly used in VLSI routing where wires can only run horizontally or vertically.
245///
246/// # Arguments
247///
248/// * `p1` - First point
249/// * `p2` - Second point
250///
251/// # Examples
252///
253/// ```
254/// use physdes::{Point, vlsi_ops::manhattan_distance};
255///
256/// let p1 = Point::new(0, 0);
257/// let p2 = Point::new(3, 4);
258/// let dist = manhattan_distance(&p1, &p2);
259/// assert_eq!(dist, 7); // |3-0| + |4-0| = 7
260/// ```
261pub fn manhattan_distance<T>(p1: &Point<T, T>, p2: &Point<T, T>) -> T
262where
263    T: Ord + Copy + std::ops::Sub<Output = T> + std::ops::Add<Output = T>,
264{
265    let dx = if p1.xcoord > p2.xcoord {
266        p1.xcoord - p2.xcoord
267    } else {
268        p2.xcoord - p1.xcoord
269    };
270    let dy = if p1.ycoord > p2.ycoord {
271        p1.ycoord - p2.ycoord
272    } else {
273        p2.ycoord - p1.ycoord
274    };
275    dx + dy
276}
277
278/// Checks if two rectangles satisfy minimum spacing requirements
279///
280/// Two rectangles satisfy spacing $s$ if they do not overlap and the gap on
281/// each axis is at least $s$:
282///
283/// $$\\text{spacing}_x \ge s \land \\text{spacing}_y \ge s$$
284///
285/// # Arguments
286///
287/// * `rect1` - First rectangle
288/// * `rect2` - Second rectangle
289/// * `min_spacing` - Minimum required spacing
290///
291/// # Examples
292///
293/// ```
294/// use physdes::{Point, vlsi_ops::{Rectangle, check_spacing}};
295///
296/// let rect1 = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
297/// let rect2 = Rectangle::new(Point::new(10, 0), Point::new(20, 10));
298///
299/// // These rectangles touch (spacing = 0)
300/// assert!(!check_spacing(&rect1, &rect2, 1));
301///
302/// let rect3 = Rectangle::new(Point::new(12, 0), Point::new(22, 10));
303/// // These have spacing of 2
304/// assert!(check_spacing(&rect1, &rect3, 1));
305/// ```
306pub fn check_spacing<T>(rect1: &Rectangle<T>, rect2: &Rectangle<T>, min_spacing: T) -> bool
307where
308    T: Ord + Copy + std::ops::Sub<Output = T> + std::ops::Add<Output = T>,
309{
310    if rect1.overlaps(rect2) {
311        return false;
312    }
313
314    // Calculate horizontal spacing
315    let horiz_spacing = if rect1.max.xcoord <= rect2.min.xcoord {
316        rect2.min.xcoord - rect1.max.xcoord
317    } else if rect2.max.xcoord <= rect1.min.xcoord {
318        rect1.min.xcoord - rect2.max.xcoord
319    } else {
320        T::clone(&min_spacing) // Overlapping in x, check y
321    };
322
323    // Calculate vertical spacing
324    let vert_spacing = if rect1.max.ycoord <= rect2.min.ycoord {
325        rect2.min.ycoord - rect1.max.ycoord
326    } else if rect2.max.ycoord <= rect1.min.ycoord {
327        rect1.min.ycoord - rect2.max.ycoord
328    } else {
329        T::clone(&min_spacing) // Overlapping in y, check x
330    };
331
332    horiz_spacing >= min_spacing && vert_spacing >= min_spacing
333}
334
335/// Computes the minimum bounding rectangle of a set of rectangles
336///
337/// $$\text{bbox} = \left\[\\min_i x_{i\\min},\; \\max_i x_{i\\max}\\right\] \times \left\[\\min_i y_{i\\min},\; \\max_i y_{i\\max}\\right\]$$
338///
339/// # Arguments
340///
341/// * `rects` - Slice of rectangles
342///
343/// # Examples
344///
345/// ```
346/// use physdes::{Point, vlsi_ops::{Rectangle, bounding_rect}};
347///
348/// let rects = vec![
349///     Rectangle::new(Point::new(0, 0), Point::new(10, 10)),
350///     Rectangle::new(Point::new(5, 5), Point::new(15, 15)),
351/// ];
352///
353/// let bbox = bounding_rect(&rects).unwrap();
354/// assert_eq!(bbox.min, Point::new(0, 0));
355/// assert_eq!(bbox.max, Point::new(15, 15));
356/// ```
357pub fn bounding_rect<T>(rects: &[Rectangle<T>]) -> Option<Rectangle<T>>
358where
359    T: Ord + Copy + std::ops::Add<Output = T>,
360{
361    if rects.is_empty() {
362        return None;
363    }
364
365    let mut min_x = rects[0].min.xcoord;
366    let mut min_y = rects[0].min.ycoord;
367    let mut max_x = rects[0].max.xcoord;
368    let mut max_y = rects[0].max.ycoord;
369
370    for rect in &rects[1..] {
371        min_x = min_x.min(rect.min.xcoord);
372        min_y = min_y.min(rect.min.ycoord);
373        max_x = max_x.max(rect.max.xcoord);
374        max_y = max_y.max(rect.max.ycoord);
375    }
376
377    Some(Rectangle::new(
378        Point::new(min_x, min_y),
379        Point::new(max_x, max_y),
380    ))
381}
382
383/// Computes total area covered by rectangles, accounting for overlaps
384///
385/// $$A_{\\text{total}} = \sum_i A(R_i) - \sum_{i<j} A(R_i \cap R_j)$$
386///
387/// # Examples
388///
389/// ```
390/// use physdes::{Point, vlsi_ops::{Rectangle, total_area}};
391///
392/// let rects = vec![
393///     Rectangle::new(Point::new(0, 0), Point::new(10, 10)),
394///     Rectangle::new(Point::new(5, 5), Point::new(15, 15)),
395/// ];
396///
397/// let area = total_area(&rects);
398/// // First rect: 100, second rect: 100, overlap: 25, total: 175
399/// assert_eq!(area, 175);
400/// ```
401pub fn total_area(rects: &[Rectangle<i32>]) -> i32 {
402    if rects.is_empty() {
403        return 0;
404    }
405
406    let mut total = 0;
407    for (i, rect) in rects.iter().enumerate() {
408        total += rect.area();
409        // Subtract overlaps with previously counted rectangles
410        for other in &rects[..i] {
411            if let Some(intersection) = rect.intersect(other) {
412                total -= intersection.area();
413            }
414        }
415    }
416
417    total
418}
419
420#[cfg(test)]
421mod tests {
422    use super::*;
423
424    #[test]
425    fn test_rectangle_creation() {
426        let rect = Rectangle::new(Point::new(0, 0), Point::new(10, 20));
427        assert_eq!(rect.min, Point::new(0, 0));
428        assert_eq!(rect.max, Point::new(10, 20));
429    }
430
431    #[test]
432    fn test_rectangle_overlap() {
433        let rect1 = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
434        let rect2 = Rectangle::new(Point::new(5, 5), Point::new(15, 15));
435        assert!(rect1.overlaps(&rect2));
436
437        let rect3 = Rectangle::new(Point::new(20, 20), Point::new(30, 30));
438        assert!(!rect1.overlaps(&rect3));
439    }
440
441    #[test]
442    fn test_rectangle_area() {
443        let rect = Rectangle::new(Point::new(0, 0), Point::new(10, 20));
444        assert_eq!(rect.area(), 200);
445    }
446
447    #[test]
448    fn test_manhattan_distance() {
449        let p1 = Point::new(0, 0);
450        let p2 = Point::new(3, 4);
451        assert_eq!(manhattan_distance(&p1, &p2), 7);
452
453        let p3 = Point::new(5, 0);
454        assert_eq!(manhattan_distance(&p1, &p3), 5);
455    }
456
457    #[test]
458    fn test_check_spacing() {
459        let rect1 = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
460        let rect2 = Rectangle::new(Point::new(10, 0), Point::new(20, 10));
461        assert!(!check_spacing(&rect1, &rect2, 1));
462
463        let rect3 = Rectangle::new(Point::new(12, 0), Point::new(22, 10));
464        assert!(check_spacing(&rect1, &rect3, 1));
465    }
466
467    #[test]
468    fn test_bounding_rect() {
469        let rects = vec![
470            Rectangle::new(Point::new(0, 0), Point::new(10, 10)),
471            Rectangle::new(Point::new(5, 5), Point::new(15, 15)),
472        ];
473
474        let bbox = bounding_rect(&rects).unwrap();
475        assert_eq!(bbox.min, Point::new(0, 0));
476        assert_eq!(bbox.max, Point::new(15, 15));
477    }
478
479    #[test]
480    fn test_total_area() {
481        let rects = vec![
482            Rectangle::new(Point::new(0, 0), Point::new(10, 10)),
483            Rectangle::new(Point::new(5, 5), Point::new(15, 15)),
484        ];
485
486        let area = total_area(&rects);
487        assert_eq!(area, 175);
488    }
489
490    #[test]
491    fn test_from_dimensions() {
492        let origin = Point::new(5, 10);
493        let rect = Rectangle::from_dimensions(origin, 20, 30);
494        assert_eq!(rect.min, origin);
495        assert_eq!(rect.max, Point::new(25, 40));
496    }
497
498    #[test]
499    fn test_rectangle_contains() {
500        let rect = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
501        let inner = Rectangle::new(Point::new(2, 2), Point::new(8, 8));
502        let outer = Rectangle::new(Point::new(-5, -5), Point::new(15, 15));
503
504        assert!(rect.contains(&inner));
505        assert!(!rect.contains(&outer));
506    }
507
508    #[test]
509    fn test_rectangle_contains_point() {
510        let rect = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
511        let inside = Point::new(5, 5);
512        let outside = Point::new(15, 15);
513        let on_edge = Point::new(10, 5);
514
515        assert!(rect.contains_point(&inside));
516        assert!(!rect.contains_point(&outside));
517        assert!(rect.contains_point(&on_edge));
518    }
519
520    #[test]
521    fn test_bounding_rect_method() {
522        let rect1 = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
523        let rect2 = Rectangle::new(Point::new(5, 5), Point::new(15, 15));
524        let bbox = rect1.bounding_rect(&rect2);
525
526        assert_eq!(bbox.min, Point::new(0, 0));
527        assert_eq!(bbox.max, Point::new(15, 15));
528    }
529
530    #[test]
531    fn test_to_polygon() {
532        let rect = Rectangle::new(Point::new(0, 0), Point::new(10, 20));
533        let polygon = rect.to_polygon();
534
535        assert_eq!(polygon.vertices().len(), 4);
536        assert!(polygon.is_rectilinear());
537    }
538
539    #[test]
540    fn test_bounding_rect_empty() {
541        let rects: Vec<Rectangle<i32>> = vec![];
542        assert!(bounding_rect(&rects).is_none());
543    }
544
545    #[test]
546    fn test_total_area_empty() {
547        let rects: Vec<Rectangle<i32>> = vec![];
548        assert_eq!(total_area(&rects), 0);
549    }
550
551    #[test]
552    fn test_manhattan_distance_reverse() {
553        // Test case where p2 > p1 (different branch)
554        let p1 = Point::new(5, 3);
555        let p2 = Point::new(1, 0);
556        assert_eq!(manhattan_distance(&p1, &p2), 7); // |5-1| + |3-0| = 7
557    }
558
559    #[test]
560    fn test_manhattan_distance_same() {
561        // Test case where coordinates are equal
562        let p1 = Point::new(5, 5);
563        let p2 = Point::new(5, 5);
564        assert_eq!(manhattan_distance(&p1, &p2), 0);
565    }
566
567    #[test]
568    fn test_check_spacing_vertical() {
569        // Test vertical spacing
570        let rect1 = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
571        let rect2 = Rectangle::new(Point::new(0, 10), Point::new(10, 20));
572        assert!(!check_spacing(&rect1, &rect2, 1)); // touching
573
574        let rect3 = Rectangle::new(Point::new(0, 12), Point::new(10, 22));
575        assert!(check_spacing(&rect1, &rect3, 1)); // spacing of 2
576    }
577
578    #[test]
579    fn test_check_spacing_overlapping() {
580        // Test case where rectangles overlap
581        let rect1 = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
582        let rect2 = Rectangle::new(Point::new(5, 5), Point::new(15, 15));
583        assert!(!check_spacing(&rect1, &rect2, 1)); // overlapping
584    }
585
586    #[test]
587    fn test_rectangle_intersect_non_overlapping() {
588        let r1 = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
589        let r2 = Rectangle::new(Point::new(20, 20), Point::new(30, 30));
590        assert!(r1.intersect(&r2).is_none());
591    }
592
593    #[test]
594    fn test_detect_overlap_empty() {
595        let rects: Vec<Rectangle<i32>> = vec![];
596        assert!(detect_overlap(&rects).is_none());
597    }
598
599    #[test]
600    fn test_detect_overlap_single() {
601        let rects = vec![Rectangle::new(Point::new(0, 0), Point::new(10, 10))];
602        assert!(detect_overlap(&rects).is_none());
603    }
604
605    #[test]
606    fn test_detect_overlap_non_overlapping() {
607        let rects = vec![
608            Rectangle::new(Point::new(0, 0), Point::new(10, 10)),
609            Rectangle::new(Point::new(20, 20), Point::new(30, 30)),
610        ];
611        assert!(detect_overlap(&rects).is_none());
612    }
613
614    #[test]
615    fn test_detect_overlap_three_rects() {
616        // First and third overlap, second is in between
617        let rects = vec![
618            Rectangle::new(Point::new(0, 0), Point::new(10, 10)),
619            Rectangle::new(Point::new(15, 15), Point::new(25, 25)),
620            Rectangle::new(Point::new(5, 5), Point::new(12, 12)), // overlaps with first
621        ];
622        let result = detect_overlap(&rects);
623        assert!(result.is_some());
624        // Should find overlap between 0 and 2 (or 2 and 0)
625        let (i, j) = result.unwrap();
626        assert!((i == 0 && j == 2) || (i == 2 && j == 0));
627    }
628
629    #[test]
630    fn test_check_spacing_x_overlap_y_separate() {
631        // Rectangles that overlap in x but are separated in y
632        let r1 = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
633        let r2 = Rectangle::new(Point::new(5, 20), Point::new(15, 30));
634        // x: [0,10] and [5,15] overlap; y: [0,10] and [20,30] separated by 10
635        assert!(check_spacing(&r1, &r2, 10));
636        assert!(!check_spacing(&r1, &r2, 11));
637    }
638
639    #[test]
640    fn test_check_spacing_vertical_overlap_horizontal_separate() {
641        // Rectangles that overlap in y but are separated in x
642        let r1 = Rectangle::new(Point::new(0, 0), Point::new(10, 10));
643        let r2 = Rectangle::new(Point::new(20, 5), Point::new(30, 15));
644        assert!(check_spacing(&r1, &r2, 10));
645        assert!(!check_spacing(&r1, &r2, 11));
646    }
647}