File: rectangle.rb

package info (click to toggle)
ruby-pdf-reader 2.15.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 33,512 kB
  • sloc: ruby: 11,959; sh: 46; makefile: 11
file content (136 lines) | stat: -rw-r--r-- 3,716 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# coding: utf-8
# typed: strict
# frozen_string_literal: true

module PDF
  class Reader

    # PDFs represent rectangles all over the place. They're 4 element arrays, like this:
    #
    #     [A, B, C, D]
    #
    # Four element arrays are yucky to work with though, so here's a class that's better.
    # Initialize it with the 4 elements, and get utility functions (width, height, etc)
    # for free.
    #
    # By convention the first two elements are x1, y1, the co-ords for the bottom left corner
    # of the rectangle. The third and fourth elements are x2, y2, the co-ords for the top left
    # corner of the rectangle. It's valid for the alternative corners to be used though, so
    # we don't assume which is which.
    #
    class Rectangle

      #: PDF::Reader::Point
      attr_reader :bottom_left

      #: PDF::Reader::Point
      attr_reader :bottom_right

      #: PDF::Reader::Point
      attr_reader :top_left

      #: PDF::Reader::Point
      attr_reader :top_right

      #: (Numeric, Numeric, Numeric, Numeric) -> void
      def initialize(x1, y1, x2, y2)
        @bottom_left = Point.new(0,0) #: PDF::Reader::Point
        @bottom_right = Point.new(0,0) #: PDF::Reader::Point
        @top_left = Point.new(0,0) #: PDF::Reader::Point
        @top_right = Point.new(0,0) #: PDF::Reader::Point
        set_corners(x1, y1, x2, y2)
      end

      #: (Array[Numeric]) -> PDF::Reader::Rectangle
      def self.from_array(arr)
        if arr.size != 4
          raise ArgumentError, "Only 4-element Arrays can be converted to a Rectangle"
        end

        PDF::Reader::Rectangle.new(
          arr[0].to_f,
          arr[1].to_f,
          arr[2].to_f,
          arr[3].to_f,
        )
      end

      #: (PDF::Reader::Rectangle) -> bool
      def ==(other)
        to_a == other.to_a
      end

      #: () -> Numeric
      def height
        top_right.y - bottom_right.y
      end

      #: () -> Numeric
      def width
        bottom_right.x - bottom_left.x
      end

      #: (PDF::Reader::Point) -> bool
      def contains?(point)
        point.x >= bottom_left.x && point.x <= top_right.x &&
          point.y >= bottom_left.y && point.y <= top_right.y
      end

      # A pdf-style 4-number array
      #: () -> Array[Numeric]
      def to_a
        [
          bottom_left.x,
          bottom_left.y,
          top_right.x,
          top_right.y,
        ]
      end

      #: (Integer) -> void
      def apply_rotation(degrees)
        return if degrees != 90 && degrees != 180 && degrees != 270

        if degrees == 90
          new_x1 = bottom_left.x
          new_y1 = bottom_left.y - width
          new_x2 = bottom_left.x + height
          new_y2 = bottom_left.y
        elsif degrees == 180
          new_x1 = bottom_left.x - width
          new_y1 = bottom_left.y - height
          new_x2 = bottom_left.x
          new_y2 = bottom_left.y
        elsif degrees == 270
          new_x1 = bottom_left.x - height
          new_y1 = bottom_left.y
          new_x2 = bottom_left.x
          new_y2 = bottom_left.y + width
        end
        set_corners(new_x1 || 0, new_y1 || 0, new_x2 || 0, new_y2 || 0)
      end

      private

      #: (Numeric, Numeric, Numeric, Numeric) -> void
      def set_corners(x1, y1, x2, y2)
        @bottom_left = PDF::Reader::Point.new(
          [x1, x2].min,
          [y1, y2].min,
        )
        @bottom_right = PDF::Reader::Point.new(
          [x1, x2].max,
          [y1, y2].min,
        )
        @top_left = PDF::Reader::Point.new(
          [x1, x2].min,
          [y1, y2].max,
        )
        @top_right = PDF::Reader::Point.new(
          [x1, x2].max,
          [y1, y2].max,
        )
      end
    end
  end
end