Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9ee4e42
Moulding of cubic bezier
4adex May 21, 2025
07cff31
Implemented falloff with interpolation
4adex May 23, 2025
b49947e
remove conflict
4adex May 23, 2025
35ff626
Merge branch 'GraphiteEditor:master' into moulding_segment
4adex May 23, 2025
81bfca4
Move falloff to consts
4adex May 23, 2025
aff6f6d
Spelling
Keavon May 24, 2025
211f5d2
Refine falloff param and bug fix
4adex May 24, 2025
6b412a8
Merge branch 'master' into moulding_segment
4adex May 24, 2025
8f2c9e6
Merge branch 'master' into moulding_segment
Keavon May 25, 2025
a53efe9
Code review
Keavon May 26, 2025
7de2364
Add colinear disable modes to molding degment feat
4adex May 27, 2025
db1840b
Clean comments and unused code
4adex May 27, 2025
e7d1dcf
Merge branch 'master' into moulding_segment
4adex May 27, 2025
93b1040
Code refactor
4adex May 27, 2025
ea44ae7
Merge branch 'moulding_segment' of github.com:4adex/Graphite into mou…
4adex May 27, 2025
e8ee850
Merge branch 'master' into moulding_segment
4adex May 28, 2025
3bc33fa
Fix error
4adex May 28, 2025
55cc159
Merge branch 'master' into moulding_segment
Keavon May 30, 2025
04b269a
Change colinear toggle behaviour
4adex Jun 1, 2025
6baca4e
Merge branch 'moulding_segment' of github.com:4adex/Graphite into mou…
4adex Jun 1, 2025
24fda85
Merge branch 'master' into moulding_segment
Keavon Jun 7, 2025
6d28377
Code review
Keavon Jun 7, 2025
f312170
Merge branch 'master' into moulding_segment
4adex Jun 9, 2025
65cbc13
Remove KeyC feat + Fix overlay
4adex Jun 9, 2025
b142009
Dynamic hints in path tool
4adex Jun 10, 2025
033a761
Revamp molding logic
4adex Jun 11, 2025
07bac09
Code review
Keavon Jun 13, 2025
3665ba7
Remove unused Bezier algorithms (maybe useful for future reference)
Keavon Jun 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion editor/src/messages/input_mapper/input_mappings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ pub fn input_mappings() -> Mapping {
entry!(KeyDown(KeyG); action_dispatch=PathToolMessage::GRS { key: KeyG }),
entry!(KeyDown(KeyR); action_dispatch=PathToolMessage::GRS { key: KeyR }),
entry!(KeyDown(KeyS); action_dispatch=PathToolMessage::GRS { key: KeyS }),
entry!(PointerMove; refresh_keys=[KeyC, Space, Control, Shift, Alt], action_dispatch=PathToolMessage::PointerMove { toggle_colinear: KeyC, equidistant: Alt, move_anchor_with_handles: Space, snap_angle: Shift, lock_angle: Control, delete_segment: Alt }),
entry!(PointerMove; refresh_keys=[KeyC, Space, Control, Shift, Alt], action_dispatch=PathToolMessage::PointerMove { toggle_colinear: KeyC, equidistant: Alt, move_anchor_with_handles: Space, snap_angle: Shift, lock_angle: Control, delete_segment: Alt, break_colinear_molding: Alt }),
entry!(KeyDown(Delete); action_dispatch=PathToolMessage::Delete),
entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=PathToolMessage::SelectAllAnchors),
entry!(KeyDown(KeyA); modifiers=[Accel, Shift], action_dispatch=PathToolMessage::DeselectAllPoints),
Expand Down
67 changes: 66 additions & 1 deletion editor/src/messages/tool/common_functionality/shape_editor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::graph_modification_utils::merge_layers;
use super::snapping::{SnapCache, SnapCandidatePoint, SnapData, SnapManager, SnappedPoint};
use super::utility_functions::calculate_segment_angle;
use super::utility_functions::{adjust_handle_colinearity, calculate_segment_angle, restore_g1_continuity, restore_previous_handle_position};
use crate::consts::HANDLE_LENGTH_FACTOR;
use crate::messages::portfolio::document::overlays::utility_functions::selected_segments;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
Expand Down Expand Up @@ -282,6 +282,71 @@ impl ClosestSegment {
.unwrap_or(DVec2::ZERO);
tangent.perp()
}

/// Molding the bezier curve.
/// Returns adjacent handles' [`HandleId`] if colinearity is broken temporarily.
pub fn mold_handle_positions(
&self,
document: &DocumentMessageHandler,
responses: &mut VecDeque<Message>,
(c1, c2): (DVec2, DVec2),
new_b: DVec2,
break_colinear_molding: bool,
temporary_adjacent_handles_while_molding: Option<[Option<HandleId>; 2]>,
) -> Option<[Option<HandleId>; 2]> {
let transform = document.metadata().transform_to_viewport(self.layer);

let start = self.bezier.start;
let end = self.bezier.end;

// Apply the drag delta to the segment's handles
let b = self.bezier_point_to_viewport;
let delta = transform.inverse().transform_vector2(new_b - b);
let (nc1, nc2) = (c1 + delta, c2 + delta);

let handle1 = HandleId::primary(self.segment);
let handle2 = HandleId::end(self.segment);
let layer = self.layer;

let modification_type = handle1.set_relative_position(nc1 - start);
responses.add(GraphOperationMessage::Vector { layer, modification_type });

let modification_type = handle2.set_relative_position(nc2 - end);
responses.add(GraphOperationMessage::Vector { layer, modification_type });

// If adjacent segments have colinear handles, their direction is changed but their handle lengths is preserved
// TODO: Find something which is more appropriate
let vector_data = document.network_interface.compute_modified_vector(self.layer())?;

if break_colinear_molding {
// Disable G1 continuity
let other_handles = [
restore_previous_handle_position(handle1, c1, start, &vector_data, layer, responses),
restore_previous_handle_position(handle2, c2, end, &vector_data, layer, responses),
];

// Store other HandleId in tool data to regain colinearity later
if temporary_adjacent_handles_while_molding.is_some() {
temporary_adjacent_handles_while_molding
} else {
Some(other_handles)
}
} else {
// Move the colinear handles so that colinearity is maintained
adjust_handle_colinearity(handle1, start, nc1, &vector_data, layer, responses);
adjust_handle_colinearity(handle2, end, nc2, &vector_data, layer, responses);

if let Some(adjacent_handles) = temporary_adjacent_handles_while_molding {
if let Some(other_handle1) = adjacent_handles[0] {
restore_g1_continuity(handle1, other_handle1, nc1, start, &vector_data, layer, responses);
}
if let Some(other_handle2) = adjacent_handles[1] {
restore_g1_continuity(handle2, other_handle2, nc2, end, &vector_data, layer, responses);
}
}
None
}
}
}

// TODO Consider keeping a list of selected manipulators to minimize traversals of the layers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::messages::tool::tool_messages::path_tool::PathOverlayMode;
use glam::DVec2;
use graphene_core::renderer::Quad;
use graphene_core::text::{FontCache, load_face};
use graphene_std::vector::{ManipulatorPointId, PointId, SegmentId, VectorData};
use graphene_std::vector::{HandleId, ManipulatorPointId, PointId, SegmentId, VectorData, VectorModificationType};

/// Determines if a path should be extended. Goal in viewport space. Returns the path and if it is extending from the start, if applicable.
pub fn should_extend(
Expand Down Expand Up @@ -95,6 +95,65 @@ pub fn calculate_segment_angle(anchor: PointId, segment: SegmentId, vector_data:
required_handle.map(|handle| -(handle - anchor_position).angle_to(DVec2::X))
}

pub fn adjust_handle_colinearity(handle: HandleId, anchor_position: DVec2, target_control_point: DVec2, vector_data: &VectorData, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>) {
let Some(other_handle) = vector_data.other_colinear_handle(handle) else { return };
let Some(handle_position) = other_handle.to_manipulator_point().get_position(vector_data) else {
return;
};
let Some(direction) = (anchor_position - target_control_point).try_normalize() else { return };

let new_relative_position = (handle_position - anchor_position).length() * direction;
let modification_type = other_handle.set_relative_position(new_relative_position);

responses.add(GraphOperationMessage::Vector { layer, modification_type });
}

pub fn restore_previous_handle_position(
handle: HandleId,
original_c: DVec2,
anchor_position: DVec2,
vector_data: &VectorData,
layer: LayerNodeIdentifier,
responses: &mut VecDeque<Message>,
) -> Option<HandleId> {
let other_handle = vector_data.other_colinear_handle(handle)?;
let handle_position = other_handle.to_manipulator_point().get_position(vector_data)?;
let direction = (anchor_position - original_c).try_normalize()?;

let old_relative_position = (handle_position - anchor_position).length() * direction;
let modification_type = other_handle.set_relative_position(old_relative_position);
responses.add(GraphOperationMessage::Vector { layer, modification_type });

let handles = [handle, other_handle];
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
responses.add(GraphOperationMessage::Vector { layer, modification_type });

Some(other_handle)
}

pub fn restore_g1_continuity(
handle: HandleId,
other_handle: HandleId,
control_point: DVec2,
anchor_position: DVec2,
vector_data: &VectorData,
layer: LayerNodeIdentifier,
responses: &mut VecDeque<Message>,
) {
let Some(handle_position) = other_handle.to_manipulator_point().get_position(vector_data) else {
return;
};
let Some(direction) = (anchor_position - control_point).try_normalize() else { return };

let new_relative_position = (handle_position - anchor_position).length() * direction;
let modification_type = other_handle.set_relative_position(new_relative_position);
responses.add(GraphOperationMessage::Vector { layer, modification_type });

let handles = [handle, other_handle];
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: true };
responses.add(GraphOperationMessage::Vector { layer, modification_type });
}

/// Check whether a point is visible in the current overlay mode.
pub fn is_visible_point(
manipulator_point_id: ManipulatorPointId,
Expand Down
Loading
Loading