wg_engine: merged math functions with common

issue: https://github.com/thorvg/thorvg/issues/2313
This commit is contained in:
Hermet Park 2024-10-17 20:57:04 +09:00 committed by Hermet Park
parent a26a386ccd
commit 1e9609c6f7
3 changed files with 109 additions and 68 deletions

View file

@ -176,6 +176,24 @@ Point normal(const Point& p1, const Point& p2);
void normalize(Point& pt); void normalize(Point& pt);
static inline Point min(const Point& lhs, const Point& rhs)
{
return {std::min(lhs.x, rhs.x), std::min(lhs.y, rhs.y)};
}
static inline Point max(const Point& lhs, const Point& rhs)
{
return {std::max(lhs.x, rhs.x), std::max(lhs.y, rhs.y)};
}
static inline float dot(const Point& lhs, const Point& rhs)
{
return lhs.x * rhs.x + lhs.y * rhs.y;
}
static inline bool zero(const Point& p) static inline bool zero(const Point& p)
{ {
return tvg::zero(p.x) && tvg::zero(p.y); return tvg::zero(p.x) && tvg::zero(p.y);
@ -200,6 +218,12 @@ static inline float length(const Point& a)
} }
static inline float length2(const Point& a)
{
return a.x * a.x + a.y * a.y;
};
static inline bool operator==(const Point& lhs, const Point& rhs) static inline bool operator==(const Point& lhs, const Point& rhs)
{ {
return tvg::equal(lhs.x, rhs.x) && tvg::equal(lhs.y, rhs.y); return tvg::equal(lhs.x, rhs.x) && tvg::equal(lhs.y, rhs.y);
@ -266,6 +290,12 @@ static inline Point operator/(const Point& lhs, const float rhs)
} }
static inline Point operator-(const Point& a)
{
return {-a.x, -a.y};
}
static inline void log(const Point& pt) static inline void log(const Point& pt)
{ {
TVGLOG("COMMON", "Point: [%f %f]", pt.x, pt.y); TVGLOG("COMMON", "Point: [%f %f]", pt.x, pt.y);

View file

@ -1756,10 +1756,10 @@ void Stroker::strokeLineTo(const Point& curr)
mRightBottom.y = mLeftTop.y = curr.y; mRightBottom.y = mLeftTop.y = curr.y;
} }
mLeftTop.x = std::min(mLeftTop.x, min(min(a.x, b.x), min(c.x, d.x))); mLeftTop.x = std::min(mLeftTop.x, std::min(std::min(a.x, b.x), std::min(c.x, d.x)));
mLeftTop.y = std::min(mLeftTop.y, min(min(a.y, b.y), min(c.y, d.y))); mLeftTop.y = std::min(mLeftTop.y, std::min(std::min(a.y, b.y), std::min(c.y, d.y)));
mRightBottom.x = std::max(mRightBottom.x, max(max(a.x, b.x), max(c.x, d.x))); mRightBottom.x = std::max(mRightBottom.x, std::max(std::max(a.x, b.x), std::max(c.x, d.x)));
mRightBottom.y = std::max(mRightBottom.y, max(max(a.y, b.y), max(c.y, d.y))); mRightBottom.y = std::max(mRightBottom.y, std::max(std::max(a.y, b.y), std::max(c.y, d.y)));
} }
@ -1839,10 +1839,10 @@ void Stroker::strokeRound(const Point &prev, const Point& curr, const Point& cen
{ {
if (_calcOrientation(prev, center, curr) == Orientation::Linear) return; if (_calcOrientation(prev, center, curr) == Orientation::Linear) return;
mLeftTop.x = std::min(mLeftTop.x, min(center.x, min(prev.x, curr.x))); mLeftTop.x = std::min(mLeftTop.x, std::min(center.x, std::min(prev.x, curr.x)));
mLeftTop.y = std::min(mLeftTop.y, min(center.y, min(prev.y, curr.y))); mLeftTop.y = std::min(mLeftTop.y, std::min(center.y, std::min(prev.y, curr.y)));
mRightBottom.x = std::max(mRightBottom.x, max(center.x, max(prev.x, curr.x))); mRightBottom.x = std::max(mRightBottom.x, std::max(center.x, std::max(prev.x, curr.x)));
mRightBottom.y = std::max(mRightBottom.y, max(center.y, max(prev.y, curr.y))); mRightBottom.y = std::max(mRightBottom.y, std::max(center.y, std::max(prev.y, curr.y)));
// Fixme: just use bezier curve to calculate step count // Fixme: just use bezier curve to calculate step count
auto count = _bezierCurveCount(_bezFromArc(prev, curr, strokeRadius())); auto count = _bezierCurveCount(_bezFromArc(prev, curr, strokeRadius()));
@ -1943,10 +1943,10 @@ void Stroker::strokeSquare(const Point& p, const Point& outDir)
mResIndices->push(bi); mResIndices->push(bi);
mResIndices->push(di); mResIndices->push(di);
mLeftTop.x = std::min(mLeftTop.x, min(min(a.x, b.x), min(c.x, d.x))); mLeftTop.x = std::min(mLeftTop.x, std::min(std::min(a.x, b.x), std::min(c.x, d.x)));
mLeftTop.y = std::min(mLeftTop.y, min(min(a.y, b.y), min(c.y, d.y))); mLeftTop.y = std::min(mLeftTop.y, std::min(std::min(a.y, b.y), std::min(c.y, d.y)));
mRightBottom.x = std::max(mRightBottom.x, max(max(a.x, b.x), max(c.x, d.x))); mRightBottom.x = std::max(mRightBottom.x, std::max(std::max(a.x, b.x), std::max(c.x, d.x)));
mRightBottom.y = std::max(mRightBottom.y, max(max(a.y, b.y), max(c.y, d.y))); mRightBottom.y = std::max(mRightBottom.y, std::max(std::max(a.y, b.y), std::max(c.y, d.y)));
} }
@ -2481,10 +2481,10 @@ uint32_t BWTessellator::pushVertex(float x, float y)
mRightBottom.x = mLeftTop.x = x; mRightBottom.x = mLeftTop.x = x;
mRightBottom.y = mLeftTop.y = y; mRightBottom.y = mLeftTop.y = y;
} else { } else {
mLeftTop.x = min(mLeftTop.x, x); mLeftTop.x = std::min(mLeftTop.x, x);
mLeftTop.y = min(mLeftTop.y, y); mLeftTop.y = std::min(mLeftTop.y, y);
mRightBottom.x = max(mRightBottom.x, x); mRightBottom.x = std::max(mRightBottom.x, x);
mRightBottom.y = max(mRightBottom.y , y); mRightBottom.y = std::max(mRightBottom.y , y);
} }
return index; return index;

