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);
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)
{
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)
{
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)
{
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;
}
mLeftTop.x = std::min(mLeftTop.x, min(min(a.x, b.x), min(c.x, d.x)));
mLeftTop.y = std::min(mLeftTop.y, min(min(a.y, b.y), min(c.y, d.y)));
mRightBottom.x = std::max(mRightBottom.x, max(max(a.x, b.x), max(c.x, d.x)));
mRightBottom.y = std::max(mRightBottom.y, max(max(a.y, b.y), max(c.y, d.y)));
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, std::min(std::min(a.y, b.y), std::min(c.y, d.y)));
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, 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;
mLeftTop.x = std::min(mLeftTop.x, min(center.x, min(prev.x, curr.x)));
mLeftTop.y = std::min(mLeftTop.y, min(center.y, min(prev.y, curr.y)));
mRightBottom.x = std::max(mRightBottom.x, max(center.x, max(prev.x, curr.x)));
mRightBottom.y = std::max(mRightBottom.y, max(center.y, max(prev.y, curr.y)));
mLeftTop.x = std::min(mLeftTop.x, std::min(center.x, std::min(prev.x, curr.x)));
mLeftTop.y = std::min(mLeftTop.y, std::min(center.y, std::min(prev.y, curr.y)));
mRightBottom.x = std::max(mRightBottom.x, std::max(center.x, std::max(prev.x, curr.x)));
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
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(di);
mLeftTop.x = std::min(mLeftTop.x, min(min(a.x, b.x), min(c.x, d.x)));
mLeftTop.y = std::min(mLeftTop.y, min(min(a.y, b.y), min(c.y, d.y)));
mRightBottom.x = std::max(mRightBottom.x, max(max(a.x, b.x), max(c.x, d.x)));
mRightBottom.y = std::max(mRightBottom.y, max(max(a.y, b.y), max(c.y, d.y)));
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, std::min(std::min(a.y, b.y), std::min(c.y, d.y)));
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, 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.y = mLeftTop.y = y;
} else {
mLeftTop.x = min(mLeftTop.x, x);
mLeftTop.y = min(mLeftTop.y, y);
mRightBottom.x = max(mRightBottom.x, x);
mRightBottom.y = max(mRightBottom.y , y);
mLeftTop.x = std::min(mLeftTop.x, x);
mLeftTop.y = std::min(mLeftTop.y, y);
mRightBottom.x = std::max(mRightBottom.x, x);
mRightBottom.y = std::max(mRightBottom.y , y);
}
return index;

View file

