/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pikavectors-warp.c * Copyright (C) 2005 Bill Skaggs * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include "vectors-types.h" #include "libpikamath/pikamath.h" #include "core/pika-utils.h" #include "core/pikacoords.h" #include "pikaanchor.h" #include "pikastroke.h" #include "pikavectors.h" #include "pikavectors-warp.h" #define EPSILON 0.2 #define DX 2.0 static void pika_stroke_warp_point (PikaStroke *stroke, gdouble x, gdouble y, PikaCoords *point_warped, gdouble y_offset, gdouble x_len); static void pika_vectors_warp_stroke (PikaVectors *vectors, PikaStroke *stroke, gdouble y_offset); void pika_vectors_warp_point (PikaVectors *vectors, PikaCoords *point, PikaCoords *point_warped, gdouble y_offset) { gdouble x = point->x; gdouble y = point->y; gdouble len; GList *list; PikaStroke *stroke; for (list = vectors->strokes->head; list; list = g_list_next (list)) { stroke = list->data; len = pika_vectors_stroke_get_length (vectors, stroke); if (x < len || ! list->next) break; x -= len; } if (! list) { point_warped->x = 0; point_warped->y = 0; return; } pika_stroke_warp_point (stroke, x, y, point_warped, y_offset, len); } static void pika_stroke_warp_point (PikaStroke *stroke, gdouble x, gdouble y, PikaCoords *point_warped, gdouble y_offset, gdouble x_len) { PikaCoords point_zero = { 0, }; PikaCoords point_minus = { 0, }; PikaCoords point_plus = { 0, }; gdouble slope; gdouble dx, dy, nx, ny, len; if (x + DX >= x_len) { gdouble tx, ty; if (! pika_stroke_get_point_at_dist (stroke, x_len, EPSILON, &point_zero, &slope)) { point_warped->x = 0; point_warped->y = 0; return; } point_warped->x = point_zero.x; point_warped->y = point_zero.y; if (! pika_stroke_get_point_at_dist (stroke, x_len - DX, EPSILON, &point_minus, &slope)) return; dx = point_zero.x - point_minus.x; dy = point_zero.y - point_minus.y; len = hypot (dx, dy); if (len < 0.01) return; tx = dx / len; ty = dy / len; nx = - dy / len; ny = dx / len; point_warped->x += tx * (x - x_len) + nx * (y - y_offset); point_warped->y += ty * (x - x_len) + ny * (y - y_offset); return; } if (! pika_stroke_get_point_at_dist (stroke, x, EPSILON, &point_zero, &slope)) { point_warped->x = 0; point_warped->y = 0; return; } point_warped->x = point_zero.x; point_warped->y = point_zero.y; if (! pika_stroke_get_point_at_dist (stroke, x - DX, EPSILON, &point_minus, &slope)) return; if (! pika_stroke_get_point_at_dist (stroke, x + DX, EPSILON, &point_plus, &slope)) return; dx = point_plus.x - point_minus.x; dy = point_plus.y - point_minus.y; len = hypot (dx, dy); if (len < 0.01) return; nx = - dy / len; ny = dx / len; point_warped->x = point_zero.x + nx * (y - y_offset); point_warped->y = point_zero.y + ny * (y - y_offset); } static void pika_vectors_warp_stroke (PikaVectors *vectors, PikaStroke *stroke, gdouble y_offset) { GList *list; for (list = stroke->anchors->head; list; list = g_list_next (list)) { PikaAnchor *anchor = list->data; pika_vectors_warp_point (vectors, &anchor->position, &anchor->position, y_offset); } } void pika_vectors_warp_vectors (PikaVectors *vectors, PikaVectors *vectors_in, gdouble y_offset) { GList *list; for (list = vectors_in->strokes->head; list; list = g_list_next (list)) { PikaStroke *stroke = list->data; pika_vectors_warp_stroke (vectors, stroke, y_offset); } }