Path: blob/master/thirdparty/msdfgen/core/sdf-error-estimation.cpp
14710 views
1#include "sdf-error-estimation.h"23#include <cmath>4#include "arithmetics.hpp"56namespace msdfgen {78void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation) {9if (!(sdf.width > 0 && sdf.height > 0))10return line.setIntersections(std::vector<Scanline::Intersection>());11double pixelY = clamp(projection.projectY(y)-.5, double(sdf.height-1));12if (yAxisOrientation == Y_DOWNWARD)13pixelY = sdf.height-1-pixelY;14int b = (int) floor(pixelY);15int t = b+1;16double bt = pixelY-b;17if (t >= sdf.height) {18b = sdf.height-1;19t = sdf.height-1;20bt = 1;21}22bool inside = false;23std::vector<Scanline::Intersection> intersections;24float lv, rv = mix(*sdf(0, b), *sdf(0, t), bt);25if ((inside = rv > .5f)) {26Scanline::Intersection intersection = { -1e240, 1 };27intersections.push_back(intersection);28}29for (int l = 0, r = 1; r < sdf.width; ++l, ++r) {30lv = rv;31rv = mix(*sdf(r, b), *sdf(r, t), bt);32if (lv != rv) {33double lr = double(.5f-lv)/double(rv-lv);34if (lr >= 0 && lr <= 1) {35Scanline::Intersection intersection = { projection.unprojectX(l+lr+.5), sign(rv-lv) };36intersections.push_back(intersection);37}38}39}40#ifdef MSDFGEN_USE_CPP1141line.setIntersections((std::vector<Scanline::Intersection> &&) intersections);42#else43line.setIntersections(intersections);44#endif45}4647template <int N>48void scanlineMSDF(Scanline &line, const BitmapConstSection<float, N> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation) {49if (!(sdf.width > 0 && sdf.height > 0))50return line.setIntersections(std::vector<Scanline::Intersection>());51double pixelY = clamp(projection.projectY(y)-.5, double(sdf.height-1));52if (yAxisOrientation == Y_DOWNWARD)53pixelY = sdf.height-1-pixelY;54int b = (int) floor(pixelY);55int t = b+1;56double bt = pixelY-b;57if (t >= sdf.height) {58b = sdf.height-1;59t = sdf.height-1;60bt = 1;61}62bool inside = false;63std::vector<Scanline::Intersection> intersections;64float lv[3], rv[3];65rv[0] = mix(sdf(0, b)[0], sdf(0, t)[0], bt);66rv[1] = mix(sdf(0, b)[1], sdf(0, t)[1], bt);67rv[2] = mix(sdf(0, b)[2], sdf(0, t)[2], bt);68if ((inside = median(rv[0], rv[1], rv[2]) > .5f)) {69Scanline::Intersection intersection = { -1e240, 1 };70intersections.push_back(intersection);71}72for (int l = 0, r = 1; r < sdf.width; ++l, ++r) {73lv[0] = rv[0], lv[1] = rv[1], lv[2] = rv[2];74rv[0] = mix(sdf(r, b)[0], sdf(r, t)[0], bt);75rv[1] = mix(sdf(r, b)[1], sdf(r, t)[1], bt);76rv[2] = mix(sdf(r, b)[2], sdf(r, t)[2], bt);77Scanline::Intersection newIntersections[4];78int newIntersectionCount = 0;79for (int i = 0; i < 3; ++i) {80if (lv[i] != rv[i]) {81double lr = double(.5f-lv[i])/double(rv[i]-lv[i]);82if (lr >= 0 && lr <= 1) {83float v[3] = {84mix(lv[0], rv[0], lr),85mix(lv[1], rv[1], lr),86mix(lv[2], rv[2], lr)87};88if (median(v[0], v[1], v[2]) == v[i]) {89newIntersections[newIntersectionCount].x = projection.unprojectX(l+lr+.5);90newIntersections[newIntersectionCount].direction = sign(rv[i]-lv[i]);91++newIntersectionCount;92}93}94}95}96// Sort new intersections97if (newIntersectionCount >= 2) {98if (newIntersections[0].x > newIntersections[1].x)99newIntersections[3] = newIntersections[0], newIntersections[0] = newIntersections[1], newIntersections[1] = newIntersections[3];100if (newIntersectionCount >= 3 && newIntersections[1].x > newIntersections[2].x) {101newIntersections[3] = newIntersections[1], newIntersections[1] = newIntersections[2], newIntersections[2] = newIntersections[3];102if (newIntersections[0].x > newIntersections[1].x)103newIntersections[3] = newIntersections[0], newIntersections[0] = newIntersections[1], newIntersections[1] = newIntersections[3];104}105}106for (int i = 0; i < newIntersectionCount; ++i) {107if ((newIntersections[i].direction > 0) == !inside) {108intersections.push_back(newIntersections[i]);109inside = !inside;110}111}112// Consistency check113float rvScalar = median(rv[0], rv[1], rv[2]);114if ((rvScalar > .5f) != inside && rvScalar != .5f && !intersections.empty()) {115intersections.pop_back();116inside = !inside;117}118}119#ifdef MSDFGEN_USE_CPP11120line.setIntersections((std::vector<Scanline::Intersection> &&) intersections);121#else122line.setIntersections(intersections);123#endif124}125126void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation) {127scanlineMSDF(line, sdf, projection, y, yAxisOrientation);128}129void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation) {130scanlineMSDF(line, sdf, projection, y, yAxisOrientation);131}132133template <int N>134double estimateSDFErrorInner(const BitmapConstSection<float, N> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {135if (sdf.width <= 1 || sdf.height <= 1 || scanlinesPerRow < 1)136return 0;137double subRowSize = 1./scanlinesPerRow;138double xFrom = projection.unprojectX(.5);139double xTo = projection.unprojectX(sdf.width-.5);140double overlapFactor = 1/(xTo-xFrom);141double error = 0;142Scanline refScanline, sdfScanline;143for (int row = 0; row < sdf.height-1; ++row) {144for (int subRow = 0; subRow < scanlinesPerRow; ++subRow) {145double bt = (subRow+.5)*subRowSize;146double y = projection.unprojectY(row+bt+.5);147shape.scanline(refScanline, y);148scanlineSDF(sdfScanline, sdf, projection, y, shape.getYAxisOrientation());149error += 1-overlapFactor*Scanline::overlap(refScanline, sdfScanline, xFrom, xTo, fillRule);150}151}152return error/((sdf.height-1)*scanlinesPerRow);153}154155double estimateSDFError(const BitmapConstSection<float, 1> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {156return estimateSDFErrorInner(sdf, shape, projection, scanlinesPerRow, fillRule);157}158double estimateSDFError(const BitmapConstSection<float, 3> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {159return estimateSDFErrorInner(sdf, shape, projection, scanlinesPerRow, fillRule);160}161double estimateSDFError(const BitmapConstSection<float, 4> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {162return estimateSDFErrorInner(sdf, shape, projection, scanlinesPerRow, fillRule);163}164165// Legacy API166167void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Projection &projection, double y, bool inverseYAxis) {168scanlineSDF(line, sdf, projection, y, inverseYAxis ? MSDFGEN_Y_AXIS_NONDEFAULT_ORIENTATION : MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);169}170171void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Projection &projection, double y, bool inverseYAxis) {172scanlineSDF(line, sdf, projection, y, inverseYAxis ? MSDFGEN_Y_AXIS_NONDEFAULT_ORIENTATION : MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);173}174175void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Projection &projection, double y, bool inverseYAxis) {176scanlineSDF(line, sdf, projection, y, inverseYAxis ? MSDFGEN_Y_AXIS_NONDEFAULT_ORIENTATION : MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);177}178179void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {180scanlineSDF(line, sdf, Projection(scale, translate), y, inverseYAxis);181}182183void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {184scanlineSDF(line, sdf, Projection(scale, translate), y, inverseYAxis);185}186187void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {188scanlineSDF(line, sdf, Projection(scale, translate), y, inverseYAxis);189}190191double estimateSDFError(const BitmapConstSection<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {192return estimateSDFError(sdf, shape, Projection(scale, translate), scanlinesPerRow, fillRule);193}194195double estimateSDFError(const BitmapConstSection<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {196return estimateSDFError(sdf, shape, Projection(scale, translate), scanlinesPerRow, fillRule);197}198199double estimateSDFError(const BitmapConstSection<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {200return estimateSDFError(sdf, shape, Projection(scale, translate), scanlinesPerRow, fillRule);201}202203}204205206