1167 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1167 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 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
 | 
						|
 *
 | 
						|
 * pikatool3dtransformgrid.c
 | 
						|
 * Copyright (C) 2019 Ell
 | 
						|
 *
 | 
						|
 * 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 <https://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
 | 
						|
#include "config.h"
 | 
						|
 | 
						|
#include <gegl.h>
 | 
						|
#include <gtk/gtk.h>
 | 
						|
 | 
						|
#include "libpikabase/pikabase.h"
 | 
						|
#include "libpikamath/pikamath.h"
 | 
						|
 | 
						|
#include "display-types.h"
 | 
						|
 | 
						|
#include "widgets/pikawidgets-utils.h"
 | 
						|
 | 
						|
#include "core/pika-transform-3d-utils.h"
 | 
						|
#include "core/pika-utils.h"
 | 
						|
 | 
						|
#include "pikadisplayshell.h"
 | 
						|
#include "pikadisplayshell-transform.h"
 | 
						|
#include "pikatooltransform3dgrid.h"
 | 
						|
 | 
						|
#include "pika-intl.h"
 | 
						|
 | 
						|
 | 
						|
#define CONSTRAINT_MIN_DIST   8.0
 | 
						|
#define PIXELS_PER_REVOLUTION 1000
 | 
						|
 | 
						|
 | 
						|
enum
 | 
						|
{
 | 
						|
  PROP_0,
 | 
						|
  PROP_MODE,
 | 
						|
  PROP_UNIFIED,
 | 
						|
  PROP_CONSTRAIN_AXIS,
 | 
						|
  PROP_Z_AXIS,
 | 
						|
  PROP_LOCAL_FRAME,
 | 
						|
  PROP_CAMERA_X,
 | 
						|
  PROP_CAMERA_Y,
 | 
						|
  PROP_CAMERA_Z,
 | 
						|
  PROP_OFFSET_X,
 | 
						|
  PROP_OFFSET_Y,
 | 
						|
  PROP_OFFSET_Z,
 | 
						|
  PROP_ROTATION_ORDER,
 | 
						|
  PROP_ANGLE_X,
 | 
						|
  PROP_ANGLE_Y,
 | 
						|
  PROP_ANGLE_Z,
 | 
						|
  PROP_PIVOT_3D_X,
 | 
						|
  PROP_PIVOT_3D_Y,
 | 
						|
  PROP_PIVOT_3D_Z
 | 
						|
};
 | 
						|
 | 
						|
typedef enum
 | 
						|
{
 | 
						|
  AXIS_NONE,
 | 
						|
  AXIS_X,
 | 
						|
  AXIS_Y
 | 
						|
} Axis;
 | 
						|
 | 
						|
