2007-11-02 20:18:50 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2007-11-02 20:18:50 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2007-11-02 20:18:50 +08:00
|
|
|
* (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
|
2018-07-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2007-11-02 20:18:50 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
2008-10-04 03:27:54 +08:00
|
|
|
#include <string.h> /* memcmp */
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2013-10-15 07:58:39 +08:00
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
2012-04-22 03:41:36 +08:00
|
|
|
#include <gegl.h>
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2012-05-04 06:50:23 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2007-11-02 20:18:50 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2008-05-18 22:25:54 +08:00
|
|
|
#include "libgimpconfig/gimpconfig.h"
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
#include "core-types.h"
|
|
|
|
|
|
|
|
#include "gimpcurve.h"
|
|
|
|
#include "gimpcurve-load.h"
|
|
|
|
#include "gimpcurve-save.h"
|
2012-05-04 06:50:23 +08:00
|
|
|
#include "gimpparamspecs.h"
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
#define EPSILON 1e-6
|
|
|
|
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
2007-11-03 00:51:18 +08:00
|
|
|
PROP_CURVE_TYPE,
|
2008-02-28 20:34:46 +08:00
|
|
|
PROP_N_POINTS,
|
2007-11-03 00:51:18 +08:00
|
|
|
PROP_POINTS,
|
2019-04-19 22:09:08 +08:00
|
|
|
PROP_POINT_TYPES,
|
2008-02-28 20:34:46 +08:00
|
|
|
PROP_N_SAMPLES,
|
2020-05-13 04:38:41 +08:00
|
|
|
PROP_SAMPLES,
|
|
|
|
N_PROPS
|
2007-11-02 20:18:50 +08:00
|
|
|
};
|
2020-05-13 04:38:41 +08:00
|
|
|
static GParamSpec *obj_props[N_PROPS] = { NULL, };
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
|
2008-09-12 18:35:35 +08:00
|
|
|
static void gimp_curve_config_iface_init (GimpConfigInterface *iface);
|
|
|
|
|
|
|
|
static void gimp_curve_finalize (GObject *object);
|
|
|
|
static void gimp_curve_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_curve_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
|
|
|
static gint64 gimp_curve_get_memsize (GimpObject *object,
|
|
|
|
gint64 *gui_size);
|
|
|
|
|
|
|
|
static void gimp_curve_get_preview_size (GimpViewable *viewable,
|
|
|
|
gint size,
|
|
|
|
gboolean popup,
|
|
|
|
gboolean dot_for_dot,
|
|
|
|
gint *width,
|
|
|
|
gint *height);
|
|
|
|
static gboolean gimp_curve_get_popup_size (GimpViewable *viewable,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
gboolean dot_for_dot,
|
|
|
|
gint *popup_width,
|
|
|
|
gint *popup_height);
|
2012-04-09 02:25:49 +08:00
|
|
|
static GimpTempBuf * gimp_curve_get_new_preview (GimpViewable *viewable,
|
2008-09-12 18:35:35 +08:00
|
|
|
GimpContext *context,
|
|
|
|
gint width,
|
|
|
|
gint height);
|
|
|
|
static gchar * gimp_curve_get_description (GimpViewable *viewable,
|
|
|
|
gchar **tooltip);
|
|
|
|
|
|
|
|
static void gimp_curve_dirty (GimpData *data);
|
|
|
|
static const gchar * gimp_curve_get_extension (GimpData *data);
|
2017-11-05 09:21:12 +08:00
|
|
|
static void gimp_curve_data_copy (GimpData *data,
|
|
|
|
GimpData *src_data);
|
2008-09-12 18:35:35 +08:00
|
|
|
|
|
|
|
static gboolean gimp_curve_serialize (GimpConfig *config,
|
|
|
|
GimpConfigWriter *writer,
|
|
|
|
gpointer data);
|
|
|
|
static gboolean gimp_curve_deserialize (GimpConfig *config,
|
|
|
|
GScanner *scanner,
|
|
|
|
gint nest_level,
|
|
|
|
gpointer data);
|
|
|
|
static gboolean gimp_curve_equal (GimpConfig *a,
|
|
|
|
GimpConfig *b);
|
|
|
|
static void _gimp_curve_reset (GimpConfig *config);
|
2017-11-05 09:21:12 +08:00
|
|
|
static gboolean gimp_curve_config_copy (GimpConfig *src,
|
2008-09-12 18:35:35 +08:00
|
|
|
GimpConfig *dest,
|
|
|
|
GParamFlags flags);
|
|
|
|
|
|
|
|
static void gimp_curve_calculate (GimpCurve *curve);
|
|
|
|
static void gimp_curve_plot (GimpCurve *curve,
|
|
|
|
gint p1,
|
|
|
|
gint p2,
|
|
|
|
gint p3,
|
|
|
|
gint p4);
|
2008-05-18 22:25:54 +08:00
|
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (GimpCurve, gimp_curve, GIMP_TYPE_DATA,
|
|
|
|
G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG,
|
|
|
|
gimp_curve_config_iface_init))
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
#define parent_class gimp_curve_parent_class
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_curve_class_init (GimpCurveClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
|
|
|
|
GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
|
|
|
|
GimpDataClass *data_class = GIMP_DATA_CLASS (klass);
|
2008-05-19 04:07:07 +08:00
|
|
|
GParamSpec *array_spec;
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2014-05-07 07:01:56 +08:00
|
|
|
object_class->finalize = gimp_curve_finalize;
|
|
|
|
object_class->set_property = gimp_curve_set_property;
|
|
|
|
object_class->get_property = gimp_curve_get_property;
|
|
|
|
|
|
|
|
gimp_object_class->get_memsize = gimp_curve_get_memsize;
|
|
|
|
|
|
|
|
viewable_class->default_icon_name = "FIXME icon name";
|
|
|
|
viewable_class->get_preview_size = gimp_curve_get_preview_size;
|
|
|
|
viewable_class->get_popup_size = gimp_curve_get_popup_size;
|
|
|
|
viewable_class->get_new_preview = gimp_curve_get_new_preview;
|
|
|
|
viewable_class->get_description = gimp_curve_get_description;
|
|
|
|
|
|
|
|
data_class->dirty = gimp_curve_dirty;
|
|
|
|
data_class->save = gimp_curve_save;
|
|
|
|
data_class->get_extension = gimp_curve_get_extension;
|
2017-11-05 09:21:12 +08:00
|
|
|
data_class->copy = gimp_curve_data_copy;
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
obj_props[PROP_CURVE_TYPE] =
|
|
|
|
g_param_spec_enum ("curve-type",
|
2016-02-12 06:44:07 +08:00
|
|
|
"Curve Type",
|
|
|
|
"The curve type",
|
|
|
|
GIMP_TYPE_CURVE_TYPE,
|
2020-05-13 04:38:41 +08:00
|
|
|
GIMP_CURVE_SMOOTH,
|
|
|
|
GIMP_CONFIG_PARAM_FLAGS);
|
2016-02-12 06:44:07 +08:00
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
obj_props[PROP_N_POINTS] =
|
|
|
|
g_param_spec_int ("n-points",
|
2016-02-12 06:44:07 +08:00
|
|
|
"Number of Points",
|
|
|
|
"The number of points",
|
2019-04-19 16:24:24 +08:00
|
|
|
0, G_MAXINT, 0,
|
|
|
|
/* for backward compatibility */
|
2020-05-13 04:38:41 +08:00
|
|
|
GIMP_CONFIG_PARAM_IGNORE | GIMP_CONFIG_PARAM_FLAGS);
|
2008-02-28 20:34:46 +08:00
|
|
|
|
2008-05-19 04:07:07 +08:00
|
|
|
array_spec = g_param_spec_double ("point", NULL, NULL,
|
|
|
|
-1.0, 1.0, 0.0, GIMP_PARAM_READWRITE);
|
2020-05-13 04:38:41 +08:00
|
|
|
obj_props[PROP_POINTS] =
|
|
|
|
gimp_param_spec_value_array ("points",
|
|
|
|
NULL, NULL,
|
|
|
|
array_spec,
|
|
|
|
GIMP_CONFIG_PARAM_FLAGS);
|
2007-11-03 00:51:18 +08:00
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
array_spec = g_param_spec_enum ("point-type", NULL, NULL,
|
|
|
|
GIMP_TYPE_CURVE_POINT_TYPE,
|
|
|
|
GIMP_CURVE_POINT_SMOOTH,
|
|
|
|
GIMP_PARAM_READWRITE);
|
2020-05-13 04:38:41 +08:00
|
|
|
obj_props[PROP_POINT_TYPES] =
|
|
|
|
gimp_param_spec_value_array ("point-types",
|
|
|
|
NULL, NULL,
|
|
|
|
array_spec,
|
|
|
|
GIMP_CONFIG_PARAM_FLAGS);
|
|
|
|
|
|
|
|
obj_props[PROP_N_SAMPLES] =
|
|
|
|
g_param_spec_int ("n-samples",
|
|
|
|
"Number of Samples",
|
|
|
|
"The number of samples",
|
|
|
|
256, 256, 256,
|
|
|
|
GIMP_CONFIG_PARAM_FLAGS);
|
2008-02-28 20:34:46 +08:00
|
|
|
|
2008-05-19 04:07:07 +08:00
|
|
|
array_spec = g_param_spec_double ("sample", NULL, NULL,
|
|
|
|
0.0, 1.0, 0.0, GIMP_PARAM_READWRITE);
|
2020-05-13 04:38:41 +08:00
|
|
|
obj_props[PROP_SAMPLES] =
|
|
|
|
gimp_param_spec_value_array ("samples",
|
|
|
|
NULL, NULL,
|
|
|
|
array_spec,
|
|
|
|
GIMP_CONFIG_PARAM_FLAGS);
|
|
|
|
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
2008-05-18 22:25:54 +08:00
|
|
|
static void
|
|
|
|
gimp_curve_config_iface_init (GimpConfigInterface *iface)
|
|
|
|
{
|
|
|
|
iface->serialize = gimp_curve_serialize;
|
|
|
|
iface->deserialize = gimp_curve_deserialize;
|
|
|
|
iface->equal = gimp_curve_equal;
|
|
|
|
iface->reset = _gimp_curve_reset;
|
2017-11-05 09:21:12 +08:00
|
|
|
iface->copy = gimp_curve_config_copy;
|
2008-05-18 22:25:54 +08:00
|
|
|
}
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
static void
|
|
|
|
gimp_curve_init (GimpCurve *curve)
|
|
|
|
{
|
2008-05-15 00:19:33 +08:00
|
|
|
curve->n_points = 0;
|
|
|
|
curve->points = NULL;
|
|
|
|
curve->n_samples = 0;
|
|
|
|
curve->samples = NULL;
|
|
|
|
curve->identity = FALSE;
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_curve_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
GimpCurve *curve = GIMP_CURVE (object);
|
|
|
|
|
2019-05-27 23:47:55 +08:00
|
|
|
g_clear_pointer (&curve->points, g_free);
|
|
|
|
curve->n_points = 0;
|
2008-02-28 20:34:46 +08:00
|
|
|
|
2019-05-27 23:47:55 +08:00
|
|
|
g_clear_pointer (&curve->samples, g_free);
|
|
|
|
curve->n_samples = 0;
|
2008-02-28 20:34:46 +08:00
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_curve_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GimpCurve *curve = GIMP_CURVE (object);
|
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_CURVE_TYPE:
|
|
|
|
gimp_curve_set_curve_type (curve, g_value_get_enum (value));
|
|
|
|
break;
|
|
|
|
|
2008-02-28 20:34:46 +08:00
|
|
|
case PROP_N_POINTS:
|
2019-04-19 16:24:24 +08:00
|
|
|
/* ignored */
|
2008-02-28 20:34:46 +08:00
|
|
|
break;
|
|
|
|
|
2007-11-03 00:51:18 +08:00
|
|
|
case PROP_POINTS:
|
2008-05-19 04:07:07 +08:00
|
|
|
{
|
2012-05-04 06:50:23 +08:00
|
|
|
GimpValueArray *array = g_value_get_boxed (value);
|
2019-04-19 22:09:08 +08:00
|
|
|
GimpCurvePoint *points;
|
2012-05-04 06:50:23 +08:00
|
|
|
gint length;
|
2019-04-19 22:09:08 +08:00
|
|
|
gint n_points;
|
2012-05-04 06:50:23 +08:00
|
|
|
gint i;
|
2008-05-19 04:07:07 +08:00
|
|
|
|
|
|
|
if (! array)
|
2019-04-19 22:09:08 +08:00
|
|
|
{
|
|
|
|
gimp_curve_clear_points (curve);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2008-05-19 04:07:07 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
length = gimp_value_array_length (array) / 2;
|
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
n_points = 0;
|
2019-06-26 22:24:29 +08:00
|
|
|
points = g_new0 (GimpCurvePoint, length);
|
2012-05-04 06:50:23 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
for (i = 0; i < length; i++)
|
2008-05-19 04:07:07 +08:00
|
|
|
{
|
2012-05-04 06:50:23 +08:00
|
|
|
GValue *x = gimp_value_array_index (array, i * 2);
|
|
|
|
GValue *y = gimp_value_array_index (array, i * 2 + 1);
|
2008-05-19 04:07:07 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
/* for backward compatibility */
|
|
|
|
if (g_value_get_double (x) < 0.0)
|
|
|
|
continue;
|
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
points[n_points].x = CLAMP (g_value_get_double (x), 0.0, 1.0);
|
|
|
|
points[n_points].y = CLAMP (g_value_get_double (y), 0.0, 1.0);
|
2019-04-19 16:24:24 +08:00
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
if (n_points > 0)
|
2019-04-19 16:24:24 +08:00
|
|
|
{
|
2019-04-19 22:09:08 +08:00
|
|
|
points[n_points].x = MAX (points[n_points].x,
|
|
|
|
points[n_points - 1].x);
|
2019-04-19 16:24:24 +08:00
|
|
|
}
|
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
if (n_points < curve->n_points)
|
|
|
|
points[n_points].type = curve->points[n_points].type;
|
|
|
|
else
|
|
|
|
points[n_points].type = GIMP_CURVE_POINT_SMOOTH;
|
|
|
|
|
|
|
|
n_points++;
|
2008-05-19 04:07:07 +08:00
|
|
|
}
|
2019-04-19 16:24:24 +08:00
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
g_free (curve->points);
|
|
|
|
|
|
|
|
curve->n_points = n_points;
|
|
|
|
curve->points = points;
|
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (object, obj_props[PROP_N_POINTS]);
|
|
|
|
g_object_notify_by_pspec (object, obj_props[PROP_POINT_TYPES]);
|
2019-04-19 22:09:08 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_POINT_TYPES:
|
|
|
|
{
|
|
|
|
GimpValueArray *array = g_value_get_boxed (value);
|
|
|
|
GimpCurvePoint *points;
|
|
|
|
gint length;
|
|
|
|
gdouble x = 0.0;
|
|
|
|
gdouble y = 0.0;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
if (! array)
|
|
|
|
{
|
|
|
|
gimp_curve_clear_points (curve);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
length = gimp_value_array_length (array);
|
|
|
|
|
2019-06-26 22:24:29 +08:00
|
|
|
points = g_new0 (GimpCurvePoint, length);
|
2019-04-19 22:09:08 +08:00
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
GValue *type = gimp_value_array_index (array, i);
|
|
|
|
|
|
|
|
points[i].type = g_value_get_enum (type);
|
|
|
|
|
|
|
|
if (i < curve->n_points)
|
|
|
|
{
|
|
|
|
x = curve->points[i].x;
|
|
|
|
y = curve->points[i].y;
|
|
|
|
}
|
|
|
|
|
|
|
|
points[i].x = x;
|
|
|
|
points[i].y = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (curve->points);
|
|
|
|
|
|
|
|
curve->n_points = length;
|
|
|
|
curve->points = points;
|
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (object, obj_props[PROP_N_POINTS]);
|
|
|
|
g_object_notify_by_pspec (object, obj_props[PROP_POINTS]);
|
2008-05-19 04:07:07 +08:00
|
|
|
}
|
2008-02-28 20:34:46 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_N_SAMPLES:
|
|
|
|
gimp_curve_set_n_samples (curve, g_value_get_int (value));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_SAMPLES:
|
2008-05-19 04:07:07 +08:00
|
|
|
{
|
2012-05-04 06:50:23 +08:00
|
|
|
GimpValueArray *array = g_value_get_boxed (value);
|
|
|
|
gint length;
|
|
|
|
gint i;
|
2008-05-19 04:07:07 +08:00
|
|
|
|
|
|
|
if (! array)
|
|
|
|
break;
|
|
|
|
|
2012-05-04 06:50:23 +08:00
|
|
|
length = gimp_value_array_length (array);
|
|
|
|
|
|
|
|
for (i = 0; i < curve->n_samples && i < length; i++)
|
2008-05-19 04:07:07 +08:00
|
|
|
{
|
2012-05-04 06:50:23 +08:00
|
|
|
GValue *v = gimp_value_array_index (array, i);
|
2008-05-19 04:07:07 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
curve->samples[i] = CLAMP (g_value_get_double (v), 0.0, 1.0);
|
2008-05-19 04:07:07 +08:00
|
|
|
}
|
|
|
|
}
|
2007-11-03 00:51:18 +08:00
|
|
|
break;
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_curve_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GimpCurve *curve = GIMP_CURVE (object);
|
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_CURVE_TYPE:
|
|
|
|
g_value_set_enum (value, curve->curve_type);
|
|
|
|
break;
|
|
|
|
|
2008-02-28 20:34:46 +08:00
|
|
|
case PROP_N_POINTS:
|
|
|
|
g_value_set_int (value, curve->n_points);
|
|
|
|
break;
|
|
|
|
|
2007-11-03 00:51:18 +08:00
|
|
|
case PROP_POINTS:
|
2008-05-19 04:07:07 +08:00
|
|
|
{
|
2012-05-04 06:50:23 +08:00
|
|
|
GimpValueArray *array = gimp_value_array_new (curve->n_points * 2);
|
2016-03-26 22:59:26 +08:00
|
|
|
GValue v = G_VALUE_INIT;
|
2012-05-04 06:50:23 +08:00
|
|
|
gint i;
|
2008-05-19 04:07:07 +08:00
|
|
|
|
|
|
|
g_value_init (&v, G_TYPE_DOUBLE);
|
|
|
|
|
|
|
|
for (i = 0; i < curve->n_points; i++)
|
|
|
|
{
|
|
|
|
g_value_set_double (&v, curve->points[i].x);
|
2012-05-04 06:50:23 +08:00
|
|
|
gimp_value_array_append (array, &v);
|
2008-05-19 04:07:07 +08:00
|
|
|
|
|
|
|
g_value_set_double (&v, curve->points[i].y);
|
2012-05-04 06:50:23 +08:00
|
|
|
gimp_value_array_append (array, &v);
|
2008-05-19 04:07:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
g_value_unset (&v);
|
|
|
|
|
|
|
|
g_value_take_boxed (value, array);
|
|
|
|
}
|
2008-02-28 20:34:46 +08:00
|
|
|
break;
|
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
case PROP_POINT_TYPES:
|
|
|
|
{
|
|
|
|
GimpValueArray *array = gimp_value_array_new (curve->n_points);
|
|
|
|
GValue v = G_VALUE_INIT;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_value_init (&v, GIMP_TYPE_CURVE_POINT_TYPE);
|
|
|
|
|
|
|
|
for (i = 0; i < curve->n_points; i++)
|
|
|
|
{
|
|
|
|
g_value_set_enum (&v, curve->points[i].type);
|
|
|
|
gimp_value_array_append (array, &v);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_value_unset (&v);
|
|
|
|
|
|
|
|
g_value_take_boxed (value, array);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-02-28 20:34:46 +08:00
|
|
|
case PROP_N_SAMPLES:
|
|
|
|
g_value_set_int (value, curve->n_samples);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_SAMPLES:
|
2008-05-19 04:07:07 +08:00
|
|
|
{
|
2012-05-04 06:50:23 +08:00
|
|
|
GimpValueArray *array = gimp_value_array_new (curve->n_samples);
|
2016-03-26 22:59:26 +08:00
|
|
|
GValue v = G_VALUE_INIT;
|
2012-05-04 06:50:23 +08:00
|
|
|
gint i;
|
2008-05-19 04:07:07 +08:00
|
|
|
|
|
|
|
g_value_init (&v, G_TYPE_DOUBLE);
|
|
|
|
|
|
|
|
for (i = 0; i < curve->n_samples; i++)
|
|
|
|
{
|
|
|
|
g_value_set_double (&v, curve->samples[i]);
|
2012-05-04 06:50:23 +08:00
|
|
|
gimp_value_array_append (array, &v);
|
2008-05-19 04:07:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
g_value_unset (&v);
|
|
|
|
|
|
|
|
g_value_take_boxed (value, array);
|
|
|
|
}
|
2007-11-03 00:51:18 +08:00
|
|
|
break;
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint64
|
|
|
|
gimp_curve_get_memsize (GimpObject *object,
|
2008-09-20 06:41:58 +08:00
|
|
|
gint64 *gui_size)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
|
|
|
GimpCurve *curve = GIMP_CURVE (object);
|
|
|
|
gint64 memsize = 0;
|
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
memsize += curve->n_points * sizeof (GimpCurvePoint);
|
2008-02-28 20:34:46 +08:00
|
|
|
memsize += curve->n_samples * sizeof (gdouble);
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
|
|
|
gui_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_curve_get_preview_size (GimpViewable *viewable,
|
|
|
|
gint size,
|
|
|
|
gboolean popup,
|
|
|
|
gboolean dot_for_dot,
|
|
|
|
gint *width,
|
|
|
|
gint *height)
|
|
|
|
{
|
|
|
|
*width = size;
|
|
|
|
*height = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_curve_get_popup_size (GimpViewable *viewable,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
gboolean dot_for_dot,
|
|
|
|
gint *popup_width,
|
|
|
|
gint *popup_height)
|
|
|
|
{
|
|
|
|
*popup_width = width * 2;
|
|
|
|
*popup_height = height * 2;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2012-04-09 02:25:49 +08:00
|
|
|
static GimpTempBuf *
|
2007-11-02 20:18:50 +08:00
|
|
|
gimp_curve_get_new_preview (GimpViewable *viewable,
|
|
|
|
GimpContext *context,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gchar *
|
|
|
|
gimp_curve_get_description (GimpViewable *viewable,
|
|
|
|
gchar **tooltip)
|
|
|
|
{
|
|
|
|
GimpCurve *curve = GIMP_CURVE (viewable);
|
|
|
|
|
2009-08-29 18:40:40 +08:00
|
|
|
return g_strdup_printf ("%s", gimp_object_get_name (curve));
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
2007-11-05 18:02:20 +08:00
|
|
|
static void
|
|
|
|
gimp_curve_dirty (GimpData *data)
|
|
|
|
{
|
2008-05-13 15:10:48 +08:00
|
|
|
GimpCurve *curve = GIMP_CURVE (data);
|
|
|
|
|
|
|
|
curve->identity = FALSE;
|
|
|
|
|
|
|
|
gimp_curve_calculate (curve);
|
2007-11-05 18:02:20 +08:00
|
|
|
|
|
|
|
GIMP_DATA_CLASS (parent_class)->dirty (data);
|
|
|
|
}
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2008-09-12 18:35:35 +08:00
|
|
|
static const gchar *
|
2007-11-02 20:18:50 +08:00
|
|
|
gimp_curve_get_extension (GimpData *data)
|
|
|
|
{
|
|
|
|
return GIMP_CURVE_FILE_EXTENSION;
|
|
|
|
}
|
|
|
|
|
2017-11-05 09:21:12 +08:00
|
|
|
static void
|
|
|
|
gimp_curve_data_copy (GimpData *data,
|
|
|
|
GimpData *src_data)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
2017-11-05 09:21:12 +08:00
|
|
|
gimp_data_freeze (data);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2017-11-05 09:21:12 +08:00
|
|
|
gimp_config_copy (GIMP_CONFIG (src_data),
|
|
|
|
GIMP_CONFIG (data), 0);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2017-11-05 09:21:12 +08:00
|
|
|
gimp_data_thaw (data);
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
2008-05-18 22:25:54 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_curve_serialize (GimpConfig *config,
|
|
|
|
GimpConfigWriter *writer,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
return gimp_config_serialize_properties (config, writer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_curve_deserialize (GimpConfig *config,
|
|
|
|
GScanner *scanner,
|
|
|
|
gint nest_level,
|
|
|
|
gpointer data)
|
|
|
|
{
|
2008-05-19 04:07:07 +08:00
|
|
|
gboolean success;
|
|
|
|
|
|
|
|
success = gimp_config_deserialize_properties (config, scanner, nest_level);
|
|
|
|
|
|
|
|
GIMP_CURVE (config)->identity = FALSE;
|
|
|
|
|
|
|
|
return success;
|
2008-05-18 22:25:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_curve_equal (GimpConfig *a,
|
|
|
|
GimpConfig *b)
|
|
|
|
{
|
|
|
|
GimpCurve *a_curve = GIMP_CURVE (a);
|
|
|
|
GimpCurve *b_curve = GIMP_CURVE (b);
|
|
|
|
|
|
|
|
if (a_curve->curve_type != b_curve->curve_type)
|
|
|
|
return FALSE;
|
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
if (a_curve->n_points != b_curve->n_points ||
|
|
|
|
memcmp (a_curve->points, b_curve->points,
|
2019-04-19 22:09:08 +08:00
|
|
|
sizeof (GimpCurvePoint) * a_curve->n_points))
|
2019-04-19 16:24:24 +08:00
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a_curve->n_samples != b_curve->n_samples ||
|
2008-05-18 22:25:54 +08:00
|
|
|
memcmp (a_curve->samples, b_curve->samples,
|
2019-04-19 16:24:24 +08:00
|
|
|
sizeof (gdouble) * a_curve->n_samples))
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
2008-05-18 22:25:54 +08:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_gimp_curve_reset (GimpConfig *config)
|
|
|
|
{
|
|
|
|
gimp_curve_reset (GIMP_CURVE (config), TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2017-11-05 09:21:12 +08:00
|
|
|
gimp_curve_config_copy (GimpConfig *src,
|
|
|
|
GimpConfig *dest,
|
|
|
|
GParamFlags flags)
|
2008-05-18 22:25:54 +08:00
|
|
|
{
|
|
|
|
GimpCurve *src_curve = GIMP_CURVE (src);
|
|
|
|
GimpCurve *dest_curve = GIMP_CURVE (dest);
|
|
|
|
|
2020-04-14 22:50:54 +08:00
|
|
|
/* make sure the curve type is copied *before* the points, so that we don't
|
|
|
|
* overwrite the copied points when changing the type
|
|
|
|
*/
|
|
|
|
dest_curve->curve_type = src_curve->curve_type;
|
|
|
|
|
2008-05-18 22:25:54 +08:00
|
|
|
gimp_config_sync (G_OBJECT (src), G_OBJECT (dest), flags);
|
|
|
|
|
|
|
|
dest_curve->identity = src_curve->identity;
|
|
|
|
|
2008-09-29 20:33:58 +08:00
|
|
|
gimp_data_dirty (GIMP_DATA (dest));
|
|
|
|
|
|
|
|
return TRUE;
|
2008-05-18 22:25:54 +08:00
|
|
|
}
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
|
|
|
GimpData *
|
|
|
|
gimp_curve_new (const gchar *name)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
g_return_val_if_fail (*name != '\0', NULL);
|
|
|
|
|
|
|
|
return g_object_new (GIMP_TYPE_CURVE,
|
|
|
|
"name", name,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpData *
|
|
|
|
gimp_curve_get_standard (void)
|
|
|
|
{
|
|
|
|
static GimpData *standard_curve = NULL;
|
|
|
|
|
|
|
|
if (! standard_curve)
|
|
|
|
{
|
|
|
|
standard_curve = gimp_curve_new ("Standard");
|
|
|
|
|
2009-11-01 01:48:38 +08:00
|
|
|
gimp_data_clean (standard_curve);
|
2008-12-12 15:03:42 +08:00
|
|
|
gimp_data_make_internal (standard_curve,
|
|
|
|
"gimp-curve-standard");
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
g_object_ref (standard_curve);
|
|
|
|
}
|
|
|
|
|
|
|
|
return standard_curve;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_curve_reset (GimpCurve *curve,
|
|
|
|
gboolean reset_type)
|
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
|
|
|
|
2008-02-28 20:34:46 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (curve));
|
|
|
|
|
|
|
|
for (i = 0; i < curve->n_samples; i++)
|
|
|
|
curve->samples[i] = (gdouble) i / (gdouble) (curve->n_samples - 1);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_SAMPLES]);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
g_free (curve->points);
|
|
|
|
|
|
|
|
curve->n_points = 2;
|
2019-06-26 22:24:29 +08:00
|
|
|
curve->points = g_new0 (GimpCurvePoint, 2);
|
2019-04-19 16:24:24 +08:00
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
curve->points[0].x = 0.0;
|
|
|
|
curve->points[0].y = 0.0;
|
|
|
|
curve->points[0].type = GIMP_CURVE_POINT_SMOOTH;
|
2008-02-28 20:34:46 +08:00
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
curve->points[1].x = 1.0;
|
|
|
|
curve->points[1].y = 1.0;
|
|
|
|
curve->points[1].type = GIMP_CURVE_POINT_SMOOTH;
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_POINTS]);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
|
2007-11-03 00:51:18 +08:00
|
|
|
|
|
|
|
if (reset_type)
|
2008-02-28 20:34:46 +08:00
|
|
|
{
|
|
|
|
curve->curve_type = GIMP_CURVE_SMOOTH;
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_CURVE_TYPE]);
|
2008-02-28 20:34:46 +08:00
|
|
|
}
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2008-05-19 19:08:24 +08:00
|
|
|
curve->identity = TRUE;
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
g_object_thaw_notify (G_OBJECT (curve));
|
2007-11-05 18:02:20 +08:00
|
|
|
|
|
|
|
gimp_data_dirty (GIMP_DATA (curve));
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_curve_set_curve_type (GimpCurve *curve,
|
|
|
|
GimpCurveType curve_type)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
|
|
|
|
|
|
|
if (curve->curve_type != curve_type)
|
|
|
|
{
|
2019-04-19 16:24:24 +08:00
|
|
|
gimp_data_freeze (GIMP_DATA (curve));
|
|
|
|
|
2007-11-03 00:51:18 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (curve));
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
curve->curve_type = curve_type;
|
|
|
|
|
|
|
|
if (curve_type == GIMP_CURVE_SMOOTH)
|
|
|
|
{
|
2008-02-09 18:01:51 +08:00
|
|
|
gint i;
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
g_free (curve->points);
|
2008-02-28 20:34:46 +08:00
|
|
|
|
|
|
|
/* pick some points from the curve and make them control
|
|
|
|
* points
|
2007-11-02 20:18:50 +08:00
|
|
|
*/
|
2019-04-19 16:24:24 +08:00
|
|
|
curve->n_points = 9;
|
2019-06-26 22:24:29 +08:00
|
|
|
curve->points = g_new0 (GimpCurvePoint, 9);
|
2008-02-28 20:34:46 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
for (i = 0; i < curve->n_points; i++)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
2019-04-19 16:24:24 +08:00
|
|
|
gint sample = i * (curve->n_samples - 1) / (curve->n_points - 1);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
curve->points[i].x = (gdouble) sample /
|
|
|
|
(gdouble) (curve->n_samples - 1);
|
|
|
|
curve->points[i].y = curve->samples[sample];
|
|
|
|
curve->points[i].type = GIMP_CURVE_POINT_SMOOTH;
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_POINTS]);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
|
2007-11-05 18:02:20 +08:00
|
|
|
}
|
2019-04-19 16:24:24 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_curve_clear_points (curve);
|
|
|
|
}
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_CURVE_TYPE]);
|
2007-11-03 00:51:18 +08:00
|
|
|
|
|
|
|
g_object_thaw_notify (G_OBJECT (curve));
|
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
gimp_data_thaw (GIMP_DATA (curve));
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpCurveType
|
|
|
|
gimp_curve_get_curve_type (GimpCurve *curve)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_CURVE (curve), GIMP_CURVE_SMOOTH);
|
|
|
|
|
|
|
|
return curve->curve_type;
|
|
|
|
}
|
|
|
|
|
2008-02-28 20:34:46 +08:00
|
|
|
gint
|
|
|
|
gimp_curve_get_n_points (GimpCurve *curve)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_CURVE (curve), 0);
|
|
|
|
|
|
|
|
return curve->n_points;
|
|
|
|
}
|
|
|
|
|
2014-06-18 02:07:24 +08:00
|
|
|
void
|
2008-02-28 20:34:46 +08:00
|
|
|
gimp_curve_set_n_samples (GimpCurve *curve,
|
|
|
|
gint n_samples)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
2014-06-18 02:07:24 +08:00
|
|
|
g_return_if_fail (n_samples >= 256);
|
|
|
|
g_return_if_fail (n_samples <= 4096);
|
2008-02-28 20:34:46 +08:00
|
|
|
|
|
|
|
if (n_samples != curve->n_samples)
|
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_object_freeze_notify (G_OBJECT (curve));
|
|
|
|
|
|
|
|
curve->n_samples = n_samples;
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_SAMPLES]);
|
2008-02-28 20:34:46 +08:00
|
|
|
|
|
|
|
curve->samples = g_renew (gdouble, curve->samples, curve->n_samples);
|
|
|
|
|
|
|
|
for (i = 0; i < curve->n_samples; i++)
|
|
|
|
curve->samples[i] = (gdouble) i / (gdouble) (curve->n_samples - 1);
|
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_SAMPLES]);
|
2008-02-28 20:34:46 +08:00
|
|
|
|
2008-05-19 19:08:24 +08:00
|
|
|
if (curve->curve_type == GIMP_CURVE_FREE)
|
|
|
|
curve->identity = TRUE;
|
|
|
|
|
2008-02-28 20:34:46 +08:00
|
|
|
g_object_thaw_notify (G_OBJECT (curve));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
|
|
|
gimp_curve_get_n_samples (GimpCurve *curve)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_CURVE (curve), 0);
|
|
|
|
|
|
|
|
return curve->n_samples;
|
|
|
|
}
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
gint
|
2019-04-19 16:24:24 +08:00
|
|
|
gimp_curve_get_point_at (GimpCurve *curve,
|
|
|
|
gdouble x)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
2019-04-19 16:24:24 +08:00
|
|
|
gint closest_point = -1;
|
|
|
|
gdouble distance = EPSILON;
|
2008-02-09 18:01:51 +08:00
|
|
|
gint i;
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_CURVE (curve), -1);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2008-02-28 20:34:46 +08:00
|
|
|
for (i = 0; i < curve->n_points; i++)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
2019-04-19 16:24:24 +08:00
|
|
|
gdouble point_distance;
|
|
|
|
|
|
|
|
point_distance = fabs (x - curve->points[i].x);
|
|
|
|
|
|
|
|
if (point_distance <= distance)
|
2008-02-10 01:40:57 +08:00
|
|
|
{
|
|
|
|
closest_point = i;
|
2019-04-19 16:24:24 +08:00
|
|
|
distance = point_distance;
|
2008-02-10 01:40:57 +08:00
|
|
|
}
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
return closest_point;
|
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
|
|
|
gimp_curve_get_closest_point (GimpCurve *curve,
|
|
|
|
gdouble x,
|
|
|
|
gdouble y,
|
|
|
|
gdouble max_distance)
|
|
|
|
{
|
|
|
|
gint closest_point = -1;
|
|
|
|
gdouble distance2 = G_MAXDOUBLE;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_CURVE (curve), -1);
|
|
|
|
|
|
|
|
if (max_distance >= 0.0)
|
|
|
|
distance2 = SQR (max_distance);
|
|
|
|
|
|
|
|
for (i = curve->n_points - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
gdouble point_distance2;
|
|
|
|
|
|
|
|
point_distance2 = SQR (x - curve->points[i].x) +
|
|
|
|
SQR (y - curve->points[i].y);
|
|
|
|
|
|
|
|
if (point_distance2 <= distance2)
|
|
|
|
{
|
|
|
|
closest_point = i;
|
|
|
|
distance2 = point_distance2;
|
|
|
|
}
|
|
|
|
}
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
return closest_point;
|
|
|
|
}
|
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
gint
|
|
|
|
gimp_curve_add_point (GimpCurve *curve,
|
2008-02-09 18:01:51 +08:00
|
|
|
gdouble x,
|
|
|
|
gdouble y)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
2019-04-19 22:09:08 +08:00
|
|
|
GimpCurvePoint *points;
|
|
|
|
gint point;
|
2019-04-19 16:24:24 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_CURVE (curve), -1);
|
|
|
|
|
|
|
|
if (curve->curve_type == GIMP_CURVE_FREE)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
x = CLAMP (x, 0.0, 1.0);
|
|
|
|
y = CLAMP (y, 0.0, 1.0);
|
|
|
|
|
|
|
|
for (point = 0; point < curve->n_points; point++)
|
|
|
|
{
|
|
|
|
if (curve->points[point].x > x)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-06-26 22:24:29 +08:00
|
|
|
points = g_new0 (GimpCurvePoint, curve->n_points + 1);
|
2019-04-19 16:24:24 +08:00
|
|
|
|
|
|
|
memcpy (points, curve->points,
|
2019-04-19 22:09:08 +08:00
|
|
|
point * sizeof (GimpCurvePoint));
|
2019-04-19 16:24:24 +08:00
|
|
|
memcpy (points + point + 1, curve->points + point,
|
2019-04-19 22:09:08 +08:00
|
|
|
(curve->n_points - point) * sizeof (GimpCurvePoint));
|
2019-04-19 16:24:24 +08:00
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
points[point].x = x;
|
|
|
|
points[point].y = y;
|
|
|
|
points[point].type = GIMP_CURVE_POINT_SMOOTH;
|
2019-04-19 16:24:24 +08:00
|
|
|
|
|
|
|
g_free (curve->points);
|
|
|
|
|
|
|
|
curve->n_points++;
|
|
|
|
curve->points = points;
|
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_POINTS]);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
|
2019-04-19 16:24:24 +08:00
|
|
|
|
|
|
|
gimp_data_dirty (GIMP_DATA (curve));
|
|
|
|
|
|
|
|
return point;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_curve_delete_point (GimpCurve *curve,
|
|
|
|
gint point)
|
|
|
|
{
|
2019-04-19 22:09:08 +08:00
|
|
|
GimpCurvePoint *points;
|
2019-04-19 16:24:24 +08:00
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
2008-02-28 20:34:46 +08:00
|
|
|
g_return_if_fail (point >= 0 && point < curve->n_points);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-06-26 22:24:29 +08:00
|
|
|
points = g_new0 (GimpCurvePoint, curve->n_points - 1);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
memcpy (points, curve->points,
|
2019-04-19 22:09:08 +08:00
|
|
|
point * sizeof (GimpCurvePoint));
|
2019-04-19 16:24:24 +08:00
|
|
|
memcpy (points + point, curve->points + point + 1,
|
2019-04-19 22:09:08 +08:00
|
|
|
(curve->n_points - point - 1) * sizeof (GimpCurvePoint));
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
g_free (curve->points);
|
|
|
|
|
|
|
|
curve->n_points--;
|
|
|
|
curve->points = points;
|
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_POINTS]);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
|
2007-11-03 00:51:18 +08:00
|
|
|
|
2007-11-05 18:02:20 +08:00
|
|
|
gimp_data_dirty (GIMP_DATA (curve));
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 16:24:24 +08:00
|
|
|
gimp_curve_set_point (GimpCurve *curve,
|
|
|
|
gint point,
|
|
|
|
gdouble x,
|
|
|
|
gdouble y)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
2008-02-28 20:34:46 +08:00
|
|
|
g_return_if_fail (point >= 0 && point < curve->n_points);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
curve->points[point].x = CLAMP (x, 0.0, 1.0);
|
|
|
|
curve->points[point].y = CLAMP (y, 0.0, 1.0);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
if (point > 0)
|
|
|
|
curve->points[point].x = MAX (x, curve->points[point - 1].x);
|
|
|
|
|
|
|
|
if (point < curve->n_points - 1)
|
|
|
|
curve->points[point].x = MIN (x, curve->points[point + 1].x);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
|
2007-11-03 00:51:18 +08:00
|
|
|
|
2007-11-05 18:02:20 +08:00
|
|
|
gimp_data_dirty (GIMP_DATA (curve));
|
2007-11-03 00:51:18 +08:00
|
|
|
}
|
|
|
|
|
2010-07-26 07:08:44 +08:00
|
|
|
void
|
2019-04-19 16:24:24 +08:00
|
|
|
gimp_curve_move_point (GimpCurve *curve,
|
|
|
|
gint point,
|
|
|
|
gdouble y)
|
2010-07-26 07:08:44 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
|
|
|
g_return_if_fail (point >= 0 && point < curve->n_points);
|
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
curve->points[point].y = CLAMP (y, 0.0, 1.0);
|
2010-07-26 07:08:44 +08:00
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
|
2010-07-26 07:08:44 +08:00
|
|
|
|
|
|
|
gimp_data_dirty (GIMP_DATA (curve));
|
|
|
|
}
|
|
|
|
|
2008-02-11 18:22:59 +08:00
|
|
|
void
|
|
|
|
gimp_curve_get_point (GimpCurve *curve,
|
|
|
|
gint point,
|
|
|
|
gdouble *x,
|
|
|
|
gdouble *y)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
2008-02-28 20:34:46 +08:00
|
|
|
g_return_if_fail (point >= 0 && point < curve->n_points);
|
2008-02-11 18:22:59 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
if (x) *x = curve->points[point].x;
|
|
|
|
if (y) *y = curve->points[point].y;
|
|
|
|
}
|
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
void
|
|
|
|
gimp_curve_set_point_type (GimpCurve *curve,
|
|
|
|
gint point,
|
|
|
|
GimpCurvePointType type)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
|
|
|
g_return_if_fail (point >= 0 && point < curve->n_points);
|
|
|
|
|
|
|
|
curve->points[point].type = type;
|
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
|
2019-04-19 22:09:08 +08:00
|
|
|
|
|
|
|
gimp_data_dirty (GIMP_DATA (curve));
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpCurvePointType
|
|
|
|
gimp_curve_get_point_type (GimpCurve *curve,
|
|
|
|
gint point)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_CURVE (curve), GIMP_CURVE_POINT_SMOOTH);
|
|
|
|
g_return_val_if_fail (point >= 0 && point < curve->n_points, GIMP_CURVE_POINT_SMOOTH);
|
|
|
|
|
|
|
|
return curve->points[point].type;
|
|
|
|
}
|
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
void
|
|
|
|
gimp_curve_clear_points (GimpCurve *curve)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
|
|
|
|
|
|
|
if (curve->points)
|
2008-10-09 17:44:08 +08:00
|
|
|
{
|
2019-04-19 16:24:24 +08:00
|
|
|
g_clear_pointer (&curve->points, g_free);
|
2019-05-27 23:47:55 +08:00
|
|
|
curve->n_points = 0;
|
2008-10-09 17:44:08 +08:00
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_N_POINTS]);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINTS]);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_POINT_TYPES]);
|
2008-02-11 18:22:59 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
gimp_data_dirty (GIMP_DATA (curve));
|
|
|
|
}
|
2008-02-11 18:22:59 +08:00
|
|
|
}
|
|
|
|
|
2007-11-03 00:51:18 +08:00
|
|
|
void
|
|
|
|
gimp_curve_set_curve (GimpCurve *curve,
|
2008-02-09 18:01:51 +08:00
|
|
|
gdouble x,
|
|
|
|
gdouble y)
|
2007-11-03 00:51:18 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
2008-02-20 21:48:37 +08:00
|
|
|
g_return_if_fail (x >= 0 && x <= 1.0);
|
|
|
|
g_return_if_fail (y >= 0 && y <= 1.0);
|
2007-11-03 00:51:18 +08:00
|
|
|
|
|
|
|
if (curve->curve_type == GIMP_CURVE_SMOOTH)
|
|
|
|
return;
|
|
|
|
|
2008-02-28 20:34:46 +08:00
|
|
|
curve->samples[ROUND (x * (gdouble) (curve->n_samples - 1))] = y;
|
2007-11-03 00:51:18 +08:00
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_SAMPLES]);
|
2007-11-03 00:51:18 +08:00
|
|
|
|
2007-11-05 18:02:20 +08:00
|
|
|
gimp_data_dirty (GIMP_DATA (curve));
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
2008-05-13 15:10:48 +08:00
|
|
|
/**
|
|
|
|
* gimp_curve_is_identity:
|
|
|
|
* @curve: a #GimpCurve object
|
|
|
|
*
|
|
|
|
* If this function returns %TRUE, then the curve maps each value to
|
|
|
|
* itself. If it returns %FALSE, then this assumption can not be made.
|
|
|
|
*
|
2019-08-03 06:10:14 +08:00
|
|
|
* Returns: %TRUE if the curve is an identity mapping, %FALSE otherwise.
|
2008-05-13 15:10:48 +08:00
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
gimp_curve_is_identity (GimpCurve *curve)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_CURVE (curve), FALSE);
|
|
|
|
|
|
|
|
return curve->identity;
|
|
|
|
}
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
void
|
|
|
|
gimp_curve_get_uchar (GimpCurve *curve,
|
2008-02-28 20:34:46 +08:00
|
|
|
gint n_samples,
|
|
|
|
guchar *samples)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
2008-02-09 18:01:51 +08:00
|
|
|
gint i;
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
g_return_if_fail (GIMP_IS_CURVE (curve));
|
2009-07-20 17:53:02 +08:00
|
|
|
/* FIXME: support n_samples != curve->n_samples */
|
2008-02-28 20:34:46 +08:00
|
|
|
g_return_if_fail (n_samples == curve->n_samples);
|
|
|
|
g_return_if_fail (samples != NULL);
|
|
|
|
|
|
|
|
for (i = 0; i < curve->n_samples; i++)
|
|
|
|
samples[i] = curve->samples[i] * 255.999;
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* private functions */
|
|
|
|
|
2007-11-05 18:02:20 +08:00
|
|
|
static void
|
2007-11-02 20:18:50 +08:00
|
|
|
gimp_curve_calculate (GimpCurve *curve)
|
|
|
|
{
|
2019-04-19 16:24:24 +08:00
|
|
|
gint i;
|
|
|
|
gint p1, p2, p3, p4;
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2009-11-01 01:48:38 +08:00
|
|
|
if (gimp_data_is_frozen (GIMP_DATA (curve)))
|
2007-11-05 18:02:20 +08:00
|
|
|
return;
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
switch (curve->curve_type)
|
|
|
|
{
|
|
|
|
case GIMP_CURVE_SMOOTH:
|
|
|
|
/* Initialize boundary curve points */
|
2019-04-19 16:24:24 +08:00
|
|
|
if (curve->n_points > 0)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
2019-04-19 22:09:08 +08:00
|
|
|
GimpCurvePoint point;
|
|
|
|
gint boundary;
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
point = curve->points[0];
|
2008-02-28 20:34:46 +08:00
|
|
|
boundary = ROUND (point.x * (gdouble) (curve->n_samples - 1));
|
|
|
|
|
|
|
|
for (i = 0; i < boundary; i++)
|
|
|
|
curve->samples[i] = point.y;
|
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
point = curve->points[curve->n_points - 1];
|
2008-02-28 20:34:46 +08:00
|
|
|
boundary = ROUND (point.x * (gdouble) (curve->n_samples - 1));
|
|
|
|
|
|
|
|
for (i = boundary; i < curve->n_samples; i++)
|
|
|
|
curve->samples[i] = point.y;
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
for (i = 0; i < curve->n_points - 1; i++)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
2019-04-19 16:24:24 +08:00
|
|
|
p1 = MAX (i - 1, 0);
|
|
|
|
p2 = i;
|
|
|
|
p3 = i + 1;
|
|
|
|
p4 = MIN (i + 2, curve->n_points - 1);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2019-04-19 22:09:08 +08:00
|
|
|
if (curve->points[p2].type == GIMP_CURVE_POINT_CORNER)
|
|
|
|
p1 = p2;
|
|
|
|
|
|
|
|
if (curve->points[p3].type == GIMP_CURVE_POINT_CORNER)
|
|
|
|
p4 = p3;
|
|
|
|
|
2007-11-02 20:18:50 +08:00
|
|
|
gimp_curve_plot (curve, p1, p2, p3, p4);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ensure that the control points are used exactly */
|
2019-04-19 16:24:24 +08:00
|
|
|
for (i = 0; i < curve->n_points; i++)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
2019-04-19 16:24:24 +08:00
|
|
|
gdouble x = curve->points[i].x;
|
|
|
|
gdouble y = curve->points[i].y;
|
2007-11-02 20:18:50 +08:00
|
|
|
|
2008-02-28 20:34:46 +08:00
|
|
|
curve->samples[ROUND (x * (gdouble) (curve->n_samples - 1))] = y;
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
2007-11-03 00:51:18 +08:00
|
|
|
|
2020-05-13 04:38:41 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (curve), obj_props[PROP_SAMPLES]);
|
2007-11-02 20:18:50 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GIMP_CURVE_FREE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function calculates the curve values between the control points
|
|
|
|
* p2 and p3, taking the potentially existing neighbors p1 and p4 into
|
|
|
|
* account.
|
|
|
|
*
|
|
|
|
* This function uses a cubic bezier curve for the individual segments and
|
|
|
|
* calculates the necessary intermediate control points depending on the
|
|
|
|
* neighbor curve control points.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
gimp_curve_plot (GimpCurve *curve,
|
|
|
|
gint p1,
|
|
|
|
gint p2,
|
|
|
|
gint p3,
|
|
|
|
gint p4)
|
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
gdouble x0, x3;
|
|
|
|
gdouble y0, y1, y2, y3;
|
|
|
|
gdouble dx, dy;
|
|
|
|
gdouble slope;
|
|
|
|
|
|
|
|
/* the outer control points for the bezier curve. */
|
2008-02-10 01:40:57 +08:00
|
|
|
x0 = curve->points[p2].x;
|
|
|
|
y0 = curve->points[p2].y;
|
|
|
|
x3 = curve->points[p3].x;
|
|
|
|
y3 = curve->points[p3].y;
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* the x values of the inner control points are fixed at
|
2008-09-19 03:48:04 +08:00
|
|
|
* x1 = 2/3*x0 + 1/3*x3 and x2 = 1/3*x0 + 2/3*x3
|
2018-04-26 02:31:11 +08:00
|
|
|
* this ensures that the x values increase linearly with the
|
2007-11-02 20:18:50 +08:00
|
|
|
* parameter t and enables us to skip the calculation of the x
|
2018-04-26 02:31:11 +08:00
|
|
|
* values altogether - just calculate y(t) evenly spaced.
|
2007-11-02 20:18:50 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
dx = x3 - x0;
|
|
|
|
dy = y3 - y0;
|
|
|
|
|
2019-04-19 16:24:24 +08:00
|
|
|
if (dx <= EPSILON)
|
|
|
|
{
|
|
|
|
gint index;
|
|
|
|
|
|
|
|
index = ROUND (x0 * (gdouble) (curve->n_samples - 1));
|
|
|
|
|
|
|
|
curve->samples[index] = y3;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
if (p1 == p2 && p3 == p4)
|
|
|
|
{
|
|
|
|
/* No information about the neighbors,
|
|
|
|
* calculate y1 and y2 to get a straight line
|
|
|
|
*/
|
|
|
|
y1 = y0 + dy / 3.0;
|
|
|
|
y2 = y0 + dy * 2.0 / 3.0;
|
|
|
|
}
|
|
|
|
else if (p1 == p2 && p3 != p4)
|
|
|
|
{
|
|
|
|
/* only the right neighbor is available. Make the tangent at the
|
|
|
|
* right endpoint parallel to the line between the left endpoint
|
|
|
|
* and the right neighbor. Then point the tangent at the left towards
|
|
|
|
* the control handle of the right tangent, to ensure that the curve
|
|
|
|
* does not have an inflection point.
|
|
|
|
*/
|
2008-09-19 05:55:28 +08:00
|
|
|
slope = (curve->points[p4].y - y0) / (curve->points[p4].x - x0);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
y2 = y3 - slope * dx / 3.0;
|
|
|
|
y1 = y0 + (y2 - y0) / 2.0;
|
|
|
|
}
|
|
|
|
else if (p1 != p2 && p3 == p4)
|
|
|
|
{
|
|
|
|
/* see previous case */
|
2008-09-19 05:55:28 +08:00
|
|
|
slope = (y3 - curve->points[p1].y) / (x3 - curve->points[p1].x);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
y1 = y0 + slope * dx / 3.0;
|
|
|
|
y2 = y3 + (y1 - y3) / 2.0;
|
|
|
|
}
|
|
|
|
else /* (p1 != p2 && p3 != p4) */
|
|
|
|
{
|
|
|
|
/* Both neighbors are available. Make the tangents at the endpoints
|
|
|
|
* parallel to the line between the opposite endpoint and the adjacent
|
|
|
|
* neighbor.
|
|
|
|
*/
|
2008-09-19 05:55:28 +08:00
|
|
|
slope = (y3 - curve->points[p1].y) / (x3 - curve->points[p1].x);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
y1 = y0 + slope * dx / 3.0;
|
|
|
|
|
2008-09-19 05:55:28 +08:00
|
|
|
slope = (curve->points[p4].y - y0) / (curve->points[p4].x - x0);
|
2007-11-02 20:18:50 +08:00
|
|
|
|
|
|
|
y2 = y3 - slope * dx / 3.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* finally calculate the y(t) values for the given bezier values. We can
|
2019-04-06 22:36:03 +08:00
|
|
|
* use homogeneously distributed values for t, since x(t) increases linearly.
|
2007-11-02 20:18:50 +08:00
|
|
|
*/
|
2008-02-28 20:34:46 +08:00
|
|
|
for (i = 0; i <= ROUND (dx * (gdouble) (curve->n_samples - 1)); i++)
|
2007-11-02 20:18:50 +08:00
|
|
|
{
|
2008-02-28 20:34:46 +08:00
|
|
|
gdouble y, t;
|
|
|
|
gint index;
|
|
|
|
|
|
|
|
t = i / dx / (gdouble) (curve->n_samples - 1);
|
2007-11-02 20:18:50 +08:00
|
|
|
y = y0 * (1-t) * (1-t) * (1-t) +
|
|
|
|
3 * y1 * (1-t) * (1-t) * t +
|
|
|
|
3 * y2 * (1-t) * t * t +
|
|
|
|
y3 * t * t * t;
|
|
|
|
|
2008-05-15 00:19:33 +08:00
|
|
|
index = i + ROUND (x0 * (gdouble) (curve->n_samples - 1));
|
2008-02-28 20:34:46 +08:00
|
|
|
|
2008-05-15 00:19:33 +08:00
|
|
|
if (index < curve->n_samples)
|
|
|
|
curve->samples[index] = CLAMP (y, 0.0, 1.0);
|
2007-11-02 20:18:50 +08:00
|
|
|
}
|
|
|
|
}
|