View file

@ -24,26 +24,16 @@
#define _TVG_WG_GEOMETRY_H_ #define _TVG_WG_GEOMETRY_H_
#include <cassert> #include <cassert>
#include <functional>
#include "tvgMath.h" #include "tvgMath.h"
#include "tvgRender.h" #include "tvgRender.h"
// base vector operations
static Point operator-(const Point& a) { return {-a.x, -a.y}; }
static inline float length2(const Point& a) { return a.x*a.x+a.y*a.y; };
static inline float distance2(const Point& a, const Point& b) { return length2(a - b); };
static inline float distance(const Point& a, const Point& b) { return length(a - b); };
static inline float dot(const Point& a, const Point& b) { return a.x*b.x + a.y*b.y; };
static inline Point min(const Point& a, const Point& b) { return { std::min(a.x, b.x), std::min(a.y, b.y) }; };
static inline Point max(const Point& a, const Point& b) { return { std::max(a.x, b.x), std::max(a.y, b.y) }; };
static inline Point lerp(const Point& a, const Point& b, float t) { return a * (1.0f - t) + b * t; };
static inline Point normalize(const Point& a) { float rlen = 1.0f / length(a); return { a.x * rlen, a.y * rlen }; }
// default size of vertex and index buffers // default size of vertex and index buffers
#define WG_POINTS_COUNT 32768 #define WG_POINTS_COUNT 32768
// simple vertex buffer // simple vertex buffer
struct WgVertexBuffer { struct WgVertexBuffer
{
Point vbuff[WG_POINTS_COUNT]; // vertex buffer Point vbuff[WG_POINTS_COUNT]; // vertex buffer
float vdist[WG_POINTS_COUNT]; // distance to previous point float vdist[WG_POINTS_COUNT]; // distance to previous point
float vleng[WG_POINTS_COUNT]; // distance to the first point through all previous points float vleng[WG_POINTS_COUNT]; // distance to the first point through all previous points
@ -54,28 +44,33 @@ struct WgVertexBuffer {
using onPolylineFn = std::function<void(const WgVertexBuffer& buff)>; using onPolylineFn = std::function<void(const WgVertexBuffer& buff)>;
// reset buffer // reset buffer
void reset() { void reset()
{
vcount = 0; vcount = 0;
closed = false; closed = false;
} }
// get the last point with optional index offset from the end // get the last point with optional index offset from the end
Point last(size_t offset = 0) const { Point last(size_t offset = 0) const
{
return vbuff[vcount - offset - 1]; return vbuff[vcount - offset - 1];
} }
// get the last distance with optional index offset from the end // get the last distance with optional index offset from the end
float lastDist(size_t offset = 0) const { float lastDist(size_t offset = 0) const
{
return vdist[vcount - offset - 1]; return vdist[vcount - offset - 1];
} }
// get total length // get total length
float total() const { float total() const
{
return (vcount == 0) ? 0.0f : vleng[vcount-1]; return (vcount == 0) ? 0.0f : vleng[vcount-1];
} }
// get next vertex index by length using binary search // get next vertex index by length using binary search
size_t getIndexByLength(float len) const { size_t getIndexByLength(float len) const
{
if (vcount <= 1) return 0; if (vcount <= 1) return 0;
size_t left = 0; size_t left = 0;
size_t right = vcount - 1; size_t right = vcount - 1;
@ -89,7 +84,8 @@ struct WgVertexBuffer {
} }
// get min and max values of the buffer // get min and max values of the buffer
void getMinMax(Point& pmin, Point& pmax) const { void getMinMax(Point& pmin, Point& pmax) const
{
if (vcount == 0) return; if (vcount == 0) return;
pmax = pmin = vbuff[0]; pmax = pmin = vbuff[0];
for (size_t i = 1; i < vcount; i++) { for (size_t i = 1; i < vcount; i++) {
@ -99,38 +95,43 @@ struct WgVertexBuffer {
} }
// update points distancess to the prev point and total length // update points distancess to the prev point and total length
void updateDistances() { void updateDistances()
{
if (vcount == 0) return; if (vcount == 0) return;
vdist[0] = 0.0f; vdist[0] = 0.0f;
vleng[0] = 0.0f; vleng[0] = 0.0f;
for (size_t i = 1; i < vcount; i++) { for (size_t i = 1; i < vcount; i++) {
vdist[i] = distance(vbuff[i-1], vbuff[i]); vdist[i] = length(vbuff[i-1] - vbuff[i]);
vleng[i] = vleng[i-1] + vdist[i]; vleng[i] = vleng[i-1] + vdist[i];
} }
} }
// close vertex buffer // close vertex buffer
void close() { void close()
{
// check if last point is not to close to the first point // check if last point is not to close to the first point
if (!tvg::zero(distance2(vbuff[0], last()))) if (!tvg::zero(length2(vbuff[0] - last())))
append(vbuff[0]); append(vbuff[0]);
closed = true; closed = true;
} }
// append point // append point
void append(const Point& p) { void append(const Point& p)
{
vbuff[vcount] = p; vbuff[vcount] = p;
vcount++; vcount++;
} }
// append source vertex buffer in index range from start to end (end not included) // append source vertex buffer in index range from start to end (end not included)
void appendRange(const WgVertexBuffer& buff, size_t start_index, size_t end_index) { void appendRange(const WgVertexBuffer& buff, size_t start_index, size_t end_index)
{
for (size_t i = start_index; i < end_index; i++) for (size_t i = start_index; i < end_index; i++)
append(buff.vbuff[i]); append(buff.vbuff[i]);
} }
// append circle (list of triangles) // append circle (list of triangles)
void appendCircle(float radius) { void appendCircle(float radius)
{
// get approx circle length // get approx circle length
float clen = 2.0f * radius * MATH_PI; float clen = 2.0f * radius * MATH_PI;
size_t nsegs = std::max((uint32_t)(clen / 8), 16U); size_t nsegs = std::max((uint32_t)(clen / 8), 16U);
@ -147,9 +148,10 @@ struct WgVertexBuffer {
} }
// append cubic spline // append cubic spline
void appendCubic(const Point& v0, const Point& v1, const Point& v2, const Point& v3) { void appendCubic(const Point& v0, const Point& v1, const Point& v2, const Point& v3)
{
// get approx cubic length // get approx cubic length
float clen = distance(v0, v1) + distance(v1, v2) + distance(v2, v3); float clen = length(v0 - v1) + length(v1 - v2) + length(v2 - v3);
size_t nsegs = std::max((uint32_t)(clen / 8), 16U); size_t nsegs = std::max((uint32_t)(clen / 8), 16U);
// append cubic // append cubic
Bezier bezier{v0, v1, v2, v3}; Bezier bezier{v0, v1, v2, v3};
@ -158,7 +160,8 @@ struct WgVertexBuffer {
} }
// trim source buffer // trim source buffer
void trim(const WgVertexBuffer& buff, float beg, float end) { void trim(const WgVertexBuffer& buff, float beg, float end)
{
// empty buffer guard // empty buffer guard
if (buff.vcount == 0) return; if (buff.vcount == 0) return;
// initialize // initialize
@ -183,7 +186,8 @@ struct WgVertexBuffer {
// decode path with callback for external prcesses // decode path with callback for external prcesses
void decodePath(const RenderShape& rshape, bool update_dist, onPolylineFn onPolyline) { void decodePath(const RenderShape& rshape, bool update_dist, onPolylineFn onPolyline)
{
// decode path // decode path
reset(); reset();
size_t pntIndex = 0; size_t pntIndex = 0;
@ -215,7 +219,8 @@ struct WgVertexBuffer {
}; };
// simple indexed vertex buffer // simple indexed vertex buffer
struct WgVertexBufferInd { struct WgVertexBufferInd
{
Point vbuff[WG_POINTS_COUNT*16]; Point vbuff[WG_POINTS_COUNT*16];
Point tbuff[WG_POINTS_COUNT*16]; Point tbuff[WG_POINTS_COUNT*16];
uint32_t ibuff[WG_POINTS_COUNT*16]; uint32_t ibuff[WG_POINTS_COUNT*16];
@ -223,12 +228,14 @@ struct WgVertexBufferInd {
size_t icount = 0; size_t icount = 0;
// reset buffer // reset buffer
void reset() { void reset()
{
icount = vcount = 0; icount = vcount = 0;
} }
// get min and max values of the buffer // get min and max values of the buffer
void getMinMax(Point& pmin, Point& pmax) const { void getMinMax(Point& pmin, Point& pmax) const
{
if (vcount == 0) return; if (vcount == 0) return;
pmax = pmin = vbuff[0]; pmax = pmin = vbuff[0];
for (size_t i = 1; i < vcount; i++) { for (size_t i = 1; i < vcount; i++) {
@ -238,7 +245,8 @@ struct WgVertexBufferInd {
} }
// append quad - two triangles formed from four points // append quad - two triangles formed from four points
void appendQuad(const Point& p0, const Point& p1, const Point& p2, const Point& p3) { void appendQuad(const Point& p0, const Point& p1, const Point& p2, const Point& p3)
{
// append vertexes // append vertexes
vbuff[vcount+0] = p0; vbuff[vcount+0] = p0;
vbuff[vcount+1] = p1; vbuff[vcount+1] = p1;
@ -257,7 +265,8 @@ struct WgVertexBufferInd {
} }
// dash buffer by pattern // dash buffer by pattern
void appendStrokesDashed(const WgVertexBuffer& buff, const RenderStroke* rstroke) { void appendStrokesDashed(const WgVertexBuffer& buff, const RenderStroke* rstroke)
{
// dashed buffer // dashed buffer
WgVertexBuffer dashed; WgVertexBuffer dashed;
dashed.reset(); dashed.reset();
@ -300,7 +309,8 @@ struct WgVertexBufferInd {
} }
// append buffer with optional offset // append buffer with optional offset
void appendBuffer(const WgVertexBuffer& buff, Point offset = Point{0.0f, 0.0f}) { void appendBuffer(const WgVertexBuffer& buff, Point offset = Point{0.0f, 0.0f})
{
for (uint32_t i = 0; i < buff.vcount; i++ ) { for (uint32_t i = 0; i < buff.vcount; i++ ) {
vbuff[vcount + i] = buff.vbuff[i] + offset; vbuff[vcount + i] = buff.vbuff[i] + offset;
ibuff[icount + i] = vcount + i; ibuff[icount + i] = vcount + i;
@ -309,15 +319,15 @@ struct WgVertexBufferInd {
icount += buff.vcount; icount += buff.vcount;
}; };
// append line void appendLine(const Point& v0, const Point& v1, float dist, float halfWidth)
void appendLine(const Point& v0, const Point& v1, float dist, float halfWidth) { {
Point sub = v1 - v0; Point sub = v1 - v0;
Point nrm = { +sub.y / dist * halfWidth, -sub.x / dist * halfWidth }; Point nrm = { +sub.y / dist * halfWidth, -sub.x / dist * halfWidth };
appendQuad(v0 - nrm, v0 + nrm, v1 - nrm, v1 + nrm); appendQuad(v0 - nrm, v0 + nrm, v1 - nrm, v1 + nrm);
} }
// append bevel joint void appendBevel(const Point& v0, const Point& v1, const Point& v2, float dist1, float dist2, float halfWidth)
void appendBevel(const Point& v0, const Point& v1, const Point& v2, float dist1, float dist2, float halfWidth) { {
Point sub1 = v1 - v0; Point sub1 = v1 - v0;
Point sub2 = v2 - v1; Point sub2 = v2 - v1;
Point nrm1 { +sub1.y / dist1 * halfWidth, -sub1.x / dist1 * halfWidth }; Point nrm1 { +sub1.y / dist1 * halfWidth, -sub1.x / dist1 * halfWidth };
@ -325,15 +335,16 @@ struct WgVertexBufferInd {
appendQuad(v1 - nrm1, v1 + nrm1, v1 - nrm2, v1 + nrm2); appendQuad(v1 - nrm1, v1 + nrm1, v1 - nrm2, v1 + nrm2);
} }
// append miter joint void appendMiter(const Point& v0, const Point& v1, const Point& v2, float dist1, float dist2, float halfWidth, float miterLimit)
void appendMiter(const Point& v0, const Point& v1, const Point& v2, float dist1, float dist2, float halfWidth, float miterLimit) { {
Point sub1 = v1 - v0; auto sub1 = v1 - v0;
Point sub2 = v2 - v1; auto sub2 = v2 - v1;
Point nrm1 { +sub1.y / dist1, -sub1.x / dist1 }; auto nrm1 = Point{+sub1.y / dist1, -sub1.x / dist1};
Point nrm2 { +sub2.y / dist2, -sub2.x / dist2 }; auto nrm2 = Point{+sub2.y / dist2, -sub2.x / dist2};
Point offset1 = nrm1 * halfWidth; auto offset1 = nrm1 * halfWidth;
Point offset2 = nrm2 * halfWidth; auto offset2 = nrm2 * halfWidth;
Point nrm = normalize(nrm1 + nrm2); auto nrm = nrm1 + nrm2;
normalize(nrm);
float cosine = dot(nrm, nrm1); float cosine = dot(nrm, nrm1);
if (tvg::zero(cosine)) return; if (tvg::zero(cosine)) return;
float angle = std::acos(dot(nrm1, -nrm2)); float angle = std::acos(dot(nrm1, -nrm2));
@ -347,16 +358,16 @@ struct WgVertexBufferInd {
} }
} }
// append square cap void appendSquare(Point v0, Point v1, float dist, float halfWidth)
void appendSquare(Point v0, Point v1, float dist, float halfWidth) { {
Point sub = v1 - v0; Point sub = v1 - v0;
Point offset = sub / dist * halfWidth; Point offset = sub / dist * halfWidth;
Point nrm = { +offset.y, -offset.x }; Point nrm = { +offset.y, -offset.x };
appendQuad(v1 - nrm, v1 + nrm, v1 + offset - nrm, v1 + offset + nrm); appendQuad(v1 - nrm, v1 + nrm, v1 + offset - nrm, v1 + offset + nrm);
} }
// append strokes void appendStrokes(const WgVertexBuffer& buff, const RenderStroke* rstroke)
void appendStrokes(const WgVertexBuffer& buff, const RenderStroke* rstroke) { {
assert(rstroke); assert(rstroke);
// empty buffer gueard // empty buffer gueard
if (buff.vcount < 2) return; if (buff.vcount < 2) return;