/* * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * This is a plug-in for PIKA. * * Plugin to convert a selection to a path. * * Copyright (C) 1999 Andy Thomas alt@gimp.org * * 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 . * */ /* Change log:- * 0.1 First version. */ #include "config.h" #include #include #include "types.h" #include "selection-to-path.h" #include "libpika/stdplugins-intl.h" static GSList * adjust_widgets = NULL; void scale_entry_update_double (PikaLabelSpin *entry, gdouble *value); /* Reset to recommended defaults */ void reset_adv_dialog (void) { GSList *list; GObject *widget; gdouble *value; for (list = adjust_widgets; list; list = g_slist_next (list)) { widget = G_OBJECT (list->data); value = (gdouble *) g_object_get_data (G_OBJECT (widget), "default_value"); if (GTK_IS_ADJUSTMENT (widget)) { gtk_adjustment_set_value (GTK_ADJUSTMENT (widget), *value); } else if (GTK_IS_TOGGLE_BUTTON (widget)) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), (gboolean)(*value)); } else if (PIKA_IS_SCALE_ENTRY (widget)) { pika_label_spin_set_value (PIKA_LABEL_SPIN (widget), *value); } else g_warning ("Internal widget list error"); } } static gpointer def_val (gdouble default_value) { gdouble *value = g_new0 (gdouble, 1); *value = default_value; return (value); } GtkWidget * dialog_create_selection_area (SELVALS *sels) { GtkWidget *scrolled_win; GtkWidget *grid; GtkWidget *check; GtkWidget *scale; gint row; scrolled_win = gtk_scrolled_window_new (NULL, NULL); gtk_widget_set_size_request (scrolled_win, -1, 400); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_NONE); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_overlay_scrolling (GTK_SCROLLED_WINDOW (scrolled_win), FALSE); grid = gtk_grid_new (); gtk_grid_set_row_spacing (GTK_GRID (grid), 6); gtk_grid_set_column_spacing (GTK_GRID (grid), 6); gtk_container_add (GTK_CONTAINER (scrolled_win), grid); gtk_widget_show (grid); row = 0; scale = pika_scale_entry_new (_("Align Threshold:"), sels->align_threshold, 0.2, 2.0, 2); pika_help_set_help_data (scale, _("If two endpoints are closer than this, " "they are made to be equal."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->align_threshold); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (0.5)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Corner Always Threshold:"), sels->corner_always_threshold, 30, 180, 2); pika_help_set_help_data (scale, _("If the angle defined by a point and its predecessors " "and successors is smaller than this, it's a corner, " "even if it's within 'corner_surround' pixels of a " "point with a smaller angle."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->corner_always_threshold); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (60.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Corner Surround:"), sels->corner_surround, 3, 8, 0); pika_help_set_help_data (scale, _("Number of points to consider when determining if a " "point is a corner or not."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->corner_surround); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (4.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Corner Threshold:"), sels->corner_threshold, 0, 180, 2); pika_help_set_help_data (scale, _("If a point, its predecessors, and its successors " "define an angle smaller than this, it's a corner."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->corner_threshold); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (100.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Error Threshold:"), sels->error_threshold, 0.2, 10, 2); pika_help_set_help_data (scale, _("Amount of error at which a fitted spline is " "unacceptable. If any pixel is further away " "than this from the fitted curve, we try again."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->error_threshold); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (0.40)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Filter Alternative Surround:"), sels->filter_alternative_surround, 1, 10, 0); pika_help_set_help_data (scale, _("A second number of adjacent points to consider " "when filtering."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->filter_alternative_surround); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (1.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Filter Epsilon:"), sels->filter_epsilon, 5, 40, 2); pika_help_set_help_data (scale, _("If the angles between the vectors produced by " "filter_surround and filter_alternative_surround " "points differ by more than this, use the one from " "filter_alternative_surround."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->filter_epsilon); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (10.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Filter Iteration Count:"), sels->filter_iteration_count, 4, 70, 0); pika_help_set_help_data (scale, _("Number of times to smooth original data points. " "Increasing this number dramatically --- to 50 or " "so --- can produce vastly better results. But if " "any points that 'should' be corners aren't found, " "the curve goes to hell around that point."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->filter_iteration_count); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (4.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Filter Percent:"), sels->filter_percent, 0, 1, 2); pika_help_set_help_data (scale, _("To produce the new point, use the old point plus " "this times the neighbors."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->filter_percent); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (0.33)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Filter Secondary Surround:"), sels->filter_secondary_surround, 3, 10, 0); pika_help_set_help_data (scale, _("Number of adjacent points to consider if " "'filter_surround' points defines a straight line."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->filter_secondary_surround); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (3.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Filter Surround:"), sels->filter_surround, 2, 10, 0); pika_help_set_help_data (scale, _("Number of adjacent points to consider when filtering."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->filter_surround); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (2.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); check = gtk_check_button_new_with_label (_("Keep Knees")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), sels->keep_knees); gtk_grid_attach (GTK_GRID (grid), check, 1, row, 2, 1); pika_help_set_help_data (GTK_WIDGET (check), _("Says whether or not to remove 'knee' " "points after finding the outline."), NULL); g_signal_connect (check, "toggled", G_CALLBACK (pika_toggle_button_update), &sels->keep_knees); gtk_widget_show (check); adjust_widgets = g_slist_append (adjust_widgets, check); g_object_set_data (G_OBJECT (check), "default_value", def_val ((gdouble)FALSE)); row++; scale = pika_scale_entry_new (_("Line Reversion Threshold:"), sels->line_reversion_threshold, 0.01, 0.2, 3); pika_help_set_help_data (scale, _("If a spline is closer to a straight line than this, " "it remains a straight line, even if it would otherwise " "be changed back to a curve. This is weighted by the " "square of the curve length, to make shorter curves " "more likely to be reverted."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->line_reversion_threshold); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (0.01)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Line Threshold:"), sels->line_threshold, 0.2, 4, 2); pika_help_set_help_data (scale, _("How many pixels (on the average) a spline can " "diverge from the line determined by its endpoints " "before it is changed to a straight line."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->line_threshold); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (0.5)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Reparametrize Improvement:"), sels->reparameterize_improvement, 0, 1, 2); pika_help_set_help_data (scale, _("If reparameterization doesn't improve the fit by this " "much percent, stop doing it. ""Amount of error at which " "it is pointless to reparameterize."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->reparameterize_improvement); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (0.01)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Reparametrize Threshold:"), sels->reparameterize_threshold, 1, 50, 2); pika_help_set_help_data (scale, _("Amount of error at which it is pointless to reparameterize. " "This happens, for example, when we are trying to fit the " "outline of the outside of an 'O' with a single spline. " "The initial fit is not good enough for the Newton-Raphson " "iteration to improve it. It may be that it would be better " "to detect the cases where we didn't find any corners."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->reparameterize_threshold); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (1.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Subdivide Search:"), sels->subdivide_search, 0.05, 1, 2); pika_help_set_help_data (scale, _("Percentage of the curve away from the worst point " "to look for a better place to subdivide."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->subdivide_search); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (0.1)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Subdivide Surround:"), sels->subdivide_surround, 2, 10, 0); pika_help_set_help_data (scale, _("Number of points to consider when deciding whether " "a given point is a better place to subdivide."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->subdivide_surround); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (4.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Subdivide Threshold:"), sels->subdivide_threshold, 0.01, 1, 2); pika_help_set_help_data (scale, _("How many pixels a point can diverge from a straight " "line and still be considered a better place to " "subdivide."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->subdivide_threshold); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (0.03)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); scale = pika_scale_entry_new (_("Tangent Surround:"), sels->tangent_surround, 2, 10, 0); pika_help_set_help_data (scale, _("Number of points to look at on either side of a " "point when computing the approximation to the " "tangent at that point."), NULL); g_signal_connect (scale, "value-changed", G_CALLBACK (scale_entry_update_double), &sels->tangent_surround); adjust_widgets = g_slist_append (adjust_widgets, scale); g_object_set_data (G_OBJECT (scale), "default_value", def_val (3.0)); gtk_grid_attach (GTK_GRID (grid), scale, 0, row++, 3, 1); gtk_widget_show (scale); return scrolled_win; } void scale_entry_update_double (PikaLabelSpin *entry, gdouble *value) { *value = pika_label_spin_get_value (entry); }