app: add "orientation" property to GimpToolCompass + improvements

Add an "orientation" property to GimpToolCompass, which can be one
of "auto", "horizontal", or "vertical", and which controls the
orientation of the line against which the angle is measured, when
not in 3-point mode (previously, the line would always be
horizontal.)  When "orientation" is "auto", the orientation is
automatically set to either horizontal or vertical, such that the
measured angle is <= 45 deg.

Keep the line horizontal, or vertical, in display-space, rather
than in image-space, so that the compass works correctly even when
the canvas is rotated and/or flipped.

Fix the compass's behavior when the image's horizontal and vertical
resolutions are different, both with and without dot-for-dot.

Add "pixel-angle" and "unit-angle" read-only properties, which
return the measured angle either with or without taking the image's
resolution into account, respectively.  These properties will be
used by the measure tool in the next commit, instead of having it
implement its own angle calculation.

(cherry picked from commit d2f33cf1be)
This commit is contained in:
Ell
2018-07-15 18:07:54 -04:00
parent 4cb91320a4
commit fc4ca7fbcf
5 changed files with 291 additions and 188 deletions

View File

@ -455,6 +455,37 @@ gimp_vector_mode_get_type (void)
return type;
}
GType
gimp_compass_orientation_get_type (void)
{
static const GEnumValue values[] =
{
{ GIMP_COMPASS_ORIENTATION_AUTO, "GIMP_COMPASS_ORIENTATION_AUTO", "auto" },
{ GIMP_COMPASS_ORIENTATION_HORIZONTAL, "GIMP_COMPASS_ORIENTATION_HORIZONTAL", "horizontal" },
{ GIMP_COMPASS_ORIENTATION_VERTICAL, "GIMP_COMPASS_ORIENTATION_VERTICAL", "vertical" },
{ 0, NULL, NULL }
};
static const GimpEnumDesc descs[] =
{
{ GIMP_COMPASS_ORIENTATION_AUTO, NC_("compass-orientation", "Auto"), NULL },
{ GIMP_COMPASS_ORIENTATION_HORIZONTAL, NC_("compass-orientation", "Horizontal"), NULL },
{ GIMP_COMPASS_ORIENTATION_VERTICAL, NC_("compass-orientation", "Vertical"), NULL },
{ 0, NULL, NULL }
};
static GType type = 0;
if (G_UNLIKELY (! type))
{
type = g_enum_register_static ("GimpCompassOrientation", values);
gimp_type_set_translation_context (type, "compass-orientation");
gimp_enum_set_value_descriptions (type, descs);
}
return type;
}
GType
gimp_zoom_focus_get_type (void)
{

View File

@ -197,6 +197,18 @@ typedef enum
} GimpVectorMode;
#define GIMP_TYPE_COMPASS_ORIENTATION (gimp_compass_orientation_get_type ())
GType gimp_compass_orientation_get_type (void) G_GNUC_CONST;
typedef enum
{
GIMP_COMPASS_ORIENTATION_AUTO, /*< desc="Auto" >*/
GIMP_COMPASS_ORIENTATION_HORIZONTAL, /*< desc="Horizontal" >*/
GIMP_COMPASS_ORIENTATION_VERTICAL /*< desc="Vertical" >*/
} GimpCompassOrientation;
#define GIMP_TYPE_ZOOM_FOCUS (gimp_zoom_focus_get_type ())
GType gimp_zoom_focus_get_type (void) G_GNUC_CONST;

View File

