[Racer-svn] SF.net SVN: racer:[88] trunk
Status: Alpha
Brought to you by:
jlegg
From: <jl...@us...> - 2009-11-25 00:29:49
|
Revision: 88 http://racer.svn.sourceforge.net/racer/?rev=88&view=rev Author: jlegg Date: 2009-11-25 00:29:38 +0000 (Wed, 25 Nov 2009) Log Message: ----------- Implement vertex rotation in the editor. Modified Paths: -------------- trunk/libtrack/Path.cpp trunk/libtrack/Path.h trunk/libtrack/document/Makefile.am trunk/libtrack/document/MoveNodeDelta.cpp trunk/libtrack/edit_base/Makefile.am trunk/libtrack/edit_base/RotationHandle.cpp trunk/racer_editor/EditorWindow.cpp trunk/racer_editor/EditorWindow.h trunk/racer_editor/View.cpp trunk/racer_editor/View.h trunk/racer_editor/Viewport.cpp trunk/racer_editor/Viewport.h Added Paths: ----------- trunk/libtrack/document/RotateVertexDelta.cpp trunk/libtrack/document/RotateVertexDelta.h trunk/libtrack/edit_base/VertexRotationHandle.cpp trunk/libtrack/edit_base/VertexRotationHandle.h Modified: trunk/libtrack/Path.cpp =================================================================== --- trunk/libtrack/Path.cpp 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/libtrack/Path.cpp 2009-11-25 00:29:38 UTC (rev 88) @@ -24,15 +24,21 @@ , segment(0) , segment_index(0) , gradient(btVector3(1.0, 0.0, 0.0)) + , up_handle(get_name(), EditAssist::VertexRotationHandle::DIR_UP) + , forward_handle(get_name(), EditAssist::VertexRotationHandle::DIR_FORWARD) { set_angle(btQuaternion::getIdentity()); + update_handles(); } PathVertex::PathVertex(std::istream & source, const Theme & theme) + : up_handle(get_name(), EditAssist::VertexRotationHandle::DIR_UP) + , forward_handle(get_name(), EditAssist::VertexRotationHandle::DIR_FORWARD) { source >> position >> gradient >> angle >> segment_index; segment = &theme.get_segment(segment_index); set_angle(angle); + update_handles(); } PathVertex::~PathVertex() @@ -40,6 +46,26 @@ } +const btVector3 & PathVertex::get_position() const +{ + return position; +} + +void PathVertex::set_position(const btVector3 & position_in) +{ + position = position_in; + update_handles(); +} + +void PathVertex::update_handles() +{ + up_handle.set_centre(position); + up_handle.update_angle(angle); + + forward_handle.set_centre(position); + forward_handle.update_angle(angle); +} + const btVector3 & PathVertex::get_gradient() const { return gradient; @@ -56,6 +82,8 @@ const btTransform transform(angle_in); gradient = transform(btVector3(0, 1.0, 0.0)); up = transform(btVector3(0, 0.0, 1.0)); + + update_handles(); } const btQuaternion & PathVertex::get_angle() const @@ -95,6 +123,27 @@ ); } +const EditAssist::ControlPoint * PathVertex::get_control_point_here(btVector3 start, btVector3 stop, btScalar radius) const +{ + if (up_handle.is_here(start, stop, radius)) + { + return &up_handle; + } + else if (forward_handle.is_here(start, stop, radius)) + { + return &forward_handle; + } + // There is no appropriate control point. + return 0; +} + +void PathVertex::set_handle_lengths(btScalar handle_length) +{ + up_handle.set_length(handle_length); + forward_handle.set_length(handle_length); + update_handles(); +} + std::ostream & operator<<(std::ostream & destination, const PathVertex & path_vertex) { destination << path_vertex.position << ' ' @@ -181,9 +230,9 @@ // A cubic bezier spline isn't analytically intergratable. // Instead of hard numerical approximations, I'll do a piecewise linear // estimation. - const btVector3 & p0 = source_in.position; + const btVector3 & p0 = source_in.get_position(); const btVector3 p1 = p0 + source_in.get_gradient() * start.gradient_strength; - const btVector3 & p3 = target_in.position; + const btVector3 & p3 = target_in.get_position(); const btVector3 p2 = p0 - target_in.get_gradient() * finish.gradient_strength; btVector3 last_position = p0; @@ -211,7 +260,15 @@ // round to the nearest whole number of segments. number_of_repetions = int (length / segment->get_length() + 0.5); } - + if (number_of_repetions == 0) + { + // even short gaps between vertices must be filled. + number_of_repetions = 1; + } + if (number_of_repetions > 64) + { + DEBUG_MESSAGE("Warning: large number of meshes (" << number_of_repetions << ") needed for edge " << get_name()); + } // make the meshes. meshes.clear(); meshes.reserve(number_of_repetions); @@ -243,9 +300,9 @@ const btScalar rposition_squared = rposition * rposition; const btScalar position_cubed = position_squared * position; const btScalar rposition_cubed = rposition_squared * rposition; - const btVector3 & p0 = source->position; + const btVector3 & p0 = source->get_position(); const btVector3 p1 = p0 + source->get_gradient() * start.gradient_strength; - const btVector3 & p3 = target->position; + const btVector3 & p3 = target->get_position(); const btVector3 p2 = p3 - target->get_gradient() * finish.gradient_strength; const btVector3 translation = rposition_cubed * p0 + 3.0 * rposition_squared * position * p1 @@ -316,7 +373,6 @@ if (section > denominator) section = denominator; // find distance btScalar distance = (w + (screen * length - section * ed) / denominator).length2(); - DEBUG_MESSAGE("Line to path segment distance: " << distance); if (distance < radius * radius) { return true; @@ -380,8 +436,8 @@ { // add two vertices and two edges connecting them in a loop. PathVertex vertex_1, vertex_2; - vertex_1.position = btVector3(300.0, 0.0, 200.0); - vertex_2.position = btVector3(-300.0, 0.0, -200.0); + vertex_1.set_position(btVector3(300.0, 0.0, 200.0)); + vertex_2.set_position(btVector3(-300.0, 0.0, -200.0)); vertex_1.set_angle(btQuaternion(0.0, 0.0, 0.0)); vertex_2.set_angle(btQuaternion(0.0, 0.0, M_PI)); vertex_1.segment = &(theme.get_segment(0)); @@ -463,7 +519,7 @@ vertex_range.first != vertex_range.second; vertex_range.first++) { - result |= graph[*(vertex_range.first)].position; + result |= graph[*(vertex_range.first)].get_position(); } // now expand to include control points @@ -473,11 +529,11 @@ edge_range.first != edge_range.second; edge_range.first++) { - btVector3 position = graph[source(*(edge_range.first), graph)].position; + btVector3 position = graph[source(*(edge_range.first), graph)].get_position(); btVector3 gradient = graph[source(*(edge_range.first), graph)].get_gradient(); btScalar magnitude = graph[*(edge_range.first)].start.gradient_strength; result |= position + gradient * magnitude; - position = graph[target(*(edge_range.first), graph)].position; + position = graph[target(*(edge_range.first), graph)].get_position(); gradient = graph[target(*(edge_range.first), graph)].get_gradient(); magnitude = graph[*(edge_range.first)].finish.gradient_strength; result |= position - gradient * magnitude; @@ -570,4 +626,16 @@ throw; } +void Path::set_handle_lengths(btScalar handle_length) +{ + typedef boost::graph_traits<Path::Graph>::vertex_iterator VertexIterator; + std::pair<VertexIterator, VertexIterator> vertex_range; + for (vertex_range = boost::vertices(graph); + vertex_range.first != vertex_range.second; + vertex_range.first++) + { + graph[*(vertex_range.first)].set_handle_lengths(handle_length); + } } + +} Modified: trunk/libtrack/Path.h =================================================================== --- trunk/libtrack/Path.h 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/libtrack/Path.h 2009-11-25 00:29:38 UTC (rev 88) @@ -35,6 +35,7 @@ #include "UniqueIdentifier.h" #include "Selectable.h" #include "Dragable.h" +#include "edit_base/VertexRotationHandle.h" namespace Track { @@ -51,10 +52,15 @@ PathVertex(); PathVertex(std::istream & source, const Theme & theme); virtual ~PathVertex(); - + +protected: /// The position of the vertex btVector3 position; +public: + const btVector3 & get_position() const; + void set_position(const btVector3 & position); + /** Get the tangent of the arcs where they meet the vertex. * It is unit length. */ @@ -87,10 +93,34 @@ // Implement virtual functions from Selectable. virtual bool is_here(btVector3 start, btVector3 stop, btScalar radius) const; virtual boost::shared_ptr<Document::DocumentDelta> make_delta(btVector3 new_position) const; + + /** Return any vertex handles near a line segment. + * @param start The starting point of the line segment to scan. + * @param stop The end point of the the line segment to scan + * @param radius The radius around the line to consider. + * @return A pointer to a control point that alters this vertex within a + * cylinder around the line, with the request radius, or 0 if there is no + * such control point. + */ + const EditAssist::ControlPoint * get_control_point_here(btVector3 start, btVector3 stop, btScalar radius) const; + + /// Set the lengths of the rotation handles. + void set_handle_lengths(btScalar handle_length); protected: + /// The normalised forward direction from this vertex. btVector3 gradient; + /// The normalised up direction from this vertex. btVector3 up; + /// The rotation from gradient (0, 1, 0) and up (0, 0, 1). btQuaternion angle; + + /// control point used to change the up direction in the editor. + EditAssist::VertexRotationHandle up_handle; + /// control point used to change the forward direction in the editor. + EditAssist::VertexRotationHandle forward_handle; + + /// Update the properties of the vertices control points. + void update_handles(); }; std::ostream & operator<<(std::ostream & destination, @@ -272,6 +302,13 @@ Path::Graph::edge_descriptor get_edge_descriptor(const std::size_t index); /// find a graph edge descriptor by ID const Path::Graph::edge_descriptor get_edge_descriptor(const std::size_t index) const; + + /** Set the lengths of the rotation handles present in the path's + * vertices. + * @param handle_length The length the handles extend from the point they + * rotate. + */ + void set_handle_lengths(btScalar handle_length); private: const Theme & theme; Path::Graph::vertex_descriptor get_node_descriptor_internal(const std::size_t index) const; Modified: trunk/libtrack/document/Makefile.am =================================================================== --- trunk/libtrack/document/Makefile.am 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/libtrack/document/Makefile.am 2009-11-25 00:29:38 UTC (rev 88) @@ -1,5 +1,5 @@ noinst_LIBRARIES = libdocument.a -libdocument_a_SOURCES = ChangeEdgeSegmentDelta.cpp ChangeEdgeSegmentDelta.h ChangePropertyDelta.h ChangeVertexSegmentDelta.cpp ChangeVertexSegmentDelta.h Document.cpp Document.h DocumentDelta.cpp DocumentDelta.h MoveNodeDelta.cpp MoveNodeDelta.h +libdocument_a_SOURCES = ChangeEdgeSegmentDelta.cpp ChangeEdgeSegmentDelta.h ChangePropertyDelta.h ChangeVertexSegmentDelta.cpp ChangeVertexSegmentDelta.h Document.cpp Document.h DocumentDelta.cpp DocumentDelta.h MoveNodeDelta.cpp MoveNodeDelta.h RotateVertexDelta.h RotateVertexDelta.cpp libdocument_a_CPPFLAGS = $(debug_specific_CFLAGS) $(libtrack_CFLAGS) -I@top_srcdir@ libdocument_a_AR=$(AR) $(ARFLAGS)T Modified: trunk/libtrack/document/MoveNodeDelta.cpp =================================================================== --- trunk/libtrack/document/MoveNodeDelta.cpp 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/libtrack/document/MoveNodeDelta.cpp 2009-11-25 00:29:38 UTC (rev 88) @@ -22,7 +22,7 @@ void NodePositionFinder::read(const Track::Track & track, btVector3 & new_position) { - new_position = track.get_path().get_node(node_id).position; + new_position = track.get_path().get_node(node_id).get_position(); } void NodePositionFinder::write(Track::Track & track, const btVector3 & new_position) @@ -31,7 +31,7 @@ Track::PathVertex & vertex = path.get_node(node_id); Track::Path::Graph::vertex_descriptor vertex_descriptor = path.get_node_descriptor(node_id); Track::Path::Graph & graph = path.graph; - vertex.position = new_position; + vertex.set_position(new_position); //update the connecting edges. /*typedef boost::graph_traits<Track::Path::Graph>::edge_iterator EdgeIterator; std::pair<EdgeIterator, EdgeIterator> edge_range; Added: trunk/libtrack/document/RotateVertexDelta.cpp =================================================================== --- trunk/libtrack/document/RotateVertexDelta.cpp (rev 0) +++ trunk/libtrack/document/RotateVertexDelta.cpp 2009-11-25 00:29:38 UTC (rev 88) @@ -0,0 +1,56 @@ +/** @file document/RotateVertexDelta.cpp + * @brief Implement the Document::RotateVertexDelta and Document::VertexAngleFinder classes. + * @author James Legg + */ +/* Copyright © 2009 James Legg. + 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. +*/ + +#include "RotateVertexDelta.h" +#include "../Track.h" + +namespace Document +{ + +VertexAngleFinder::VertexAngleFinder(std::size_t vertex_id) + : vertex_id(vertex_id) +{ +} + +void VertexAngleFinder::read(const Track::Track & track, btQuaternion & angle) +{ + angle = track.get_path().get_node(vertex_id).get_angle(); +} + +void VertexAngleFinder::write(Track::Track & track, const btQuaternion & new_angle) +{ + Track::Path & path = track.get_path(); + Track::PathVertex & vertex = path.get_node(vertex_id); + vertex.set_angle(new_angle); + // Update connected edges. + Track::Path::Graph::vertex_descriptor vertex_descriptor = path.get_node_descriptor(vertex_id); + Track::Path::Graph & graph = path.graph; + typedef boost::graph_traits<Track::Path::Graph>::out_edge_iterator OutEdgeIterator; + std::pair<OutEdgeIterator, OutEdgeIterator> out_edge_range; + for (out_edge_range = boost::out_edges(vertex_descriptor, graph); + out_edge_range.first != out_edge_range.second; + out_edge_range.first++) + { + Track::PathEdge & edge = path.graph[*(out_edge_range.first)]; + edge.update(); + } + typedef boost::graph_traits<Track::Path::Graph>::in_edge_iterator InEdgeIterator; + std::pair<InEdgeIterator, InEdgeIterator> in_edge_range; + for (in_edge_range = boost::in_edges(vertex_descriptor, graph); + in_edge_range.first != in_edge_range.second; + in_edge_range.first++) + { + Track::PathEdge & edge = path.graph[*(in_edge_range.first)]; + edge.update(); + } +} + +} Added: trunk/libtrack/document/RotateVertexDelta.h =================================================================== --- trunk/libtrack/document/RotateVertexDelta.h (rev 0) +++ trunk/libtrack/document/RotateVertexDelta.h 2009-11-25 00:29:38 UTC (rev 88) @@ -0,0 +1,57 @@ +/** @file document/RotateVertexDelta.h + * @brief Declare the Document::RotateVertexDelta and Document::VertexAngleFinder classes. + * @author James Legg + */ +/* Copyright © 2009 James Legg. + 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. +*/ + +#ifndef ROTATE_VERTEX_DELTA_H_ +#define ROTATE_VERTEX_DELTA_H_ + +#include <cstddef> + +#include <LinearMath/btQuaternion.h> + +#include "ChangePropertyDelta.h" + +namespace Document +{ + +/** Find/Change the angle of a particular vertex. + */ +class VertexAngleFinder + : public PropertyDeltaIdentifier<btQuaternion> +{ +public: + /** Create associating with a vertex. + * @param vertex_id The name of the vertex to associate with. + */ + VertexAngleFinder(std::size_t vertex_id); + /** Read the assiociated vertex's angle. + * @param track The track containing the associated vertex. + * @param angle Variable to set to the angle of the associated vertex. + */ + virtual void read(const Track::Track & track, btQuaternion & angle); + /** Change the associated vertex's angle. + * @param track The track containing the associated vertex. + * @param new_angle The angle to set the associated vertex to. After + * rotating, the positive z direction is used as up; and the positive y + * direction is generally forward, along the track. + */ + virtual void write(Track::Track & track, const btQuaternion & new_angle); +protected: + /// The name of the associated vertex. + std::size_t vertex_id; +}; + +/** Command for changing the angle of a PathVertex in a Path. +*/ +typedef ChangePropertyDelta<VertexAngleFinder, btQuaternion> RotateVertexDelta; + +} + +#endif // ROTATE_VERTEX_DELTA_H_ Modified: trunk/libtrack/edit_base/Makefile.am =================================================================== --- trunk/libtrack/edit_base/Makefile.am 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/libtrack/edit_base/Makefile.am 2009-11-25 00:29:38 UTC (rev 88) @@ -1,4 +1,4 @@ noinst_LIBRARIES = libedit_base.a -libedit_base_a_SOURCES = ControlPoint.cpp ControlPoint.h RotationHandle.cpp RotationHandle.h +libedit_base_a_SOURCES = ControlPoint.cpp ControlPoint.h RotationHandle.cpp RotationHandle.h VertexRotationHandle.cpp VertexRotationHandle.h libedit_base_a_CPPFLAGS = $(debug_specific_CFLAGS) $(libtrack_CFLAGS) -I@top_srcdir@ libedit_base_a_AR=$(AR) $(ARFLAGS)T Modified: trunk/libtrack/edit_base/RotationHandle.cpp =================================================================== --- trunk/libtrack/edit_base/RotationHandle.cpp 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/libtrack/edit_base/RotationHandle.cpp 2009-11-25 00:29:38 UTC (rev 88) @@ -28,7 +28,7 @@ if (proposed_length2 >= length * length) { // make perpendicular to normal. - btVector3 new_vector = proposed_vector.cross(normal).cross(normal); + btVector3 new_vector = normal.cross(proposed_vector.cross(normal)); if (proposed_position.length2() > 0.0) { // We've made a vector in a valid direction, use it. Added: trunk/libtrack/edit_base/VertexRotationHandle.cpp =================================================================== --- trunk/libtrack/edit_base/VertexRotationHandle.cpp (rev 0) +++ trunk/libtrack/edit_base/VertexRotationHandle.cpp 2009-11-25 00:29:38 UTC (rev 88) @@ -0,0 +1,113 @@ +/** @file libtrack/edit_base/VertexRotationHandle.cpp + * @brief Implement the Track::EditAssist::VertexRotationHandle class. + * @author James Legg + */ +/* Copyright © 2009 James Legg. + 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. +*/ +#include "VertexRotationHandle.h" + +#include <LinearMath/btQuaternion.h> + +#include "../Path.h" +#include "../document/RotateVertexDelta.h" + +namespace Track +{ + +namespace EditAssist +{ + + +VertexRotationHandle::VertexRotationHandle(std::size_t vertex_id, Direction direction) + : vertex_id(vertex_id) + , direction (direction) +{ + length = 1.0; +} + +boost::shared_ptr<Document::DocumentDelta> VertexRotationHandle::make_delta(btVector3 new_position) const +{ + /* Find an angle with minimal difference to the last one that fits the new + * position. + */ + btVector3 new_vector = (new_position - centre) / length; + btVector3 old_vector = (position - centre) / length; + btVector3 cross = old_vector.cross(new_vector); + bool obtuse = (new_vector + old_vector).length2() < 2; + btScalar sin_angle = cross.length(); + + // some floating point rounding fixes: + if (std::fabs(sin_angle) < 0.002) + { + if (!obtuse) + { + DEBUG_MESSAGE("Rotation too small, ignoring."); + // Didn't rotate very far. + // Vector is very short: just act as if there was no rotation to + // avoid problems normalising it. + return boost::shared_ptr<Document::DocumentDelta> + ( + new Document::RotateVertexDelta + ( + Document::VertexAngleFinder(vertex_id), + rotation + ) + ); + } + else + { + // We can't rely on the direction we are rotating about, but + // need to rotate about 180 degrees. Guess a direction. + DEBUG_MESSAGE("Rotation too close to 180 degrees, guessing direction."); + return boost::shared_ptr<Document::DocumentDelta> + ( + new Document::RotateVertexDelta + ( + Document::VertexAngleFinder(vertex_id), + /// @todo In 180 degree case use another handle's direction? + rotation * btQuaternion(btVector3(0, 0, 1), M_PI) + ) + ); + } + } + // sin_angle might be just outside the valid range. + if (sin_angle > 1.0) sin_angle = 1.0; + + btScalar angle = std::asin(sin_angle); + if (obtuse) + { + angle = M_PI - angle; + } + + cross.normalize(); + btQuaternion rotation_difference(cross, angle); + btQuaternion new_angle(rotation_difference * rotation); + + return boost::shared_ptr<Document::DocumentDelta> + ( + new Document::RotateVertexDelta + ( + Document::VertexAngleFinder(vertex_id), + new_angle + ) + ); +} + +void VertexRotationHandle::update_angle(btQuaternion angle_in) +{ + /* The position is centre position + the a vector in the direction the + * handle indicates with the requested length. + */ + rotation = angle_in; + position = centre + length * + btTransform(angle_in)(direction == DIR_FORWARD ? btVector3(0, 1, 0) : btVector3(0, 0, 1)); +} + +} + +} + Added: trunk/libtrack/edit_base/VertexRotationHandle.h =================================================================== --- trunk/libtrack/edit_base/VertexRotationHandle.h (rev 0) +++ trunk/libtrack/edit_base/VertexRotationHandle.h 2009-11-25 00:29:38 UTC (rev 88) @@ -0,0 +1,72 @@ +/** @file libtrack/edit_base/VertexRotationHandle.h + * @brief Declare the Track::EditAssist::VertexRotationHandle class. + * @author James Legg + */ +/* Copyright © 2009 James Legg. + 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. +*/ +#ifndef VERTEX_ROTATION_HANDLE_H_ +#define VERTEX_ROTATION_HANDLE_H_ + +#include <LinearMath/btQuaternion.h> + +#include "RotationHandle.h" + +namespace Track +{ + +namespace EditAssist +{ + +class VertexRotationHandle + : public RotationHandle +{ +public: + /// Directions from centre point. + enum Direction + { + /// +z direction + DIR_UP = 0, + /// +y direction + DIR_FORWARD = 1 + }; + /** Create for indicating a direction at a vertex. + * @param vertex_id The name of the vertex to associate with. + * @param direction The direction to indicate. + */ + VertexRotationHandle(std::size_t vertex_id, Direction direction = DIR_FORWARD); + + /** Make a DocumentDelta performing the rotation. + * The rotation is picked to keep the angle as close as it can be to its + * current value while moving the VertexRotationHandle to the requested + * position. + * @param position The desired new location of the vertex. This should + * have been generated by Snap(). + * @return shared pointer to a new DocumentDelta that rotates the + * associated vertex to the most appropriate angle. + */ + virtual boost::shared_ptr<Document::DocumentDelta> make_delta(btVector3 position) const; + /** Update the angle of the vertex. + * This must be called for make_delta() to work. + * This will automatically update the position to reflect the angle, + * centre, and length. + * @param angle The new angle of the vertex. + */ + void update_angle(btQuaternion angle); +protected: + /// The name of the associated vertex. + std::size_t vertex_id; + /// Which direction the handle represents. + Direction direction; + /// The current angle of the vertex. + btQuaternion rotation; +}; + +} + +} + +#endif // VERTEX_ROTATION_HANDLE_H_ Modified: trunk/racer_editor/EditorWindow.cpp =================================================================== --- trunk/racer_editor/EditorWindow.cpp 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/racer_editor/EditorWindow.cpp 2009-11-25 00:29:38 UTC (rev 88) @@ -189,6 +189,8 @@ sigc::mem_fun(*this, &EditorWindow::on_view_command)); m_viewport_top.signal_preview_command().connect( sigc::mem_fun(*this, &EditorWindow::on_view_preview_command)); + m_viewport_top.signal_preview_cancel().connect( + sigc::mem_fun(*this, &EditorWindow::on_view_preview_cancel)); m_box.pack_start(m_new_form); m_new_form.signal_theme_picked().connect( @@ -506,6 +508,11 @@ m_document->preview_command(delta); } +void EditorWindow::on_view_preview_cancel() +{ + m_document->cancel_preview(); +} + bool EditorWindow::check_clear_document() { // it doesn't matter if the document is already clear. Modified: trunk/racer_editor/EditorWindow.h =================================================================== --- trunk/racer_editor/EditorWindow.h 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/racer_editor/EditorWindow.h 2009-11-25 00:29:38 UTC (rev 88) @@ -101,6 +101,9 @@ /// Preview a change to the document using a command generated by a view void on_view_preview_command(boost::shared_ptr<Document::DocumentDelta> delta); + /// Reset the document when a previewed command is not wanted. + void on_view_preview_cancel(); + /** Check if it is OK to clear the document. If the document has unsaved * changes, this asks the user for the result. If the user agrees but wishes * to save first, the document is saved and true is called. Modified: trunk/racer_editor/View.cpp =================================================================== --- trunk/racer_editor/View.cpp 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/racer_editor/View.cpp 2009-11-25 00:29:38 UTC (rev 88) @@ -29,7 +29,8 @@ Gdk::GL::MODE_DEPTH | Gdk::GL::MODE_DOUBLE)) , document(0) - , scale(8.0) + , scale(1.0) + , handle_length(64.0 / scale) , centre(0.0, 0.0, 0.0) , view_angle(VIEW_TOP) , new_position(centre) @@ -49,6 +50,7 @@ false, Gdk::GL::RGBA_TYPE) , document(view.document) , scale(view.scale) + , handle_length(64.0 / scale) , centre(view.centre) , view_angle(VIEW_TOP) , new_position(centre) @@ -125,6 +127,8 @@ m_menu_id = m_ui_manager->add_ui_from_string(ui_buffer); m_popup_menu = (Gtk::Menu *)m_ui_manager->get_widget("/popup-menu"); assert(m_popup_menu); + + set_scale(1.0); } void View::set_angle(const ViewAngle angle_in) @@ -143,6 +147,9 @@ { scale = scale_in; needs_recentre = true; + handle_length = 64.0 / scale; + /// @todo Multiple-view friendly handle lengths. + const_cast<Track::Path &>(document->get_track().get_path()).set_handle_lengths(handle_length); queue_draw(); } @@ -302,7 +309,6 @@ // draw markers at the vertices. glClear(GL_DEPTH_BUFFER_BIT); - btScalar length_scale = 64 / scale; /** @todo use marker size to draw a square around the point regardless * of hardware maximum point size. glPointSize is not guranteed to * support sizes other than 1, which is too small. @@ -317,16 +323,16 @@ vertex_range.first++) { const Track::PathVertex & vertex = path.graph[*(vertex_range.first)]; - btVector3 up = vertex.position + length_scale * vertex.get_up(); - btVector3 forward = vertex.position + length_scale * vertex.get_gradient(); + btVector3 up = vertex.get_position() + handle_length * vertex.get_up(); + btVector3 forward = vertex.get_position() + handle_length * vertex.get_gradient(); glBegin(GL_LINES); // line pointing up glColor3ub(255, 0, 0); - glVertex(vertex.position); + glVertex(vertex.get_position()); glVertex(up); // line pointing forward glColor3ub(0, 255, 0); - glVertex(vertex.position); + glVertex(vertex.get_position()); glVertex(forward); glEnd(); glBegin(GL_POINTS); @@ -335,11 +341,18 @@ // forward marker glColor3ub(0, 255, 0 ); glVertex(forward); // vertex marker - glColor3ub(255, 255, 0 ); glVertex(vertex.position); + glColor3ub(255, 255, 0 ); glVertex(vertex.get_position()); glEnd(); } glEnd(); glColor3ub(255, 255, 255); + + #ifndef NDEBUG + // mark new position location + glBegin(GL_POINTS); + glVertex(new_position); + glEnd(); + #endif } bool View::on_button_press_event(GdkEventButton * event) @@ -400,6 +413,7 @@ if (event->button == 1 && drag_object) { // release the object + m_signal_preview_cancel.emit(); boost::shared_ptr<Document::DocumentDelta> delta( drag_object->make_delta(new_position) ); @@ -433,14 +447,25 @@ bool View::on_motion_notify_event(GdkEventMotion * event) { new_position = mouse_to_scene(event->x, event->y); - if (drag_object && !Gtk::Main::events_pending()) + if (drag_object) { - boost::shared_ptr<Document::DocumentDelta> delta + btVector3 normal ( - drag_object->make_delta(new_position) + view_angle == VIEW_SIDE ? 1 : 0, + view_angle == VIEW_FRONT ? 1 : 0, + view_angle == VIEW_TOP ? 1 : 0 ); - // anonunce the delta so it can be previewed. - m_signal_preview_command.emit(delta); + drag_object->snap(new_position, normal); + if (!Gtk::Main::events_pending()) + { + m_signal_preview_cancel.emit(); + boost::shared_ptr<Document::DocumentDelta> delta + ( + drag_object->make_delta(new_position) + ); + // anonunce the delta so it can be previewed. + m_signal_preview_command.emit(delta); + } } return false; } @@ -470,7 +495,7 @@ btVector3 stop = new_position; set_relative_depth(stop, back_depth); // find the radius of a few pixels close enough to the line - btScalar radius = 5.0 / scale; + btScalar radius = 8.0 / scale; const Track::Path & path = document->get_track().get_path(); typedef boost::graph_traits<Track::Path::Graph>::vertex_iterator VertexIterator; std::pair<VertexIterator, VertexIterator> vertex_range; @@ -482,12 +507,31 @@ if (vertex.is_here(start, stop, radius)) { // Use this vertex - new_position = vertex.position; + new_position = vertex.get_position(); + DEBUG_MESSAGE("Found vertex " << vertex.get_name()); return &vertex; } } - ///@todo vertex angle handles and edge control points - // not a vertex, try an edge + + //vertex control points + for (vertex_range = boost::vertices(path.graph); + vertex_range.first != vertex_range.second; + vertex_range.first++) + { + const Track::PathVertex & vertex = path.graph[*(vertex_range.first)]; + const Track::EditAssist::ControlPoint * control_point + (vertex.get_control_point_here(start, stop, radius)); + if (control_point) + { + new_position = control_point->get_position(); + DEBUG_MESSAGE("Found control point @ " << control_point << " on vertex " << vertex.get_name()); + return control_point; + } + } + + /// @todo edge Gradient strength control points. + + // not a vertex or control point, try an edge. typedef boost::graph_traits<Track::Path::Graph>::edge_iterator EdgeIterator; std::pair<EdgeIterator, EdgeIterator> edge_range; for (edge_range = boost::edges(path.graph); @@ -498,10 +542,12 @@ if (edge.is_here(start, stop, radius)) { // Use this edge + DEBUG_MESSAGE("Found edge " << edge.get_name()); return &edge; } } // nothing suitable found. + DEBUG_MESSAGE("Could not find suitable object under mouse pointer."); return 0; } @@ -515,6 +561,11 @@ return m_signal_preview_command; } +sigc::signal<void> View::signal_preview_cancel() +{ + return m_signal_preview_cancel; +} + void View::pick_segment(std::size_t index) { /* This is event is recieved when changing the selected menu to reflect a Modified: trunk/racer_editor/View.h =================================================================== --- trunk/racer_editor/View.h 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/racer_editor/View.h 2009-11-25 00:29:38 UTC (rev 88) @@ -118,6 +118,17 @@ * a command. */ sigc::signal<void, boost::shared_ptr<Document::DocumentDelta> > signal_preview_command(); + + /** Get signal emmited when the previewed command should be canceled. + * This allows the document to be reset to how it was if the user did not + * want the command that was previewed. + * The signal should be connected to a function of the form: + * @code void on_view_preview_cancel() + * @endcode + * @return signal that is emmited when the previewed command needs to be + * rejected. + */ + sigc::signal<void> signal_preview_cancel(); protected: // signal handlers: virtual void on_realize(); @@ -147,6 +158,9 @@ /// The scale of the drawing. Scale is in pixels per distance unit. float scale; + /// The length of the handles used to edit rotations. + btScalar handle_length; + /// The coordinates at the bottom left corner of the display. btVector3 centre; @@ -188,6 +202,10 @@ */ sigc::signal<void, boost::shared_ptr<Document::DocumentDelta> > m_signal_preview_command; + /** Signal emmited when a previewed command should be canceled. + */ + sigc::signal<void> m_signal_preview_cancel; + Glib::RefPtr<Gtk::ActionGroup> m_action_group; Glib::RefPtr<Gtk::UIManager> m_ui_manager; Gtk::UIManager::ui_merge_id m_menu_id; Modified: trunk/racer_editor/Viewport.cpp =================================================================== --- trunk/racer_editor/Viewport.cpp 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/racer_editor/Viewport.cpp 2009-11-25 00:29:38 UTC (rev 88) @@ -267,3 +267,8 @@ { return m_view.signal_preview_command(); } + +sigc::signal<void> Viewport::signal_preview_cancel() +{ + return m_view.signal_preview_cancel(); +} Modified: trunk/racer_editor/Viewport.h =================================================================== --- trunk/racer_editor/Viewport.h 2009-11-22 05:01:47 UTC (rev 87) +++ trunk/racer_editor/Viewport.h 2009-11-25 00:29:38 UTC (rev 88) @@ -75,6 +75,9 @@ /// Signal emmited when there is a command to show a preview of. sigc::signal<void, boost::shared_ptr<Document::DocumentDelta> > signal_preview_command(); + + /// Signal emmited when the previewed command should be canceled. + sigc::signal<void> signal_preview_cancel(); protected: /// Set scrollbars and events identical in all constructors. void create(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |