// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later // Copyright 2010, SIL International, All rights reserved. #pragma once #include #include "inc/Main.h" #include "inc/List.h" #include "inc/json.h" #include "inc/Position.h" // An IntervalSet represents the possible movement of a given glyph in a given direction // (horizontally, vertically, or diagonally). // A vector is needed to represent disjoint ranges, eg, -300..-150, 20..200, 500..750. // Each pair represents the min/max of a sub-range. namespace graphite2 { class Segment; enum zones_t {SD, XY}; class Zones { struct Exclusion { template static Exclusion weighted(float xmin, float xmax, float f, float a0, float m, float xi, float ai, float c, bool nega); float x, // x position xm, // xmax position c, // constant + sum(MiXi^2) sm, // sum(Mi) smx; // sum(MiXi) bool open; Exclusion(float x, float w, float smi, float smxi, float c); Exclusion & operator += (Exclusion const & rhs); uint8 outcode(float p) const; Exclusion split_at(float p); void left_trim(float p); bool track_cost(float & cost, float & x, float origin) const; private: float test_position(float origin) const; float cost(float x) const; }; typedef Vector exclusions; typedef exclusions::iterator iterator; typedef Exclusion * pointer; typedef Exclusion & reference; typedef std::reverse_iterator reverse_iterator; public: typedef exclusions::const_iterator const_iterator; typedef Exclusion const * const_pointer; typedef Exclusion const & const_reference; typedef std::reverse_iterator const_reverse_iterator; #if !defined GRAPHITE2_NTRACING struct Debug { Exclusion _excl; bool _isdel; Vector _env; Debug(Exclusion *e, bool isdel, json *dbg) : _excl(*e), _isdel(isdel), _env(dbg->getenvs()) { }; }; typedef Vector debugs; typedef debugs::const_iterator idebugs; void addDebug(Exclusion *e); void removeDebug(float pos, float posm); void setdebug(json *dbgout) { _dbg = dbgout; } idebugs dbgs_begin() const { return _dbgs.begin(); } idebugs dbgs_end() const { return _dbgs.end(); } void jsonDbgOut(Segment *seg) const; Position position() const { return Position(_pos, _posm); } #endif Zones(); template void initialise(float xmin, float xmax, float margin_len, float margin_weight, float ao); void exclude(float xmin, float xmax); void exclude_with_margins(float xmin, float xmax, int axis); template void weighted(float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega); void weightedAxis(int axis, float xmin, float xmax, float f, float a0, float mi, float xi, float ai, float c, bool nega); float closest( float origin, float &cost) const; const_iterator begin() const { return _exclusions.begin(); } const_iterator end() const { return _exclusions.end(); } private: exclusions _exclusions; #if !defined GRAPHITE2_NTRACING json * _dbg; debugs _dbgs; #endif float _margin_len, _margin_weight, _pos, _posm; void insert(Exclusion e); void remove(float x, float xm); const_iterator find_exclusion_under(float x) const; }; inline Zones::Zones() : _margin_len(0), _margin_weight(0), _pos(0), _posm(0) { #if !defined GRAPHITE2_NTRACING _dbg = 0; #endif _exclusions.reserve(8); } inline Zones::Exclusion::Exclusion(float x_, float xm_, float smi, float smxi, float c_) : x(x_), xm(xm_), c(c_), sm(smi), smx(smxi), open(false) { } template inline void Zones::initialise(float xmin, float xmax, float margin_len, float margin_weight, float a0) { _margin_len = margin_len; _margin_weight = margin_weight; _pos = xmin; _posm = xmax; _exclusions.clear(); _exclusions.push_back(Exclusion::weighted(xmin, xmax, 1, a0, 0, 0, 0, 0, false)); _exclusions.front().open = true; #if !defined GRAPHITE2_NTRACING _dbgs.clear(); #endif } inline void Zones::exclude(float xmin, float xmax) { remove(xmin, xmax); } template inline void Zones::weighted(float xmin, float xmax, float f, float a0, float m, float xi, float ai, float c, bool nega) { insert(Exclusion::weighted(xmin, xmax, f, a0, m, xi, ai, c, nega)); } inline void Zones::weightedAxis(int axis, float xmin, float xmax, float f, float a0, float m, float xi, float ai, float c, bool nega) { if (axis < 2) weighted(xmin, xmax, f, a0, m, xi, ai, c, nega); else weighted(xmin, xmax, f, a0, m, xi, ai, c, nega); } #if !defined GRAPHITE2_NTRACING inline void Zones::addDebug(Exclusion *e) { if (_dbg) _dbgs.push_back(Debug(e, false, _dbg)); } inline void Zones::removeDebug(float pos, float posm) { if (_dbg) { Exclusion e(pos, posm, 0, 0, 0); _dbgs.push_back(Debug(&e, true, _dbg)); } } #endif template<> inline Zones::Exclusion Zones::Exclusion::weighted(float xmin, float xmax, float f, float a0, float m, float xi, GR_MAYBE_UNUSED float ai, float c, GR_MAYBE_UNUSED bool nega) { return Exclusion(xmin, xmax, m + f, m * xi, m * xi * xi + f * a0 * a0 + c); } template<> inline Zones::Exclusion Zones::Exclusion::weighted(float xmin, float xmax, float f, float a0, float m, float xi, float ai,float c, bool nega) { float xia = nega ? xi - ai : xi + ai; return Exclusion(xmin, xmax, 0.25f * (m + 2.f * f), 0.25f * m * xia, 0.25f * (m * xia * xia + 2.f * f * a0 * a0) + c); } } // end of namespace graphite2