void item_data_get_absolute_bbox (ItemData *data, Coords *p1, Coords *p2) { g_return_if_fail (data != NULL); g_return_if_fail (IS_ITEM_DATA (data)); ItemDataPriv *priv; item_data_get_relative_bbox (data, p1, p2); priv = data->priv; if (p1) { p1->x += priv->translate.x0; p1->y += priv->translate.y0; } if (p2) { p2->x += priv->translate.x0; p2->y += priv->translate.y0; } }
/** * flip a part in a given direction * @direction gives the direction the item will be flipped, end users pov! * @center the center to flip over - currently ignored FIXME */ static void part_flip (ItemData *data, IDFlip direction, Coords *center) { Part *part; PartPriv *priv; int i; cairo_matrix_t affine; double x, y; double scale_v, scale_h; gboolean handler_connected; Coords pos, trans; Coords b1, b2; Coords pos_new, pos_old, delta; //FIXME properly recenter after flipping //Coords part_center_before, part_center_after, delta; g_return_if_fail (data); g_return_if_fail (IS_PART (data)); part = PART (data); priv = part->priv; item_data_get_pos (data, &trans); // mask, just for the sake of cleanness direction &= ID_FLIP_MASK; // TODO evaluate if we really want to be able to do double flips (180* rots via flipping) g_assert (direction != ID_FLIP_MASK); // create a transformation _relativ_ to the current _state_ // reverse axis and fix the created offset by adding 2*pos.x or .y // convert the flip direction to binary, used in the matrix setup // keep in mind that we do relativ manipulations within the model // which in turn makes this valid for all rotations! scale_h = ((direction & ID_FLIP_HORIZ) != 0) ? -1. : 1.; scale_v = ((direction & ID_FLIP_VERT) != 0) ? -1. : 1.; // magic, if we are in either 270 or 90 state, we need to rotate the flip state by 90° to draw it properly // TODO maybe better put this into the rotation function if ((priv->rotation / 90) % 2 == 1) { priv->flip ^= ID_FLIP_MASK; } // toggle the direction priv->flip ^= direction; if ((priv->flip & ID_FLIP_MASK)== ID_FLIP_MASK) { priv->flip = ID_FLIP_NONE; priv->rotation += 180; priv->rotation %= 360; } cairo_matrix_init_scale (&affine, scale_h, scale_v); item_data_get_pos (data, &pos_old); pos_new = pos_old; cairo_matrix_transform_point (&affine, &pos_new.x, &pos_new.y); g_printf ("\ncenter %p [old] x=%lf,y=%lf -->", data, pos_old.x, pos_old.y); g_printf (" x=%lf, y=%lf\n", pos_new.x, pos_new.y); delta.x = - pos_new.x + pos_old.x; delta.y = - pos_new.y + pos_old.y; // flip the pins for (i = 0; i < priv->num_pins; i++) { x = priv->pins[i].offset.x; y = priv->pins[i].offset.y; cairo_matrix_transform_point (&affine, &x, &y); if (fabs (x) < 1e-2) x = 0.0; if (fabs (y) < 1e-2) y = 0.0; priv->pins[i].offset.x = x; priv->pins[i].offset.y = y; } item_data_snap (data); // tell the view handler_connected = g_signal_handler_is_connected (G_OBJECT (part), ITEM_DATA(part)->flipped_handler_id); if (handler_connected) { g_signal_emit_by_name (G_OBJECT (part), "flipped", priv->flip); // TODO - proper boundingbox center calculation item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2); // flip the bounding box. cairo_matrix_transform_point (&affine, &b1.x, &b1.y); cairo_matrix_transform_point (&affine, &b2.x, &b2.y); item_data_set_relative_bbox (ITEM_DATA (part), &b1, &b2); item_data_set_pos (ITEM_DATA (part), &pos); // FIXME - proper recenter to boundingbox center } if (g_signal_handler_is_connected (G_OBJECT (part), ITEM_DATA (part)->changed_handler_id)) { g_signal_emit_by_name (G_OBJECT (part), "changed"); } }
/** * rotate an item by an @angle increment (may be negative) * @angle the increment the item will be rotated (usually 90° steps) * @center_pos if rotated as part of a group, this is the center to rotate around * FIXME XXX TODO an issue arises as the center changes with part_rotate * FIXME XXX TODO the view callback needs to compensate this somehow */ static void part_rotate (ItemData *data, int angle, Coords *center_pos) { cairo_matrix_t affine; double x, y; Part *part; PartPriv *priv; int i, tot_rotation; Coords b1, b2; Coords part_center_before, part_center_after, delta; Coords delta_cp_before, delta_cp_after; gboolean handler_connected; g_return_if_fail (data); g_return_if_fail (IS_PART (data)); if (angle == 0) return; part = PART (data); priv = part->priv; tot_rotation = (priv->rotation + angle + 360) % 360; NG_DEBUG ("rotation: angle=%i tot_rotation=%i", angle, tot_rotation); // use the cairo matrix funcs to transform the pin // positions relative to the item center // this is only indirectly related to displaying cairo_matrix_init_rotate (&affine, (double)angle * M_PI / 180.); if (center_pos) { delta_cp_before = coords_sub (&part_center_before, center_pos); delta_cp_after = delta_cp_before; cairo_matrix_transform_point (&affine, &delta_cp_after.x, &delta_cp_after.y); } priv->rotation = tot_rotation; angle = tot_rotation; // Rotate the pins. for (i = 0; i < priv->num_pins; i++) { x = priv->pins[i].offset.x; y = priv->pins[i].offset.y; cairo_matrix_transform_point (&affine, &x, &y); if (fabs (x) < 1e-2) x = 0.0; if (fabs (y) < 1e-2) y = 0.0; priv->pins[i].offset.x = x; priv->pins[i].offset.y = y; } // Rotate the bounding box, recenter to old center item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2); part_center_before = coords_average (&b1, &b2); cairo_matrix_transform_point (&affine, &b1.x, &b1.y); cairo_matrix_transform_point (&affine, &b2.x, &b2.y); item_data_set_relative_bbox (ITEM_DATA (part), &b1, &b2); part_center_after = coords_average (&b1, &b2); delta = coords_sub (&part_center_before, &part_center_after); if (center_pos) { Coords diff = coords_sub (&delta_cp_after, &delta_cp_before); coords_add (&delta, &diff); } item_data_move (data, &delta); item_data_snap (data); handler_connected = g_signal_handler_is_connected (G_OBJECT (part), ITEM_DATA (part)->rotated_handler_id); if (handler_connected) { g_signal_emit_by_name (G_OBJECT (part), "rotated", tot_rotation); } handler_connected = g_signal_handler_is_connected (G_OBJECT (part), ITEM_DATA (part)->changed_handler_id); if (handler_connected) { g_signal_emit_by_name (G_OBJECT (part), "changed"); } }
/** * \brief rotate an item by an @angle increment (may be negative) * * @angle the increment the item will be rotated (usually 90° steps) * @center_pos if rotated as part of a group, this is the center to rotate *around */ static void part_rotate (ItemData *data, int angle, Coords *center_pos) { g_return_if_fail (data); g_return_if_fail (IS_PART (data)); cairo_matrix_t morph, morph_rot, local_rot; Part *part; PartPriv *priv; gboolean handler_connected; // Coords b1, b2; part = PART (data); priv = part->priv; // FIXME store vanilla coords, apply the morph // FIXME to these and store the result in the // FIXME instance then everything will be fine // XXX also prevents rounding yiggle up downs angle /= 90; angle *= 90; cairo_matrix_init_rotate (&local_rot, (double)angle * M_PI / 180.); cairo_matrix_multiply (item_data_get_rotate (data), item_data_get_rotate (data), &local_rot); morph_rot = *(item_data_get_rotate (data)); cairo_matrix_multiply (&morph, &morph_rot, item_data_get_translate (data)); Coords delta_to_center, delta_to_center_transformed; Coords delta_to_apply, delta_bbox; Coords bbox_center, bbox_center_transformed; Coords item_pos; // get bbox #if 0 // this causes #115 to reappear item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2); bbox_center = coords_average (&b1, &b2); #endif item_data_get_pos (ITEM_DATA (part), &item_pos); Coords rotation_center; if (center_pos == NULL) { rotation_center = coords_sum (&bbox_center, &item_pos); } else { rotation_center = *center_pos; } delta_to_center_transformed = delta_to_center = coords_sub (&rotation_center, &item_pos); cairo_matrix_transform_point (&local_rot, &(delta_to_center_transformed.x), &(delta_to_center_transformed.y)); delta_to_apply = coords_sub (&delta_to_center, &delta_to_center_transformed); #define DEBUG_THIS 0 // use the cairo matrix funcs to transform the pin // positions relative to the item center // this is only indirectly related to displayin // HINT: we need to modify the actual pins to make the // pin tests work being used to detect connections gint i; gdouble x, y; // Rotate the pins. for (i = 0; i < priv->num_pins; i++) { x = priv->pins_orig[i].offset.x; y = priv->pins_orig[i].offset.y; cairo_matrix_transform_point (&morph_rot, &x, &y); if (fabs (x) < 1e-2) x = 0.0; if (fabs (y) < 1e-2) y = 0.0; priv->pins[i].offset.x = x; priv->pins[i].offset.y = y; } item_data_move (data, &delta_to_apply); handler_connected = g_signal_handler_is_connected (G_OBJECT (data), data->changed_handler_id); if (handler_connected) { g_signal_emit_by_name (G_OBJECT (data), "changed"); } else { NG_DEBUG ("handler not yet registerd."); } NG_DEBUG ("\n\n"); }