File size: 4,535 Bytes
34e0b30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
/**
 *                        INTERSEC
 *********************************************************
 * @licstart  The following is the entire license notice for the
 *  JavaScript code in this page.
 *
 * Copyright (C) 2021  Ophir LOJKINE
 *
 *
 * The JavaScript code in this page is free software: you can
 * redistribute it and/or modify it under the terms of the GNU
 * General Public License (GNU GPL) as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version.  The code is distributed WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
 *
 * As additional permission under GNU GPL version 3 section 7, you
 * may distribute non-source (e.g., minimized or compacted) forms of
 * that code without the copy of the GNU GPL normally required by
 * section 4, provided you include this license notice and a URL
 * through which recipients can access the Corresponding Source.
 *
 * @licend
 */

if (
  !SVGGraphicsElement.prototype.transformedBBox ||
  !SVGGraphicsElement.prototype.transformedBBoxContains
) {
  [pointInTransformedBBox, transformedBBoxIntersects] = (function () {
    var get_transform_matrix = function (elem) {
      // Returns the first translate or transform matrix or makes one
      var transform = null;
      for (var i = 0; i < elem.transform.baseVal.numberOfItems; ++i) {
        var baseVal = elem.transform.baseVal[i];
        // quick tests showed that even if one changes only the fields e and f or uses createSVGTransformFromMatrix
        // the brower may add a SVG_TRANSFORM_MATRIX instead of a SVG_TRANSFORM_TRANSLATE
        if (baseVal.type === SVGTransform.SVG_TRANSFORM_MATRIX) {
          transform = baseVal;
          break;
        }
      }
      if (transform == null) {
        transform = elem.transform.baseVal.createSVGTransformFromMatrix(
          Tools.svg.createSVGMatrix(),
        );
        elem.transform.baseVal.appendItem(transform);
      }
      return transform.matrix;
    };

    var transformRelative = function (m, t) {
      return [m.a * t[0] + m.c * t[1], m.b * t[0] + m.d * t[1]];
    };

    var transformAbsolute = function (m, t) {
      return [m.a * t[0] + m.c * t[1] + m.e, m.b * t[0] + m.d * t[1] + m.f];
    };

    SVGGraphicsElement.prototype.transformedBBox = function (scale = 1) {
      bbox = this.getBBox();
      tmatrix = get_transform_matrix(this);
      tmatrix.e /= scale;
      tmatrix.f /= scale;
      return {
        r: transformAbsolute(tmatrix, [bbox.x / scale, bbox.y / scale]),
        a: transformRelative(tmatrix, [bbox.width / scale, 0]),
        b: transformRelative(tmatrix, [0, bbox.height / scale]),
      };
    };

    SVGSVGElement.prototype.transformedBBox = function (scale = 1) {
      bbox = {
        x: this.x.baseVal.value,
        y: this.y.baseVal.value,
        width: this.width.baseVal.value,
        height: this.height.baseVal.value,
      };
      tmatrix = get_transform_matrix(this);
      tmatrix.e /= scale;
      tmatrix.f /= scale;
      return {
        r: transformAbsolute(tmatrix, [bbox.x / scale, bbox.y / scale]),
        a: transformRelative(tmatrix, [bbox.width / scale, 0]),
        b: transformRelative(tmatrix, [0, bbox.height / scale]),
      };
    };

    var pointInTransformedBBox = function ([x, y], { r, a, b }) {
      var d = [x - r[0], y - r[1]];
      var idet = a[0] * b[1] - a[1] * b[0];
      var c1 = (d[0] * b[1] - d[1] * b[0]) / idet;
      var c2 = (d[1] * a[0] - d[0] * a[1]) / idet;
      return c1 >= 0 && c1 <= 1 && c2 >= 0 && c2 <= 1;
    };

    SVGGraphicsElement.prototype.transformedBBoxContains = function (x, y) {
      return pointInTransformedBBox([x, y], this.transformedBBox());
    };

    function transformedBBoxIntersects(bbox_a, bbox_b) {
      var corners = [
        bbox_b.r,
        [bbox_b.r[0] + bbox_b.a[0], bbox_b.r[1] + bbox_b.a[1]],
        [bbox_b.r[0] + bbox_b.b[0], bbox_b.r[1] + bbox_b.b[1]],
        [
          bbox_b.r[0] + bbox_b.a[0] + bbox_b.b[0],
          bbox_b.r[1] + bbox_b.a[1] + bbox_b.b[1],
        ],
      ];
      return corners.every(function (corner) {
        return pointInTransformedBBox(corner, bbox_a);
      });
    }

    SVGGraphicsElement.prototype.transformedBBoxIntersects = function (bbox) {
      return transformedBBoxIntersects(this.transformedBBox(), bbox);
    };

    return [pointInTransformedBBox, transformedBBoxIntersects];
  })();
}