<commit_before>/* $id: shapes.c,v 1.82 2007/12/24 04:50:36 ellson Exp $ $Revision$ */
/* vim:set shiftwidth=4 ts=8: */

/**********************************************************
*      This software is part of the graphviz package      *
*                http://www.graphviz.org/                 *
*                                                         *
*            Copyright (c) 1994-2004 AT&T Corp.           *
*                and is licensed under the                *
*            Common Public License, Version 1.0           *
*                      by AT&T Corp.                      *
*                                                         *
*        Information and Software Systems Research        *
*              AT&T Research, Florham Park NJ             *
**********************************************************/

#include "render.h"
#include "htmltable.h"
#include <limits.h>

#define RBCONST 12
#define RBCURVE .5

static port Center = { {0, 0}, -1, 0, 0, 0, 1, 0, 0, 0 };

#define ATTR_SET(a,n) ((a) && (*(agxget(n,a->index)) != '\0'))
  /* Default point size = 0.05 inches or 3.6 points */
#define DEF_POINT 0.05
  /* Minimum point size = 0.0003 inches or 0.02 points
   * This will make the radius 0.01 points, which is the smallest
   * non-zero number output by gvprintdouble in gvdevice.c
   */
#define MIN_POINT 0.0003
  /* extra null character needed to avoid style emitter from thinking
   * there are arguments.
   */
static char *point_style[3] = { "invis\0", "filled\0", 0 };

/* forward declarations of functions used in shapes tables */

static void poly_init(node_t * n);
static void poly_free(node_t * n);
static port poly_port(node_t * n, char *portname, char *);
static boolean poly_inside(inside_t * inside_context, pointf p);
static int poly_path(node_t* n, port* p, int side, boxf rv[], int *kptr);
static void poly_gencode(GVJ_t * job, node_t * n);

static void record_init(node_t * n);
static void record_free(node_t * n);
static port record_port(node_t * n, char *portname, char *);
static boolean record_inside(inside_t * inside_context, pointf p);
static int record_path(node_t* n, port* p, int side, boxf rv[], int *kptr);
static void record_gencode(GVJ_t * job, node_t * n);

static void point_init(node_t * n);
static void point_gencode(GVJ_t * job, node_t * n);
static boolean point_inside(inside_t * inside_context, pointf p);

static boolean epsf_inside(inside_t * inside_context, pointf p);
static void epsf_gencode(GVJ_t * job, node_t * n);

/* polygon descriptions.  "polygon" with 0 sides takes all user control */

/*			       regul perip sides orien disto skew */
static polygon_t p_polygon = { FALSE, 1, 0, 0., 0., 0. };

/* builtin polygon descriptions */
static polygon_t p_ellipse = { FALSE, 1, 1, 0., 0., 0. };
static polygon_t p_circle = { TRUE, 1, 1, 0., 0., 0. };
static polygon_t p_egg = { FALSE, 1, 1, 0., -.3, 0. };
static polygon_t p_triangle = { FALSE, 1, 3, 0., 0., 0. };
static polygon_t p_box = { FALSE, 1, 4, 0., 0., 0. };
static polygon_t p_plaintext = { FALSE, 0, 4, 0., 0., 0. };
static polygon_t p_diamond = { FALSE, 1, 4, 45., 0., 0. };
static polygon_t p_trapezium = { FALSE, 1, 4, 0., -.4, 0. };
static polygon_t p_parallelogram = { FALSE, 1, 4, 0., 0., .6 };
static polygon_t p_house = { FALSE, 1, 5, 0., -.64, 0. };
static polygon_t p_pentagon = { FALSE, 1, 5, 0., 0., 0. };
static polygon_t p_hexagon = { FALSE, 1, 6, 0., 0., 0. };
static polygon_t p_septagon = { FALSE, 1, 7, 0., 0., 0. };
static polygon_t p_octagon = { FALSE, 1, 8, 0., 0., 0. };
static polygon_t p_note = { FALSE, 1, 4, 0., 0., 0., DOGEAR };
static polygon_t p_tab = { FALSE, 1, 4, 0., 0., 0., TAB };
static polygon_t p_folder = { FALSE, 1, 4, 0., 0., 0., FOLDER };
static polygon_t p_box3d = { FALSE, 1, 4, 0., 0., 0., BOX3D };
static polygon_t p_component = { FALSE, 1, 4, 0., 0., 0., COMPONENT };

