• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kermitt2 / grobid / 400

pending completion
400

push

circleci

update log levels

14847 of 37500 relevant lines covered (39.59%)

0.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.1
/grobid-core/src/main/java/org/grobid/core/layout/BoundingBox.java
1
package org.grobid.core.layout;
2

3
import com.fasterxml.jackson.core.JsonGenerator;
4

5
import org.slf4j.Logger;
6
import org.slf4j.LoggerFactory;
7

8
import java.io.IOException;
9

10
/**
11
 * Represents a bounding box to identify area in the original PDF
12
 */
13
public class BoundingBox implements Comparable {
14
    private static final Logger LOGGER = LoggerFactory.getLogger(BoundingBox.class);
1✔
15
    private int page;
16
    private double x, y, width, height;
17

18
    private double x2, y2;
19

20
    private BoundingBox(int page, double x, double y, double width, double height) {
1✔
21
        this.page = page;
1✔
22
        this.x = x;
1✔
23
        this.y = y;
1✔
24
        this.width = width;
1✔
25
        this.height = height;
1✔
26
        this.x2 = x + width;
1✔
27
        this.y2 = y + height;
1✔
28
    }
1✔
29

30
    public static BoundingBox fromTwoPoints(int page, double x1, double y1, double x2, double y2) {
31
        if (x1 > x2 || y1 > y2) {
1✔
32
            throw new IllegalArgumentException("Invalid points provided: (" + x1 + ";" + y1 + ")-(" + x2 + ";" + y2 + ")");
×
33
        }
34
        return new BoundingBox(page, x1, y1, x2 - x1, y2 - y1);
1✔
35
    }
36

37
    public static BoundingBox fromString(String coords) {
38
        try {
39
            String[] split = coords.split(",");
×
40

41
            Long pageNum = Long.valueOf(split[0], 10);
×
42

43
            float x = Float.parseFloat(split[1]);
×
44
            float y = Float.parseFloat(split[2]);
×
45
            float w = Float.parseFloat(split[3]);
×
46
            float h = Float.parseFloat(split[4]);
×
47

48
            return new BoundingBox(pageNum.intValue(), x, y, w, h);
×
49
        } catch (Exception e) {
×
50
            throw new RuntimeException(e);
×
51
        }
52
    }
53

54
    public static BoundingBox fromPointAndDimensions(int page, double x, double y, double width, double height) {
55
        return new BoundingBox(page, x, y, width, height);
1✔
56
    }
57

58
    public static BoundingBox fromLayoutToken(LayoutToken tok) {
59
        return BoundingBox.fromPointAndDimensions(tok.getPage(), tok.getX(), tok.getY(), tok.getWidth(), tok.getHeight());
1✔
60
    }
61

62
    public boolean intersect(BoundingBox b) {
63
        double ax1 = this.x;
1✔
64
        double ax2 = this.x2;
1✔
65
        double ay1 = this.y;
1✔
66
        double ay2 = this.y2;
1✔
67

68
        double bx1 = b.x;
1✔
69
        double bx2 = b.x2;
1✔
70
        double by1 = b.y;
1✔
71
        double by2 = b.y2;
1✔
72

73

74
        if (ax2 < bx1) return false;
1✔
75
        else if (ax1 > bx2) return false;
1✔
76
        else if (ay2 < by1) return false;
1✔
77
        else if (ay1 > by2) return false;
1✔
78
        else
79
            return true;
1✔
80
    }
81

82
    public int getPage() {
83
        return page;
1✔
84
    }
85

86
    public double getX() {
87
        return x;
1✔
88
    }
89

90
    public double getY() {
91
        return y;
1✔
92
    }
93

94
    public double getWidth() {
95
        return width;
1✔
96
    }
97

98
    public double getHeight() {
99
        return height;
1✔
100
    }
101

102
    public double getX2() {
103
        return x2;
1✔
104
    }
105

106
    public double getY2() {
107
        return y2;
1✔
108
    }
109

110
    public BoundingBox boundBox(BoundingBox o) {
111
        if (this.page != o.page) {
1✔
112
            throw new IllegalStateException("Cannot compute a bounding box for different pages");
×
113
        }
114
        return fromTwoPoints(o.page, Math.min(this.x, o.x), Math.min(this.y, o.y), Math.max(this.x2, o.x2), Math.max(this.y2, o.y2));
1✔
115
    }
116

117
    public BoundingBox boundBoxExcludingAnotherPage(BoundingBox o) {
118
        if (this.page != o.page) {
1✔
119
            LOGGER.debug("Cannot compute a bounding box for different pages: " + this + " and " + o + "; skipping");
1✔
120
            return this;
1✔
121
        }
122
        return fromTwoPoints(o.page, Math.min(this.x, o.x), Math.min(this.y, o.y), Math.max(this.x2, o.x2), Math.max(this.y2, o.y2));
1✔
123
    }
124

125

126
    public boolean contains(BoundingBox b) {
127
        return x <= b.x && y <= b.y && x2 >= b.x2 && y2 >= b.y2;
1✔
128
    }
129

130
    private double dist(double x1, double y1, double x2, double y2) {
131
        return Math.sqrt((x2 - x1) * (x2 - 1) + (y2 - y1) * (y2 - y1));
1✔
132
    }
133

134
    public double verticalDistanceTo(BoundingBox to) {
135
        //the current box is completely "bottomer"
136
        boolean bottom = to.y2 < y;
×
137
        boolean top = y2 < to.y;
×
138

139
        if (bottom) {
×
140
            return y - to.y2;
×
141
        } else if (top) {
×
142
            return to.y - y2;
×
143
        }
144

145
        return 0;
×
146
    }
147

148
    public double area() {
149
        return width * height;
1✔
150
    }
151
    public double distanceTo(BoundingBox to) {
152
        if (this.page != to.page) {
1✔
153
            return 1000 * Math.abs(this.page - to.page);
1✔
154
        }
155

156
        //the current box is completely "lefter"
157

158
        boolean left = x2 < to.x;
1✔
159
        boolean right = to.x2 < x;
1✔
160
        boolean bottom = to.y2 < y;
1✔
161
        boolean top = y2 < to.y;
1✔
162
        if (top && left) {
1✔
163
            return dist(x2, y2, to.x, y);
×
164
        } else if (left && bottom) {
1✔
165
            return dist(x2, y, to.x, to.y2);
1✔
166
        } else if (bottom && right) {
1✔
167
            return dist(x, y, to.x2, to.y2);
1✔
168
        } else if (right && top) {
1✔
169
            return dist(x, y2, to.x2, to.y);
1✔
170
        } else if (left) {
1✔
171
            return to.x - x2;
×
172
        } else if (right) {
1✔
173
            return x - to.x2;
1✔
174
        } else if (bottom) {
1✔
175
            return y - to.y2;
1✔
176
        } else if (top) {
1✔
177
            return to.y - y2;
1✔
178
        } else {
179
            return 0;
1✔
180
        }
181
    }
182
        
183
    public BoundingBox boundingBoxIntersection(BoundingBox b) {
184
                if (!this.intersect(b))
1✔
185
                        return null;
1✔
186
                
187
        double ax1 = this.x;
1✔
188
        double ax2 = this.x2;
1✔
189
        double ay1 = this.y;
1✔
190
        double ay2 = this.y2;
1✔
191

192
        double bx1 = b.x;
1✔
193
        double bx2 = b.x2;
1✔
194
        double by1 = b.y;
1✔
195
        double by2 = b.y2;
1✔
196

197
                double ix1 = 0.0;
1✔
198
                if (ax1 > bx1)
1✔
199
                        ix1 = ax1;
1✔
200
                else 
201
                        ix1 = bx1;
1✔
202
                
203
                double iy1 = 0.0;
1✔
204
                if (ay1 > by1)
1✔
205
                        iy1 = ay1;
×
206
                else 
207
                        iy1 = by1;
1✔
208
                
209
                double ix2 = 0.0;
1✔
210
                if (ax2 > bx2)
1✔
211
                        ix2 = bx2;
1✔
212
                else 
213
                        ix2 = ax2;
1✔
214
                
215
                double iy2 = 0.0;
1✔
216
                if (ay2 > by2)
1✔
217
                        iy2 = by2;
1✔
218
                else 
219
                        iy2 = ay2;
×
220

221
        return fromTwoPoints(page, ix1, iy1, ix2, iy2);
1✔
222
    }
223

224
    @Override
225
    public String toString() {
226
        return String.format("%d,%.2f,%.2f,%.2f,%.2f", page, x, y, width, height);
1✔
227
    }
228

229
    public String toJson() {
230
        StringBuilder builder = new StringBuilder();
×
231
        builder.append("\"p\":").append(page).append(", ");
×
232
        builder.append("\"x\":").append(x).append(", ");
×
233
        builder.append("\"y\":").append(y).append(", ");
×
234
        builder.append("\"w\":").append(width).append(", ");
×
235
        builder.append("\"h\":").append(height);
×
236
        return builder.toString();
×
237
    }
238

239
    public void writeJsonProps(JsonGenerator gen) throws IOException {
240
        gen.writeNumberField("p", page);
1✔
241
        gen.writeNumberField("x", x);
1✔
242
        gen.writeNumberField("y", y);
1✔
243
        gen.writeNumberField("w", width);
1✔
244
        gen.writeNumberField("h", height);
1✔
245
    }
1✔
246

247
    @Override
248
    public boolean equals(Object o) {
249
        if (this == o) return true;
1✔
250
        if (!(o instanceof BoundingBox)) return false;
1✔
251

252
        BoundingBox that = (BoundingBox) o;
1✔
253

254
        if (getPage() != that.getPage()) return false;
1✔
255
        if (Double.compare(that.getX(), getX()) != 0) return false;
1✔
256
        if (Double.compare(that.getY(), getY()) != 0) return false;
1✔
257
        if (Double.compare(that.getWidth(), getWidth()) != 0) return false;
1✔
258
        return Double.compare(that.getHeight(), getHeight()) == 0;
1✔
259
    }
260

261
    @Override
262
    public int compareTo(Object otherBox) {
263
        if (this.equals(otherBox)) 
×
264
            return 0;
×
265

266
        if (!(otherBox instanceof BoundingBox)) 
×
267
            return -1;
×
268

269
        BoundingBox that = (BoundingBox) otherBox;
×
270

271
        // the rest of position comparison is using the barycenter of the boxes
272
        double thisCenterX = x + (width/2);
×
273
        double thisCenterY = y + (height/2);
×
274
        double otherCenterX = that.x + (that.width/2);
×
275
        double otherCenterY = that.y+ (that.height/2);
×
276
        if (Double.compare(thisCenterY, otherCenterY) == 0)
×
277
            return Double.compare(thisCenterX, otherCenterX);
×
278
        else 
279
            return Double.compare(thisCenterY, otherCenterY);
×
280
    }
281

282
    @Override
283
    public int hashCode() {
284
        int result;
285
        long temp;
286
        result = getPage();
×
287
        temp = Double.doubleToLongBits(getX());
×
288
        result = 31 * result + (int) (temp ^ (temp >>> 32));
×
289
        temp = Double.doubleToLongBits(getY());
×
290
        result = 31 * result + (int) (temp ^ (temp >>> 32));
×
291
        temp = Double.doubleToLongBits(getWidth());
×
292
        result = 31 * result + (int) (temp ^ (temp >>> 32));
×
293
        temp = Double.doubleToLongBits(getHeight());
×
294
        result = 31 * result + (int) (temp ^ (temp >>> 32));
×
295
        return result;
×
296
    }
297
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc