]> granicus.if.org Git - graphviz/commitdiff
arrows: arrow_length_diamond: take edge penwidth into account when calculating length
authorMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Thu, 6 Oct 2022 09:02:40 +0000 (11:02 +0200)
committerMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Sat, 29 Oct 2022 09:11:40 +0000 (11:11 +0200)
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
lib/common/arrows.c
tests/test_edge_node_overlap_diamond_edge_arrow.cpp

index 46f9b2baca0c3b90d530734c5ddd23a9659aaefe..aa436bbe3951f3253c86647e53c304e240e86fc6 100644 (file)
@@ -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
index faf7a932f16c91e10f060758443ac691238f8d30..4e233dc428189edd8737512e78b107a4b5c21d2f 100644 (file)
@@ -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;
index 0ac6295d147a5e70e5c4c0b763c45332f3e9193a..0fb5b6f9f43f1605056a0f158b5983b58327400d 100644 (file)
@@ -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";