/* redundant and undocumented builtin polygons */
static polygon_t p_doublecircle = { TRUE, 2, 1, 0., 0., 0. };
static polygon_t p_invtriangle = { FALSE, 1, 3, 180., 0., 0. };
static polygon_t p_invtrapezium = { FALSE, 1, 4, 180., -.4, 0. };
static polygon_t p_invhouse = { FALSE, 1, 5, 180., -.64, 0. };
static polygon_t p_doubleoctagon = { FALSE, 2, 8, 0., 0., 0. };
static polygon_t p_tripleoctagon = { FALSE, 3, 8, 0., 0., 0. };
static polygon_t p_Mdiamond =
    { FALSE, 1, 4, 45., 0., 0., DIAGONALS | AUXLABELS };
static polygon_t p_Msquare = { TRUE, 1, 4, 0., 0., 0., DIAGONALS };
static polygon_t p_Mcircle =
    { TRUE, 1, 1, 0., 0., 0., DIAGONALS | AUXLABELS };

#define IS_BOX(n) (ND_shape(n)->polygon == &p_box)

/* True if style requires processing through node_round_corners. */
#define SPECIAL_CORNERS(style) \
	((style) & (ROUNDED | DIAGONALS | DOGEAR | TAB | FOLDER | BOX3D | COMPONENT))

/*
 * every shape has these functions:
 *
 * void		SHAPE_init(node_t *n)
 *			initialize the shape (usually at least its size).
 * void		SHAPE_free(node_t *n)
 *			free all memory used by the shape
 * port		SHAPE_port(node_t *n, char *portname)
 *			return the aiming point and slope (if constrained)
 *			of a port.
 * int		SHAPE_inside(inside_t *inside_context, pointf p, edge_t *e);
 *			test if point is inside the node shape which is
 *			assumed convex.
 *			the point is relative to the node center.  the edge
 *			is passed in case the port affects spline clipping.
 * int		SHAPE_path(node *n, edge_t *e, int pt, boxf path[], int *nbox)
 *			create a path for the port of e that touches n,
 *			return side
 * void		SHAPE_gencode(GVJ_t *job, node_t *n)
 *			generate graphics code for a node.
 *
 * some shapes, polygons in particular, use additional shape control data *
 *
 */

static shape_functions poly_fns = {
    poly_init,
    poly_free,
    poly_port,
    poly_inside,
    poly_path,
    poly_gencode
};
static shape_functions point_fns = {
    point_init,
    poly_free,
    poly_port,
    point_inside,
    NULL,
    point_gencode
};
static shape_functions record_fns = {
    record_init,
    record_free,
    record_port,
    record_inside,
    record_path,
    record_gencode
};
static shape_functions epsf_fns = {
    epsf_init,
    epsf_free,
    poly_port,
    epsf_inside,
    NULL,
    epsf_gencode
};

static shape_desc Shapes[] = {	/* first entry is default for no such shape */
    {"box", &poly_fns, &p_box},
    {"polygon", &poly_fns, &p_polygon},
    {"ellipse", &poly_fns, &p_ellipse},
    {"oval", &poly_fns, &p_ellipse},
    {"circle", &poly_fns, &p_circle},
    {"point", &point_fns, &p_circle},
    {"egg", &poly_fns, &p_egg},
    {"triangle", &poly_fns, &p_triangle},
    {"none", &poly_fns, &p_plaintext},
    {"plaintext", &poly_fns, &p_plaintext},
    {"diamond", &poly_fns, &p_diamond},
    {"trapezium", &poly_fns, &p_trapezium},
    {"parallelogram", &poly_fns, &p_parallelogram},
    {"house", &poly_fns, &p_house},
    {"pentagon", &poly_fns, &p_pentagon},
    {"hexagon", &poly_fns, &p_hexagon},
    {"septagon", &poly_fns, &p_septagon},
    {"octagon", &poly_fns, &p_octagon},
    {"note", &poly_fns, &p_note},
    {"tab", &poly_fns, &p_tab},
    {"folder", &poly_fns, &p_folder},
    {"box3d", &poly_fns, &p_box3d},
    {"component", &poly_fns, &p_component},
    {"rect", &poly_fns, &p_box},
    {"rectangle", &poly_fns, &p_box},
    {"doublecircle", &poly_fns, &p_doublecircle},
    {"doubleoctagon", &poly_fns, &p_doubleoctagon},
    {"tripleoctagon", &poly_fns, &p_tripleoctagon},
    {"invtriangle", &poly_fns, &p_invtriangle},
    {"invtrapezium", &poly_fns, &p_invtrapezium},
    {"invhouse", &poly_fns, &p_invhouse},
    {"Mdiamond", &poly_fns, &p_Mdiamond},
    {"Msquare", &poly_fns, &p_Msquare},
    {"Mcircle", &poly_fns, &p_Mcircle},
/*  *** shapes other than polygons  *** */
    {"record", &record_fns, NULL},
    {"Mrecord", &record_fns, NULL},
    {"epsf", &epsf_fns, NULL},
    {NULL, NULL, NULL}
};

