mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-24 23:28:57 +00:00
wg_engine: merged math functions with common
issue: https://github.com/thorvg/thorvg/issues/2313
This commit is contained in:
parent
a26a386ccd
commit
1e9609c6f7
3 changed files with 109 additions and 68 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue