1266 lines
36 KiB
C
1266 lines
36 KiB
C
/* -----------------------------------------------------------------------------
|
|
* The Cyberiada GraphML library implemention
|
|
*
|
|
* The geometry utilities
|
|
*
|
|
* Copyright (C) 2024 Alexey Fedoseev <aleksey@fedoseev.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see https://www.gnu.org/licenses/
|
|
*
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "geometry.h"
|
|
#include "cyb_error.h"
|
|
|
|
#define DEFAULT_NODE_SIZE 100
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Basic geometry functions
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
CyberiadaPoint* cyberiada_new_point(void)
|
|
{
|
|
CyberiadaPoint* p = (CyberiadaPoint*)malloc(sizeof(CyberiadaPoint));
|
|
memset(p, 0, sizeof(CyberiadaPoint));
|
|
return p;
|
|
}
|
|
|
|
CyberiadaPoint* cyberiada_copy_point(CyberiadaPoint* src)
|
|
{
|
|
CyberiadaPoint* dst;
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
dst = cyberiada_new_point();
|
|
dst->x = src->x;
|
|
dst->y = src->y;
|
|
return dst;
|
|
}
|
|
|
|
static void cyberiada_update_point(CyberiadaPoint* p, double dx, double dy)
|
|
{
|
|
if (!p) return ;
|
|
p->x += dx;
|
|
p->y += dy;
|
|
}
|
|
|
|
static double round_number(double num)
|
|
{
|
|
double value = (int)(num * 1000.0 + .5);
|
|
return (double)value / 1000.0;
|
|
}
|
|
|
|
static void cyberiada_round_point(CyberiadaPoint* p)
|
|
{
|
|
if (!p) return ;
|
|
p->x = round_number(p->x);
|
|
p->y = round_number(p->y);
|
|
}
|
|
|
|
CyberiadaRect* cyberiada_new_rect(void)
|
|
{
|
|
CyberiadaRect* r = (CyberiadaRect*)malloc(sizeof(CyberiadaRect));
|
|
memset(r, 0, sizeof(CyberiadaRect));
|
|
return r;
|
|
}
|
|
|
|
CyberiadaRect* cyberiada_copy_rect(CyberiadaRect* src)
|
|
{
|
|
CyberiadaRect* dst;
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
dst = cyberiada_new_rect();
|
|
dst->x = src->x;
|
|
dst->y = src->y;
|
|
dst->width = src->width;
|
|
dst->height = src->height;
|
|
return dst;
|
|
}
|
|
|
|
static void cyberiada_update_rect(CyberiadaRect* r, double dx, double dy)
|
|
{
|
|
if (!r) return ;
|
|
r->x += dx;
|
|
r->y += dy;
|
|
}
|
|
|
|
static void cyberiada_round_rect(CyberiadaRect* r)
|
|
{
|
|
if (!r) return ;
|
|
r->x = round_number(r->x);
|
|
r->y = round_number(r->y);
|
|
r->width = round_number(r->width);
|
|
r->height = round_number(r->height);
|
|
}
|
|
|
|
CyberiadaPolyline* cyberiada_new_polyline(void)
|
|
{
|
|
CyberiadaPolyline* pl = (CyberiadaPolyline*)malloc(sizeof(CyberiadaPolyline));
|
|
memset(pl, 0, sizeof(CyberiadaPolyline));
|
|
return pl;
|
|
}
|
|
|
|
CyberiadaPolyline* cyberiada_copy_polyline(CyberiadaPolyline* src)
|
|
{
|
|
CyberiadaPolyline *dst = NULL, *prev, *pl;
|
|
if (!src) {
|
|
return NULL;
|
|
}
|
|
do {
|
|
pl = cyberiada_new_polyline();
|
|
pl->point.x = src->point.x;
|
|
pl->point.y = src->point.y;
|
|
if (dst) {
|
|
prev->next = pl;
|
|
} else {
|
|
dst = pl;
|
|
}
|
|
prev = pl;
|
|
src = src->next;
|
|
} while (src);
|
|
return dst;
|
|
}
|
|
|
|
int cyberiada_destroy_polyline(CyberiadaPolyline* polyline)
|
|
{
|
|
CyberiadaPolyline* pl;
|
|
do {
|
|
pl = polyline;
|
|
polyline = polyline->next;
|
|
free(pl);
|
|
} while (polyline);
|
|
}
|
|
|
|
static void cyberiada_update_polyline(CyberiadaPolyline* pl, double dx, double dy)
|
|
{
|
|
if (!pl) return ;
|
|
do {
|
|
cyberiada_update_point(&(pl->point), dx, dy);
|
|
pl = pl->next;
|
|
} while (pl);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Geometry transformations
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int cyberiada_extend_rect_p(CyberiadaRect* rect,
|
|
double x, double y,
|
|
CyberiadaGeometryCoordFormat format)
|
|
{
|
|
double delta;
|
|
if (!rect) {
|
|
ERROR("Cannot extend rect with point\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
if (format == cybCoordAbsolute || format == cybCoordLeftTop) {
|
|
if (x < rect->x) {
|
|
delta = rect->x - x;
|
|
rect->width += delta;
|
|
rect->x -= delta;
|
|
}
|
|
if (x > rect->x + rect->width) {
|
|
delta = x - rect->x - rect->width;
|
|
rect->width += delta;
|
|
rect->x += delta;
|
|
}
|
|
if (y < rect->y) {
|
|
delta = rect->y - y;
|
|
rect->height += delta;
|
|
rect->y -= delta;
|
|
}
|
|
if (y > rect->y + rect->height) {
|
|
delta = y - rect->y - rect->height;
|
|
rect->height += delta;
|
|
rect->y += delta;
|
|
}
|
|
} else if (format == cybCoordLocalCenter) {
|
|
double r_w = rect->width / 2.0;
|
|
double r_h = rect->height / 2.0;
|
|
if (x < rect->x - r_w) {
|
|
delta = rect->x - r_w - x;
|
|
rect->width += delta;
|
|
rect->x -= delta / 2.0;
|
|
}
|
|
if (x > rect->x + r_w) {
|
|
delta = x - rect->x - r_w;
|
|
rect->width += delta;
|
|
rect->x += delta / 2.0;
|
|
}
|
|
if (y < rect->y - r_h) {
|
|
delta = rect->y - r_h - y;
|
|
rect->height += delta;
|
|
rect->y -= delta / 2.0;
|
|
}
|
|
if (y > rect->y + r_h) {
|
|
delta = y - rect->y - r_h;
|
|
rect->height += delta;
|
|
rect->y += delta / 2.0;
|
|
}
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_extend_rect_r(CyberiadaRect* result,
|
|
CyberiadaRect* rect,
|
|
CyberiadaGeometryCoordFormat format)
|
|
{
|
|
if (!result || !rect) {
|
|
ERROR("Cannot extend rect with rect\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
if (format == cybCoordLocalCenter) {
|
|
cyberiada_extend_rect_p(result,
|
|
rect->x - rect->width / 2.0,
|
|
rect->y - rect->height / 2.0,
|
|
format);
|
|
cyberiada_extend_rect_p(result,
|
|
rect->x + rect->width / 2.0,
|
|
rect->y + rect->height / 2.0,
|
|
format);
|
|
} else {
|
|
cyberiada_extend_rect_p(result,
|
|
rect->x,
|
|
rect->y,
|
|
format);
|
|
cyberiada_extend_rect_p(result,
|
|
rect->x + rect->width,
|
|
rect->y + rect->height,
|
|
format);
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_convert_geometry(CyberiadaRect* rect,
|
|
CyberiadaGeometryCoordFormat from_format,
|
|
CyberiadaGeometryCoordFormat to_format,
|
|
double* delta_x, double* delta_y)
|
|
{
|
|
if (!rect || !delta_x || !delta_y) {
|
|
ERROR("Cannot convert geometry\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
if (from_format == to_format) {
|
|
*delta_x = *delta_y = 0.0;
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
if (from_format == cybCoordAbsolute && to_format == cybCoordLeftTop) {
|
|
/* (x, y, w, h) -> (x - px, y - py, w, h) */
|
|
*delta_x = -rect->x;
|
|
*delta_y = -rect->y;
|
|
} else if (from_format == cybCoordAbsolute && to_format == cybCoordLocalCenter) {
|
|
/* (x, y, w, h) -> (x - px - pw/2, y - py - ph/2, w, h) */
|
|
*delta_x = rect->x - rect->x - rect->width / 2.0;
|
|
*delta_y = rect->y - rect->y - rect->height / 2.0;
|
|
} else if (from_format == cybCoordLeftTop && to_format == cybCoordLocalCenter) {
|
|
/* (x, y, w, h) -> (x - pw/2, y - ph/2, w, h) */
|
|
*delta_x = rect->x - rect->width / 2.0;
|
|
*delta_y = rect->y - rect->height / 2.0;
|
|
} else if (from_format == cybCoordLeftTop && to_format == cybCoordAbsolute) {
|
|
/* (x, y, w, h) -> (x + px, y + py, w, h) */
|
|
*delta_x = rect->x;
|
|
*delta_y = rect->y;
|
|
} else if (from_format == cybCoordLocalCenter && to_format == cybCoordAbsolute) {
|
|
/* (x, y, w, h) -> (x + px + pw/2, y + py + ph/2, w, h) */
|
|
*delta_x = rect->x + rect->x + rect->width / 2.0;
|
|
*delta_y = rect->y + rect->y + rect->height / 2.0;
|
|
} else if (from_format == cybCoordLocalCenter && to_format == cybCoordLeftTop) {
|
|
/* (x, y, w, h) -> (x + pw/2, y + ph/2, w, h) */
|
|
*delta_x = rect->x + rect->width / 2.0;
|
|
*delta_y = rect->y + rect->height / 2.0;
|
|
} else {
|
|
ERROR("bad node coordinates conversion from %d to %d\n", from_format, to_format);
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_convert_coordinates(CyberiadaNode* parent,
|
|
double x, double y,
|
|
double* to_x, double* to_y,
|
|
CyberiadaGeometryCoordFormat from_format,
|
|
CyberiadaGeometryCoordFormat to_format)
|
|
{
|
|
if (!to_x || !to_y) {
|
|
ERROR("Cannot convert coordinates\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
if (!parent || !parent->geometry_rect || from_format == to_format) {
|
|
*to_x = x;
|
|
*to_y = y;
|
|
} else {
|
|
CyberiadaRect* rect = parent->geometry_rect;
|
|
double delta_x, delta_y;
|
|
cyberiada_convert_geometry(rect, from_format, to_format, &delta_x, &delta_y);
|
|
cyberiada_convert_coordinates(parent->parent,
|
|
x + delta_x, y + delta_y,
|
|
to_x, to_y,
|
|
from_format,
|
|
to_format);
|
|
}
|
|
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_build_bounding_rect(CyberiadaNode* node,
|
|
CyberiadaRect* result,
|
|
CyberiadaGeometryCoordFormat format)
|
|
{
|
|
if (!node || !result) {
|
|
ERROR("Cannot build bounding rect\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
while (node) {
|
|
if (node->geometry_point) {
|
|
cyberiada_extend_rect_p(result,
|
|
node->geometry_point->x,
|
|
node->geometry_point->y,
|
|
format);
|
|
}
|
|
if (node->geometry_rect) {
|
|
cyberiada_extend_rect_r(result,
|
|
node->geometry_rect,
|
|
format);
|
|
}
|
|
if (node->children) {
|
|
int res = cyberiada_build_bounding_rect(node->children, result, format);
|
|
if (res != CYBERIADA_NO_ERROR) {
|
|
return res;
|
|
}
|
|
}
|
|
node = node->next;
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_convert_node_geometry(CyberiadaNode* node,
|
|
CyberiadaRect* parent_rect,
|
|
CyberiadaGeometryCoordFormat from_format,
|
|
CyberiadaGeometryCoordFormat to_format)
|
|
{
|
|
double delta_x, delta_y;
|
|
|
|
if (!node || !parent_rect) {
|
|
ERROR("Cannot convert node geometry\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
if (from_format == to_format) {
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
cyberiada_convert_geometry(parent_rect, from_format, to_format, &delta_x, &delta_y);
|
|
|
|
while (node) {
|
|
if (node->geometry_point) {
|
|
cyberiada_update_point(node->geometry_point, delta_x, delta_y);
|
|
}
|
|
if (node->geometry_rect) {
|
|
cyberiada_update_rect(node->geometry_rect, delta_x, delta_y);
|
|
}
|
|
if (node->children) {
|
|
int res = cyberiada_convert_node_geometry(node->children,
|
|
node->geometry_rect ? node->geometry_rect: parent_rect,
|
|
from_format,
|
|
to_format);
|
|
if (res != CYBERIADA_NO_ERROR) {
|
|
return res;
|
|
}
|
|
}
|
|
node = node->next;
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_is_point_node(CyberiadaNode* node)
|
|
{
|
|
if (!node) return 0;
|
|
return node->type & (cybNodeInitial | cybNodeFinal | cybNodeTerminate |
|
|
cybNodeEntryPoint | cybNodeExitPoint |
|
|
cybNodeShallowHistory | cybNodeDeepHistory |
|
|
cybNodeFork | cybNodeJoin);
|
|
}
|
|
|
|
static int cyberiada_is_rect_node(CyberiadaNode* node)
|
|
{
|
|
if (!node) return 0;
|
|
return !cyberiada_is_point_node(node);
|
|
}
|
|
|
|
static int cyberiada_rect_contains_point(CyberiadaRect* rect,
|
|
CyberiadaPoint* point,
|
|
CyberiadaGeometryCoordFormat format)
|
|
{
|
|
if (!rect || !point) return 0;
|
|
if (format == cybCoordAbsolute || format == cybCoordLeftTop) {
|
|
return (point->x >= rect->x &&
|
|
point->y >= rect->y &&
|
|
point->x <= rect->x + rect->width &&
|
|
point->y <= rect->y + rect->height);
|
|
} else if (format == cybCoordLocalCenter) {
|
|
return (point->x >= -rect->width / 2.0 + rect->x &&
|
|
point->y >= -rect->height / 2.0 + rect->y &&
|
|
point->x <= rect->width / 2.0 + rect->x &&
|
|
point->y <= rect->height / 2.0 + rect->y);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cyberiada_rect_contains_rect(CyberiadaRect* rect,
|
|
CyberiadaRect* r,
|
|
CyberiadaGeometryCoordFormat format)
|
|
{
|
|
if (!rect || !r) return 0;
|
|
if (format == cybCoordAbsolute || format == cybCoordLeftTop) {
|
|
return (r->x >= rect->x &&
|
|
r->y >= rect->y &&
|
|
r->x + r->width <= rect->x + rect->width &&
|
|
r->y + r->height <= rect->y + rect->height);
|
|
} else if (format == cybCoordLocalCenter) {
|
|
return (rect->x - r->width / 2.0 >= rect->x - rect->width / 2.0 &&
|
|
rect->y - r->height / 2.0 >= rect->y - rect->height / 2.0 &&
|
|
rect->x + r->width / 2.0 <= rect->x + rect->width / 2.0 &&
|
|
rect->y + r->height / 2.0 <= rect->y + rect->height / 2.0);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int cyberiada_node_contains_point(CyberiadaNode* node,
|
|
CyberiadaPoint* point,
|
|
CyberiadaGeometryCoordFormat format)
|
|
{
|
|
int res;
|
|
CyberiadaRect* bound;
|
|
if (!node || !point) return 0;
|
|
if (!node->geometry_rect) return 0;
|
|
|
|
bound = cyberiada_copy_rect(node->geometry_rect);
|
|
cyberiada_build_bounding_rect(node, bound, format);
|
|
|
|
res = cyberiada_rect_contains_point(bound, point, format);
|
|
free(bound);
|
|
return res;
|
|
}
|
|
|
|
static int cyberiada_reconstruct_nodes(CyberiadaNode* node,
|
|
CyberiadaRect* rect,
|
|
CyberiadaGeometryCoordFormat format)
|
|
{
|
|
/* TODO reconstruction algorithm:
|
|
|
|
- init the reconstruct queue
|
|
- examine the children nodes
|
|
- child is the parent itself and has geometry - recurcively continue the algorithm
|
|
- child is the parent but has no geometry
|
|
- build the bounding rect as possible limitation
|
|
- save the node in the reconstruct queue
|
|
- child is atomar but has no geometry - save the node in the reconstruct list
|
|
- recunstruct geometry for nodes from the list inside the box [if parent has geometry]
|
|
- go through the reconstructed children
|
|
- if parent has no geometry, reconstruct the geometry
|
|
|
|
Right now:
|
|
|
|
- determine the parent borders
|
|
- put nodes w/o geometry somewhere in the parent
|
|
*/
|
|
|
|
CyberiadaNode* start_node = node;
|
|
if (!node && !rect) {
|
|
ERROR("Cannot reconstruct node geometry\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
while (node) {
|
|
if (cyberiada_is_point_node(node) && !node->geometry_point) {
|
|
CyberiadaPoint* new_point = cyberiada_new_point();
|
|
CyberiadaNode* n;
|
|
int intersects;
|
|
do {
|
|
if (format == cybCoordAbsolute) {
|
|
new_point->x = rect->x + rect->width * rand();
|
|
new_point->y = rect->y + rect->height * rand();
|
|
} else if (format == cybCoordLeftTop) {
|
|
new_point->x = rect->width * rand();
|
|
new_point->y = rect->height * rand();
|
|
} else if (format == cybCoordLocalCenter) {
|
|
new_point->x = rect->width * (-0.5 + rand());
|
|
new_point->y = rect->height * (-0.5 + rand());
|
|
} else {
|
|
free(new_point);
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
intersects = 0;
|
|
for (n = start_node; n->next; n = n->next) {
|
|
if (n == node) continue;
|
|
if (n->geometry_rect && cyberiada_rect_contains_point(n->geometry_rect, new_point, format)) {
|
|
intersects = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while (intersects);
|
|
|
|
node->geometry_point = new_point;
|
|
}
|
|
|
|
if (cyberiada_is_rect_node(node) && !node->geometry_rect) {
|
|
CyberiadaRect* new_rect = cyberiada_new_rect();
|
|
CyberiadaNode* n;
|
|
int intersects;
|
|
double node_width = DEFAULT_NODE_SIZE, node_height = DEFAULT_NODE_SIZE;
|
|
if (node_width < rect->width) {
|
|
node_width = rect->width / 2.0;
|
|
}
|
|
if (node_height < rect->height) {
|
|
node_height = rect->height / 2.0;
|
|
}
|
|
do {
|
|
new_rect->width = node_width;
|
|
new_rect->height = node_height;
|
|
if (format == cybCoordAbsolute) {
|
|
new_rect->x = rect->x + (rect->width - node_width) * rand();
|
|
new_rect->y = rect->y + (rect->height - node_height) * rand();
|
|
} else if (format == cybCoordLeftTop) {
|
|
new_rect->x = (rect->width - node_width) * rand();
|
|
new_rect->y = (rect->height - node_height) * rand();
|
|
} else if (format == cybCoordLocalCenter) {
|
|
new_rect->x = (rect->width - node_width) * (-0.5 + rand());
|
|
new_rect->y = (rect->height - node_height) * (-0.5 + rand());
|
|
} else {
|
|
free(new_rect);
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
intersects = 0;
|
|
for (n = start_node; n->next; n = n->next) {
|
|
if (n == node) continue;
|
|
if (n->geometry_rect
|
|
&& cyberiada_rect_contains_rect(n->geometry_rect, new_rect, format)) {
|
|
intersects = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while (intersects);
|
|
|
|
node->geometry_rect = new_rect;
|
|
}
|
|
|
|
if (node->children) {
|
|
cyberiada_build_bounding_rect(node->children, node->geometry_rect, format);
|
|
int res = cyberiada_reconstruct_nodes(node->children, node->geometry_rect, format);
|
|
if (res != CYBERIADA_NO_ERROR) {
|
|
return res;
|
|
}
|
|
}
|
|
node = node->next;
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_reconstruct_edge(CyberiadaPoint** source_point,
|
|
CyberiadaNode* source,
|
|
CyberiadaPoint** target_point,
|
|
CyberiadaNode* target,
|
|
CyberiadaGeometryCoordFormat format,
|
|
CyberiadaGeometryEdgeFormat edge_format)
|
|
{
|
|
CyberiadaPoint* point;
|
|
|
|
if (!source_point || !source || !target_point || !target) {
|
|
ERROR("Cannot reconstruct edge\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
if (edge_format == cybEdgeLocalCenter) {
|
|
|
|
if (!*source_point) {
|
|
*source_point = cyberiada_new_point();
|
|
}
|
|
|
|
if (!*target_point) {
|
|
*target_point = cyberiada_new_point();
|
|
}
|
|
|
|
return CYBERIADA_NO_ERROR;
|
|
|
|
}
|
|
|
|
return CYBERIADA_NO_ERROR;
|
|
/*
|
|
|
|
if (source->geometry_point && !*source_point) {
|
|
*source_point = cyberiada_new_point();
|
|
}
|
|
if (target->geometry_point && !*target_point) {
|
|
*target_point = cyberiada_new_point();
|
|
}
|
|
|
|
}
|
|
|
|
if (*source_point && *target_point) {
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
if (!*source_point) {
|
|
CyberiadaPoint* to_point;
|
|
if (*target_point) {
|
|
to_point = *target_point;
|
|
} else if (target->geometry_point) {
|
|
to_point = target->geometry_point;
|
|
} else {
|
|
}
|
|
cyberiada_edge_build_border_point(source_point,
|
|
source->geometry_rect,
|
|
to_point,
|
|
edge_format);
|
|
if (source->geometry_rect) {
|
|
}
|
|
|
|
|
|
if (edge_format == cybEdgeLeftTopBorder) {
|
|
source->geometry_rect->width / 2.0;
|
|
|
|
|
|
} else if (edge_format == cybEdgeCenterBorder) {
|
|
|
|
} else {
|
|
ERROR("Wrong edge format %d\n", edge_format);
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
return CYBERIADA_NO_ERROR;*/
|
|
}
|
|
|
|
static int cyberiada_reconstruct_edges(CyberiadaEdge* edge,
|
|
CyberiadaGeometryCoordFormat format,
|
|
CyberiadaGeometryEdgeFormat edge_format)
|
|
{
|
|
while (edge) {
|
|
if (edge->source && (edge->source->geometry_rect || edge->source->geometry_point) &&
|
|
edge->target && (edge->target->geometry_rect || edge->target->geometry_point)) {
|
|
|
|
if (!edge->geometry_source_point || !edge->geometry_target_point) {
|
|
cyberiada_reconstruct_edge(&(edge->geometry_source_point),
|
|
edge->source,
|
|
&(edge->geometry_target_point),
|
|
edge->target,
|
|
format,
|
|
edge_format);
|
|
}
|
|
|
|
}
|
|
edge = edge->next;
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_reconstruct_document_geometry(CyberiadaDocument* doc)
|
|
{
|
|
CyberiadaSM* sm;
|
|
if (!doc || !doc->state_machines) {
|
|
ERROR("Cannot round SM document geometry\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
for (sm = doc->state_machines; sm; sm = sm->next) {
|
|
cyberiada_reconstruct_nodes(sm->nodes, sm->bounding_rect, doc->geometry_format);
|
|
cyberiada_reconstruct_edges(sm->edges, doc->geometry_format, doc->edge_geom_format);
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_clean_nodes_geometry(CyberiadaNode* node)
|
|
{
|
|
while (node) {
|
|
if (node->geometry_point) {
|
|
free(node->geometry_point);
|
|
node->geometry_point = NULL;
|
|
}
|
|
if (node->geometry_rect) {
|
|
free(node->geometry_rect);
|
|
node->geometry_rect = NULL;
|
|
}
|
|
if (node->children) {
|
|
int res = cyberiada_clean_nodes_geometry(node->children);
|
|
if (res != CYBERIADA_NO_ERROR) {
|
|
return res;
|
|
}
|
|
}
|
|
node = node->next;
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_clean_edge_geometry(CyberiadaEdge* edge)
|
|
{
|
|
if (edge->geometry_polyline) {
|
|
cyberiada_destroy_polyline(edge->geometry_polyline);
|
|
edge->geometry_polyline = NULL;
|
|
}
|
|
if (edge->geometry_source_point) {
|
|
free(edge->geometry_source_point);
|
|
edge->geometry_source_point = NULL;
|
|
}
|
|
if (edge->geometry_target_point) {
|
|
free(edge->geometry_target_point);
|
|
edge->geometry_target_point = NULL;
|
|
}
|
|
if (edge->geometry_label_point) {
|
|
free(edge->geometry_label_point);
|
|
edge->geometry_label_point = NULL;
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_clean_edges_geometry(CyberiadaEdge* edge)
|
|
{
|
|
while (edge) {
|
|
cyberiada_clean_edge_geometry(edge);
|
|
edge = edge->next;
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
int cyberiada_clean_document_geometry(CyberiadaDocument* doc)
|
|
{
|
|
CyberiadaSM* sm;
|
|
|
|
if (!doc) {
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
for (sm = doc->state_machines; sm; sm = sm->next) {
|
|
cyberiada_clean_nodes_geometry(sm->nodes);
|
|
cyberiada_clean_edges_geometry(sm->edges);
|
|
if (sm->bounding_rect) {
|
|
free(sm->bounding_rect);
|
|
sm->bounding_rect = NULL;
|
|
}
|
|
}
|
|
|
|
doc->geometry_format = cybCoordNone;
|
|
doc->edge_geom_format = cybEdgeNone;
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_convert_edges_geometry(CyberiadaEdge* edges,
|
|
CyberiadaRect* parent_rect,
|
|
CyberiadaGeometryCoordFormat from_format,
|
|
CyberiadaGeometryCoordFormat to_format)
|
|
{
|
|
/* CyberiadaSM* sm;
|
|
CyberiadaNode* node;
|
|
CyberiadaEdge* edge;
|
|
CyberiadaPolyline* pl;
|
|
double from_x, from_y, to_x, to_y;
|
|
double src_from_x, src_from_y, src_to_x, src_to_y, tgt_from_x, tgt_from_y, tgt_to_x, tgt_to_y;
|
|
|
|
for (edge = edges; edge; edge = edge->next) {
|
|
if (edge->source && (edge->source->geometry_rect || edge->source->geometry_point) &&
|
|
edge->target && (edge->target->geometry_rect || edge->target->geometry_point) &&
|
|
(edge->geometry_source_point ||
|
|
edge->geometry_target_point ||
|
|
edge->geometry_polyline ||
|
|
edge->geometry_label_point)) {
|
|
|
|
from_x = from_y = to_x = to_y = 0.0;
|
|
if (edge->source->geometry_point) {
|
|
from_x += edge->source->geometry_point->x;
|
|
from_y += edge->source->geometry_point->y;
|
|
} else {
|
|
from_x += edge->source->geometry_rect->x + edge->source->geometry_rect->width / 2.0;
|
|
from_y += edge->source->geometry_rect->y + edge->source->geometry_rect->height / 2.0;
|
|
if (edge->geometry_source_point) {
|
|
from_x += edge->geometry_source_point->x;
|
|
from_y += edge->geometry_source_point->y;
|
|
}
|
|
}
|
|
if (edge->target->geometry_point) {
|
|
to_x += edge->target->geometry_point->x;
|
|
to_y += edge->target->geometry_point->y;
|
|
} else {
|
|
to_x += edge->target->geometry_rect->x + edge->target->geometry_rect->width / 2.0;
|
|
to_y += edge->target->geometry_rect->y + edge->target->geometry_rect->height / 2.0;
|
|
if (edge->geometry_target_point) {
|
|
to_x += edge->geometry_target_point->x;
|
|
to_y += edge->geometry_target_point->y;
|
|
}
|
|
}
|
|
|
|
if (edge->geometry_polyline) {
|
|
double first_p_x = edge->geometry_polyline->point.x;
|
|
double first_p_y = edge->geometry_polyline->point.y;
|
|
double last_p_x;
|
|
double last_p_y;
|
|
|
|
pl = edge->geometry_polyline;
|
|
while (pl->next) pl = pl->next;
|
|
last_p_x = pl->point.x;
|
|
last_p_y = pl->point.y;
|
|
|
|
src_from_x = from_x;
|
|
src_from_y = from_y;
|
|
src_to_x = first_p_x;
|
|
src_to_y = first_p_y;
|
|
tgt_from_x = last_p_x;
|
|
tgt_from_y = last_p_y;
|
|
tgt_to_x = to_x;
|
|
tgt_to_y = to_y;
|
|
} else {
|
|
src_from_x = tgt_from_x = from_x;
|
|
src_from_y = tgt_from_y = from_y;
|
|
src_to_x = tgt_to_x = to_x;
|
|
src_to_y = tgt_to_y = to_y;
|
|
}
|
|
|
|
DEBUG("edge (%f; %f) -> (%f; %f) and (%f; %f) -> (%f; %f)\n",
|
|
src_from_x, src_from_y, src_to_x, src_to_y,
|
|
tgt_from_x, tgt_from_y, tgt_to_x, tgt_to_y);
|
|
|
|
if (edge->geometry_source_point) {
|
|
if (edge->source->geometry_point) {
|
|
if (src_from_x == src_to_x) {
|
|
edge->geometry_source_point->x = 0.0;
|
|
if (src_from_y >= src_to_y) {
|
|
edge->geometry_source_point->y = -PSEUDO_NODE_SIZE / 2.0;
|
|
} else {
|
|
edge->geometry_source_point->y = PSEUDO_NODE_SIZE / 2.0;
|
|
}
|
|
} else {
|
|
double alpha = atan((src_from_y - src_to_y) / (src_to_x - src_from_x));
|
|
edge->geometry_source_point->x = cos(alpha) * PSEUDO_NODE_SIZE / 2.0;
|
|
edge->geometry_source_point->y = -sin(alpha) * PSEUDO_NODE_SIZE / 2.0;
|
|
}
|
|
} else {
|
|
if (src_from_x == src_to_x) {
|
|
edge->geometry_source_point->x = edge->source->geometry_rect->width / 2.0;
|
|
if (src_from_y >= src_to_y) {
|
|
edge->geometry_source_point->y = 0.0;
|
|
} else {
|
|
edge->geometry_source_point->y = edge->source->geometry_rect->height;
|
|
}
|
|
} else {
|
|
double alpha = atan((src_from_y - src_to_y) / (src_to_x - src_from_x));
|
|
if (src_to_x < src_from_x) alpha += M_PI;
|
|
double alpha_g = 180.0 * alpha / M_PI;
|
|
DEBUG("src alpha %f\n", alpha_g);
|
|
if (alpha_g < 0.0) alpha_g += 360.0;
|
|
if (alpha_g <= 45.0 || alpha_g > 315.0) {
|
|
edge->geometry_source_point->x = edge->source->geometry_rect->width;
|
|
edge->geometry_source_point->y += (-tan(alpha) * edge->source->geometry_rect->width +
|
|
edge->source->geometry_rect->height) / 2.0;
|
|
} else if (alpha_g > 45.0 && alpha_g <= 135.0) {
|
|
edge->geometry_source_point->x += ((double)tan(alpha) * edge->source->geometry_rect->height +
|
|
edge->source->geometry_rect->width) / 2.0;
|
|
edge->geometry_source_point->y = 0.0;
|
|
} else if (alpha_g > 135.0 && alpha_g <= 225.0) {
|
|
edge->geometry_source_point->x = 0.0;
|
|
edge->geometry_source_point->y += (-(double)tan(alpha) * edge->source->geometry_rect->width +
|
|
edge->source->geometry_rect->height) / 2.0;
|
|
} else {
|
|
edge->geometry_source_point->x += (-(double)tan(alpha) * edge->source->geometry_rect->height +
|
|
edge->source->geometry_rect->width) / 2.0;
|
|
edge->geometry_source_point->y = edge->source->geometry_rect->height;
|
|
}
|
|
|
|
if (edge->geometry_source_point->x < 0) {
|
|
edge->geometry_source_point->x = 0.0;
|
|
}
|
|
if (edge->geometry_source_point->x > edge->source->geometry_rect->width) {
|
|
edge->geometry_source_point->x = edge->source->geometry_rect->width;
|
|
}
|
|
if (edge->geometry_source_point->y < 0) {
|
|
edge->geometry_source_point->y = 0.0;
|
|
}
|
|
if (edge->geometry_source_point->y > edge->source->geometry_rect->height) {
|
|
edge->geometry_source_point->y = edge->source->geometry_rect->height;
|
|
}
|
|
}
|
|
}
|
|
DEBUG("sp: (%f; %f)\n", edge->geometry_source_point->x, edge->geometry_source_point->y);
|
|
}
|
|
|
|
if (edge->geometry_target_point) {
|
|
if (edge->target->geometry_point) {
|
|
if (tgt_from_x == tgt_to_x) {
|
|
edge->geometry_target_point->x = 0.0;
|
|
if (tgt_from_y >= tgt_to_y) {
|
|
edge->geometry_target_point->y = PSEUDO_NODE_SIZE / 2.0;
|
|
} else {
|
|
edge->geometry_target_point->y = -PSEUDO_NODE_SIZE / 2.0;
|
|
}
|
|
} else {
|
|
double alpha = atan((tgt_from_y - tgt_to_y) / (tgt_to_x - tgt_from_x));
|
|
edge->geometry_target_point->x = cos(alpha) * PSEUDO_NODE_SIZE / 2.0;
|
|
edge->geometry_target_point->y = -sin(alpha) * PSEUDO_NODE_SIZE / 2.0;
|
|
}
|
|
} else {
|
|
if (tgt_from_x == tgt_to_x) {
|
|
edge->geometry_target_point->x = edge->target->geometry_rect->width / 2.0;
|
|
if (tgt_from_y >= tgt_to_y) {
|
|
edge->geometry_target_point->y = edge->target->geometry_rect->height;
|
|
} else {
|
|
edge->geometry_target_point->y = 0.0;
|
|
}
|
|
} else {
|
|
double alpha = atan((tgt_from_y - tgt_to_y) / (tgt_to_x - tgt_from_x));
|
|
if (tgt_to_x < tgt_from_x) alpha += M_PI;
|
|
alpha += M_PI; /* target = incoming edge */
|
|
/*double alpha_g = 180.0 * alpha / M_PI;
|
|
DEBUG("tgt alpha %f\n", alpha_g);
|
|
if (alpha_g < 0.0) alpha_g += 360.0;
|
|
if (alpha_g <= 45.0 || alpha_g > 315.0) {
|
|
edge->geometry_target_point->x = edge->target->geometry_rect->width;
|
|
edge->geometry_target_point->y += (-tan(alpha) * edge->target->geometry_rect->width +
|
|
edge->target->geometry_rect->height) / 2.0;
|
|
} else if (alpha_g > 45.0 && alpha_g <= 135.0) {
|
|
edge->geometry_target_point->x += (tan(alpha) * edge->target->geometry_rect->height +
|
|
edge->target->geometry_rect->width) / 2.0;
|
|
edge->geometry_target_point->y = 0.0;
|
|
} else if (alpha_g > 135.0 && alpha_g <= 225.0) {
|
|
edge->geometry_target_point->x = 0.0;
|
|
edge->geometry_target_point->y += (-tan(alpha) * edge->target->geometry_rect->width +
|
|
edge->target->geometry_rect->height) / 2.0;
|
|
} else {
|
|
edge->geometry_target_point->x += (-tan(alpha) * edge->target->geometry_rect->height +
|
|
edge->target->geometry_rect->width) / 2.0;
|
|
edge->geometry_target_point->y = edge->target->geometry_rect->height;
|
|
}
|
|
}
|
|
|
|
if (edge->geometry_target_point->x < 0) {
|
|
edge->geometry_target_point->x = 0.0;
|
|
}
|
|
if (edge->geometry_target_point->x > edge->target->geometry_rect->width) {
|
|
edge->geometry_target_point->x = edge->target->geometry_rect->width;
|
|
}
|
|
if (edge->geometry_target_point->y < 0) {
|
|
edge->geometry_target_point->y = 0.0;
|
|
}
|
|
if (edge->geometry_target_point->y > edge->target->geometry_rect->height) {
|
|
edge->geometry_target_point->y = edge->target->geometry_rect->height;
|
|
}
|
|
}
|
|
DEBUG("tp: (%f; %f)\n", edge->geometry_target_point->x, edge->geometry_target_point->y);
|
|
}
|
|
}
|
|
}*/
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_convert_edge_geometry(CyberiadaEdge* edge,
|
|
CyberiadaGeometryCoordFormat from_format,
|
|
CyberiadaGeometryCoordFormat to_format,
|
|
CyberiadaGeometryEdgeFormat from_edge_format,
|
|
CyberiadaGeometryEdgeFormat to_edge_format)
|
|
{
|
|
while (edge) {
|
|
if (edge->source && (edge->source->geometry_rect || edge->source->geometry_point) &&
|
|
edge->target && (edge->target->geometry_rect || edge->target->geometry_point)) {
|
|
/*
|
|
if (edge->geometry_source_point) {
|
|
|
|
}
|
|
|
|
if (edge->geometry_target_point) {
|
|
cyberiada_convert_edge_source_target_geometry(edge,
|
|
from_format,
|
|
to_fotmat);
|
|
}
|
|
|
|
if (edge->geometry_polyline) {
|
|
}
|
|
|
|
if (edge->geometry_label_point) {
|
|
}*/
|
|
} else {
|
|
/* TODO: update non-trivial edges properly */
|
|
cyberiada_clean_edge_geometry(edge);
|
|
}
|
|
edge = edge->next;
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
int cyberiada_convert_document_geometry(CyberiadaDocument* doc,
|
|
CyberiadaGeometryCoordFormat new_format,
|
|
CyberiadaGeometryEdgeFormat new_edge_format)
|
|
{
|
|
CyberiadaSM* sm;
|
|
CyberiadaRect* bounding_rect;
|
|
for (sm = doc->state_machines; sm; sm = sm->next) {
|
|
if (!sm->nodes || sm->nodes->next) {
|
|
ERROR("SM should have single root node\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
cyberiada_convert_node_geometry(sm->nodes, sm->bounding_rect,
|
|
doc->geometry_format, new_format);
|
|
if (sm->edges) {
|
|
cyberiada_convert_edge_geometry(sm->edges,
|
|
doc->geometry_format, new_format,
|
|
doc->edge_geom_format, new_edge_format);
|
|
}
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_round_node_geometry(CyberiadaNode* node)
|
|
{
|
|
while (node) {
|
|
if (node->children) {
|
|
if (node->geometry_point) {
|
|
cyberiada_round_point(node->geometry_point);
|
|
}
|
|
if (node->geometry_rect) {
|
|
cyberiada_round_rect(node->geometry_rect);
|
|
}
|
|
cyberiada_round_node_geometry(node->children);
|
|
}
|
|
node = node->next;
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_round_edges_geometry(CyberiadaEdge* edges)
|
|
{
|
|
while (edges) {
|
|
if (edges->geometry_source_point) {
|
|
cyberiada_round_point(edges->geometry_source_point);
|
|
}
|
|
if (edges->geometry_target_point) {
|
|
cyberiada_round_point(edges->geometry_target_point);
|
|
}
|
|
if (edges->geometry_label_point) {
|
|
cyberiada_round_point(edges->geometry_label_point);
|
|
}
|
|
if (edges->geometry_polyline) {
|
|
CyberiadaPolyline* pl = edges->geometry_polyline;
|
|
while (pl) {
|
|
cyberiada_round_point(&(pl->point));
|
|
pl = pl->next;
|
|
}
|
|
}
|
|
edges = edges->next;
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_round_document_geometry(CyberiadaDocument* doc)
|
|
{
|
|
CyberiadaSM* sm;
|
|
if (!doc || !doc->state_machines) {
|
|
ERROR("Cannot round SM document geometry\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
for (sm = doc->state_machines; sm; sm = sm->next) {
|
|
cyberiada_round_rect(sm->bounding_rect);
|
|
cyberiada_round_node_geometry(sm->nodes);
|
|
cyberiada_round_edges_geometry(sm->edges);
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
int cyberiada_import_document_geometry(CyberiadaDocument* doc,
|
|
int flags, CyberiadaXMLFormat file_format)
|
|
{
|
|
CyberiadaSM* sm;
|
|
CyberiadaGeometryCoordFormat old_format, new_format;
|
|
CyberiadaGeometryEdgeFormat old_edge_format, new_edge_format;
|
|
|
|
if (!doc) {
|
|
ERROR("Cannot import document geometry\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
if (file_format == cybxmlYED) {
|
|
old_format = cybCoordAbsolute;
|
|
old_edge_format = cybEdgeLocalCenter;
|
|
} else if (file_format == cybxmlCyberiada10) {
|
|
old_format = cybCoordLeftTop;
|
|
old_edge_format = cybEdgeLeftTopBorder;
|
|
} else {
|
|
ERROR("Bad XML format %d\n", file_format);
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
if (flags & CYBERIADA_FLAG_ABSOLUTE_GEOMETRY) {
|
|
new_format = cybCoordAbsolute;
|
|
} else if (flags & CYBERIADA_FLAG_LEFTTOP_LOCAL_GEOMETRY) {
|
|
new_format = cybCoordLeftTop;
|
|
} else if (flags & CYBERIADA_FLAG_CENTER_LOCAL_GEOMETRY) {
|
|
new_format = cybCoordLocalCenter;
|
|
} else {
|
|
ERROR("No geometry coordinates flag for import\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
if (flags & CYBERIADA_FLAG_CENTER_BORDER_EDGE_GEOMETRY) {
|
|
new_edge_format = cybEdgeCenterBorder;
|
|
} else if (flags & CYBERIADA_FLAG_LEFTTOP_BORDER_EDGE_GEOMETRY) {
|
|
new_edge_format = cybEdgeLeftTopBorder;
|
|
} else if (flags & CYBERIADA_FLAG_CENTER_EDGE_GEOMETRY) {
|
|
new_edge_format = cybEdgeLocalCenter;
|
|
} else {
|
|
ERROR("No edge geometry flag for import\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
for (sm = doc->state_machines; sm; sm = sm->next) {
|
|
if (sm->nodes->geometry_rect) {
|
|
sm->bounding_rect = cyberiada_copy_rect(sm->nodes->geometry_rect);
|
|
} else {
|
|
CyberiadaRect* bounding_rect = cyberiada_new_rect();
|
|
bounding_rect->x = bounding_rect->y = bounding_rect->width = bounding_rect->height = 0.0;
|
|
cyberiada_build_bounding_rect(sm->nodes, bounding_rect, old_format);
|
|
sm->bounding_rect = bounding_rect;
|
|
}
|
|
|
|
cyberiada_convert_node_geometry(sm->nodes, sm->bounding_rect,
|
|
old_format, new_format);
|
|
}
|
|
|
|
doc->geometry_format = new_format;
|
|
doc->edge_geom_format = new_edge_format;
|
|
|
|
if (flags & CYBERIADA_FLAG_RECONSTRUCT_GEOMETRY) {
|
|
cyberiada_reconstruct_document_geometry(doc);
|
|
}
|
|
|
|
for (sm = doc->state_machines; sm; sm = sm->next) {
|
|
if (sm->edges) {
|
|
cyberiada_convert_edge_geometry(sm->edges,
|
|
old_format, new_format,
|
|
old_edge_format, new_edge_format);
|
|
}
|
|
}
|
|
|
|
if (flags & CYBERIADA_FLAG_ROUND_GEOMETRY) {
|
|
cyberiada_round_document_geometry(doc);
|
|
}
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
int cyberiada_export_document_geometry(CyberiadaDocument* doc,
|
|
int flags, CyberiadaXMLFormat file_format)
|
|
{
|
|
CyberiadaSM* sm;
|
|
CyberiadaGeometryCoordFormat to_format;
|
|
CyberiadaGeometryEdgeFormat to_edge_format;
|
|
|
|
if (!doc) {
|
|
ERROR("Cannot export document geometry\n");
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
if (file_format == cybxmlYED) {
|
|
to_format = cybCoordAbsolute;
|
|
to_edge_format = cybEdgeLocalCenter;
|
|
} else if (file_format == cybxmlCyberiada10) {
|
|
to_format = cybCoordLeftTop;
|
|
to_edge_format = cybEdgeLeftTopBorder;
|
|
} else {
|
|
ERROR("Bad XML format %d\n", file_format);
|
|
return CYBERIADA_BAD_PARAMETER;
|
|
}
|
|
|
|
if (flags & CYBERIADA_FLAG_RECONSTRUCT_GEOMETRY) {
|
|
cyberiada_reconstruct_document_geometry(doc);
|
|
} else if (!cyberiada_document_has_geometry(doc)) {
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
if (flags & CYBERIADA_FLAG_ROUND_GEOMETRY) {
|
|
cyberiada_round_document_geometry(doc);
|
|
}
|
|
|
|
for (sm = doc->state_machines; sm; sm = sm->next) {
|
|
if (sm->bounding_rect) {
|
|
cyberiada_convert_node_geometry(sm->nodes, sm->bounding_rect,
|
|
doc->geometry_format, to_format);
|
|
}
|
|
if (sm->edges) {
|
|
cyberiada_convert_edge_geometry(sm->edges,
|
|
doc->geometry_format, to_format,
|
|
doc->edge_geom_format, to_edge_format);
|
|
}
|
|
}
|
|
|
|
return CYBERIADA_NO_ERROR;
|
|
}
|
|
|
|
static int cyberiada_node_has_geometry(CyberiadaNode* node)
|
|
{
|
|
while (node) {
|
|
if (node->geometry_point) {
|
|
return 1;
|
|
}
|
|
if (node->geometry_rect) {
|
|
return 1;
|
|
}
|
|
if (node->children) {
|
|
int found = cyberiada_node_has_geometry(node->children);
|
|
if (found) {
|
|
return 1;
|
|
}
|
|
}
|
|
node = node->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int cyberiada_document_has_geometry(CyberiadaDocument* doc)
|
|
{
|
|
CyberiadaSM* sm;
|
|
CyberiadaEdge* edge;
|
|
|
|
if (!doc) {
|
|
return 0;
|
|
}
|
|
|
|
for (sm = doc->state_machines; sm; sm = sm->next) {
|
|
if (cyberiada_node_has_geometry(sm->nodes)) {
|
|
return 1;
|
|
}
|
|
edge = sm->edges;
|
|
while (edge) {
|
|
if (edge->geometry_polyline) {
|
|
return 1;
|
|
}
|
|
if (edge->geometry_source_point) {
|
|
return 1;
|
|
}
|
|
if (edge->geometry_target_point) {
|
|
return 1;
|
|
}
|
|
if (edge->geometry_label_point) {
|
|
return 1;
|
|
}
|
|
edge = edge->next;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|