static void unrecognized(node_t * n, char *p)
{
    agerr(AGWARN, "node %s, port %s unrecognized\n", agnameof(n), p);
}

static double quant(double val, double q)
{
    int i;
    i = val / q;
    if (i * q + .00001 < val)
	i++;
    return i * q;
}

static int same_side(pointf p0, pointf p1, pointf L0, pointf L1)
{
    int s0, s1;
    double a, b, c;

    /* a x + b y = c */
    a = -(L1.y - L0.y);
    b = (L1.x - L0.x);
    c = a * L0.x + b * L0.y;

    s0 = (a * p0.x + b * p0.y - c >= 0);
    s1 = (a * p1.x + b * p1.y - c >= 0);
    return (s0 == s1);
}

static
void pencolor(GVJ_t * job, node_t * n)
{
    char *color;

    color = late_nnstring(n, N_color, "");
    if (color[0])
	gvrender_set_pencolor(job, color);
    else
	gvrender_set_pencolor(job, DEFAULT_COLOR);
}

static
char* findPen(node_t * n)
{
    char *color;

    color = late_nnstring(n, N_color, "");
    if (color[0])
	return color;
    else
	return DEFAULT_COLOR;
}

static
char *findFillDflt(node_t * n, char* dflt)
{
    char *color;

    color = late_nnstring(n, N_fillcolor, "");
    if (!color[0]) {
	/* for backward compatibilty, default fill is same as pen */
	color = late_nnstring(n, N_color, "");
	if (!color[0]) {
	    color = dflt;
	}
    }
    return color;
}

static
char *findFill (node_t * n)
{
    return (findFillDflt (n, DEFAULT_FILL));
}

static char **checkStyle(node_t * n, int *flagp)
{
    char *style;
    char **pstyle = 0;
    int istyle = 0;
    polygon_t *poly;

    style = late_nnstring(n, N_style, "");
    if (style[0]) {
	char **pp;
	char **qp;
	char *p;
	pp = pstyle = parse_style(style);
	while ((p = *pp)) {
	    if (streq(p, "filled")) {
		istyle |= FILLED;
		pp++;
	    } else if (streq(p, "rounded")) {
		istyle |= ROUNDED;
		qp = pp; /* remove rounded from list passed to renderer */
		do {
		    qp++;
		    *(qp-1) = *qp;
		} while (*qp);
	    } else if (streq(p, "diagonals")) {
		istyle |= DIAGONALS;
		qp = pp; /* remove diagonals from list passed to renderer */
		do {
		    qp++;
		    *(qp-1) = *qp;
		} while (*qp);
	    } else if (streq(p, "invis")) {
		istyle |= INVISIBLE;
		pp++;
	    }
	    else pp++;
	}
    }
    if ((poly = ND_shape(n)->polygon))
	istyle |= poly->option;

    *flagp = istyle;
    return pstyle;
}

