From 7a5b32e9334fef7e5e4171ea6012daa91138a319 Mon Sep 17 00:00:00 2001 From: Magnus Jacobsson Date: Thu, 6 Oct 2022 11:02:40 +0200 Subject: [PATCH] arrows: arrow_length_diamond: take edge penwidth into account when calculating length The test_edge_node_overlap_diamond_edge_arrow test case now succeeds, so the expectancy that it should fail is removed. Towards https://gitlab.com/graphviz/graphviz/-/issues/372. --- CHANGELOG.md | 5 +++ lib/common/arrows.c | 44 ++++++++++++++++++- ...t_edge_node_overlap_diamond_edge_arrow.cpp | 4 +- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46f9b2bac..aa436bbe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased (7.0.1)] +### Fixed + +- Failure of arrowhead and arrowtail to respect penwidth #372 \ + Fixed also for the `diamond` [edge arrow shape](https://graphviz.org/doc/info/arrows.html#primitive-shapes). + ## [7.0.0] – 2022-10-22 ### Changed diff --git a/lib/common/arrows.c b/lib/common/arrows.c index faf7a932f..4e233dc42 100644 --- a/lib/common/arrows.c +++ b/lib/common/arrows.c @@ -126,6 +126,7 @@ static pointf arrow_type_gap(GVJ_t * job, pointf p, pointf u, double arrowsize, static double arrow_length_generic(double lenfact, double arrowsize, double penwidth, int flag); static double arrow_length_normal(double lenfact, double arrowsize, double penwidth, int flag); static double arrow_length_box(double lenfact, double arrowsize, double penwidth, int flag); +static double arrow_length_diamond(double lenfact, double arrowsize, double penwidth, int flag); static double arrow_length_dot(double lenfact, double arrowsize, double penwidth, int flag); static const arrowtype_t Arrowtypes[] = { @@ -133,7 +134,7 @@ static const arrowtype_t Arrowtypes[] = { {ARR_TYPE_CROW, 1.0, arrow_type_crow, arrow_length_generic}, {ARR_TYPE_TEE, 0.5, arrow_type_tee, arrow_length_generic}, {ARR_TYPE_BOX, 1.0, arrow_type_box, arrow_length_box}, - {ARR_TYPE_DIAMOND, 1.2, arrow_type_diamond, arrow_length_generic}, + {ARR_TYPE_DIAMOND, 1.2, arrow_type_diamond, arrow_length_diamond}, {ARR_TYPE_DOT, 0.8, arrow_type_dot, arrow_length_dot}, {ARR_TYPE_CURVE, 1.0, arrow_type_curve, arrow_length_generic}, {ARR_TYPE_GAP, 0.5, arrow_type_gap, arrow_length_generic}, @@ -1041,6 +1042,47 @@ static double arrow_length_box(double lenfact, double arrowsize, return lenfact * arrowsize * ARROW_LENGTH + penwidth / 2; } +static double arrow_length_diamond(double lenfact, double arrowsize, + double penwidth, int flag) { + pointf a[5]; + // set arrow end point at origin + const pointf p = {0, 0}; + // generate an arrowhead vector along x-axis + const pointf u = {lenfact * arrowsize * ARROW_LENGTH, 0}; + + // arrow start point + pointf q = arrow_type_diamond0(p, u, penwidth, flag, a); + + // calculate overlap using a triangle with its base at the left and right + // corners of the diamond and its tip at the end point + const pointf base1 = a[3]; + const pointf base2 = a[1]; + const pointf tip = a[2]; + const double full_length = q.x / 2; + assert(full_length > 0 && "non-positive full length"); + const double nominal_length = fabs(base1.x - tip.x); + const double nominal_base_width = base2.y - base1.y; + assert(nominal_base_width > 0 && "non-positive nominal base width"); + // the full base width is proportionally scaled with the length + const double full_base_width = + nominal_base_width * full_length / nominal_length; + assert(full_base_width > 0 && "non-positive full base width"); + + // we want a small overlap between the edge path (stem) and the arrow to avoid + // gaps beetween them in case the arrow has a corner towards the edge path + + // overlap the tip to a point where its width is equal to the penwidth + const double length_where_width_is_penwidth = + full_length * penwidth / full_base_width; + const double overlap_at_tip = length_where_width_is_penwidth; + + const double overlap = overlap_at_tip; + + // arrow length is the x value of the start point since the arrow points along + // the positive x axis and ends at origin + return 2 * full_length - overlap; +} + static double arrow_length_dot(double lenfact, double arrowsize, double penwidth, int flag) { (void)flag; diff --git a/tests/test_edge_node_overlap_diamond_edge_arrow.cpp b/tests/test_edge_node_overlap_diamond_edge_arrow.cpp index 0ac6295d1..0fb5b6f9f 100644 --- a/tests/test_edge_node_overlap_diamond_edge_arrow.cpp +++ b/tests/test_edge_node_overlap_diamond_edge_arrow.cpp @@ -6,8 +6,8 @@ #include "test_utilities.h" TEST_CASE("Edge node overlap for diamond arrow", - "[!shouldfail] An edge connected to a node shall touch that node and " - "not overlap it too much") { + "An edge connected to a node shall touch that node and not overlap " + "it too much") { const std::string_view primitive_arrow_shape = "diamond"; -- 2.40.0