]> O.S.I.I.S - jp/vkvg.git/commitdiff
elliptical_arc, ellipse, rounded_rectangle2
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 6 Jan 2022 10:15:54 +0000 (11:15 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 6 Jan 2022 10:15:54 +0000 (11:15 +0100)
include/vkvg.h
screenshot3.png [new file with mode: 0644]
src/vkvg_context.c
src/vkvg_context_internal.c
src/vkvg_context_internal.h

index 0d60d348cc7105b0c5f05f1553bbbeec3d2a6c7a..931036d5fa31f14a83c59fc2621d175956302d6e 100644 (file)
@@ -1070,6 +1070,25 @@ vkvg_status_t vkvg_rectangle(VkvgContext ctx, float x, float y, float w, float h
 */
 vkvg_public
 vkvg_status_t vkvg_rounded_rectangle (VkvgContext ctx, float x, float y, float w, float h, float radius);
+/**
+* @brief Add an axis aligned rectangle with rounded corners defined in both axis to the current path.
+*
+* Adds a closed sub-path rectangle of the given size to the current path at position (x, y).
+* @param ctx The vkvg context pointer.
+* @param x The x coordinate of the top left corner of the rectangle to emit.
+* @param y The y coordinate of the top left corner of the rectangle to emit.
+* @param w The width in pixel of the rectangle to draw.
+* @param h The height in pixel of the rectangle to draw.
+* @param rx The horizontal radius of the corners.
+* @param ry The vertical radius of the corners.
+* @return VKVG_STATUS_SUCCESS or VKVG_STATUS_INVALID_RECT if width or height is equal to 0.
+*/
+vkvg_public
+void vkvg_rounded_rectangle2 (VkvgContext ctx, float x, float y, float w, float h, float rx, float ry);
+vkvg_public
+void vkvg_ellipse (VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle);
+vkvg_public
+void vkvg_elliptic_arc (VkvgContext ctx, float x2, float y2, bool largeArc, bool counterClockWise, float rx, float ry, float phi);
 /**
  * @brief Stroke command
  *
diff --git a/screenshot3.png b/screenshot3.png
new file mode 100644 (file)
index 0000000..aeba2ba
Binary files /dev/null and b/screenshot3.png differ
index d590694dc5635a6faa8329bae600d49a63bffef4..5f51734378a4cbc0f1379783a2c9fe20a6b9be97 100644 (file)
@@ -1299,3 +1299,56 @@ void vkvg_set_matrix (VkvgContext ctx, const vkvg_matrix_t* matrix){
 void vkvg_get_matrix (VkvgContext ctx, const vkvg_matrix_t* matrix){
        memcpy ((void*)matrix, &ctx->pushConsts.mat, sizeof(vkvg_matrix_t));
 }
+
+void vkvg_elliptic_arc (VkvgContext ctx, float x2, float y2, bool largeArc, bool counterClockWise, float rx, float ry, float phi) {
+       float x1, y1;
+       vkvg_get_current_point(ctx, &x1, &y1);
+       _elliptic_arc(ctx, x1, y1, x2, y2, largeArc, counterClockWise, rx, ry, phi);
+}
+
+void vkvg_ellipse (VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle) {
+       if (ctx->status)
+               return;
+
+       float width_two_thirds = radiusX * 4 / 3;
+
+       float dx1 = sinf(rotationAngle) * radiusY;
+       float dy1 = cosf(rotationAngle) * radiusY;
+       float dx2 = cosf(rotationAngle) * width_two_thirds;
+       float dy2 = sinf(rotationAngle) * width_two_thirds;
+
+       float topCenterX = x - dx1;
+       float topCenterY = y + dy1;
+       float topRightX = topCenterX + dx2;
+       float topRightY = topCenterY + dy2;
+       float topLeftX = topCenterX - dx2;
+       float topLeftY = topCenterY - dy2;
+
+       float bottomCenterX = x + dx1;
+       float bottomCenterY = y - dy1;
+       float bottomRightX = bottomCenterX + dx2;
+       float bottomRightY = bottomCenterY + dy2;
+       float bottomLeftX = bottomCenterX - dx2;
+       float bottomLeftY = bottomCenterY - dy2;
+
+       vkvg_move_to (ctx, bottomCenterX, bottomCenterY);
+       vkvg_curve_to (ctx, bottomRightX, bottomRightY, topRightX, topRightY, topCenterX, topCenterY);
+       vkvg_curve_to (ctx, topLeftX, topLeftY, bottomLeftX, bottomLeftY, bottomCenterX, bottomCenterY);
+       vkvg_close_path (ctx);
+}
+void vkvg_rounded_rectangle2 (VkvgContext ctx, float x, float y, float w, float h, float rx, float ry){
+       vkvg_move_to (ctx, x+rx, y);
+       vkvg_line_to (ctx, x+w-rx, y);
+       vkvg_elliptic_arc(ctx, x+w, y+ry, false, true, rx, ry, 0);
+
+       vkvg_line_to (ctx, x+w, y+h-ry);
+       vkvg_elliptic_arc(ctx, x+w-rx, y+h, false, true, rx, ry, 0);
+
+       vkvg_line_to (ctx, x+rx, y+h);
+       vkvg_elliptic_arc(ctx, x, y+h-ry , false, true, rx, ry, 0);
+
+       vkvg_line_to (ctx, x, y+ry);
+       vkvg_elliptic_arc(ctx, x+rx, y , false, true, rx, ry, 0);
+
+       vkvg_close_path(ctx);
+}
index a3edd2f80f87dfce75190fe96bf2477c847c7c90..5af91aaf3ed65ff8739c67a8fb1c156562fcaaa5 100644 (file)
@@ -1314,6 +1314,132 @@ void _recursive_bezier (VkvgContext ctx, float distanceTolerance,
 }
 #pragma warning(default:4127)
 
+void _elliptic_arc (VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, float _rx, float _ry, float phi) {
+       if (ctx->status)
+               return;
+
+       if (_rx==0||_ry==0) {
+               if (_current_path_is_empty(ctx))
+                       vkvg_move_to(ctx, x1, y1);
+               vkvg_line_to(ctx, x2, y2);
+               return;
+       }
+       float rx = fabsf(_rx);
+       float ry = fabsf(_ry);
+
+       mat2 m = {
+               { cosf (phi), sinf (phi)},
+               {-sinf (phi), cosf (phi)}
+       };
+       vec2 p = {(x1 - x2)/2, (y1 - y2)/2};
+       vec2 p1 = mat2_mult_vec2 (m, p);
+
+       //radii corrections
+       double lambda = powf (p1.x, 2) / powf (rx, 2) + powf (p1.y, 2) / powf (ry, 2);
+       if (lambda > 1) {
+               lambda = sqrtf (lambda);
+               rx *= lambda;
+               ry *= lambda;
+       }
+
+       p = (vec2){rx * p1.y / ry, -ry * p1.x / rx};
+
+       vec2 cp = vec2_mult_s (p, sqrtf (fabsf (
+               (powf (rx,2) * powf (ry,2) - powf (rx,2) * powf (p1.y, 2) - powf (ry,2) * powf (p1.x, 2)) /
+               (powf (rx,2) * powf (p1.y, 2) + powf (ry,2) * powf (p1.x, 2))
+       )));
+
+       if (largeArc == counterClockWise)
+               vec2_inv(&cp);
+
+       m = (mat2) {
+               {cosf (phi),-sinf (phi)},
+               {sinf (phi), cosf (phi)}
+       };
+       p = (vec2){(x1 + x2)/2, (y1 + y2)/2};
+       vec2 c = vec2_add (mat2_mult_vec2(m, cp) , p);
+
+       vec2 u = vec2_unit_x;
+       vec2 v = {(p1.x-cp.x)/rx, (p1.y-cp.y)/ry};
+       double sa = acosf (vec2_dot (u, v) / (fabsf(vec2_length(v)) * fabsf(vec2_length(u))));
+       if (isnanf(sa))
+               sa=M_PIF;
+       if (u.x*v.y-u.y*v.x < 0)
+               sa = -sa;
+
+       u = v;
+       v = (vec2) {(-p1.x-cp.x)/rx, (-p1.y-cp.y)/ry};
+       double delta_theta = acosf (vec2_dot (u, v) / (fabsf(vec2_length (v)) * fabsf(vec2_length (u))));
+       if (isnanf(delta_theta))
+               delta_theta=M_PIF;
+       if (u.x*v.y-u.y*v.x < 0)
+               delta_theta = -delta_theta;
+
+       if (counterClockWise) {
+               if (delta_theta < 0)
+                       delta_theta += M_PIF * 2.0;
+       } else if (delta_theta > 0)
+               delta_theta -= M_PIF * 2.0;
+
+       m = (mat2) {
+               {cosf (phi),-sinf (phi)},
+               {sinf (phi), cosf (phi)}
+       };
+
+       double theta = sa;
+       double ea = sa + delta_theta;
+
+       float step = _get_arc_step(ctx, fminf (rx, ry))*0.1f;
+
+       p = (vec2) {
+               rx * cosf (theta),
+               ry * sinf (theta)
+       };
+       vec2 xy = vec2_add (mat2_mult_vec2 (m, p), c);
+
+       if (_current_path_is_empty(ctx)){
+               _set_curve_start (ctx);
+               _add_point (ctx, xy.x, xy.y);
+       }else{
+               vkvg_line_to(ctx, xy.x, xy.y);
+               _set_curve_start (ctx);
+       }
+
+       _set_curve_start (ctx);
+
+       if (sa < ea) {
+               theta += step;
+               while (theta < ea) {
+                       p = (vec2) {
+                               rx * cosf (theta),
+                               ry * sinf (theta)
+                       };
+                       xy = vec2_add (mat2_mult_vec2 (m, p), c);
+                       _add_point (ctx, xy.x, xy.y);
+                       theta += step;
+               }
+       } else {
+               theta -= step;
+               while (theta > ea) {
+                       p = (vec2) {
+                               rx * cosf (theta),
+                               ry * sinf (theta)
+                       };
+                       xy = vec2_add (mat2_mult_vec2 (m, p), c);
+                       _add_point (ctx, xy.x, xy.y);
+                       theta -= step;
+               }
+       }
+       p = (vec2) {
+               rx * cosf (ea),
+               ry * sinf (ea)
+       };
+       xy = vec2_add (mat2_mult_vec2 (m, p), c);
+       _add_point (ctx, xy.x, xy.y);
+       _set_curve_end(ctx);
+}
+
+
 //Even-Odd inside test with stencil buffer implementation.
 void _poly_fill (VkvgContext ctx){
        //we anticipate the check for vbo buffer size, ibo is not used in poly_fill
index 5bd51f612755783d696e277b8ccf98ebfe55d4ea..699fce7f9f10dfc55b847411aca4a05426172937 100644 (file)
@@ -283,4 +283,6 @@ void _recursive_bezier(VkvgContext ctx, float distanceTolerance,
 void _bezier (VkvgContext ctx,
                          float x1, float y1, float x2, float y2,
                          float x3, float y3, float x4, float y4);
+
+void _elliptic_arc (VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, float _rx, float _ry, float phi);
 #endif