@ -42,6 +42,7 @@
#include "gimpdisplay.h"
#include "gimpdisplayshell.h"
#include "gimpdisplayshell-appearance.h"
#include "gimpdisplayshell-transform.h"
#include "gimpdisplayshell-utils.h"
#include "gimptoolcompass.h"
@ -49,6 +50,8 @@
#define ARC_RADIUS 30
#define EPSILON 1e-6
/* possible measure functions */
typedef enum
@ -64,13 +67,16 @@ typedef enum
enum
{
PROP_0,
PROP_ORIENTATION,
PROP_N_POINTS,
PROP_X1,
PROP_Y1,
PROP_X2,
PROP_Y2,
PROP_X3,
PROP_Y3
PROP_Y3,
PROP_PIXEL_ANGLE,
PROP_UNIT_ANGLE
};
enum
@ -81,78 +87,85 @@ enum
struct _GimpToolCompassPrivate
{
gint n_points;
gint x[3];
gint y[3];
GimpCompassOrientation orientation;
gint n_points;
gint x[3];
gint y[3];
gdouble angle1;
gdouble angle2;
GimpVector2 radius1;
GimpVector2 radius2;
gdouble display_angle;
gdouble pixel_angle;
gdouble unit_angle;
CompassFunction function;
gdouble mouse_x;
gdouble mouse_y;
gint last_x;
gint last_y;
gint point;
CompassFunction function;
gdouble mouse_x;
gdouble mouse_y;
gint last_x;
gint last_y;
gint point;
GimpCanvasItem *line1;
GimpCanvasItem *line2;
GimpCanvasItem *angle;
GimpCanvasItem *angle_line;
GimpCanvasItem *handles[3];
GimpCanvasItem *line1;
GimpCanvasItem *line2;
GimpCanvasItem *arc;
GimpCanvasItem *arc_line;
GimpCanvasItem *handles[3];
};
/* local function prototypes */
static void gimp_tool_compass_constructed (GObject *object);
static void gimp_tool_compass_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_tool_compass_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_tool_compass_constructed (GObject *object);
static void gimp_tool_compass_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_tool_compass_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_tool_compass_changed (GimpToolWidget *widget);
static gint gimp_tool_compass_button_press (GimpToolWidget *widget,
const GimpCoords *coords,
guint32 time,
GdkModifierType state,
GimpButtonPressType press_type);
static void gimp_tool_compass_button_release (GimpToolWidget *widget,
const GimpCoords *coords,
guint32 time,
GdkModifierType state,
GimpButtonReleaseType release_type);
static void gimp_tool_compass_motion (GimpToolWidget *widget,
const GimpCoords *coords,
guint32 time,
GdkModifierType state);
static GimpHit gimp_tool_compass_hit (GimpToolWidget *widget,
const GimpCoords *coords,
GdkModifierType state,
gboolean proximity);
static void gimp_tool_compass_hover (GimpToolWidget *widget,
const GimpCoords *coords,
GdkModifierType state,
gboolean proximity);
static void gimp_tool_compass_leave_notify (GimpToolWidget *widget);
static void gimp_tool_compass_motion_modifier (GimpToolWidget *widget,
GdkModifierType key,
gboolean press,
GdkModifierType state);
static gboolean gimp_tool_compass_get_cursor (GimpToolWidget *widget,
const GimpCoords *coords,
GdkModifierType state,
GimpCursorType *cursor,
GimpToolCursorType *tool_cursor,
GimpCursorModifier *modifier);
static void gimp_tool_compass_changed (GimpToolWidget *widget);
static gint gimp_tool_compass_button_press (GimpToolWidget *widget,
const GimpCoords *coords,
guint32 time,
GdkModifierType state,
GimpButtonPressType press_type);
static void gimp_tool_compass_button_release (GimpToolWidget *widget,
const GimpCoords *coords,
guint32 time,
GdkModifierType state,
GimpButtonReleaseType release_type);
static void gimp_tool_compass_motion (GimpToolWidget *widget,
const GimpCoords *coords,
guint32 time,
GdkModifierType state);
static GimpHit gimp_tool_compass_hit (GimpToolWidget *widget,
const GimpCoords *coords,
GdkModifierType state,
gboolean proximity);
static void gimp_tool_compass_hover (GimpToolWidget *widget,
const GimpCoords *coords,
GdkModifierType state,
gboolean proximity);
static void gimp_tool_compass_leave_notify (GimpToolWidget *widget);
static void gimp_tool_compass_motion_modifier (GimpToolWidget *widget,
GdkModifierType key,
gboolean press,
GdkModifierType state);
static gboolean gimp_tool_compass_get_cursor (GimpToolWidget *widget,
const GimpCoords *coords,
GdkModifierType state,
GimpCursorType *cursor,
GimpToolCursorType *tool_cursor,
GimpCursorModifier *modifier);
static gint gimp_tool_compass_get_point (GimpToolCompass *compass,
const GimpCoords *coords);
static void gimp_tool_compass_update_hilight (GimpToolCompass *compass);
static gint gimp_tool_compass_get_point (GimpToolCompass *compass,
const GimpCoords *coords);
static void gimp_tool_compass_update_hilight (GimpToolCompass *compass);
static void gimp_tool_compass_update_angle (GimpToolCompass *compass,
GimpCompassOrientation orientation,
gboolean flip);
G_DEFINE_TYPE (GimpToolCompass, gimp_tool_compass, GIMP_TYPE_TOOL_WIDGET)
@ -195,6 +208,13 @@ gimp_tool_compass_class_init (GimpToolCompassClass *klass)
G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN);
g_object_class_install_property (object_class, PROP_ORIENTATION,
g_param_spec_enum ("orientation", NULL, NULL,
GIMP_TYPE_COMPASS_ORIENTATION,
GIMP_COMPASS_ORIENTATION_AUTO,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_N_POINTS,
g_param_spec_int ("n-points", NULL, NULL,
1, 3, 1,
@ -243,6 +263,16 @@ gimp_tool_compass_class_init (GimpToolCompassClass *klass)
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_PIXEL_ANGLE,
g_param_spec_double ("pixel-angle", NULL, NULL,
-G_PI, G_PI, 0.0,
GIMP_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_UNIT_ANGLE,
g_param_spec_double ("unit-angle", NULL, NULL,
-G_PI, G_PI, 0.0,
GIMP_PARAM_READABLE));
g_type_class_add_private (klass, sizeof (GimpToolCompassPrivate));
}
@ -256,72 +286,6 @@ gimp_tool_compass_init (GimpToolCompass *compass)
compass->private->point = -1;
}
static gdouble
gimp_tool_compass_get_angle (gint dx,
gint dy,
gdouble xres,
gdouble yres)
{
gdouble angle;
if (dx)
angle = gimp_rad_to_deg (atan (((gdouble) (dy) / yres) /
((gdouble) (dx) / xres)));
else if (dy)
angle = dy > 0 ? 270.0 : 90.0;
else
angle = 180.0;
if (dx > 0)
{
if (dy > 0)
angle = 360.0 - angle;
else
angle = -angle;
}
else
{
angle = 180.0 - angle;
}
return angle;
}
static void
gimp_tool_compass_update_angles (GimpToolCompass *compass)
{
GimpToolWidget *widget = GIMP_TOOL_WIDGET (compass);
GimpToolCompassPrivate *private = compass->private;
GimpDisplayShell *shell = gimp_tool_widget_get_shell (widget);
GimpImage *image = gimp_display_get_image (shell->display);
gint ax, ay;
gint bx, by;
gdouble xres;
gdouble yres;
ax = private->x[1] - private->x[0];
ay = private->y[1] - private->y[0];
if (private->n_points == 3)
{
bx = private->x[2] - private->x[0];
by = private->y[2] - private->y[0];
}
else
{
bx = 0;
by = 0;
}
gimp_image_get_resolution (image, &xres, &yres);
if (private->n_points != 3)
bx = ax > 0 ? 1 : -1;
private->angle1 = gimp_tool_compass_get_angle (ax, ay, xres, yres);
private->angle2 = gimp_tool_compass_get_angle (bx, by, xres, yres);
}
static void
gimp_tool_compass_constructed (GObject *object)
{
@ -349,19 +313,19 @@ gimp_tool_compass_constructed (GObject *object)
private->x[2],
private->y[2]);
private->angle = gimp_tool_widget_add_handle (widget,
GIMP_HANDLE_CIRCLE,
private->x[0],
private->y[0],
ARC_RADIUS * 2 + 1,
ARC_RADIUS * 2 + 1,
GIMP_HANDLE_ANCHOR_CENTER);
private->arc = gimp_tool_widget_add_handle (widget,
GIMP_HANDLE_CIRCLE,
private->x[0],
private->y[0],
ARC_RADIUS * 2 + 1,
ARC_RADIUS * 2 + 1,
GIMP_HANDLE_ANCHOR_CENTER);
private->angle_line = gimp_tool_widget_add_line (widget,
private->x[0],
private->y[0],
private->x[0] + 10,
private->y[0]);
private->arc_line = gimp_tool_widget_add_line (widget,
private->x[0],
private->y[0],
private->x[0] + 10,
private->y[0]);
gimp_tool_widget_pop_group (widget);
@ -413,6 +377,9 @@ gimp_tool_compass_set_property (GObject *object,
case PROP_Y3:
private->y[2] = g_value_get_int (value);
break;
case PROP_ORIENTATION:
private->orientation = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -452,6 +419,15 @@ gimp_tool_compass_get_property (GObject *object,
case PROP_Y3:
g_value_set_int (value, private->y[2]);
break;
case PROP_ORIENTATION:
g_value_set_enum (value, private->orientation);
break;
case PROP_PIXEL_ANGLE:
g_value_set_double (value, private->pixel_angle);
break;
case PROP_UNIT_ANGLE:
g_value_set_double (value, private->unit_angle);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -468,10 +444,13 @@ gimp_tool_compass_changed (GimpToolWidget *widget)
gdouble angle1;
gdouble angle2;
gint draw_arc = 0;
gdouble target;
gdouble arc_radius;
gdouble arc_line_length;
gimp_tool_compass_update_angles (compass);
gimp_tool_compass_update_angle (compass, private->orientation, FALSE);
angle1 = -atan2 (private->radius1.y * shell->scale_y,
private->radius1.x * shell->scale_x);
angle2 = -private->display_angle;
gimp_canvas_line_set (private->line1,
private->x[0],
@ -505,36 +484,26 @@ gimp_tool_compass_changed (GimpToolWidget *widget)
draw_arc++;
}
angle1 = private->angle2 / 180.0 * G_PI;
angle2 = (private->angle1 - private->angle2) / 180.0 * G_PI;
if (angle2 > G_PI)
angle2 -= 2.0 * G_PI;
if (angle2 < -G_PI)
angle2 += 2.0 * G_PI;
gimp_canvas_handle_set_position (private->angle,
gimp_canvas_handle_set_position (private->arc,
private->x[0], private->y[0]);
gimp_canvas_handle_set_angles (private->angle, angle1, angle2);
gimp_canvas_item_set_visible (private->angle,
gimp_canvas_handle_set_angles (private->arc, angle1, angle2);
gimp_canvas_item_set_visible (private->arc,
private->n_points > 1 &&
draw_arc == private->n_points - 1 &&
angle2 != 0.0);
fabs (angle2) > EPSILON);
target = FUNSCALEX (shell, (GIMP_CANVAS_HANDLE_SIZE_CROSS >> 1));
arc_radius = FUNSCALEX (shell, ARC_RADIUS);
arc_line_length = (ARC_RADIUS + (GIMP_CANVAS_HANDLE_SIZE_CROSS >> 1)) /
hypot (private->radius2.x * shell->scale_x,
private->radius2.y * shell->scale_y);
gimp_canvas_line_set (private->angle_line,
gimp_canvas_line_set (private->arc_line,
private->x[0],
private->y[0],
private->x[0] + (private->x[1] > private->x[0] ?
(arc_radius + target) :
-(arc_radius + target)),
private->y[0]);
gimp_canvas_item_set_visible (private->angle_line,
private->x[0] + private->radius2.x * arc_line_length,
private->y[0] + private->radius2.y * arc_line_length);
gimp_canvas_item_set_visible (private->arc_line,
private->n_points == 2 &&
angle2 != 0.0);
fabs (angle2) > EPSILON);
gimp_canvas_handle_set_position (private->handles[0],
private->x[0], private->y[0]);
@ -1051,27 +1020,116 @@ gimp_tool_compass_update_hilight (GimpToolCompass *compass)
}
}
static void
gimp_tool_compass_update_angle (GimpToolCompass *compass,
GimpCompassOrientation orientation,
gboolean flip)
{
GimpToolWidget *widget = GIMP_TOOL_WIDGET (compass);
GimpToolCompassPrivate *private = compass->private;
GimpDisplayShell *shell = gimp_tool_widget_get_shell (widget);
GimpImage *image = gimp_display_get_image (shell->display);
GimpVector2 radius1;
GimpVector2 radius2;
gdouble xres;
gdouble yres;
gimp_image_get_resolution (image, &xres, &yres);
private->radius1.x = private->x[1] - private->x[0];
private->radius1.y = private->y[1] - private->y[0];
if (private->n_points == 3)
{
private->radius2.x = private->x[2] - private->x[0];
private->radius2.y = private->y[2] - private->y[0];
}
else
{
gdouble angle = -shell->rotate_angle * G_PI / 180.0;
if (orientation == GIMP_COMPASS_ORIENTATION_VERTICAL)
angle -= G_PI / 2.0;
if (flip)
angle += G_PI;
if (shell->flip_horizontally)
angle = G_PI - angle;
if (shell->flip_vertically)
angle = -angle;
private->radius2.x = cos (angle);
private->radius2.y = sin (angle);
if (! shell->dot_for_dot)
{
private->radius2.x *= xres;
private->radius2.y *= yres;
gimp_vector2_normalize (&private->radius2);
}
}
radius1 = private->radius1;
radius2 = private->radius2;
private->pixel_angle = atan2 (gimp_vector2_cross_product (&radius1, &radius2).x,
gimp_vector2_inner_product (&radius1, &radius2));
radius1.x /= xres;
radius1.y /= yres;
radius2.x /= xres;
radius2.y /= yres;
private->unit_angle = atan2 (gimp_vector2_cross_product (&radius1, &radius2).x,
gimp_vector2_inner_product (&radius1, &radius2));
if (shell->dot_for_dot)
private->display_angle = private->pixel_angle;
else
private->display_angle = private->unit_angle;
if (private->n_points == 2)
{
if (! flip && fabs (private->display_angle) > G_PI / 2.0 + EPSILON)
{
gimp_tool_compass_update_angle (compass, orientation, TRUE);
}
else if (orientation == GIMP_COMPASS_ORIENTATION_AUTO &&
fabs (private->display_angle) > G_PI / 4.0 + EPSILON)
{
gimp_tool_compass_update_angle (compass,
GIMP_COMPASS_ORIENTATION_VERTICAL,
FALSE);
}
}
}
/* public functions */
GimpToolWidget *
gimp_tool_compass_new (GimpDisplayShell *shell,
gint n_points,
gint x1,
gint y1,
gint x2,
gint y2,
gint x3,
gint y3)
gimp_tool_compass_new (GimpDisplayShell *shell,
GimpCompassOrientation orientation,
gint n_points,
gint x1,
gint y1,
gint x2,
gint y2,
gint x3,
gint y3)
{
g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
return g_object_new (GIMP_TYPE_TOOL_COMPASS,
"shell", shell,
"n-points", n_points,
"x1", x1,
"y1", y1,
"x2", x2,
"y2", y2,
"shell", shell,
"orientation", orientation,
"n-points", n_points,
"x1", x1,
"y1", y1,
"x2", x2,
"y2", y2,
NULL);
}

View File

@ -58,14 +58,15 @@ struct _GimpToolCompassClass
GType gimp_tool_compass_get_type (void) G_GNUC_CONST;
GimpToolWidget * gimp_tool_compass_new (GimpDisplayShell *shell,
gint n_points,
gint x1,
gint y1,
gint x2,
gint y2,
gint y3,
gint x3);
GimpToolWidget * gimp_tool_compass_new (GimpDisplayShell *shell,
GimpCompassOrientation orinetation,
gint n_points,
gint x1,
gint y1,
gint x2,
gint y2,
gint y3,
gint x3);
#endif /* __GIMP_TOOL_COMPASS_H__ */

View File

@ -436,6 +436,7 @@ gimp_measure_tool_start (GimpMeasureTool *measure,
measure->y[2] = 0;
measure->widget = gimp_tool_compass_new (shell,
GIMP_COMPASS_ORIENTATION_AUTO,
measure->n_points,
measure->x[0],
measure->y[0],