@ -24,26 +24,16 @@
#define _TVG_WG_GEOMETRY_H_
#include <cassert>
#include <functional>
#include "tvgMath.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
#define WG_POINTS_COUNT 32768
// simple vertex buffer
struct WgVertexBuffer {
struct WgVertexBuffer
{
Point vbuff[WG_POINTS_COUNT]; // vertex buffer
float vdist[WG_POINTS_COUNT]; // distance to previous point
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)>;
// reset buffer
void reset() {
void reset()
{
vcount = 0;
closed = false;
}
// 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];
}
// 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];
}
// get total length
float total() const {
float total() const
{
return (vcount == 0) ? 0.0f : vleng[vcount-1];
}
// 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;
size_t left = 0;
size_t right = vcount - 1;
@ -89,7 +84,8 @@ struct WgVertexBuffer {
}
// 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;
pmax = pmin = vbuff[0];
for (size_t i = 1; i < vcount; i++) {
@ -99,38 +95,43 @@ struct WgVertexBuffer {
}
// update points distancess to the prev point and total length
void updateDistances() {
void updateDistances()
{
if (vcount == 0) return;
vdist[0] = 0.0f;
vleng[0] = 0.0f;
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];
}
}
// close vertex buffer
void close() {
void close()
{
// 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]);
closed = true;
}
// append point
void append(const Point& p) {
void append(const Point& p)
{
vbuff[vcount] = p;
vcount++;
}
// 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++)
append(buff.vbuff[i]);
}
// append circle (list of triangles)
void appendCircle(float radius) {
void appendCircle(float radius)
{
// get approx circle length
float clen = 2.0f * radius * MATH_PI;
size_t nsegs = std::max((uint32_t)(clen / 8), 16U);
@ -147,9 +148,10 @@ struct WgVertexBuffer {
}
// 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
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);
// append cubic
Bezier bezier{v0, v1, v2, v3};
@ -158,7 +160,8 @@ struct WgVertexBuffer {
}
// trim source buffer
void trim(const WgVertexBuffer& buff, float beg, float end) {
void trim(const WgVertexBuffer& buff, float beg, float end)
{
// empty buffer guard
if (buff.vcount == 0) return;
// initialize
@ -183,7 +186,8 @@ struct WgVertexBuffer {
// 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
reset();
size_t pntIndex = 0;
@ -215,7 +219,8 @@ struct WgVertexBuffer {
};
// simple indexed vertex buffer
struct WgVertexBufferInd {
struct WgVertexBufferInd
{
Point vbuff[WG_POINTS_COUNT*16];
Point tbuff[WG_POINTS_COUNT*16];
uint32_t ibuff[WG_POINTS_COUNT*16];
@ -223,12 +228,14 @@ struct WgVertexBufferInd {
size_t icount = 0;
// reset buffer
void reset() {
void reset()
{
icount = vcount = 0;
}
// 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;
pmax = pmin = vbuff[0];
for (size_t i = 1; i < vcount; i++) {
@ -238,7 +245,8 @@ struct WgVertexBufferInd {
}
// 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
vbuff[vcount+0] = p0;
vbuff[vcount+1] = p1;
@ -257,7 +265,8 @@ struct WgVertexBufferInd {
}
// dash buffer by pattern
void appendStrokesDashed(const WgVertexBuffer& buff, const RenderStroke* rstroke) {
void appendStrokesDashed(const WgVertexBuffer& buff, const RenderStroke* rstroke)
{
// dashed buffer
WgVertexBuffer dashed;
dashed.reset();
@ -300,7 +309,8 @@ struct WgVertexBufferInd {
}
// 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++ ) {
vbuff[vcount + i] = buff.vbuff[i] + offset;
ibuff[icount + i] = vcount + i;
@ -309,15 +319,15 @@ struct WgVertexBufferInd {
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 nrm = { +sub.y / dist * halfWidth, -sub.x / dist * halfWidth };
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 sub2 = v2 - v1;
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);
}
// append miter joint
void appendMiter(const Point& v0, const Point& v1, const Point& v2, float dist1, float dist2, float halfWidth, float miterLimit) {
Point sub1 = v1 - v0;
Point sub2 = v2 - v1;
Point nrm1 { +sub1.y / dist1, -sub1.x / dist1 };
Point nrm2 { +sub2.y / dist2, -sub2.x / dist2 };
Point offset1 = nrm1 * halfWidth;
Point offset2 = nrm2 * halfWidth;
Point nrm = normalize(nrm1 + nrm2);
void appendMiter(const Point& v0, const Point& v1, const Point& v2, float dist1, float dist2, float halfWidth, float miterLimit)
{
auto sub1 = v1 - v0;
auto sub2 = v2 - v1;
auto nrm1 = Point{+sub1.y / dist1, -sub1.x / dist1};
auto nrm2 = Point{+sub2.y / dist2, -sub2.x / dist2};
auto offset1 = nrm1 * halfWidth;
auto offset2 = nrm2 * halfWidth;
auto nrm = nrm1 + nrm2;
normalize(nrm);
float cosine = dot(nrm, nrm1);
if (tvg::zero(cosine)) return;
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 offset = sub / dist * halfWidth;
Point nrm = { +offset.y, -offset.x };
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);
// empty buffer gueard
if (buff.vcount < 2) return;