static int stylenode(GVJ_t * job, node_t * n)
{
    char **pstyle, *s;
    int istyle, penwidth;

    if ((pstyle = checkStyle(n, &istyle)))
	gvrender_set_style(job, pstyle);

#ifndef WITH_CGRAPH
    if (N_penwidth && ((s=agxget(n, N_penwidth->index)) && s[0])) {
#else
    if (N_penwidth && ((s=agxget(n, N_penwidth)) && s[0])) {
#endif
        penwidth = late_double(n, N_penwidth, 1.0, 0.0);
        gvrender_set_penwidth(job, penwidth);
    }

    return istyle;
}

static void Mcircle_hack(GVJ_t * job, node_t * n)
{
    double x, y;
    pointf AF[2], p;

    y = .7500;
    x = .6614;			/* x^2 + y^2 = 1.0 */<commit_msg>fix fractional penwidths<commit_after>/* $id: shapes.c,v 1.82 2007/12/24 04:50:36 ellson Exp $ $Revision$ */
/* vim:set shiftwidth=4 ts=8: */

/**********************************************************
*      This software is part of the graphviz package      *
*                http://www.graphviz.org/                 *
*                                                         *
*            Copyright (c) 1994-2004 AT&T Corp.           *
*                and is licensed under the                *
*            Common Public License, Version 1.0           *
*                      by AT&T Corp.                      *
*                                                         *
*        Information and Software Systems Research        *
*              AT&T Research, Florham Park NJ             *
**********************************************************/

#include "render.h"
#include "htmltable.h"
#include <limits.h>

#define RBCONST 12
#define RBCURVE .5

static port Center = { {0, 0}, -1, 0, 0, 0, 1, 0, 0, 0 };

#define ATTR_SET(a,n) ((a) && (*(agxget(n,a->index)) != '\0'))
  /* Default point size = 0.05 inches or 3.6 points */
#define DEF_POINT 0.05
  /* Minimum point size = 0.0003 inches or 0.02 points
   * This will make the radius 0.01 points, which is the smallest
   * non-zero number output by gvprintdouble in gvdevice.c
   */
#define MIN_POINT 0.0003
  /* extra null character needed to avoid style emitter from thinking
   * there are arguments.
   */
static char *point_style[3] = { "invis\0", "filled\0", 0 };

/* forward declarations of functions used in shapes tables */

static void poly_init(node_t * n);
static void poly_free(node_t * n);
static port poly_port(node_t * n, char *portname, char *);
static boolean poly_inside(inside_t * inside_context, pointf p);
static int poly_path(node_t* n, port* p, int side, boxf rv[], int *kptr);
static void poly_gencode(GVJ_t * job, node_t * n);

static void record_init(node_t * n);
static void record_free(node_t * n);
static port record_port(node_t * n, char *portname, char *);
static boolean record_inside(inside_t * inside_context, pointf p);
static int record_path(node_t* n, port* p, int side, boxf rv[], int *kptr);
static void record_gencode(GVJ_t * job, node_t * n);

static void point_init(node_t * n);
static void point_gencode(GVJ_t * job, node_t * n);
static boolean point_inside(inside_t * inside_context, pointf p);

static boolean epsf_inside(inside_t * inside_context, pointf p);
static void epsf_gencode(GVJ_t * job, node_t * n);

/* polygon descriptions.  "polygon" with 0 sides takes all user control */

/*			       regul perip sides orien disto skew */
static polygon_t p_polygon = { FALSE, 1, 0, 0., 0., 0. };

/* builtin polygon descriptions */
static polygon_t p_ellipse = { FALSE, 1, 1, 0., 0., 0. };
static polygon_t p_circle = { TRUE, 1, 1, 0., 0., 0. };
static polygon_t p_egg = { FALSE, 1, 1, 0., -.3, 0. };
static polygon_t p_triangle = { FALSE, 1, 3, 0., 0., 0. };
static polygon_t p_box = { FALSE, 1, 4, 0., 0., 0. };
static polygon_t p_plaintext = { FALSE, 0, 4, 0., 0., 0. };
static polygon_t p_diamond = { FALSE, 1, 4, 45., 0., 0. };
static polygon_t p_trapezium = { FALSE, 1, 4, 0., -.4, 0. };
static polygon_t p_parallelogram = { FALSE, 1, 4, 0., 0., .6 };
static polygon_t p_house = { FALSE, 1, 5, 0., -.64, 0. };
static polygon_t p_pentagon = { FALSE, 1, 5, 0., 0., 0. };
static polygon_t p_hexagon = { FALSE, 1, 6, 0., 0., 0. };
static polygon_t p_septagon = { FALSE, 1, 7, 0., 0., 0. };
static polygon_t p_octagon = { FALSE, 1, 8, 0., 0., 0. };
static polygon_t p_note = { FALSE, 1, 4, 0., 0., 0., DOGEAR };
static polygon_t p_tab = { FALSE, 1, 4, 0., 0., 0., TAB };
static polygon_t p_folder = { FALSE, 1, 4, 0., 0., 0., FOLDER };
static polygon_t p_box3d = { FALSE, 1, 4, 0., 0., 0., BOX3D };
static polygon_t p_component = { FALSE, 1, 4, 0., 0., 0., COMPONENT };

/* redundant and undocumented builtin polygons */
static polygon_t p_doublecircle = { TRUE, 2, 1, 0., 0., 0. };
static polygon_t p_invtriangle = { FALSE, 1, 3, 180., 0., 0. };
static polygon_t p_invtrapezium = { FALSE, 1, 4, 180., -.4, 0. };
static polygon_t p_invhouse = { FALSE, 1, 5, 180., -.64, 0. };
static polygon_t p_doubleoctagon = { FALSE, 2, 8, 0., 0., 0. };
static polygon_t p_tripleoctagon = { FALSE, 3, 8, 0., 0., 0. };
static polygon_t p_Mdiamond =
    { FALSE, 1, 4, 45., 0., 0., DIAGONALS | AUXLABELS };
static polygon_t p_Msquare = { TRUE, 1, 4, 0., 0., 0., DIAGONALS };
static polygon_t p_Mcircle =
    { TRUE, 1, 1, 0., 0., 0., DIAGONALS | AUXLABELS };

#define IS_BOX(n) (ND_shape(n)->polygon == &p_box)

/* True if style requires processing through node_round_corners. */
#define SPECIAL_CORNERS(style) \
	((style) & (ROUNDED | DIAGONALS | DOGEAR | TAB | FOLDER | BOX3D | COMPONENT))

/*
 * every shape has these functions:
 *
 * void		SHAPE_init(node_t *n)
 *			initialize the shape (usually at least its size).
 * void		SHAPE_free(node_t *n)
 *			free all memory used by the shape
 * port		SHAPE_port(node_t *n, char *portname)
 *			return the aiming point and slope (if constrained)
 *			of a port.
 * int		SHAPE_inside(inside_t *inside_context, pointf p, edge_t *e);
 *			test if point is inside the node shape which is
 *			assumed convex.
 *			the point is relative to the node center.  the edge
 *			is passed in case the port affects spline clipping.
 * int		SHAPE_path(node *n, edge_t *e, int pt, boxf path[], int *nbox)
 *			create a path for the port of e that touches n,
 *			return side
 * void		SHAPE_gencode(GVJ_t *job, node_t *n)
 *			generate graphics code for a node.
 *
 * some shapes, polygons in particular, use additional shape control data *
 *
 */

static shape_functions poly_fns = {
    poly_init,
    poly_free,
    poly_port,
    poly_inside,
    poly_path,
    poly_gencode
};
static shape_functions point_fns = {
    point_init,
    poly_free,
    poly_port,
    point_inside,
    NULL,
    point_gencode
};
static shape_functions record_fns = {
    record_init,
    record_free,
    record_port,
    record_inside,
    record_path,
    record_gencode
};
static shape_functions epsf_fns = {
    epsf_init,
    epsf_free,
    poly_port,
    epsf_inside,
    NULL,
    epsf_gencode
};

static shape_desc Shapes[] = {	/* first entry is default for no such shape */
    {"box", &poly_fns, &p_box},
    {"polygon", &poly_fns, &p_polygon},
    {"ellipse", &poly_fns, &p_ellipse},
    {"oval", &poly_fns, &p_ellipse},
    {"circle", &poly_fns, &p_circle},
    {"point", &point_fns, &p_circle},
    {"egg", &poly_fns, &p_egg},
    {"triangle", &poly_fns, &p_triangle},
    {"none", &poly_fns, &p_plaintext},
    {"plaintext", &poly_fns, &p_plaintext},
    {"diamond", &poly_fns, &p_diamond},
    {"trapezium", &poly_fns, &p_trapezium},
    {"parallelogram", &poly_fns, &p_parallelogram},
    {"house", &poly_fns, &p_house},
    {"pentagon", &poly_fns, &p_pentagon},
    {"hexagon", &poly_fns, &p_hexagon},
    {"septagon", &poly_fns, &p_septagon},
    {"octagon", &poly_fns, &p_octagon},
    {"note", &poly_fns, &p_note},
    {"tab", &poly_fns, &p_tab},
    {"folder", &poly_fns, &p_folder},
    {"box3d", &poly_fns, &p_box3d},
    {"component", &poly_fns, &p_component},
    {"rect", &poly_fns, &p_box},
    {"rectangle", &poly_fns, &p_box},
    {"doublecircle", &poly_fns, &p_doublecircle},
    {"doubleoctagon", &poly_fns, &p_doubleoctagon},
    {"tripleoctagon", &poly_fns, &p_tripleoctagon},
    {"invtriangle", &poly_fns, &p_invtriangle},
    {"invtrapezium", &poly_fns, &p_invtrapezium},
    {"invhouse", &poly_fns, &p_invhouse},
    {"Mdiamond", &poly_fns, &p_Mdiamond},
    {"Msquare", &poly_fns, &p_Msquare},
    {"Mcircle", &poly_fns, &p_Mcircle},
/*  *** shapes other than polygons  *** */
    {"record", &record_fns, NULL},
    {"Mrecord", &record_fns, NULL},
    {"epsf", &epsf_fns, NULL},
    {NULL, NULL, NULL}
};

static void unrecognized(node_t * n, char *p)
{
    agerr(AGWARN, "node %s, port %s unrecognized\n", agnameof(n), p);
}

static double quant(double val, double q)
{
    int i;
    i = val / q;
    if (i * q + .00001 < val)
	i++;
    return i * q;
}

static int same_side(pointf p0, pointf p1, pointf L0, pointf L1)
{
    int s0, s1;
    double a, b, c;

    /* a x + b y = c */
    a = -(L1.y - L0.y);
    b = (L1.x - L0.x);
    c = a * L0.x + b * L0.y;

    s0 = (a * p0.x + b * p0.y - c >= 0);
    s1 = (a * p1.x + b * p1.y - c >= 0);
    return (s0 == s1);
}

static
void pencolor(GVJ_t * job, node_t * n)
{
    char *color;

    color = late_nnstring(n, N_color, "");
    if (color[0])
	gvrender_set_pencolor(job, color);
    else
	gvrender_set_pencolor(job, DEFAULT_COLOR);
}

static
char* findPen(node_t * n)
{
    char *color;

    color = late_nnstring(n, N_color, "");
    if (color[0])
	return color;
    else
	return DEFAULT_COLOR;
}

static
char *findFillDflt(node_t * n, char* dflt)
{
    char *color;

    color = late_nnstring(n, N_fillcolor, "");
    if (!color[0]) {
	/* for backward compatibilty, default fill is same as pen */
	color = late_nnstring(n, N_color, "");
	if (!color[0]) {
	    color = dflt;
	}
    }
    return color;
}

static
char *findFill (node_t * n)
{
    return (findFillDflt (n, DEFAULT_FILL));
}

static char **checkStyle(node_t * n, int *flagp)
{
    char *style;
    char **pstyle = 0;
    int istyle = 0;
    polygon_t *poly;

    style = late_nnstring(n, N_style, "");
    if (style[0]) {
	char **pp;
	char **qp;
	char *p;
	pp = pstyle = parse_style(style);
	while ((p = *pp)) {
	    if (streq(p, "filled")) {
		istyle |= FILLED;
		pp++;
	    } else if (streq(p, "rounded")) {
		istyle |= ROUNDED;
		qp = pp; /* remove rounded from list passed to renderer */
		do {
		    qp++;
		    *(qp-1) = *qp;
		} while (*qp);
	    } else if (streq(p, "diagonals")) {
		istyle |= DIAGONALS;
		qp = pp; /* remove diagonals from list passed to renderer */
		do {
		    qp++;
		    *(qp-1) = *qp;
		} while (*qp);
	    } else if (streq(p, "invis")) {
		istyle |= INVISIBLE;
		pp++;
	    }
	    else pp++;
	}
    }
    if ((poly = ND_shape(n)->polygon))
	istyle |= poly->option;

    *flagp = istyle;
    return pstyle;
}

static int stylenode(GVJ_t * job, node_t * n)
{
    char **pstyle, *s;
    int istyle;
    double penwidth;

    if ((pstyle = checkStyle(n, &istyle)))
	gvrender_set_style(job, pstyle);

#ifndef WITH_CGRAPH
    if (N_penwidth && ((s=agxget(n, N_penwidth->index)) && s[0])) {
#else
    if (N_penwidth && ((s=agxget(n, N_penwidth)) && s[0])) {
#endif
        penwidth = late_double(n, N_penwidth, 1.0, 0.0);
        gvrender_set_penwidth(job, penwidth);
    }

    return istyle;
}

static void Mcircle_hack(GVJ_t * job, node_t * n)
{
    double x, y;
    pointf AF[2], p;

    y = .7500;
    x = .6614;			/* x^2 + y^2 = 1.0 */
{'fraction_non_alphanumeric': 0.1653462578059465, 'fraction_numerical': 0.02674993009600149, 'mean_word_length': 2.925905598243688, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1505300', 'n_tokens_mistral': 8959, 'n_tokens_neox': 8167, 'n_words': 2353}