struct _PikaToolTransform3DGridPrivate
 | 
						|
{
 | 
						|
  PikaTransform3DMode mode;
 | 
						|
  gboolean            unified;
 | 
						|
 | 
						|
  gboolean            constrain_axis;
 | 
						|
  gboolean            z_axis;
 | 
						|
  gboolean            local_frame;
 | 
						|
 | 
						|
  gdouble             camera_x;
 | 
						|
  gdouble             camera_y;
 | 
						|
  gdouble             camera_z;
 | 
						|
 | 
						|
  gdouble             offset_x;
 | 
						|
  gdouble             offset_y;
 | 
						|
  gdouble             offset_z;
 | 
						|
 | 
						|
  gint                rotation_order;
 | 
						|
  gdouble             angle_x;
 | 
						|
  gdouble             angle_y;
 | 
						|
  gdouble             angle_z;
 | 
						|
 | 
						|
  gdouble             pivot_x;
 | 
						|
  gdouble             pivot_y;
 | 
						|
  gdouble             pivot_z;
 | 
						|
 | 
						|
  PikaTransformHandle handle;
 | 
						|
 | 
						|
  gdouble             orig_x;
 | 
						|
  gdouble             orig_y;
 | 
						|
  gdouble             orig_offset_x;
 | 
						|
  gdouble             orig_offset_y;
 | 
						|
  gdouble             orig_offset_z;
 | 
						|
  PikaMatrix3         orig_transform;
 | 
						|
 | 
						|
  gdouble             last_x;
 | 
						|
  gdouble             last_y;
 | 
						|
 | 
						|
  Axis                constrained_axis;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/*  local function prototypes  */
 | 
						|
 | 
						|
static void       pika_tool_transform_3d_grid_constructed            (GObject                 *object);
 | 
						|
static void       pika_tool_transform_3d_grid_set_property           (GObject                 *object,
 | 
						|
                                                                      guint                    property_id,
 | 
						|
                                                                      const GValue            *value,
 | 
						|
                                                                      GParamSpec              *pspec);
 | 
						|
static void       pika_tool_transform_3d_grid_get_property           (GObject                 *object,
 | 
						|
                                                                      guint                    property_id,
 | 
						|
                                                                      GValue                  *value,
 | 
						|
                                                                      GParamSpec              *pspec);
 | 
						|
 | 
						|
static gint       pika_tool_transform_3d_grid_button_press           (PikaToolWidget          *widget,
 | 
						|
                                                                      const PikaCoords        *coords,
 | 
						|
                                                                      guint32                  time,
 | 
						|
                                                                      GdkModifierType          state,
 | 
						|
                                                                      PikaButtonPressType      press_type);
 | 
						|
static void       pika_tool_transform_3d_grid_motion                 (PikaToolWidget          *widget,
 | 
						|
                                                                      const PikaCoords        *coords,
 | 
						|
                                                                      guint32                  time,
 | 
						|
                                                                      GdkModifierType          state);
 | 
						|
static void       pika_tool_transform_3d_grid_hover                  (PikaToolWidget          *widget,
 | 
						|
                                                                      const PikaCoords        *coords,
 | 
						|
                                                                      GdkModifierType          state,
 | 
						|
                                                                      gboolean                 proximity);
 | 
						|
static void       pika_tool_transform_3d_grid_hover_modifier         (PikaToolWidget          *widget,
 | 
						|
                                                                      GdkModifierType          key,
 | 
						|
                                                                      gboolean                 press,
 | 
						|
                                                                      GdkModifierType          state);
 | 
						|
static gboolean   pika_tool_transform_3d_grid_get_cursor              (PikaToolWidget          *widget,
 | 
						|
                                                                      const PikaCoords        *coords,
 | 
						|
                                                                      GdkModifierType          state,
 | 
						|
                                                                      PikaCursorType          *cursor,
 | 
						|
                                                                      PikaToolCursorType      *tool_cursor,
 | 
						|
                                                                      PikaCursorModifier      *modifier);
 | 
						|
 | 
						|
static void       pika_tool_transform_3d_grid_update_mode            (PikaToolTransform3DGrid *grid);
 | 
						|
static void       pika_tool_transform_3d_grid_reset_motion           (PikaToolTransform3DGrid *grid);
 | 
						|
static gboolean   pika_tool_transform_3d_grid_constrain              (PikaToolTransform3DGrid *grid,
 | 
						|
                                                                      gdouble                  x,
 | 
						|
                                                                      gdouble                  y,
 | 
						|
                                                                      gdouble                  ox,
 | 
						|
                                                                      gdouble                  oy,
 | 
						|
                                                                      gdouble                 *tx,
 | 
						|
                                                                      gdouble                 *ty);
 | 
						|
 | 
						|
static gboolean   pika_tool_transform_3d_grid_motion_vanishing_point (PikaToolTransform3DGrid *grid,
 | 
						|
                                                                      gdouble                  x,
 | 
						|
                                                                      gdouble                  y);
 | 
						|
static gboolean   pika_tool_transform_3d_grid_motion_move            (PikaToolTransform3DGrid *grid,
 | 
						|
                                                                      gdouble                  x,
 | 
						|
                                                                      gdouble                  y);
 | 
						|
static gboolean   pika_tool_transform_3d_grid_motion_rotate          (PikaToolTransform3DGrid *grid,
 | 
						|
                                                                      gdouble                  x,
 | 
						|
                                                                      gdouble                  y);
 | 
						|
 | 
						|
 | 
						|
G_DEFINE_TYPE_WITH_PRIVATE (PikaToolTransform3DGrid, pika_tool_transform_3d_grid,
 | 
						|
                            PIKA_TYPE_TOOL_TRANSFORM_GRID)
 | 
						|
 | 
						|
#define parent_class pika_tool_transform_3d_grid_parent_class
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
pika_tool_transform_3d_grid_class_init (PikaToolTransform3DGridClass *klass)
 | 
						|
{
 | 
						|
  GObjectClass        *object_class = G_OBJECT_CLASS (klass);
 | 
						|
  PikaToolWidgetClass *widget_class = PIKA_TOOL_WIDGET_CLASS (klass);
 | 
						|
 | 
						|
  object_class->constructed     = pika_tool_transform_3d_grid_constructed;
 | 
						|
  object_class->set_property    = pika_tool_transform_3d_grid_set_property;
 | 
						|
  object_class->get_property    = pika_tool_transform_3d_grid_get_property;
 | 
						|
 | 
						|
  widget_class->button_press    = pika_tool_transform_3d_grid_button_press;
 | 
						|
  widget_class->motion          = pika_tool_transform_3d_grid_motion;
 | 
						|
  widget_class->hover           = pika_tool_transform_3d_grid_hover;
 | 
						|
  widget_class->hover_modifier  = pika_tool_transform_3d_grid_hover_modifier;
 | 
						|
  widget_class->get_cursor      = pika_tool_transform_3d_grid_get_cursor;
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_MODE,
 | 
						|
                                   g_param_spec_enum ("mode",
 | 
						|
                                                      NULL, NULL,
 | 
						|
                                                      PIKA_TYPE_TRANSFORM_3D_MODE,
 | 
						|
                                                      PIKA_TRANSFORM_3D_MODE_CAMERA,
 | 
						|
                                                      PIKA_PARAM_READWRITE |
 | 
						|
                                                      G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_UNIFIED,
 | 
						|
                                   g_param_spec_boolean ("unified",
 | 
						|
                                                         NULL, NULL,
 | 
						|
                                                         FALSE,
 | 
						|
                                                         PIKA_PARAM_READWRITE |
 | 
						|
                                                         G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_CONSTRAIN_AXIS,
 | 
						|
                                   g_param_spec_boolean ("constrain-axis",
 | 
						|
                                                         NULL, NULL,
 | 
						|
                                                         FALSE,
 | 
						|
                                                         PIKA_PARAM_READWRITE |
 | 
						|
                                                         G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_Z_AXIS,
 | 
						|
                                   g_param_spec_boolean ("z-axis",
 | 
						|
                                                         NULL, NULL,
 | 
						|
                                                         FALSE,
 | 
						|
                                                         PIKA_PARAM_READWRITE |
 | 
						|
                                                         G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_LOCAL_FRAME,
 | 
						|
                                   g_param_spec_boolean ("local-frame",
 | 
						|
                                                         NULL, NULL,
 | 
						|
                                                         FALSE,
 | 
						|
                                                         PIKA_PARAM_READWRITE |
 | 
						|
                                                         G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_CAMERA_X,
 | 
						|
                                   g_param_spec_double ("camera-x",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_CAMERA_Y,
 | 
						|
                                   g_param_spec_double ("camera-y",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_CAMERA_Z,
 | 
						|
                                   g_param_spec_double ("camera-z",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -(1.0 / 0.0),
 | 
						|
                                                        1.0 / 0.0,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_OFFSET_X,
 | 
						|
                                   g_param_spec_double ("offset-x",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_OFFSET_Y,
 | 
						|
                                   g_param_spec_double ("offset-y",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_OFFSET_Z,
 | 
						|
                                   g_param_spec_double ("offset-z",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_ROTATION_ORDER,
 | 
						|
                                   g_param_spec_int ("rotation-order",
 | 
						|
                                                     NULL, NULL,
 | 
						|
                                                     0, 6, 0,
 | 
						|
                                                     PIKA_PARAM_READWRITE |
 | 
						|
                                                     G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_ANGLE_X,
 | 
						|
                                   g_param_spec_double ("angle-x",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_ANGLE_Y,
 | 
						|
                                   g_param_spec_double ("angle-y",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_ANGLE_Z,
 | 
						|
                                   g_param_spec_double ("angle-z",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_PIVOT_3D_X,
 | 
						|
                                   g_param_spec_double ("pivot-3d-x",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_PIVOT_3D_Y,
 | 
						|
                                   g_param_spec_double ("pivot-3d-y",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
 | 
						|
  g_object_class_install_property (object_class, PROP_PIVOT_3D_Z,
 | 
						|
                                   g_param_spec_double ("pivot-3d-z",
 | 
						|
                                                        NULL, NULL,
 | 
						|
                                                        -G_MAXDOUBLE,
 | 
						|
                                                        G_MAXDOUBLE,
 | 
						|
                                                        0.0,
 | 
						|
                                                        PIKA_PARAM_READWRITE |
 | 
						|
                                                        G_PARAM_CONSTRUCT));
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pika_tool_transform_3d_grid_init (PikaToolTransform3DGrid *grid)
 | 
						|
{
 | 
						|
  grid->priv = pika_tool_transform_3d_grid_get_instance_private (grid);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pika_tool_transform_3d_grid_constructed (GObject *object)
 | 
						|
{
 | 
						|
  G_OBJECT_CLASS (parent_class)->constructed (object);
 | 
						|
 | 
						|
  g_object_set (object,
 | 
						|
                "clip-guides",         TRUE,
 | 
						|
                "dynamic-handle-size", FALSE,
 | 
						|
                NULL);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pika_tool_transform_3d_grid_set_property (GObject      *object,
 | 
						|
                                          guint         property_id,
 | 
						|
                                          const GValue *value,
 | 
						|
                                          GParamSpec   *pspec)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGrid        *grid = PIKA_TOOL_TRANSFORM_3D_GRID (object);
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
 | 
						|
  switch (property_id)
 | 
						|
    {
 | 
						|
    case PROP_MODE:
 | 
						|
      priv->mode = g_value_get_enum (value);
 | 
						|
      pika_tool_transform_3d_grid_update_mode (grid);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_UNIFIED:
 | 
						|
      priv->unified = g_value_get_boolean (value);
 | 
						|
      pika_tool_transform_3d_grid_update_mode (grid);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_CONSTRAIN_AXIS:
 | 
						|
      priv->constrain_axis = g_value_get_boolean (value);
 | 
						|
      pika_tool_transform_3d_grid_reset_motion (grid);
 | 
						|
      break;
 | 
						|
    case PROP_Z_AXIS:
 | 
						|
      priv->z_axis = g_value_get_boolean (value);
 | 
						|
      pika_tool_transform_3d_grid_reset_motion (grid);
 | 
						|
      break;
 | 
						|
    case PROP_LOCAL_FRAME:
 | 
						|
      priv->local_frame = g_value_get_boolean (value);
 | 
						|
      pika_tool_transform_3d_grid_reset_motion (grid);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_CAMERA_X:
 | 
						|
      priv->camera_x = g_value_get_double (value);
 | 
						|
      g_object_set (grid,
 | 
						|
                    "pivot-x", priv->camera_x,
 | 
						|
                    NULL);
 | 
						|
      break;
 | 
						|
    case PROP_CAMERA_Y:
 | 
						|
      priv->camera_y = g_value_get_double (value);
 | 
						|
      g_object_set (grid,
 | 
						|
                    "pivot-y", priv->camera_y,
 | 
						|
                    NULL);
 | 
						|
      break;
 | 
						|
    case PROP_CAMERA_Z:
 | 
						|
      priv->camera_z = g_value_get_double (value);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_OFFSET_X:
 | 
						|
      priv->offset_x = g_value_get_double (value);
 | 
						|
      break;
 | 
						|
    case PROP_OFFSET_Y:
 | 
						|
      priv->offset_y = g_value_get_double (value);
 | 
						|
      break;
 | 
						|
    case PROP_OFFSET_Z:
 | 
						|
      priv->offset_z = g_value_get_double (value);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_ROTATION_ORDER:
 | 
						|
      priv->rotation_order = g_value_get_int (value);
 | 
						|
      break;
 | 
						|
    case PROP_ANGLE_X:
 | 
						|
      priv->angle_x = g_value_get_double (value);
 | 
						|
      break;
 | 
						|
    case PROP_ANGLE_Y:
 | 
						|
      priv->angle_y = g_value_get_double (value);
 | 
						|
      break;
 | 
						|
    case PROP_ANGLE_Z:
 | 
						|
      priv->angle_z = g_value_get_double (value);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_PIVOT_3D_X:
 | 
						|
      priv->pivot_x = g_value_get_double (value);
 | 
						|
      break;
 | 
						|
    case PROP_PIVOT_3D_Y:
 | 
						|
      priv->pivot_y = g_value_get_double (value);
 | 
						|
      break;
 | 
						|
    case PROP_PIVOT_3D_Z:
 | 
						|
      priv->pivot_z = g_value_get_double (value);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pika_tool_transform_3d_grid_get_property (GObject    *object,
 | 
						|
                                          guint       property_id,
 | 
						|
                                          GValue     *value,
 | 
						|
                                          GParamSpec *pspec)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGrid        *grid = PIKA_TOOL_TRANSFORM_3D_GRID (object);
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
 | 
						|
  switch (property_id)
 | 
						|
    {
 | 
						|
    case PROP_MODE:
 | 
						|
      g_value_set_enum (value, priv->mode);
 | 
						|
      break;
 | 
						|
    case PROP_UNIFIED:
 | 
						|
      g_value_set_boolean (value, priv->unified);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_CONSTRAIN_AXIS:
 | 
						|
      g_value_set_boolean (value, priv->constrain_axis);
 | 
						|
      break;
 | 
						|
    case PROP_Z_AXIS:
 | 
						|
      g_value_set_boolean (value, priv->z_axis);
 | 
						|
      break;
 | 
						|
    case PROP_LOCAL_FRAME:
 | 
						|
      g_value_set_boolean (value, priv->local_frame);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_CAMERA_X:
 | 
						|
      g_value_set_double (value, priv->camera_x);
 | 
						|
      break;
 | 
						|
    case PROP_CAMERA_Y:
 | 
						|
      g_value_set_double (value, priv->camera_y);
 | 
						|
      break;
 | 
						|
    case PROP_CAMERA_Z:
 | 
						|
      g_value_set_double (value, priv->camera_z);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_OFFSET_X:
 | 
						|
      g_value_set_double (value, priv->offset_x);
 | 
						|
      break;
 | 
						|
    case PROP_OFFSET_Y:
 | 
						|
      g_value_set_double (value, priv->offset_y);
 | 
						|
      break;
 | 
						|
    case PROP_OFFSET_Z:
 | 
						|
      g_value_set_double (value, priv->offset_z);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_ROTATION_ORDER:
 | 
						|
      g_value_set_int (value, priv->rotation_order);
 | 
						|
      break;
 | 
						|
    case PROP_ANGLE_X:
 | 
						|
      g_value_set_double (value, priv->angle_x);
 | 
						|
      break;
 | 
						|
    case PROP_ANGLE_Y:
 | 
						|
      g_value_set_double (value, priv->angle_y);
 | 
						|
      break;
 | 
						|
    case PROP_ANGLE_Z:
 | 
						|
      g_value_set_double (value, priv->angle_z);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PROP_PIVOT_3D_X:
 | 
						|
      g_value_set_double (value, priv->pivot_x);
 | 
						|
      break;
 | 
						|
    case PROP_PIVOT_3D_Y:
 | 
						|
      g_value_set_double (value, priv->pivot_y);
 | 
						|
      break;
 | 
						|
    case PROP_PIVOT_3D_Z:
 | 
						|
      g_value_set_double (value, priv->pivot_z);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static gint
 | 
						|
pika_tool_transform_3d_grid_button_press (PikaToolWidget      *widget,
 | 
						|
                                          const PikaCoords    *coords,
 | 
						|
                                          guint32              time,
 | 
						|
                                          GdkModifierType      state,
 | 
						|
                                          PikaButtonPressType  press_type)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGrid        *grid = PIKA_TOOL_TRANSFORM_3D_GRID (widget);
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
 | 
						|
  priv->handle = PIKA_TOOL_WIDGET_CLASS (parent_class)->button_press (
 | 
						|
    widget, coords, time, state, press_type);
 | 
						|
 | 
						|
  priv->orig_x           = coords->x;
 | 
						|
  priv->orig_y           = coords->y;
 | 
						|
  priv->orig_offset_x    = priv->offset_x;
 | 
						|
  priv->orig_offset_y    = priv->offset_y;
 | 
						|
  priv->orig_offset_z    = priv->offset_z;
 | 
						|
  priv->last_x           = coords->x;
 | 
						|
  priv->last_y           = coords->y;
 | 
						|
 | 
						|
  pika_tool_transform_3d_grid_reset_motion (grid);
 | 
						|
 | 
						|
  return priv->handle;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pika_tool_transform_3d_grid_motion (PikaToolWidget   *widget,
 | 
						|
                                    const PikaCoords *coords,
 | 
						|
                                    guint32           time,
 | 
						|
                                    GdkModifierType   state)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGrid        *grid = PIKA_TOOL_TRANSFORM_3D_GRID (widget);
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
  PikaMatrix3                     transform;
 | 
						|
  gboolean                        update = TRUE;
 | 
						|
 | 
						|
  switch (priv->handle)
 | 
						|
    {
 | 
						|
    case PIKA_TRANSFORM_HANDLE_PIVOT:
 | 
						|
      update = pika_tool_transform_3d_grid_motion_vanishing_point (
 | 
						|
        grid, coords->x, coords->y);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PIKA_TRANSFORM_HANDLE_CENTER:
 | 
						|
      update = pika_tool_transform_3d_grid_motion_move (
 | 
						|
        grid, coords->x, coords->y);
 | 
						|
      break;
 | 
						|
 | 
						|
    case PIKA_TRANSFORM_HANDLE_ROTATION:
 | 
						|
      update = pika_tool_transform_3d_grid_motion_rotate (
 | 
						|
        grid, coords->x, coords->y);
 | 
						|
    break;
 | 
						|
 | 
						|
    default:
 | 
						|
      g_return_if_reached ();
 | 
						|
    }
 | 
						|
 | 
						|
  if (update)
 | 
						|
    {
 | 
						|
      pika_transform_3d_matrix (&transform,
 | 
						|
 | 
						|
                                priv->camera_x,
 | 
						|
                                priv->camera_y,
 | 
						|
                                priv->camera_z,
 | 
						|
 | 
						|
                                priv->offset_x,
 | 
						|
                                priv->offset_y,
 | 
						|
                                priv->offset_z,
 | 
						|
 | 
						|
                                priv->rotation_order,
 | 
						|
                                priv->angle_x,
 | 
						|
                                priv->angle_y,
 | 
						|
                                priv->angle_z,
 | 
						|
 | 
						|
                                priv->pivot_x,
 | 
						|
                                priv->pivot_y,
 | 
						|
                                priv->pivot_z);
 | 
						|
 | 
						|
      g_object_set (widget,
 | 
						|
                    "transform", &transform,
 | 
						|
                    NULL);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pika_tool_transform_3d_grid_hover (PikaToolWidget   *widget,
 | 
						|
                                   const PikaCoords *coords,
 | 
						|
                                   GdkModifierType   state,
 | 
						|
                                   gboolean          proximity)
 | 
						|
{
 | 
						|
  PIKA_TOOL_WIDGET_CLASS (parent_class)->hover (widget,
 | 
						|
                                                coords, state, proximity);
 | 
						|
 | 
						|
  if (proximity &&
 | 
						|
      pika_tool_transform_grid_get_handle (PIKA_TOOL_TRANSFORM_GRID (widget)) ==
 | 
						|
      PIKA_TRANSFORM_HANDLE_PIVOT)
 | 
						|
    {
 | 
						|
      pika_tool_widget_set_status (widget,
 | 
						|
                                   _("Click-Drag to move the vanishing point"));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pika_tool_transform_3d_grid_hover_modifier (PikaToolWidget  *widget,
 | 
						|
                                            GdkModifierType  key,
 | 
						|
                                            gboolean         press,
 | 
						|
                                            GdkModifierType  state)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGrid        *grid = PIKA_TOOL_TRANSFORM_3D_GRID (widget);
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
 | 
						|
  PIKA_TOOL_WIDGET_CLASS (parent_class)->hover_modifier (widget,
 | 
						|
                                                         key, press, state);
 | 
						|
 | 
						|
  priv->local_frame = (state & pika_get_extend_selection_mask ()) != 0;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
pika_tool_transform_3d_grid_get_cursor (PikaToolWidget     *widget,
 | 
						|
                                        const PikaCoords   *coords,
 | 
						|
                                        GdkModifierType     state,
 | 
						|
                                        PikaCursorType     *cursor,
 | 
						|
                                        PikaToolCursorType *tool_cursor,
 | 
						|
                                        PikaCursorModifier *modifier)
 | 
						|
{
 | 
						|
  if (! PIKA_TOOL_WIDGET_CLASS (parent_class)->get_cursor (widget,
 | 
						|
                                                           coords,
 | 
						|
                                                           state,
 | 
						|
                                                           cursor,
 | 
						|
                                                           tool_cursor,
 | 
						|
                                                           modifier))
 | 
						|
    {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
  if (pika_tool_transform_grid_get_handle (PIKA_TOOL_TRANSFORM_GRID (widget)) ==
 | 
						|
      PIKA_TRANSFORM_HANDLE_PIVOT)
 | 
						|
    {
 | 
						|
      *tool_cursor = PIKA_TOOL_CURSOR_TRANSFORM_3D_CAMERA;
 | 
						|
    }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pika_tool_transform_3d_grid_update_mode (PikaToolTransform3DGrid *grid)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
 | 
						|
  if (priv->unified)
 | 
						|
    {
 | 
						|
      g_object_set (grid,
 | 
						|
                    "inside-function",  PIKA_TRANSFORM_FUNCTION_MOVE,
 | 
						|
                    "outside-function", PIKA_TRANSFORM_FUNCTION_ROTATE,
 | 
						|
                    "use-pivot-handle", TRUE,
 | 
						|
                    NULL);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      switch (priv->mode)
 | 
						|
        {
 | 
						|
        case PIKA_TRANSFORM_3D_MODE_CAMERA:
 | 
						|
          g_object_set (grid,
 | 
						|
                        "inside-function",  PIKA_TRANSFORM_FUNCTION_NONE,
 | 
						|
                        "outside-function", PIKA_TRANSFORM_FUNCTION_NONE,
 | 
						|
                        "use-pivot-handle", TRUE,
 | 
						|
                        NULL);
 | 
						|
          break;
 | 
						|
 | 
						|
        case PIKA_TRANSFORM_3D_MODE_MOVE:
 | 
						|
          g_object_set (grid,
 | 
						|
                        "inside-function",  PIKA_TRANSFORM_FUNCTION_MOVE,
 | 
						|
                        "outside-function", PIKA_TRANSFORM_FUNCTION_MOVE,
 | 
						|
                        "use-pivot-handle", FALSE,
 | 
						|
                        NULL);
 | 
						|
          break;
 | 
						|
 | 
						|
        case PIKA_TRANSFORM_3D_MODE_ROTATE:
 | 
						|
          g_object_set (grid,
 | 
						|
                        "inside-function",  PIKA_TRANSFORM_FUNCTION_ROTATE,
 | 
						|
                        "outside-function", PIKA_TRANSFORM_FUNCTION_ROTATE,
 | 
						|
                        "use-pivot-handle", FALSE,
 | 
						|
                        NULL);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pika_tool_transform_3d_grid_reset_motion (PikaToolTransform3DGrid *grid)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
  PikaMatrix3                    *transform;
 | 
						|
 | 
						|
  priv->constrained_axis = AXIS_NONE;
 | 
						|
 | 
						|
  g_object_get (grid,
 | 
						|
                "transform", &transform,
 | 
						|
                NULL);
 | 
						|
 | 
						|
  priv->orig_transform = *transform;
 | 
						|
 | 
						|
  g_free (transform);
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
pika_tool_transform_3d_grid_constrain (PikaToolTransform3DGrid *grid,
 | 
						|
                                       gdouble                  x,
 | 
						|
                                       gdouble                  y,
 | 
						|
                                       gdouble                  ox,
 | 
						|
                                       gdouble                  oy,
 | 
						|
                                       gdouble                 *tx,
 | 
						|
                                       gdouble                 *ty)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
 | 
						|
  if (! priv->constrain_axis)
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  if (priv->constrained_axis == AXIS_NONE)
 | 
						|
    {
 | 
						|
      PikaDisplayShell *shell;
 | 
						|
      gdouble           x1, y1;
 | 
						|
      gdouble           x2, y2;
 | 
						|
 | 
						|
      shell = pika_tool_widget_get_shell (PIKA_TOOL_WIDGET (grid));
 | 
						|
 | 
						|
      pika_display_shell_transform_xy_f (shell,
 | 
						|
                                         priv->last_x, priv->last_y,
 | 
						|
                                         &x1,          &y1);
 | 
						|
      pika_display_shell_transform_xy_f (shell,
 | 
						|
                                         x,            y,
 | 
						|
                                         &x2,          &y2);
 | 
						|
 | 
						|
      if (hypot (x2 - x1, y2 - y1) < CONSTRAINT_MIN_DIST)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
      if (fabs (*tx - ox) >= fabs (*ty - oy))
 | 
						|
        priv->constrained_axis = AXIS_X;
 | 
						|
      else
 | 
						|
        priv->constrained_axis = AXIS_Y;
 | 
						|
    }
 | 
						|
 | 
						|
  if (priv->constrained_axis == AXIS_X)
 | 
						|
    *ty = oy;
 | 
						|
  else
 | 
						|
    *tx = ox;
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
pika_tool_transform_3d_grid_motion_vanishing_point (PikaToolTransform3DGrid *grid,
 | 
						|
                                                    gdouble                  x,
 | 
						|
                                                    gdouble                  y)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
  PikaCoords                      c    = {};
 | 
						|
  gdouble                         pivot_x;
 | 
						|
  gdouble                         pivot_y;
 | 
						|
 | 
						|
  if (! pika_tool_transform_3d_grid_constrain (grid,
 | 
						|
                                               x,            y,
 | 
						|
                                               priv->last_x, priv->last_y,
 | 
						|
                                               &x,           &y))
 | 
						|
    {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
  c.x = x;
 | 
						|
  c.y = y;
 | 
						|
 | 
						|
  PIKA_TOOL_WIDGET_CLASS (parent_class)->motion (PIKA_TOOL_WIDGET (grid),
 | 
						|
                                                 &c, 0, 0);
 | 
						|
 | 
						|
  g_object_get (grid,
 | 
						|
                "pivot-x", &pivot_x,
 | 
						|
                "pivot-y", &pivot_y,
 | 
						|
                NULL);
 | 
						|
 | 
						|
  g_object_set (grid,
 | 
						|
                "camera-x", pivot_x,
 | 
						|
                "camera-y", pivot_y,
 | 
						|
                NULL);
 | 
						|
 | 
						|
  priv->last_x = c.x;
 | 
						|
  priv->last_y = c.y;
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
pika_tool_transform_3d_grid_motion_move (PikaToolTransform3DGrid *grid,
 | 
						|
                                         gdouble                  x,
 | 
						|
                                         gdouble                  y)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
  PikaMatrix4                     matrix;
 | 
						|
 | 
						|
  if (! priv->z_axis)
 | 
						|
    {
 | 
						|
      gdouble x1, y1, z1, w1;
 | 
						|
      gdouble x2, y2, z2, w2;
 | 
						|
 | 
						|
      if (! priv->local_frame)
 | 
						|
        {
 | 
						|
          pika_matrix4_identity (&matrix);
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          PikaMatrix3 transform_inv = priv->orig_transform;;
 | 
						|
 | 
						|
          pika_matrix3_invert (&transform_inv);
 | 
						|
 | 
						|
          pika_transform_3d_matrix3_to_matrix4 (&transform_inv, &matrix, 2);
 | 
						|
        }
 | 
						|
 | 
						|
      w1 = pika_matrix4_transform_point (&matrix,
 | 
						|
                                         priv->last_x, priv->last_y, 0.0,
 | 
						|
                                         &x1,          &y1,          &z1);
 | 
						|
      w2 = pika_matrix4_transform_point (&matrix,
 | 
						|
                                         x,            y,            0.0,
 | 
						|
                                         &x2,          &y2,          &z2);
 | 
						|
 | 
						|
      if (w1 <= 0.0)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
      if (! pika_tool_transform_3d_grid_constrain (grid,
 | 
						|
                                                   x,   y,
 | 
						|
                                                   x1,  y1,
 | 
						|
                                                   &x2, &y2))
 | 
						|
        {
 | 
						|
          return FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
      if (priv->local_frame)
 | 
						|
        {
 | 
						|
          pika_matrix4_identity (&matrix);
 | 
						|
 | 
						|
          pika_transform_3d_matrix4_rotate_euler (&matrix,
 | 
						|
                                                  priv->rotation_order,
 | 
						|
                                                  priv->angle_x,
 | 
						|
                                                  priv->angle_y,
 | 
						|
                                                  priv->angle_z,
 | 
						|
                                                  0.0, 0.0, 0.0);
 | 
						|
 | 
						|
          pika_matrix4_transform_point (&matrix,
 | 
						|
                                        x1,  y1,  z1,
 | 
						|
                                        &x1, &y1, &z1);
 | 
						|
          pika_matrix4_transform_point (&matrix,
 | 
						|
                                        x2,  y2,  z2,
 | 
						|
                                        &x2, &y2, &z2);
 | 
						|
        }
 | 
						|
 | 
						|
      if (w2 > 0.0)
 | 
						|
        {
 | 
						|
          g_object_set (grid,
 | 
						|
                        "offset-x", priv->offset_x + (x2 - x1),
 | 
						|
                        "offset-y", priv->offset_y + (y2 - y1),
 | 
						|
                        "offset-z", priv->offset_z + (z2 - z1),
 | 
						|
                        NULL);
 | 
						|
 | 
						|
          priv->last_x = x;
 | 
						|
          priv->last_y = y;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          g_object_set (grid,
 | 
						|
                        "offset-x", priv->orig_offset_x,
 | 
						|
                        "offset-y", priv->orig_offset_y,
 | 
						|
                        "offset-z", priv->orig_offset_z,
 | 
						|
                        NULL);
 | 
						|
 | 
						|
          priv->last_x = priv->orig_x;
 | 
						|
          priv->last_y = priv->orig_y;
 | 
						|
        }
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      PikaVector3 axis;
 | 
						|
      gdouble     amount;
 | 
						|
 | 
						|
      if (! priv->local_frame)
 | 
						|
        {
 | 
						|
          axis.x = 0.0;
 | 
						|
          axis.y = 0.0;
 | 
						|
          axis.z = 1.0;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          pika_matrix4_identity (&matrix);
 | 
						|
 | 
						|
          pika_transform_3d_matrix4_rotate_euler (&matrix,
 | 
						|
                                                  priv->rotation_order,
 | 
						|
                                                  priv->angle_x,
 | 
						|
                                                  priv->angle_y,
 | 
						|
                                                  priv->angle_z,
 | 
						|
                                                  0.0, 0.0, 0.0);
 | 
						|
 | 
						|
          axis.x = matrix.coeff[0][2];
 | 
						|
          axis.y = matrix.coeff[1][2];
 | 
						|
          axis.z = matrix.coeff[2][2];
 | 
						|
 | 
						|
          if (axis.x < 0.0)
 | 
						|
            pika_vector3_neg (&axis);
 | 
						|
        }
 | 
						|
 | 
						|
      amount = x - priv->last_x;
 | 
						|
 | 
						|
      g_object_set (grid,
 | 
						|
                    "offset-x", priv->offset_x + axis.x * amount,
 | 
						|
                    "offset-y", priv->offset_y + axis.y * amount,
 | 
						|
                    "offset-z", priv->offset_z + axis.z * amount,
 | 
						|
                    NULL);
 | 
						|
 | 
						|
      priv->last_x = x;
 | 
						|
      priv->last_y = y;
 | 
						|
    }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
pika_tool_transform_3d_grid_motion_rotate (PikaToolTransform3DGrid *grid,
 | 
						|
                                           gdouble                  x,
 | 
						|
                                           gdouble                  y)
 | 
						|
{
 | 
						|
  PikaToolTransform3DGridPrivate *priv = grid->priv;
 | 
						|
  PikaDisplayShell               *shell;
 | 
						|
  PikaMatrix4                     matrix;
 | 
						|
  PikaMatrix2                     basis_inv;
 | 
						|
  PikaVector3                     omega;
 | 
						|
  gdouble                         z_sign;
 | 
						|
  gboolean                        local_frame;
 | 
						|
 | 
						|
  shell = pika_tool_widget_get_shell (PIKA_TOOL_WIDGET (grid));
 | 
						|
 | 
						|
  local_frame = priv->local_frame && (priv->constrain_axis || priv->z_axis);
 | 
						|
 | 
						|
  if (! local_frame)
 | 
						|
    {
 | 
						|
      pika_matrix2_identity (&basis_inv);
 | 
						|
      z_sign = 1.0;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      {
 | 
						|
        PikaVector3 o, n, c;
 | 
						|
 | 
						|
        pika_matrix4_identity (&matrix);
 | 
						|
 | 
						|
        pika_transform_3d_matrix4_rotate_euler (&matrix,
 | 
						|
                                                priv->rotation_order,
 | 
						|
                                                priv->angle_x,
 | 
						|
                                                priv->angle_y,
 | 
						|
                                                priv->angle_z,
 | 
						|
                                                priv->pivot_x,
 | 
						|
                                                priv->pivot_y,
 | 
						|
                                                priv->pivot_z);
 | 
						|
 | 
						|
        pika_transform_3d_matrix4_translate (&matrix,
 | 
						|
                                             priv->offset_x,
 | 
						|
                                             priv->offset_y,
 | 
						|
                                             priv->offset_z);
 | 
						|
 | 
						|
        pika_matrix4_transform_point (&matrix,
 | 
						|
                                      0.0,  0.0,  0.0,
 | 
						|
                                      &o.x, &o.y, &o.z);
 | 
						|
        pika_matrix4_transform_point (&matrix,
 | 
						|
                                      0.0,  0.0,  1.0,
 | 
						|
                                      &n.x, &n.y, &n.z);
 | 
						|
 | 
						|
        c.x = priv->camera_x;
 | 
						|
        c.y = priv->camera_y;
 | 
						|
        c.z = priv->camera_z;
 | 
						|
 | 
						|
        pika_vector3_sub (&n, &n, &o);
 | 
						|
        pika_vector3_sub (&c, &c, &o);
 | 
						|
 | 
						|
        z_sign = pika_vector3_inner_product (&c, &n) <= 0.0 ? +1.0 : -1.0;
 | 
						|
      }
 | 
						|
 | 
						|
      {
 | 
						|
        PikaVector2 o, u, v;
 | 
						|
 | 
						|
        pika_matrix3_transform_point (&priv->orig_transform,
 | 
						|
                                      priv->pivot_x, priv->pivot_y,
 | 
						|
                                      &o.x, &o.y);
 | 
						|
        pika_matrix3_transform_point (&priv->orig_transform,
 | 
						|
                                      priv->pivot_x + 1.0, priv->pivot_y,
 | 
						|
                                      &u.x, &u.y);
 | 
						|
        pika_matrix3_transform_point (&priv->orig_transform,
 | 
						|
                                      priv->pivot_x, priv->pivot_y + 1.0,
 | 
						|
                                      &v.x, &v.y);
 | 
						|
 | 
						|
        pika_vector2_sub (&u, &u, &o);
 | 
						|
        pika_vector2_sub (&v, &v, &o);
 | 
						|
 | 
						|
        pika_vector2_normalize (&u);
 | 
						|
        pika_vector2_normalize (&v);
 | 
						|
 | 
						|
        basis_inv.coeff[0][0] = u.x;
 | 
						|
        basis_inv.coeff[1][0] = u.y;
 | 
						|
        basis_inv.coeff[0][1] = v.x;
 | 
						|
        basis_inv.coeff[1][1] = v.y;
 | 
						|
 | 
						|
        pika_matrix2_invert (&basis_inv);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
  if (! priv->z_axis)
 | 
						|
    {
 | 
						|
      PikaVector2 scale;
 | 
						|
      gdouble     norm;
 | 
						|
 | 
						|
      pika_matrix2_transform_point (&basis_inv,
 | 
						|
                                    -(y - priv->last_y),
 | 
						|
                                    x - priv->last_x,
 | 
						|
                                    &omega.x, &omega.y);
 | 
						|
 | 
						|
      omega.z = 0.0;
 | 
						|
 | 
						|
      if (! pika_tool_transform_3d_grid_constrain (grid,
 | 
						|
                                                   x,        y,
 | 
						|
                                                   0.0,      0.0,
 | 
						|
                                                   &omega.x, &omega.y))
 | 
						|
        {
 | 
						|
          return FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
      norm = pika_vector3_length (&omega);
 | 
						|
 | 
						|
      if (norm > 0.0)
 | 
						|
        {
 | 
						|
          scale.x = shell->scale_x * omega.y / norm;
 | 
						|
          scale.y = shell->scale_y * omega.x / norm;
 | 
						|
 | 
						|
          pika_vector3_mul (&omega, pika_vector2_length (&scale));
 | 
						|
          pika_vector3_mul (&omega, 2.0 * G_PI / PIXELS_PER_REVOLUTION);
 | 
						|
        }
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      PikaVector2 o;
 | 
						|
      PikaVector2 v1 = {priv->last_x,  priv->last_y};
 | 
						|
      PikaVector2 v2 = {x,             y};
 | 
						|
 | 
						|
      g_warn_if_fail (priv->pivot_z == 0.0);
 | 
						|
 | 
						|
      pika_matrix3_transform_point (&priv->orig_transform,
 | 
						|
                                    priv->pivot_x, priv->pivot_y,
 | 
						|
                                    &o.x,          &o.y);
 | 
						|
 | 
						|
      pika_vector2_sub (&v1, &v1, &o);
 | 
						|
      pika_vector2_sub (&v2, &v2, &o);
 | 
						|
 | 
						|
      pika_vector2_normalize (&v1);
 | 
						|
      pika_vector2_normalize (&v2);
 | 
						|
 | 
						|
      omega.x = 0.0;
 | 
						|
      omega.y = 0.0;
 | 
						|
      omega.z = atan2 (pika_vector2_cross_product (&v1, &v2).y,
 | 
						|
                       pika_vector2_inner_product (&v1, &v2));
 | 
						|
 | 
						|
      omega.z *= z_sign;
 | 
						|
    }
 | 
						|
 | 
						|
  pika_matrix4_identity (&matrix);
 | 
						|
 | 
						|
  if (local_frame)
 | 
						|
    pika_transform_3d_matrix4_rotate (&matrix, &omega);
 | 
						|
 | 
						|
  pika_transform_3d_matrix4_rotate_euler (&matrix,
 | 
						|
                                          priv->rotation_order,
 | 
						|
                                          priv->angle_x,
 | 
						|
                                          priv->angle_y,
 | 
						|
                                          priv->angle_z,
 | 
						|
                                          0.0, 0.0, 0.0);
 | 
						|
 | 
						|
  if (! local_frame)
 | 
						|
    pika_transform_3d_matrix4_rotate (&matrix, &omega);
 | 
						|
 | 
						|
  pika_transform_3d_matrix4_rotate_euler_decompose (&matrix,
 | 
						|
                                                    priv->rotation_order,
 | 
						|
                                                    &priv->angle_x,
 | 
						|
                                                    &priv->angle_y,
 | 
						|
                                                    &priv->angle_z);
 | 
						|
 | 
						|
  priv->last_x = x;
 | 
						|
  priv->last_y = y;
 | 
						|
 | 
						|
  g_object_set (grid,
 | 
						|
                "angle-x", priv->angle_x,
 | 
						|
                "angle-y", priv->angle_y,
 | 
						|
                "angle-z", priv->angle_z,
 | 
						|
                NULL);
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*  public functions  */
 | 
						|
 | 
						|
PikaToolWidget *
 | 
						|
pika_tool_transform_3d_grid_new (PikaDisplayShell *shell,
 | 
						|
                                 gdouble           x1,
 | 
						|
                                 gdouble           y1,
 | 
						|
                                 gdouble           x2,
 | 
						|
                                 gdouble           y2,
 | 
						|
                                 gdouble           camera_x,
 | 
						|
                                 gdouble           camera_y,
 | 
						|
                                 gdouble           camera_z)
 | 
						|
{
 | 
						|
  g_return_val_if_fail (PIKA_IS_DISPLAY_SHELL (shell), NULL);
 | 
						|
 | 
						|
  return g_object_new (PIKA_TYPE_TOOL_TRANSFORM_3D_GRID,
 | 
						|
                       "shell",      shell,
 | 
						|
                       "x1",         x1,
 | 
						|
                       "y1",         y1,
 | 
						|
                       "x2",         x2,
 | 
						|
                       "y2",         y2,
 | 
						|
                       "camera-x",   camera_x,
 | 
						|
                       "camera-y",   camera_y,
 | 
						|
                       "camera-z",   camera_z,
 | 
						|
                       "pivot-3d-x", (x1 + x2) / 2.0,
 | 
						|
                       "pivot-3d-y", (y1 + y2) / 2.0,
 | 
						|
                       "pivot-3d-z", 0.0,
 | 
						|
                       NULL);
 | 
						|
}
 |