mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 07:38:12 +08:00
Fix tool overlays and snap targets to use upstream Path node geometry, not downstream final geometry (#4114)
* Fix tool overlays and snap targets to use upstream Path node geometry not downstream final geometry * Snap to upstream Path free points, dedupe the lookup via a helper
This commit is contained in:
@@ -26,7 +26,7 @@ use graphene_std::ContextDependencies;
|
|||||||
use graphene_std::math::quad::Quad;
|
use graphene_std::math::quad::Quad;
|
||||||
use graphene_std::subpath::Subpath;
|
use graphene_std::subpath::Subpath;
|
||||||
use graphene_std::transform::Footprint;
|
use graphene_std::transform::Footprint;
|
||||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType, FreePoint};
|
||||||
use graphene_std::vector::{PointId, Vector, VectorModificationType};
|
use graphene_std::vector::{PointId, Vector, VectorModificationType};
|
||||||
use kurbo::BezPath;
|
use kurbo::BezPath;
|
||||||
use memo_network::MemoNetwork;
|
use memo_network::MemoNetwork;
|
||||||
@@ -3191,8 +3191,8 @@ impl NodeNetworkInterface {
|
|||||||
let nodes = network_metadata
|
let nodes = network_metadata
|
||||||
.persistent_metadata
|
.persistent_metadata
|
||||||
.node_metadata
|
.node_metadata
|
||||||
.iter()
|
.keys()
|
||||||
.filter_map(|(node_id, _)| if self.is_layer(node_id, network_path) { Some(*node_id) } else { None })
|
.filter_map(|node_id| if self.is_layer(node_id, network_path) { Some(*node_id) } else { None })
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let layer_widths = nodes
|
let layer_widths = nodes
|
||||||
.iter()
|
.iter()
|
||||||
@@ -3234,6 +3234,39 @@ impl NodeNetworkInterface {
|
|||||||
self.document_metadata.layer_vector_data.get(&layer).map(|arc| arc.as_ref().clone())
|
self.document_metadata.layer_vector_data.get(&layer).map(|arc| arc.as_ref().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The vector geometry an upstream Path node would surface for editing.
|
||||||
|
/// This is the result of `compute_modified_vector`, but only if a visible 'Path' node is actually upstream.
|
||||||
|
/// Useful for tool overlays and snap target collection usages that want to match the Path tool's view
|
||||||
|
/// (e.g. the pre-solidified centerline for a Solidify Stroke layer) and otherwise do nothing.
|
||||||
|
pub fn upstream_path_node_vector(&self, layer: LayerNodeIdentifier) -> Option<Vector> {
|
||||||
|
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self);
|
||||||
|
graph_layer.upstream_visible_node_id_from_name_in_layer(&DefinitionIdentifier::Network("Path".into()))?;
|
||||||
|
self.compute_modified_vector(layer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Outline targets for the Select tool's hover/selection overlay, mirroring the Path tool's view.
|
||||||
|
/// Returns `Some` when an upstream Path node exists so the outline matches what the Path tool edits
|
||||||
|
/// (e.g. the pre-solidified centerline for a Solidify Stroke layer); returns `None` otherwise so the
|
||||||
|
/// caller can fall back to the layer's recorded `outlines`/`click_targets`.
|
||||||
|
pub fn path_aware_outline_targets(&self, layer: LayerNodeIdentifier) -> Option<Vec<ClickTargetType>> {
|
||||||
|
let vector = self.upstream_path_node_vector(layer)?;
|
||||||
|
|
||||||
|
let mut targets = Vec::new();
|
||||||
|
let subpaths: Vec<Subpath<PointId>> = vector.stroke_bezier_paths().collect();
|
||||||
|
if !subpaths.is_empty() {
|
||||||
|
targets.push(ClickTargetType::CompoundPath(subpaths));
|
||||||
|
}
|
||||||
|
|
||||||
|
for &point_id in vector.point_domain.ids() {
|
||||||
|
if !vector.any_connected(point_id) {
|
||||||
|
let position = vector.point_domain.position_from_id(point_id).unwrap_or_default();
|
||||||
|
targets.push(ClickTargetType::FreePoint(FreePoint::new(point_id, position)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(targets)
|
||||||
|
}
|
||||||
|
|
||||||
/// Loads the structure of layer nodes from a node graph.
|
/// Loads the structure of layer nodes from a node graph.
|
||||||
pub fn load_structure(&mut self) {
|
pub fn load_structure(&mut self) {
|
||||||
self.document_metadata.structure = HashMap::from_iter([(LayerNodeIdentifier::ROOT_PARENT, NodeRelations::default())]);
|
self.document_metadata.structure = HashMap::from_iter([(LayerNodeIdentifier::ROOT_PARENT, NodeRelations::default())]);
|
||||||
|
|||||||
@@ -472,11 +472,18 @@ impl SnapManager {
|
|||||||
if let Some(ind) = &self.indicator {
|
if let Some(ind) = &self.indicator {
|
||||||
for layer in &ind.outline_layers {
|
for layer in &ind.outline_layers {
|
||||||
let &Some(layer) = layer else { continue };
|
let &Some(layer) = layer else { continue };
|
||||||
overlay_context.outline(
|
// Mirror the Path tool's view (e.g. pre-solidified centerline) when an upstream Path node exists,
|
||||||
snap_data.document.metadata().layer_with_free_points_outline(layer),
|
// otherwise fall back to the layer's recorded outline geometry
|
||||||
snap_data.document.metadata().transform_to_viewport(layer),
|
if let Some(targets) = snap_data.document.network_interface.path_aware_outline_targets(layer) {
|
||||||
None,
|
let transform = snap_data.document.metadata().transform_to_viewport_if_feeds(layer, &snap_data.document.network_interface);
|
||||||
);
|
overlay_context.outline(targets.iter(), transform, None);
|
||||||
|
} else {
|
||||||
|
overlay_context.outline(
|
||||||
|
snap_data.document.metadata().layer_with_free_points_outline(layer),
|
||||||
|
snap_data.document.metadata().transform_to_viewport(layer),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(quad) = ind.target_bounds {
|
if let Some(quad) = ind.target_bounds {
|
||||||
overlay_context.quad(to_viewport * quad, None, None);
|
overlay_context.quad(to_viewport * quad, None, None);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ impl LayerSnapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::IntersectionPoint)) || document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::AlongPath)) {
|
if document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::IntersectionPoint)) || document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::AlongPath)) {
|
||||||
for subpath in document.metadata().layer_outline(layer) {
|
let mut push_candidates = |subpath: &Subpath<PointId>, transform: DAffine2| {
|
||||||
for (start_index, curve) in subpath.iter().enumerate() {
|
for (start_index, curve) in subpath.iter().enumerate() {
|
||||||
let document_curve = Affine::new(transform.to_cols_array()) * curve;
|
let document_curve = Affine::new(transform.to_cols_array()) * curve;
|
||||||
let start = subpath.manipulator_groups()[start_index].id;
|
let start = subpath.manipulator_groups()[start_index].id;
|
||||||
@@ -89,6 +89,22 @@ impl LayerSnapper {
|
|||||||
bounds: None,
|
bounds: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Post-solidified outline (the layer's recorded geometry)
|
||||||
|
for subpath in document.metadata().layer_outline(layer) {
|
||||||
|
push_candidates(subpath, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-solidified centerline (the Path tool's view) when an upstream Path node exists,
|
||||||
|
// so a drag can snap to either the visible solidified shape or the editable centerline
|
||||||
|
if let Some(vector) = document.network_interface.upstream_path_node_vector(layer) {
|
||||||
|
let path_aware_transform = document.metadata().transform_to_document_if_feeds(layer, &document.network_interface);
|
||||||
|
if path_aware_transform.is_finite() {
|
||||||
|
for subpath in vector.stroke_bezier_paths() {
|
||||||
|
push_candidates(&subpath, path_aware_transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -616,10 +632,40 @@ pub fn get_layer_snap_points(layer: LayerNodeIdentifier, snap_data: &SnapData, p
|
|||||||
for child in layer.descendants(document.metadata()) {
|
for child in layer.descendants(document.metadata()) {
|
||||||
get_layer_snap_points(child, snap_data, points);
|
get_layer_snap_points(child, snap_data, points);
|
||||||
}
|
}
|
||||||
} else if document.metadata().layer_outline(layer).next().is_some() {
|
} else {
|
||||||
let to_document = document.metadata().transform_to_document(layer);
|
// Post-solidified outline (the layer's recorded geometry)
|
||||||
for subpath in document.metadata().layer_outline(layer) {
|
if document.metadata().layer_outline(layer).next().is_some() {
|
||||||
subpath_anchor_snap_points(layer, subpath, snap_data, points, to_document);
|
let to_document = document.metadata().transform_to_document(layer);
|
||||||
|
for subpath in document.metadata().layer_outline(layer) {
|
||||||
|
subpath_anchor_snap_points(layer, subpath, snap_data, points, to_document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-solidified centerline (the Path tool's view) when an upstream Path node exists,
|
||||||
|
// so anchor snaps can also target the editable anchor positions and isolated free points,
|
||||||
|
// matching what the Path tool's overlay shows
|
||||||
|
if let Some(vector) = document.network_interface.upstream_path_node_vector(layer) {
|
||||||
|
let to_document = document.metadata().transform_to_document_if_feeds(layer, &document.network_interface);
|
||||||
|
for subpath in vector.stroke_bezier_paths() {
|
||||||
|
subpath_anchor_snap_points(layer, &subpath, snap_data, points, to_document);
|
||||||
|
}
|
||||||
|
|
||||||
|
if document.snapping_state.target_enabled(SnapTarget::Path(PathSnapTarget::AnchorPointWithFreeHandles)) {
|
||||||
|
for &point_id in vector.point_domain.ids() {
|
||||||
|
if points.len() >= crate::consts::MAX_LAYER_SNAP_POINTS {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !vector.any_connected(point_id) {
|
||||||
|
let position = vector.point_domain.position_from_id(point_id).unwrap_or_default();
|
||||||
|
points.push(SnapCandidatePoint::new(
|
||||||
|
to_document.transform_point2(position),
|
||||||
|
SnapSource::Path(PathSnapSource::AnchorPointWithFreeHandles),
|
||||||
|
SnapTarget::Path(PathSnapTarget::AnchorPointWithFreeHandles),
|
||||||
|
Some(layer),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -609,7 +609,10 @@ struct PathToolData {
|
|||||||
drill_through_cycle_index: usize,
|
drill_through_cycle_index: usize,
|
||||||
drill_through_cycle_count: usize,
|
drill_through_cycle_count: usize,
|
||||||
hovered_layers: Vec<LayerNodeIdentifier>,
|
hovered_layers: Vec<LayerNodeIdentifier>,
|
||||||
ghost_outline: Vec<(Vec<ClickTargetType>, LayerNodeIdentifier)>,
|
/// Snapshot of each selected layer's outline geometry at drag start, drawn in gray as a "before" reference.
|
||||||
|
/// The `bool` flags whether the snapshot came from `path_aware_outline_targets`, in which case the draw
|
||||||
|
/// site uses `transform_to_viewport_if_feeds` to match the Path tool's coordinate space.
|
||||||
|
ghost_outline: Vec<(Vec<ClickTargetType>, LayerNodeIdentifier, bool)>,
|
||||||
make_path_editable_is_allowed: bool,
|
make_path_editable_is_allowed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,10 +711,15 @@ impl PathToolData {
|
|||||||
fn set_ghost_outline(&mut self, shape_editor: &ShapeState, document: &DocumentMessageHandler) {
|
fn set_ghost_outline(&mut self, shape_editor: &ShapeState, document: &DocumentMessageHandler) {
|
||||||
self.ghost_outline.clear();
|
self.ghost_outline.clear();
|
||||||
for &layer in shape_editor.selected_shape_state.keys() {
|
for &layer in shape_editor.selected_shape_state.keys() {
|
||||||
// We probably need to collect here
|
// Mirror the Path tool's view (e.g. pre-solidified centerline) when an upstream Path node exists,
|
||||||
let outline: Vec<ClickTargetType> = document.metadata().layer_with_free_points_outline(layer).cloned().collect();
|
// otherwise fall back to the layer's recorded outline geometry
|
||||||
|
let (outline, path_aware) = if let Some(targets) = document.network_interface.path_aware_outline_targets(layer) {
|
||||||
|
(targets, true)
|
||||||
|
} else {
|
||||||
|
(document.metadata().layer_with_free_points_outline(layer).cloned().collect(), false)
|
||||||
|
};
|
||||||
|
|
||||||
self.ghost_outline.push((outline, layer));
|
self.ghost_outline.push((outline, layer, path_aware));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1712,8 +1720,12 @@ impl Fsm for PathToolFsmState {
|
|||||||
(_, PathToolMessage::Overlays { context: mut overlay_context }) => {
|
(_, PathToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
// Set this to show ghost line only if drag actually happened
|
// Set this to show ghost line only if drag actually happened
|
||||||
if matches!(self, Self::Dragging(_)) && tool_data.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD {
|
if matches!(self, Self::Dragging(_)) && tool_data.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD {
|
||||||
for (outline, layer) in &tool_data.ghost_outline {
|
for (outline, layer, path_aware) in &tool_data.ghost_outline {
|
||||||
let transform = document.metadata().transform_to_viewport(*layer);
|
let transform = if *path_aware {
|
||||||
|
document.metadata().transform_to_viewport_if_feeds(*layer, &document.network_interface)
|
||||||
|
} else {
|
||||||
|
document.metadata().transform_to_viewport(*layer)
|
||||||
|
};
|
||||||
overlay_context.outline(outline.iter(), transform, Some(COLOR_OVERLAY_GRAY));
|
overlay_context.outline(outline.iter(), transform, Some(COLOR_OVERLAY_GRAY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1877,9 +1889,6 @@ impl Fsm for PathToolFsmState {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let layer_to_viewport = document.metadata().transform_to_viewport(hovered_layer);
|
|
||||||
let outline = document.metadata().layer_with_free_points_outline(hovered_layer);
|
|
||||||
|
|
||||||
// Determine highlight color based on drill-through state
|
// Determine highlight color based on drill-through state
|
||||||
let color = match (index, mouse_has_moved) {
|
let color = match (index, mouse_has_moved) {
|
||||||
// If the layer is the next selected one and mouse has not moved, highlight it blue
|
// If the layer is the next selected one and mouse has not moved, highlight it blue
|
||||||
@@ -1891,7 +1900,14 @@ impl Fsm for PathToolFsmState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Make this draw underneath all other overlays
|
// TODO: Make this draw underneath all other overlays
|
||||||
overlay_context.outline(outline, layer_to_viewport, Some(color));
|
// Mirror the Path tool's view (e.g. pre-solidified centerline) when an upstream Path node exists
|
||||||
|
if let Some(targets) = document.network_interface.path_aware_outline_targets(hovered_layer) {
|
||||||
|
let layer_to_viewport = document.metadata().transform_to_viewport_if_feeds(hovered_layer, &document.network_interface);
|
||||||
|
overlay_context.outline(targets.iter(), layer_to_viewport, Some(color));
|
||||||
|
} else {
|
||||||
|
let layer_to_viewport = document.metadata().transform_to_viewport(hovered_layer);
|
||||||
|
overlay_context.outline(document.metadata().layer_with_free_points_outline(hovered_layer), layer_to_viewport, Some(color));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Drawing { selection_shape } => {
|
Self::Drawing { selection_shape } => {
|
||||||
|
|||||||
@@ -581,6 +581,18 @@ impl SelectToolData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draws the hover/selection outline for a layer. When a Path node is upstream, mirrors the Path tool's view
|
||||||
|
/// (e.g. the pre-solidified centerline for a Solidify Stroke layer); otherwise uses the layer's recorded outlines.
|
||||||
|
fn draw_layer_outline(overlay_context: &mut OverlayContext, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, color: Option<&str>) {
|
||||||
|
if let Some(targets) = document.network_interface.path_aware_outline_targets(layer) {
|
||||||
|
let layer_to_viewport = document.metadata().transform_to_viewport_if_feeds(layer, &document.network_interface);
|
||||||
|
overlay_context.outline(targets.iter(), layer_to_viewport, color);
|
||||||
|
} else {
|
||||||
|
let layer_to_viewport = document.metadata().transform_to_viewport(layer);
|
||||||
|
overlay_context.outline(document.metadata().layer_with_free_points_outline(layer), layer_to_viewport, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Bounding boxes are unfortunately not axis aligned. The bounding boxes are found after a transformation is applied to all of the layers.
|
/// Bounding boxes are unfortunately not axis aligned. The bounding boxes are found after a transformation is applied to all of the layers.
|
||||||
/// This uses some rather confusing logic to determine what transform that should be.
|
/// This uses some rather confusing logic to determine what transform that should be.
|
||||||
pub fn create_bounding_box_transform(document: &DocumentMessageHandler) -> DAffine2 {
|
pub fn create_bounding_box_transform(document: &DocumentMessageHandler) -> DAffine2 {
|
||||||
@@ -626,10 +638,10 @@ impl Fsm for SelectToolFsmState {
|
|||||||
.selected_visible_and_unlocked_layers(&document.network_interface)
|
.selected_visible_and_unlocked_layers(&document.network_interface)
|
||||||
.filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]))
|
.filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]))
|
||||||
{
|
{
|
||||||
let layer_to_viewport = document.metadata().transform_to_viewport(layer);
|
draw_layer_outline(&mut overlay_context, document, layer, None);
|
||||||
overlay_context.outline(document.metadata().layer_with_free_points_outline(layer), layer_to_viewport, None);
|
|
||||||
|
|
||||||
if document.metadata().is_text_layer(layer) {
|
if document.metadata().is_text_layer(layer) {
|
||||||
|
let layer_to_viewport = document.metadata().transform_to_viewport(layer);
|
||||||
let transformed_quad = layer_to_viewport * text_bounding_box(layer, document, &cached_data.font_cache);
|
let transformed_quad = layer_to_viewport * text_bounding_box(layer, document, &cached_data.font_cache);
|
||||||
overlay_context.dashed_quad(transformed_quad, None, None, Some(7.), Some(5.), None);
|
overlay_context.dashed_quad(transformed_quad, None, None, Some(7.), Some(5.), None);
|
||||||
}
|
}
|
||||||
@@ -667,14 +679,13 @@ impl Fsm for SelectToolFsmState {
|
|||||||
let not_selected_click = click.filter(|&hovered_layer| !document.network_interface.selected_nodes().selected_layers_contains(hovered_layer, document.metadata()));
|
let not_selected_click = click.filter(|&hovered_layer| !document.network_interface.selected_nodes().selected_layers_contains(hovered_layer, document.metadata()));
|
||||||
if let Some(layer) = not_selected_click {
|
if let Some(layer) = not_selected_click {
|
||||||
if overlay_context.visibility_settings.hover_outline() && !document.network_interface.is_artboard(&layer.to_node(), &[]) {
|
if overlay_context.visibility_settings.hover_outline() && !document.network_interface.is_artboard(&layer.to_node(), &[]) {
|
||||||
let layer_to_viewport = document.metadata().transform_to_viewport(layer);
|
|
||||||
let mut hover_overlay_draw = |layer: LayerNodeIdentifier, color: Option<&str>| {
|
let mut hover_overlay_draw = |layer: LayerNodeIdentifier, color: Option<&str>| {
|
||||||
if layer.has_children(document.metadata()) {
|
if layer.has_children(document.metadata()) {
|
||||||
if let Some(bounds) = document.metadata().bounding_box_viewport(layer) {
|
if let Some(bounds) = document.metadata().bounding_box_viewport(layer) {
|
||||||
overlay_context.quad(Quad::from_box(bounds), color, None);
|
overlay_context.quad(Quad::from_box(bounds), color, None);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
overlay_context.outline(document.metadata().layer_with_free_points_outline(layer), layer_to_viewport, color);
|
draw_layer_outline(&mut overlay_context, document, layer, color);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let layer = match tool_data.nested_selection_behavior {
|
let layer = match tool_data.nested_selection_behavior {
|
||||||
@@ -954,8 +965,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
if overlay_context.visibility_settings.selection_outline() {
|
if overlay_context.visibility_settings.selection_outline() {
|
||||||
// Draws a temporary outline on the layers that will be selected by the current box/lasso area
|
// Draws a temporary outline on the layers that will be selected by the current box/lasso area
|
||||||
for layer in layers_to_outline {
|
for layer in layers_to_outline {
|
||||||
let layer_to_viewport = document.metadata().transform_to_viewport(layer);
|
draw_layer_outline(&mut overlay_context, document, layer, None);
|
||||||
overlay_context.outline(document.metadata().layer_with_free_points_outline(layer), layer_to_viewport, None);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -653,9 +653,16 @@ impl TransformLayerMessageHandler {
|
|||||||
fn set_ghost_outline(ghost_outline: &mut Vec<(Vec<ClickTargetType>, DAffine2)>, shape_editor: &ShapeState, document: &DocumentMessageHandler) {
|
fn set_ghost_outline(ghost_outline: &mut Vec<(Vec<ClickTargetType>, DAffine2)>, shape_editor: &ShapeState, document: &DocumentMessageHandler) {
|
||||||
ghost_outline.clear();
|
ghost_outline.clear();
|
||||||
for &layer in shape_editor.selected_shape_state.keys() {
|
for &layer in shape_editor.selected_shape_state.keys() {
|
||||||
// We probably need to collect here
|
// Mirror the Path tool's view (e.g. pre-solidified centerline) when an upstream Path node exists,
|
||||||
let outline = document.metadata().layer_with_free_points_outline(layer).cloned().collect();
|
// otherwise fall back to the layer's recorded outline geometry
|
||||||
let transform = document.metadata().transform_to_viewport(layer);
|
let (outline, transform) = if let Some(targets) = document.network_interface.path_aware_outline_targets(layer) {
|
||||||
|
(targets, document.metadata().transform_to_viewport_if_feeds(layer, &document.network_interface))
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
document.metadata().layer_with_free_points_outline(layer).cloned().collect(),
|
||||||
|
document.metadata().transform_to_viewport(layer),
|
||||||
|
)
|
||||||
|
};
|
||||||
ghost_outline.push((outline, transform));
|
ghost_outline.push((outline, transform));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user