Reverse manipulations for Scale Convert – Part 3

Right after the CanvasView::on_duck_changed() function I have found CanvasView::on_duck_angle_changed() function. Looks like Angle ducks defining rotation are handled exclusively. Why? Let’s examine it…

bool
CanvasView::on_duck_angle_changed(const synfig::Angle &rotation,const synfigapp::ValueDesc& value_desc)
{
	if (ValueNode_BLineCalcTangent::Handle bline_tangent = ValueNode_BLineCalcTangent::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		int offset_index(bline_tangent->get_link_index_from_name("offset"));
		Angle old_offset((*(bline_tangent->get_link(offset_index)))(get_time()).get(Angle()));
		return canvas_interface()->change_value(synfigapp::ValueDesc(bline_tangent,offset_index), old_offset + rotation);
	}

	// \todo will this really always be the case?
	assert(value_desc.get_value_type() == ValueBase::TYPE_ANGLE);
	return canvas_interface()->change_value(value_desc, value_desc.get_value(get_time()).get(Angle()) + rotation);
}

See that “+ rotation” in last line? So the rotation passed to the on_duck_angle_changed() callback is not absolute rotation. It is delta-rotation not global-rotation. That looks reasonable. Imagine if we have angle duck at position 350 degrees and then we rotate it 20 degrees CCW. If we will get the global rotation, the result will be 10 degrees. So in animation it will look like turning 340 degrees CW! With delta-rotation approach we will get 370 degrees and duck will be animated as expected – CCW movement.

K, NP, let’s add Scale Convert reverse¬† transformation code to that function. By analogy with previous parts:

	if (ValueNode_Scale::Handle scale_value_node = ValueNode_Scale::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		int scalar_index(scale_value_node->get_link_index_from_name("scalar"));
		Real scalar((*(scale_value_node->get_link(scalar_index)))(get_time()).get(Real()));
		if (scalar == 0.0)
		{
			return false;
		}
		else
		{
			int link_index(scale_value_node->get_link_index_from_name("link"));
			Angle old_offset((*(scale_value_node->get_link(link_index)))(get_time()).get(Angle()));
			return canvas_interface()->change_value(synfigapp::ValueDesc(scale_value_node,link_index),old_offset + rotation / scalar);
		}
	}

As result patch will look like this:

diff --git a/synfig-studio/trunk/src/gtkmm/canvasview.cpp b/synfig-studio/trunk/src/gtkmm/canvasview.cpp
index 3154ae4..2f72600 100644
--- a/synfig-studio/trunk/src/gtkmm/canvasview.cpp
+++ b/synfig-studio/trunk/src/gtkmm/canvasview.cpp
@@ -2684,6 +2684,30 @@ CanvasView::on_duck_changed(const synfig::Point &value,const synfigapp::ValueDes
 		}
 	}

