calculate SM bound rectangles + test
This commit is contained in:
@@ -36,10 +36,10 @@ namespace Cyberiada {
|
||||
static const String DEFAULT_GRAPHML_FORMAT = "Cyberiada-GraphML-1.0";
|
||||
static const String META_NODE_NAME = "CGML_META";
|
||||
static const String META_NODE_ID = "nMeta";
|
||||
const String VERTEX_ID_PREFIX = "n";
|
||||
const String SM_ID_PREFIX = "G";
|
||||
const String TRANTISION_ID_SEP = "-";
|
||||
const String TRANTISION_ID_NUM_SEP = "#";
|
||||
static const String VERTEX_ID_PREFIX = "n";
|
||||
static const String SM_ID_PREFIX = "G";
|
||||
static const String TRANTISION_ID_SEP = "-";
|
||||
static const String TRANTISION_ID_NUM_SEP = "#";
|
||||
static const std::string tab = "\t";
|
||||
};
|
||||
|
||||
@@ -286,6 +286,50 @@ std::ostream& Action::dump(std::ostream& os) const
|
||||
// Geometry objects
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool Rect::operator==(const Rect& r)
|
||||
{
|
||||
if (!valid && !r.valid) return true;
|
||||
if (!valid || !r.valid) return false;
|
||||
return x == r.x && y == r.y && width == r.width && height == r.height;
|
||||
}
|
||||
|
||||
void Rect::expand(const Point& p)
|
||||
{
|
||||
if (p.valid) {
|
||||
if (valid) {
|
||||
if (p.x < x) x = p.x;
|
||||
if (p.x > x + width) width = p.x - x;
|
||||
if (p.y < y) y = p.y;
|
||||
if (p.y > y + height) height = p.y - y;
|
||||
} else {
|
||||
x = p.x;
|
||||
y = p.y;
|
||||
width = height = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rect::expand(const Rect& r)
|
||||
{
|
||||
if (r.valid) {
|
||||
if (valid) {
|
||||
expand(Point(r.x, r.y));
|
||||
expand(Point(r.x + r.width, r.y + r.height));
|
||||
} else {
|
||||
*this = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rect::expand(const Polyline& pl)
|
||||
{
|
||||
if (pl.size() > 0) {
|
||||
for (Polyline::const_iterator i = pl.begin(); i != pl.end(); i++) {
|
||||
expand(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& Cyberiada::operator<<(std::ostream& os, const Point& p)
|
||||
{
|
||||
if (!p.valid) {
|
||||
@@ -348,6 +392,23 @@ CommentSubject& CommentSubject::operator=(const CommentSubject& cs)
|
||||
return *this;
|
||||
}
|
||||
|
||||
Rect CommentSubject::get_bound_rect() const
|
||||
{
|
||||
Rect r;
|
||||
if (has_geometry()) {
|
||||
if (has_geometry_source_point()) {
|
||||
r.expand(source_point);
|
||||
}
|
||||
if (has_geometry_target_point()) {
|
||||
r.expand(target_point);
|
||||
}
|
||||
if (has_polyline()) {
|
||||
r.expand(polyline);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ostream& Cyberiada::operator<<(std::ostream& os, const CommentSubject& cs)
|
||||
{
|
||||
cs.dump(os);
|
||||
@@ -499,6 +560,20 @@ CyberiadaEdge* Comment::subjects_to_edges() const
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect Comment::get_bound_rect() const
|
||||
{
|
||||
Rect r;
|
||||
if (has_geometry()) {
|
||||
r = geometry_rect;
|
||||
}
|
||||
if (has_subjects()) {
|
||||
for (std::list<CommentSubject>::const_iterator i = subjects.begin(); i != subjects.end(); i++) {
|
||||
r.expand(i->get_bound_rect());
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ostream& Comment::dump(std::ostream& os) const
|
||||
{
|
||||
Element::dump(os);
|
||||
@@ -534,6 +609,15 @@ Vertex::Vertex(Element* _parent, ElementType _type, const ID& _id, const Name& _
|
||||
{
|
||||
}
|
||||
|
||||
Rect Vertex::get_bound_rect() const
|
||||
{
|
||||
Rect r;
|
||||
if (has_geometry()) {
|
||||
r.expand(geometry_point);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ostream& Vertex::dump(std::ostream& os) const
|
||||
{
|
||||
Element::dump(os);
|
||||
@@ -876,6 +960,15 @@ CyberiadaNode* ElementCollection::to_node() const
|
||||
return node;
|
||||
}
|
||||
|
||||
Rect ElementCollection::get_bound_rect() const
|
||||
{
|
||||
Rect r;
|
||||
if (has_geometry()) {
|
||||
r = geometry_rect;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ostream& ElementCollection::dump(std::ostream& os) const
|
||||
{
|
||||
if (has_geometry()) {
|
||||
@@ -967,6 +1060,15 @@ CyberiadaNode* ChoicePseudostate::to_node() const
|
||||
return node;
|
||||
}
|
||||
|
||||
Rect ChoicePseudostate::get_bound_rect() const
|
||||
{
|
||||
Rect r;
|
||||
if (has_geometry()) {
|
||||
r = geometry_rect;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ostream& ChoicePseudostate::dump(std::ostream& os) const
|
||||
{
|
||||
Element::dump(os);
|
||||
@@ -1160,6 +1262,26 @@ CyberiadaEdge* Transition::to_edge() const
|
||||
return edge;
|
||||
}
|
||||
|
||||
Rect Transition::get_bound_rect() const
|
||||
{
|
||||
Rect r;
|
||||
if (has_geometry()) {
|
||||
if (has_geometry_source_point()) {
|
||||
r.expand(source_point);
|
||||
}
|
||||
if (has_geometry_target_point()) {
|
||||
r.expand(target_point);
|
||||
}
|
||||
if (has_geometry_label_point()) {
|
||||
r.expand(label_point);
|
||||
}
|
||||
if (has_polyline()) {
|
||||
r.expand(polyline);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ostream& Transition::dump(std::ostream& os) const
|
||||
{
|
||||
Element::dump(os);
|
||||
@@ -1243,6 +1365,19 @@ std::list<Transition*> StateMachine::get_transitions()
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect StateMachine::get_bound_rect() const
|
||||
{
|
||||
Rect r;
|
||||
if (has_geometry()) {
|
||||
r = ElementCollection::get_bound_rect();
|
||||
} else if (has_children()) {
|
||||
for (ElementList::const_iterator i = children.begin(); i != children.end(); i++) {
|
||||
r.expand((*i)->get_bound_rect());
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ostream& StateMachine::dump(std::ostream& os) const
|
||||
{
|
||||
Element::dump(os);
|
||||
|
||||
@@ -61,6 +61,47 @@ namespace Cyberiada {
|
||||
|
||||
const String QUALIFIED_NAME_SEPARATOR = "::";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Geometry
|
||||
// -----------------------------------------------------------------------------
|
||||
struct Point {
|
||||
Point(): valid(false) {}
|
||||
Point(float _x, float _y):
|
||||
valid(true), x(_x), y(_y) {}
|
||||
Point(CyberiadaPoint* p);
|
||||
|
||||
CyberiadaPoint* c_point() const;
|
||||
|
||||
bool valid;
|
||||
float x, y;
|
||||
};
|
||||
typedef std::list<Point> Polyline;
|
||||
|
||||
struct Rect {
|
||||
Rect(): valid(false) {}
|
||||
Rect(float _x, float _y, float _width, float _height):
|
||||
valid(true), x(_x), y(_y), width(_width), height(_height) {}
|
||||
Rect(CyberiadaRect* r);
|
||||
|
||||
void expand(const Point& p);
|
||||
void expand(const Rect& r);
|
||||
void expand(const Polyline& pl);
|
||||
|
||||
CyberiadaRect* c_rect() const;
|
||||
|
||||
bool operator==(const Rect& r);
|
||||
|
||||
bool valid;
|
||||
float x, y;
|
||||
float width, height;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Point& p);
|
||||
std::ostream& operator<<(std::ostream& os, const Rect& r);
|
||||
std::ostream& operator<<(std::ostream& os, const Polyline& pl);
|
||||
|
||||
CyberiadaPolyline* c_polyline(const Polyline& polyline);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Base Element
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -89,6 +130,7 @@ namespace Cyberiada {
|
||||
virtual int index() const;
|
||||
|
||||
virtual bool has_geometry() const = 0;
|
||||
virtual Rect get_bound_rect() const = 0;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Element& e);
|
||||
virtual CyberiadaNode* to_node() const;
|
||||
@@ -109,42 +151,6 @@ namespace Cyberiada {
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Element& e);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Geometry
|
||||
// -----------------------------------------------------------------------------
|
||||
struct Point {
|
||||
Point(): valid(false) {}
|
||||
Point(float _x, float _y):
|
||||
valid(true), x(_x), y(_y) {}
|
||||
Point(CyberiadaPoint* p);
|
||||
|
||||
CyberiadaPoint* c_point() const;
|
||||
|
||||
bool valid;
|
||||
float x, y;
|
||||
};
|
||||
|
||||
struct Rect {
|
||||
Rect(): valid(false) {}
|
||||
Rect(float _x, float _y, float _width, float _height):
|
||||
valid(true), x(_x), y(_y), width(_width), height(_height) {}
|
||||
Rect(CyberiadaRect* r);
|
||||
|
||||
CyberiadaRect* c_rect() const;
|
||||
|
||||
bool valid;
|
||||
float x, y;
|
||||
float width, height;
|
||||
};
|
||||
|
||||
typedef std::list<Point> Polyline;
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Point& p);
|
||||
std::ostream& operator<<(std::ostream& os, const Rect& r);
|
||||
std::ostream& operator<<(std::ostream& os, const Polyline& pl);
|
||||
|
||||
CyberiadaPolyline* c_polyline(const Polyline& polyline);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Comment
|
||||
@@ -179,6 +185,7 @@ namespace Cyberiada {
|
||||
const Point& get_geometry_source_point() const { return source_point; }
|
||||
const Point& get_geometry_target_point() const { return target_point; }
|
||||
const Polyline& get_geometry_polyline() const { return polyline; }
|
||||
Rect get_bound_rect() const;
|
||||
|
||||
protected:
|
||||
std::ostream& dump(std::ostream& os) const;
|
||||
@@ -218,6 +225,7 @@ namespace Cyberiada {
|
||||
|
||||
virtual bool has_geometry() const { return geometry_rect.valid; }
|
||||
const Rect& get_geometry_rect() const { return geometry_rect; }
|
||||
virtual Rect get_bound_rect() const;
|
||||
|
||||
virtual bool has_children() const { return false; }
|
||||
|
||||
@@ -254,6 +262,7 @@ namespace Cyberiada {
|
||||
|
||||
virtual bool has_geometry() const { return geometry_point.valid; }
|
||||
const Point& get_geometry_point() const { return geometry_point; }
|
||||
virtual Rect get_bound_rect() const;
|
||||
|
||||
virtual bool has_children() const { return false; }
|
||||
|
||||
@@ -309,7 +318,8 @@ namespace Cyberiada {
|
||||
|
||||
virtual bool has_geometry() const { return geometry_rect.valid; }
|
||||
const Rect& get_geometry_rect() const { return geometry_rect; }
|
||||
|
||||
virtual Rect get_bound_rect() const;
|
||||
|
||||
bool has_color() const { return !color.empty(); }
|
||||
const Color& get_color() const { return color; }
|
||||
|
||||
@@ -355,6 +365,7 @@ namespace Cyberiada {
|
||||
|
||||
virtual bool has_geometry() const { return geometry_rect.valid; }
|
||||
const Rect& get_geometry_rect() const { return geometry_rect; }
|
||||
virtual Rect get_bound_rect() const;
|
||||
|
||||
bool has_color() const { return !color.empty(); }
|
||||
const Color& get_color() const { return color; }
|
||||
@@ -490,6 +501,7 @@ namespace Cyberiada {
|
||||
const Point& get_source_point() const { return source_point; }
|
||||
const Point& get_target_point() const { return target_point; }
|
||||
const Point& get_label_point() const { return label_point; }
|
||||
virtual Rect get_bound_rect() const;
|
||||
|
||||
bool has_color() const { return !color.empty(); }
|
||||
const Color& get_color() const { return color; }
|
||||
@@ -522,6 +534,8 @@ namespace Cyberiada {
|
||||
std::list<const Transition*> get_transitions() const;
|
||||
std::list<Transition*> get_transitions();
|
||||
|
||||
virtual Rect get_bound_rect() const;
|
||||
|
||||
protected:
|
||||
virtual std::ostream& dump(std::ostream& os) const;
|
||||
};
|
||||
@@ -637,6 +651,9 @@ namespace Cyberiada {
|
||||
std::list<StateMachine*> get_state_machines();
|
||||
const StateMachine* get_parent_sm(const Element* element) const;
|
||||
|
||||
virtual bool has_geometry() const { return false; }
|
||||
virtual Rect get_bound_rect() const { return Rect(); }
|
||||
|
||||
protected:
|
||||
virtual std::ostream& dump(std::ostream& os) const;
|
||||
|
||||
|
||||
44
tests/22-bound-rect.cpp
Normal file
44
tests/22-bound-rect.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
* The Cyberiada GraphML C++ library implemention
|
||||
*
|
||||
* The test
|
||||
*
|
||||
* 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 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 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 <iostream>
|
||||
#include "cyberiadamlpp.h"
|
||||
#include "testutils.h"
|
||||
|
||||
using namespace Cyberiada;
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Document d;
|
||||
StateMachine* sm = d.new_state_machine("SM");
|
||||
d.new_state(sm, "A", Action(), Rect(0, 50, 100, 25));
|
||||
State* s = d.new_state(sm, "B", Action(), Rect(-100, -250, 100, 250));
|
||||
d.new_state(s, "B2", Action(), Rect(0, 200, 50, 50));
|
||||
d.new_initial(s, Point(0, 0));
|
||||
d.new_state(sm, "C", Action(), Rect(-50, 0, 1000, 250));
|
||||
try {
|
||||
CYB_ASSERT(sm->get_bound_rect() == Rect(-100, -250, 1050, 500));
|
||||
} catch (const Cyberiada::Exception&) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user