feat: add shape transforms

This commit is contained in:
2026-03-11 14:11:03 +00:00
parent 562cbc12da
commit 237bb02a8c
7 changed files with 129 additions and 110 deletions

View File

@@ -1,5 +1,6 @@
#include "primitives.h"
#include "glib.h"
#include "src/core/matrix.h"
#include "src/core/vector.h"
#include <assert.h>
#include <math.h>
@@ -78,9 +79,7 @@ void vektor_circle_set_radius(VektorCircle* circle, double radius) {
circle->radius = radius;
}
void vektor_circle_free(VektorCircle* circle) {
free(circle);
}
void vektor_circle_free(VektorCircle* circle) { free(circle); }
VektorRectangle* vektor_rectangle_new(void) {
VektorRectangle* rct = malloc(sizeof(VektorRectangle));
@@ -146,9 +145,8 @@ VektorBBox vektor_rectangle_get_bbox(VektorPrimitive prim) {
VektorBBox vektor_circle_get_bbox(VektorPrimitive prim) {
return (VektorBBox){
vec2_sub(prim.circle.center, vec2_fromfloat(prim.circle.radius)),
vec2_add(prim.circle.center, vec2_fromfloat(prim.circle.radius))
};
vec2_sub(prim.circle.center, vec2_fromfloat(prim.circle.radius)),
vec2_add(prim.circle.center, vec2_fromfloat(prim.circle.radius))};
}
VektorBBox vektor_primitive_get_bbox(VektorPrimitive prim) {
@@ -178,84 +176,95 @@ VektorBBox vektor_primitive_get_bbox(VektorPrimitive prim) {
// ------ PRIMITIVE HANDLES GENERATION ------
/* [n]: polyline vertices */
void vektor_polyline_create_handles(VektorPolyline* polyline, V2** handleArr, size_t* count) {
void vektor_polyline_create_handles(VektorPolyline* polyline, V2** handleArr,
size_t* count) {
*count = 0;
*handleArr = NULL;
}
/* [n]: polygon vertices */
void vektor_polygon_create_handles(VektorPolygon* polygon, V2** handleArr, size_t* count) {
void vektor_polygon_create_handles(VektorPolygon* polygon, V2** handleArr,
size_t* count) {
*count = 0;
*handleArr = NULL;
}
/* [0]: center; [1]: radius */
void vektor_circle_create_handles(VektorCircle* circle, V2** handleArr, size_t* count) {
void vektor_circle_create_handles(VektorCircle* circle, V2** handleArr,
size_t* count) {
*count = 2;
*handleArr = (V2*)malloc(sizeof(V2)*(*count));
*handleArr = (V2*)malloc(sizeof(V2) * (*count));
(*handleArr)[0] = circle->center;
(*handleArr)[1] = (V2){circle->radius + circle->center.x, circle->center.y};
}
/* [0]: center; [1-4]: corners (l2r, t2b); */
void vektor_rectangle_create_handles(VektorRectangle* rectangle, V2** handleArr, size_t* count) {
void vektor_rectangle_create_handles(VektorRectangle* rectangle, V2** handleArr,
size_t* count) {
*count = 5;
free(*handleArr);
*handleArr = (V2*)malloc(sizeof(V2)*(*count));
*handleArr = (V2*)malloc(sizeof(V2) * (*count));
V2 halfdist = vec2_scale(vec2_sub(rectangle->end, rectangle->start), 0.5f);
V2 center = vec2_add(rectangle->start, halfdist);
g_print("boobs: %f %f\n", rectangle->start.x, rectangle->start.y);
g_print("pussy: %f %f\n", rectangle->end.x, rectangle->end.y);
(*handleArr)[0] = center;
(*handleArr)[1] = vec2_add( center, vec2_mul(halfdist, (V2){-1.0f, 1.0f}) );
(*handleArr)[2] = vec2_add( center, halfdist);
(*handleArr)[3] = vec2_add( center, vec2_mul(halfdist, (V2){-1.0f, -1.0f}) );
(*handleArr)[4] = vec2_add( center, vec2_mul(halfdist, (V2){1.0f, -1.0f}) );
(*handleArr)[1] = vec2_add(center, vec2_mul(halfdist, (V2){-1.0f, 1.0f}));
(*handleArr)[2] = vec2_add(center, halfdist);
(*handleArr)[3] = vec2_add(center, vec2_mul(halfdist, (V2){-1.0f, -1.0f}));
(*handleArr)[4] = vec2_add(center, vec2_mul(halfdist, (V2){1.0f, -1.0f}));
}
void vektor_shape_create_handles(VektorShape* shape) {
switch(shape->primitive.kind) {
case VEKTOR_POLYLINE:
vektor_polyline_create_handles(shape->primitive.polyline, &shape->handles, &shape->handleCount);
break;
case VEKTOR_POLYGON:
vektor_polygon_create_handles(shape->primitive.polygon, &shape->handles, &shape->handleCount);
break;
case VEKTOR_CIRCLE:
vektor_circle_create_handles(&shape->primitive.circle, &shape->handles, &shape->handleCount);
break;
case VEKTOR_RECTANGLE:
vektor_rectangle_create_handles(&shape->primitive.rectangle, &shape->handles, &shape->handleCount);
break;
switch (shape->primitive.kind) {
case VEKTOR_POLYLINE:
vektor_polyline_create_handles(shape->primitive.polyline,
&shape->handles, &shape->handleCount);
break;
case VEKTOR_POLYGON:
vektor_polygon_create_handles(shape->primitive.polygon, &shape->handles,
&shape->handleCount);
break;
case VEKTOR_CIRCLE:
vektor_circle_create_handles(&shape->primitive.circle, &shape->handles,
&shape->handleCount);
break;
case VEKTOR_RECTANGLE:
vektor_rectangle_create_handles(&shape->primitive.rectangle,
&shape->handles, &shape->handleCount);
break;
}
}
// ------ PRIMITIVE HANDLES UPDATING ------
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles, size_t* count) {
if(*count != polyline->count) {
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles,
size_t* count) {
if (*count != polyline->count) {
g_warning("handle count & point count mismatch in polyline");
return;
}
for(size_t i = 0; i < *count; i++) {
for (size_t i = 0; i < *count; i++) {
polyline->points[i] = (*handles)[i];
}
}
void vektor_polygon_handles_updated(VektorPolygon* polygon, V2** handles, size_t* count) {
if(*count != polygon->count) {
void vektor_polygon_handles_updated(VektorPolygon* polygon, V2** handles,
size_t* count) {
if (*count != polygon->count) {
g_warning("handle count & point count mismatch in polygon");
return;
}
for(size_t i = 0; i < *count; i++) {
for (size_t i = 0; i < *count; i++) {
polygon->points[i] = (*handles)[i];
}
}
void vektor_circle_handles_updated(VektorCircle* circle, V2** handles, size_t* count) {
if(*count != 2) {
void vektor_circle_handles_updated(VektorCircle* circle, V2** handles,
size_t* count) {
if (*count != 2) {
g_warning("unexpected circle handle count (%zu)", *count);
return;
}
@@ -263,12 +272,13 @@ void vektor_circle_handles_updated(VektorCircle* circle, V2** handles, size_t* c
circle->radius = vec2_length(vec2_sub((*handles)[0], (*handles)[1]));
}
void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles, size_t* count) {
if(*count != 5) {
void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles,
size_t* count) {
if (*count != 5) {
g_warning("unexpected rectangle handle count (%zu)", *count);
return;
}
// get rectangle center
V2 halfdist = vec2_scale(vec2_sub(rectangle->end, rectangle->start), 0.5f);
V2 rectcenter = vec2_add(rectangle->start, halfdist);
@@ -276,7 +286,7 @@ void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles,
// center according to handles
V2 center = (*handles)[0];
if(vec2_equals(center, rectcenter)) { // corner handles were changed
if (vec2_equals(center, rectcenter)) { // corner handles were changed
V2 p1 = (*handles)[1];
V2 p2 = (*handles)[2];
V2 p3 = (*handles)[3];
@@ -290,7 +300,7 @@ void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles,
V2 min = (V2){min_x, min_y};
V2 max = (V2){max_x, max_y};
VektorRectangle propertRect = (VektorRectangle){min,max};
VektorRectangle propertRect = (VektorRectangle){min, max};
// overwrite handles array (create_handles() frees the passed one)
vektor_rectangle_create_handles(&propertRect, handles, count);
@@ -299,26 +309,29 @@ void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles,
V2 newmax = vec2_add((*handles)[2], translation);
V2 newmin = vec2_add((*handles)[3], translation);
VektorRectangle propertRect = (VektorRectangle){newmin,newmax};
VektorRectangle propertRect = (VektorRectangle){newmin, newmax};
vektor_rectangle_create_handles(&propertRect, handles, count);
}
}
void vektor_shape_handles_updated(VektorShape* shape) {
switch(shape->primitive.kind) {
case VEKTOR_POLYLINE:
vektor_polyline_handles_updated(shape->primitive.polyline, &shape->handles, &shape->handleCount);
break;
case VEKTOR_POLYGON:
vektor_polygon_handles_updated(shape->primitive.polygon, &shape->handles, &shape->handleCount);
break;
case VEKTOR_CIRCLE:
vektor_circle_handles_updated(&shape->primitive.circle, &shape->handles, &shape->handleCount);
break;
case VEKTOR_RECTANGLE:
vektor_rectangle_handles_updated(&shape->primitive.rectangle, &shape->handles, &shape->handleCount);
break;
switch (shape->primitive.kind) {
case VEKTOR_POLYLINE:
vektor_polyline_handles_updated(shape->primitive.polyline,
&shape->handles, &shape->handleCount);
break;
case VEKTOR_POLYGON:
vektor_polygon_handles_updated(shape->primitive.polygon,
&shape->handles, &shape->handleCount);
break;
case VEKTOR_CIRCLE:
vektor_circle_handles_updated(&shape->primitive.circle, &shape->handles,
&shape->handleCount);
break;
case VEKTOR_RECTANGLE:
vektor_rectangle_handles_updated(&shape->primitive.rectangle,
&shape->handles, &shape->handleCount);
break;
}
}
@@ -327,7 +340,8 @@ void vektor_shape_add_handle(VektorShape* shape, V2 handle) {
// but this function is only called when adding new
// points to polyline and polygon, so it should
// not be that much of an overhead
shape->handles = realloc(shape->handles, sizeof(V2) * shape->handleCount + 1);
shape->handles =
realloc(shape->handles, sizeof(V2) * shape->handleCount + 1);
shape->handles[shape->handleCount++] = handle;
}
@@ -342,14 +356,12 @@ VektorBBox vektor_bbox_fromcenter(V2 center, float dist) {
V2 v2dist = vec2_fromfloat(dist);
V2 min = vec2_sub(center, v2dist);
V2 max = vec2_add(center, v2dist);
return (VektorBBox){min,max};
return (VektorBBox){min, max};
}
VektorBBox vektor_bbox_expand(VektorBBox bbox, float val) {
return (VektorBBox){
vec2_sub(bbox.min, vec2_fromfloat(val)),
vec2_add(bbox.max, vec2_fromfloat(val))
};
return (VektorBBox){vec2_sub(bbox.min, vec2_fromfloat(val)),
vec2_add(bbox.max, vec2_fromfloat(val))};
}
// ------ SHAPE METHODS ------
@@ -357,14 +369,16 @@ VektorBBox vektor_bbox_expand(VektorBBox bbox, float val) {
VektorShape vektor_shape_new(VektorPrimitive prim, VektorStyle style,
int z_index) {
VektorShape shape = (VektorShape){.primitive = prim,
.style = style,
.z_index = z_index,
.bbox = vektor_primitive_get_bbox(prim)};
.style = style,
.transform = m33_identity(),
.z_index = z_index,
.bbox = vektor_primitive_get_bbox(prim)};
/*
create_handles() allocates new buffer for handles,
and even if the local shape variable goes out of scope and deallocates,
the passed value's pointer to an array of handles remains valid in the passed copy.
the passed value's pointer to an array of handles remains valid in the
passed copy.
*/
vektor_shape_create_handles(&shape);
return shape;