+	if (ValueNode_Scale::Handle scale_value_node = ValueNode_Scale::Handle::cast_dynamic(value_desc.get_value_node()))
+	{
+		int scalar_index(scale_value_node->get_link_index_from_name("scalar"));
+		Real scalar((*(scale_value_node->get_link(scalar_index)))(get_time()).get(Real()));
+		if (scalar == 0.0)
+		{
+			return false;
+		}
+		else
+		{
+			int link_index(scale_value_node->get_link_index_from_name("link"));
+			switch(value_desc.get_value_type())
+			{
+			case ValueBase::TYPE_REAL:
+				return canvas_interface()->change_value(synfigapp::ValueDesc(scale_value_node,link_index),value.mag() / scalar);
+			case ValueBase::TYPE_ANGLE:
+				//Never happen? (see on_duck_angle_changed() below)
+				return canvas_interface()->change_value(synfigapp::ValueDesc(scale_value_node,link_index),Angle::tan(value[1] / scalar ,value[0] / scalar));
+			default:
+				return canvas_interface()->change_value(synfigapp::ValueDesc(scale_value_node,link_index), value / scalar);
+			}
+		}
+	}
+
 	switch(value_desc.get_value_type())
 	{
 	case ValueBase::TYPE_REAL:
@@ -2704,6 +2728,21 @@ CanvasView::on_duck_angle_changed(const synfig::Angle &rotation,const synfigapp:
 		Angle old_offset((*(bline_tangent->get_link(offset_index)))(get_time()).get(Angle()));
 		return canvas_interface()->change_value(synfigapp::ValueDesc(bline_tangent,offset_index), old_offset + rotation);
 	}
+	if (ValueNode_Scale::Handle scale_value_node = ValueNode_Scale::Handle::cast_dynamic(value_desc.get_value_node()))
+	{
+		int scalar_index(scale_value_node->get_link_index_from_name("scalar"));
+		Real scalar((*(scale_value_node->get_link(scalar_index)))(get_time()).get(Real()));
+		if (scalar == 0.0)
+		{
+			return false;
+		}
+		else
+		{
+			int link_index(scale_value_node->get_link_index_from_name("link"));
+			Angle old_offset((*(scale_value_node->get_link(link_index)))(get_time()).get(Angle()));
+			return canvas_interface()->change_value(synfigapp::ValueDesc(scale_value_node,link_index),old_offset + rotation / scalar);
+		}
+	}

 	// \todo will this really always be the case?
 	assert(value_desc.get_value_type() == ValueBase::TYPE_ANGLE);
diff --git a/synfig-studio/trunk/src/synfigapp/instance.cpp b/synfig-studio/trunk/src/synfigapp/instance.cpp
index 020d337..c3c542b 100644
--- a/synfig-studio/trunk/src/synfigapp/instance.cpp
+++ b/synfig-studio/trunk/src/synfigapp/instance.cpp
@@ -42,6 +42,7 @@
 #include
 #include
 #include
+#include
 #include 

 #include "general.h"
@@ -74,6 +75,7 @@ synfigapp::is_editable(synfig::ValueNode::Handle value_node)
 		|| ValueNode_BLineCalcVertex::Handle::cast_dynamic(value_node)
 		|| ValueNode_BLineCalcTangent::Handle::cast_dynamic(value_node)
 		|| ValueNode_BLineCalcWidth::Handle::cast_dynamic(value_node)
+		|| ValueNode_Scale::Handle::cast_dynamic(value_node)
 	)
 		return true;
 	return false;

Now we’re done 1/3 implementing smart tangents linking feature. Sending patch to synfig tracker, waiting for response and proceeding to next part…

bool
CanvasView::on_duck_angle_changed(const synfig::Angle &rotation,const synfigapp::ValueDesc& value_desc)
{
if (ValueNode_BLineCalcTangent::Handle bline_tangent = ValueNode_BLineCalcTangent::Handle::cast_dynamic(value_desc.get_value_node()))
{
int offset_index(bline_tangent->get_link_index_from_name(“offset”));
Angle old_offset((*(bline_tangent->get_link(offset_index)))(get_time()).get(Angle()));
return canvas_interface()->change_value(synfigapp::ValueDesc(bline_tangent,offset_index), old_offset + rotation);
}
if (ValueNode_Scale::Handle scale_value_node = ValueNode_Scale::Handle::cast_dynamic(value_desc.get_value_node()))
{
int scalar_index(scale_value_node->get_link_index_from_name(“scalar”));
Real scalar((*(scale_value_node->get_link(scalar_index)))(get_time()).get(Real()));
if (scalar == 0.0)
{
return false;
}
else
{
int link_index(scale_value_node->get_link_index_from_name(“link”));
Angle old_offset((*(scale_value_node->get_link(link_index)))(get_time()).get(Angle()));
return canvas_interface()->change_value(synfigapp::ValueDesc(scale_value_node,link_index),old_offset + rotation / scalar);
}
}

// \todo will this really always be the case?
assert(value_desc.get_value_type() == ValueBase::TYPE_ANGLE);
return canvas_interface()->change_value(value_desc, value_desc.get_value(get_time()).get(Angle()) + rotation);
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: