1// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later
2// Copyright 2010, SIL International, All rights reserved.
3
4#pragma once
5
6#include <utility>
7
8#include "inc/Main.h"
9#include "inc/List.h"
10#include "inc/json.h"
11#include "inc/Position.h"
12
13// An IntervalSet represents the possible movement of a given glyph in a given direction
14// (horizontally, vertically, or diagonally).
15// A vector is needed to represent disjoint ranges, eg, -300..-150, 20..200, 500..750.
16// Each pair represents the min/max of a sub-range.
17
18namespace graphite2 {
19
20class Segment;
21
22enum zones_t {SD, XY};
23
24class Zones
25{
26 struct Exclusion
27 {
28 template<zones_t O>
29 static Exclusion weighted(float xmin, float xmax, float f, float a0,
30 float m, float xi, float ai, float c, bool nega);
31
32 float x, // x position
33 xm, // xmax position
34 c, // constant + sum(MiXi^2)
35 sm, // sum(Mi)
36 smx; // sum(MiXi)
37 bool open;
38
39 Exclusion(float x, float w, float smi, float smxi, float c);
40 Exclusion & operator += (Exclusion const & rhs);
41 uint8 outcode(float p) const;
42
43 Exclusion split_at(float p);
44 void left_trim(float p);
45
46 bool track_cost(float & cost, float & x, float origin) const;
47
48 private:
49 float test_position(float origin) const;
50 float cost(float x) const;
51 };
52
53 typedef Vector<Exclusion> exclusions;
54
55 typedef exclusions::iterator iterator;
56 typedef Exclusion * pointer;
57 typedef Exclusion & reference;
58 typedef std::reverse_iterator<iterator> reverse_iterator;
59
60public:
61 typedef exclusions::const_iterator const_iterator;
62 typedef Exclusion const * const_pointer;
63 typedef Exclusion const & const_reference;
64 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
65
66#if !defined GRAPHITE2_NTRACING
67 struct Debug
68 {
69 Exclusion _excl;
70 bool _isdel;
71 Vector<void *> _env;
72
73 Debug(Exclusion *e, bool isdel, json *dbg) : _excl(*e), _isdel(isdel), _env(dbg->getenvs()) { };
74 };
75
76 typedef Vector<Debug> debugs;
77 typedef debugs::const_iterator idebugs;
78 void addDebug(Exclusion *e);
79 void removeDebug(float pos, float posm);
80 void setdebug(json *dbgout) { _dbg = dbgout; }
81 idebugs dbgs_begin() const { return _dbgs.begin(); }
82 idebugs dbgs_end() const { return _dbgs.end(); }
83 void jsonDbgOut(Segment *seg) const;
84 Position position() const { return Position(_pos, _posm); }
85#endif
86
87 Zones();
88 template<zones_t O>
89 void initialise(float xmin, float xmax, float margin_len, float margin_weight, float ao);
90
91 void exclude(float xmin, float xmax);
92 void exclude_with_margins(float xmin, float xmax, int axis);
93
94 template<zones_t O>
95 void weighted(float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega);
96 void weightedAxis(int axis, float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega);
97
98 float closest( float origin, float &cost) const;
99
100 const_iterator begin() const { return _exclusions.begin(); }
101 const_iterator end() const { return _exclusions.end(); }
102
103private:
104 exclusions _exclusions;
105#if !defined GRAPHITE2_NTRACING
106 json * _dbg;
107 debugs _dbgs;
108#endif
109 float _margin_len,
110 _margin_weight,
111 _pos,
112 _posm;
113
114 void insert(Exclusion e);
115 void remove(float x, float xm);
116 const_iterator find_exclusion_under(float x) const;
117};
118
119
120inline
121Zones::Zones()
122: _margin_len(0), _margin_weight(0), _pos(0), _posm(0)
123{
124#if !defined GRAPHITE2_NTRACING
125 _dbg = 0;
126#endif
127 _exclusions.reserve(8);
128}
129
130inline
131Zones::Exclusion::Exclusion(float x_, float xm_, float smi, float smxi, float c_)
132: x(x_), xm(xm_), c(c_), sm(smi), smx(smxi), open(false)
133{ }
134
135template<zones_t O>
136inline
137void Zones::initialise(float xmin, float xmax, float margin_len,
138 float margin_weight, float a0)
139{
140 _margin_len = margin_len;
141 _margin_weight = margin_weight;
142 _pos = xmin;
143 _posm = xmax;
144 _exclusions.clear();
145 _exclusions.push_back(Exclusion::weighted<O>(xmin, xmax, 1, a0, 0, 0, 0, 0, false));
146 _exclusions.front().open = true;
147#if !defined GRAPHITE2_NTRACING
148 _dbgs.clear();
149#endif
150}
151
152inline
153void Zones::exclude(float xmin, float xmax) {
154 remove(xmin, xmax);
155}
156
157template<zones_t O>
158inline
159void Zones::weighted(float xmin, float xmax, float f, float a0,
160 float m, float xi, float ai, float c, bool nega) {
161 insert(Exclusion::weighted<O>(xmin, xmax, f, a0, m, xi, ai, c, nega));
162}
163
164inline
165void Zones::weightedAxis(int axis, float xmin, float xmax, float f, float a0,
166 float m, float xi, float ai, float c, bool nega) {
167 if (axis < 2)
168 weighted<XY>(xmin, xmax, f, a0, m, xi, ai, c, nega);
169 else
170 weighted<SD>(xmin, xmax, f, a0, m, xi, ai, c, nega);
171}
172
173#if !defined GRAPHITE2_NTRACING
174inline
175void Zones::addDebug(Exclusion *e) {
176 if (_dbg)
177 _dbgs.push_back(Debug(e, false, _dbg));
178}
179
180inline
181void Zones::removeDebug(float pos, float posm) {
182 if (_dbg)
183 {
184 Exclusion e(pos, posm, 0, 0, 0);
185 _dbgs.push_back(Debug(&e, true, _dbg));
186 }
187}
188#endif
189
190template<>
191inline
192Zones::Exclusion Zones::Exclusion::weighted<XY>(float xmin, float xmax, float f, float a0,
193 float m, float xi, GR_MAYBE_UNUSED float ai, float c, GR_MAYBE_UNUSED bool nega) {
194 return Exclusion(xmin, xmax,
195 m + f,
196 m * xi,
197 m * xi * xi + f * a0 * a0 + c);
198}
199
200template<>
201inline
202Zones::Exclusion Zones::Exclusion::weighted<SD>(float xmin, float xmax, float f, float a0,
203 float m, float xi, float ai,float c, bool nega) {
204 float xia = nega ? xi - ai : xi + ai;
205 return Exclusion(xmin, xmax,
206 0.25f * (m + 2.f * f),
207 0.25f * m * xia,
208 0.25f * (m * xia * xia + 2.f * f * a0 * a0) + c);
209}
210
211} // end of namespace graphite2
212