mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 21:06:59 -04:00
New symbol part list control that shows previews and has a built in editor
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@529 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+118
-70
@@ -18,13 +18,17 @@ DECLARE_TYPEOF_COLLECTION(ControlPointP);
|
||||
// ----------------------------------------------------------------------------- : Utility
|
||||
|
||||
String action_name_for(const set<SymbolPartP>& parts, const String& action) {
|
||||
return format_string(action, parts.size() == 1 ? _TYPE_("shape") : _TYPE_("shapes"));
|
||||
return format_string(action, parts.size() == 1 ? (*parts.begin())->name : _TYPE_("shapes"));
|
||||
}
|
||||
|
||||
SymbolPartsAction::SymbolPartsAction(const set<SymbolPartP>& parts)
|
||||
: parts(parts)
|
||||
{}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Moving symbol parts
|
||||
|
||||
SymbolPartMoveAction::SymbolPartMoveAction(const set<SymbolPartP>& parts, const Vector2D& delta)
|
||||
: parts(parts)
|
||||
: SymbolPartsAction(parts)
|
||||
, delta(delta), moved(-delta)
|
||||
, min_pos(Vector2D::infinity()), max_pos(-Vector2D::infinity())
|
||||
, constrain(false)
|
||||
@@ -32,10 +36,8 @@ SymbolPartMoveAction::SymbolPartMoveAction(const set<SymbolPartP>& parts, const
|
||||
{
|
||||
// Determine min/max_pos
|
||||
FOR_EACH(p, parts) {
|
||||
if (SymbolShape* s = p->isSymbolShape()) {
|
||||
min_pos = piecewise_min(min_pos, s->min_pos);
|
||||
max_pos = piecewise_max(max_pos, s->max_pos);
|
||||
}
|
||||
min_pos = piecewise_min(min_pos, p->min_pos);
|
||||
max_pos = piecewise_max(max_pos, p->max_pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,20 +48,28 @@ String SymbolPartMoveAction::getName(bool to_undo) const {
|
||||
void SymbolPartMoveAction::perform(bool to_undo) {
|
||||
// move the points back
|
||||
FOR_EACH(p, parts) {
|
||||
if (SymbolShape* s = p->isSymbolShape()) {
|
||||
s->min_pos -= moved;
|
||||
s->max_pos -= moved;
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos -= moved;
|
||||
}
|
||||
} else if (SymbolSymmetry* s = p->isSymbolSymmetry()) {
|
||||
s->center -= moved;
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
movePart(*p);
|
||||
}
|
||||
moved = -moved;
|
||||
}
|
||||
void SymbolPartMoveAction::movePart(SymbolPart& part) {
|
||||
if (SymbolShape* s = part.isSymbolShape()) {
|
||||
s->min_pos -= moved;
|
||||
s->max_pos -= moved;
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos -= moved;
|
||||
}
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
s->center -= moved;
|
||||
} else if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
movePart(*p);
|
||||
}
|
||||
g->calculateBoundsNonRec();
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolPartMoveAction::move(const Vector2D& deltaDelta) {
|
||||
delta += deltaDelta;
|
||||
@@ -75,26 +85,34 @@ void SymbolPartMoveAction::move(const Vector2D& deltaDelta) {
|
||||
// ----------------------------------------------------------------------------- : Rotating symbol parts
|
||||
|
||||
SymbolPartMatrixAction::SymbolPartMatrixAction(const set<SymbolPartP>& parts, const Vector2D& center)
|
||||
: parts(parts)
|
||||
: SymbolPartsAction(parts)
|
||||
, center(center)
|
||||
{}
|
||||
|
||||
void SymbolPartMatrixAction::transform(const Vector2D& mx, const Vector2D& my) {
|
||||
// Transform each point
|
||||
void SymbolPartMatrixAction::transform(const Matrix2D& m) {
|
||||
// Transform each part
|
||||
FOR_EACH(p, parts) {
|
||||
if (SymbolShape* s = p->isSymbolShape()) {
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos = (pnt->pos - center).mul(mx,my) + center;
|
||||
pnt->delta_before = pnt->delta_before.mul(mx,my);
|
||||
pnt->delta_after = pnt->delta_after .mul(mx,my);
|
||||
}
|
||||
// bounds change after transforming
|
||||
s->calculateBounds();
|
||||
} else if (SymbolSymmetry* s = p->isSymbolSymmetry()) {
|
||||
s->handle = s->handle.mul(mx,my);
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
transform(*p, m);
|
||||
}
|
||||
}
|
||||
void SymbolPartMatrixAction::transform(SymbolPart& part, const Matrix2D& m) {
|
||||
if (SymbolShape* s = part.isSymbolShape()) {
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos = ((pnt->pos - center) * m) + center;
|
||||
pnt->delta_before = pnt->delta_before * m;
|
||||
pnt->delta_after = pnt->delta_after * m;
|
||||
}
|
||||
// bounds change after transforming
|
||||
s->calculateBounds();
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
s->handle = s->handle * m;
|
||||
} else if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
transform(*p, m);
|
||||
}
|
||||
g->calculateBoundsNonRec();
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,8 +148,8 @@ void SymbolPartRotateAction::rotateTo(double newAngle) {
|
||||
void SymbolPartRotateAction::rotateBy(double deltaAngle) {
|
||||
// Rotation 'matrix'
|
||||
transform(
|
||||
Vector2D(cos(deltaAngle), -sin(deltaAngle)),
|
||||
Vector2D(sin(deltaAngle), cos(deltaAngle))
|
||||
Matrix2D(cos(deltaAngle), -sin(deltaAngle)
|
||||
,sin(deltaAngle), cos(deltaAngle))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -170,8 +188,8 @@ void SymbolPartShearAction::move(const Vector2D& deltaShear) {
|
||||
void SymbolPartShearAction::shearBy(const Vector2D& shear) {
|
||||
// Shear 'matrix'
|
||||
transform(
|
||||
Vector2D(1, shear.x),
|
||||
Vector2D(shear.y, 1)
|
||||
Matrix2D(1, shear.x
|
||||
,shear.y, 1)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -180,7 +198,7 @@ void SymbolPartShearAction::shearBy(const Vector2D& shear) {
|
||||
|
||||
|
||||
SymbolPartScaleAction::SymbolPartScaleAction(const set<SymbolPartP>& parts, int scaleX, int scaleY)
|
||||
: parts(parts)
|
||||
: SymbolPartsAction(parts)
|
||||
, scaleX(scaleX), scaleY(scaleY)
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
@@ -189,10 +207,8 @@ SymbolPartScaleAction::SymbolPartScaleAction(const set<SymbolPartP>& parts, int
|
||||
old_min = Vector2D( 1e6, 1e6);
|
||||
Vector2D old_max (-1e6,-1e6);
|
||||
FOR_EACH(p, parts) {
|
||||
if (SymbolShape* s = p->isSymbolShape()) {
|
||||
old_min = piecewise_min(old_min, s->min_pos);
|
||||
old_max = piecewise_max(old_max, s->max_pos);
|
||||
}
|
||||
old_min = piecewise_min(old_min, p->min_pos);
|
||||
old_max = piecewise_max(old_max, p->max_pos);
|
||||
}
|
||||
// new == old
|
||||
new_min = new_real_min = old_min;
|
||||
@@ -244,26 +260,34 @@ void SymbolPartScaleAction::update() {
|
||||
}
|
||||
|
||||
void SymbolPartScaleAction::transformAll() {
|
||||
Vector2D scale = new_size.div(old_size);
|
||||
FOR_EACH(p, parts) {
|
||||
if (SymbolShape* s = p->isSymbolShape()) {
|
||||
s->min_pos = transform(s->min_pos);
|
||||
s->max_pos = transform(s->max_pos);
|
||||
// make sure that max >= min
|
||||
if (s->min_pos.x > s->max_pos.x) swap(s->min_pos.x, s->max_pos.x);
|
||||
if (s->min_pos.y > s->max_pos.y) swap(s->min_pos.y, s->max_pos.y);
|
||||
// scale all points
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos = transform(pnt->pos);
|
||||
// also scale handles
|
||||
pnt->delta_before = pnt->delta_before.mul(scale);
|
||||
pnt->delta_after = pnt->delta_after .mul(scale);
|
||||
}
|
||||
} else if (SymbolSymmetry* s = p->isSymbolSymmetry()) {
|
||||
throw "TODO";
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
transformPart(*p);
|
||||
}
|
||||
}
|
||||
void SymbolPartScaleAction::transformPart(SymbolPart& part) {
|
||||
if (SymbolShape* s = part.isSymbolShape()) {
|
||||
Vector2D scale = new_size.div(old_size);
|
||||
s->min_pos = transform(s->min_pos);
|
||||
s->max_pos = transform(s->max_pos);
|
||||
// make sure that max >= min
|
||||
if (s->min_pos.x > s->max_pos.x) swap(s->min_pos.x, s->max_pos.x);
|
||||
if (s->min_pos.y > s->max_pos.y) swap(s->min_pos.y, s->max_pos.y);
|
||||
// scale all points
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos = transform(pnt->pos);
|
||||
// also scale handles
|
||||
pnt->delta_before = pnt->delta_before.mul(scale);
|
||||
pnt->delta_after = pnt->delta_after .mul(scale);
|
||||
}
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
throw "TODO";
|
||||
} else if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
transformPart(*p);
|
||||
}
|
||||
g->calculateBoundsNonRec();
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,11 +298,18 @@ Vector2D SymbolPartScaleAction::transform(const Vector2D& v) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change combine mode
|
||||
|
||||
CombiningModeAction::CombiningModeAction(const set<SymbolPartP>& parts, SymbolShapeCombine mode) {
|
||||
CombiningModeAction::CombiningModeAction(const set<SymbolPartP>& parts, SymbolShapeCombine mode)
|
||||
: SymbolPartsAction(parts)
|
||||
{
|
||||
FOR_EACH(p, parts) {
|
||||
if (p->isSymbolShape()) {
|
||||
this->parts.push_back(make_pair(static_pointer_cast<SymbolShape>(p),mode));
|
||||
}
|
||||
add(p,mode);
|
||||
}
|
||||
}
|
||||
void CombiningModeAction::add(const SymbolPartP& part, SymbolShapeCombine mode) {
|
||||
if (part->isSymbolShape()) {
|
||||
this->parts.push_back(make_pair(static_pointer_cast<SymbolShape>(part),mode));
|
||||
} else if (SymbolGroup* g = part->isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) add(p, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,16 +325,28 @@ void CombiningModeAction::perform(bool to_undo) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change name
|
||||
|
||||
SymbolPartNameAction::SymbolPartNameAction(const SymbolPartP& part, const String& name)
|
||||
SymbolPartNameAction::SymbolPartNameAction(const SymbolPartP& part, const String& name, size_t old_cursor, size_t new_cursor)
|
||||
: part(part), part_name(name)
|
||||
, new_cursor(old_cursor), old_cursor(new_cursor) // will be swapped
|
||||
{}
|
||||
|
||||
String SymbolPartNameAction::getName(bool to_undo) const {
|
||||
return _ACTION_("change shape name");
|
||||
}
|
||||
bool SymbolPartNameAction::merge(const Action& action) {
|
||||
TYPE_CASE(action, SymbolPartNameAction) {
|
||||
if (action.part == part) {
|
||||
// adjacent actions on the same part, discard the other one,
|
||||
// because it only keeps an intermediate value
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SymbolPartNameAction::perform(bool to_undo) {
|
||||
swap(part->name, part_name);
|
||||
swap(old_cursor, new_cursor);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Add symbol part
|
||||
@@ -313,7 +356,7 @@ AddSymbolPartAction::AddSymbolPartAction(Symbol& symbol, const SymbolPartP& part
|
||||
{}
|
||||
|
||||
String AddSymbolPartAction::getName(bool to_undo) const {
|
||||
return format_string(_ACTION_("add"), part->name);
|
||||
return format_string(_ACTION_("add part"), part->name);
|
||||
}
|
||||
|
||||
void AddSymbolPartAction::perform(bool to_undo) {
|
||||
@@ -407,8 +450,8 @@ void DuplicateSymbolPartsAction::getParts(set<SymbolPartP>& parts) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reorder symbol parts
|
||||
|
||||
ReorderSymbolPartsAction::ReorderSymbolPartsAction(Symbol& symbol, size_t part_id1, size_t part_id2)
|
||||
: symbol(symbol), part_id1(part_id1), part_id2(part_id2)
|
||||
ReorderSymbolPartsAction::ReorderSymbolPartsAction(Symbol& symbol, size_t old_position, size_t new_position)
|
||||
: symbol(symbol), old_position(old_position), new_position(new_position)
|
||||
{}
|
||||
|
||||
String ReorderSymbolPartsAction::getName(bool to_undo) const {
|
||||
@@ -416,9 +459,12 @@ String ReorderSymbolPartsAction::getName(bool to_undo) const {
|
||||
}
|
||||
|
||||
void ReorderSymbolPartsAction::perform(bool to_undo) {
|
||||
assert(part_id1 < symbol.parts.size());
|
||||
assert(part_id2 < symbol.parts.size());
|
||||
swap(symbol.parts[part_id1], symbol.parts[part_id2]);
|
||||
assert(old_position < symbol.parts.size());
|
||||
assert(new_position < symbol.parts.size());
|
||||
SymbolPartP part = symbol.parts.at(old_position);
|
||||
symbol.parts.erase( symbol.parts.begin() + old_position);
|
||||
symbol.parts.insert(symbol.parts.begin() + new_position, part);
|
||||
swap(old_position, new_position);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Group symbol parts
|
||||
@@ -439,6 +485,7 @@ GroupSymbolPartsAction::GroupSymbolPartsAction(Symbol& symbol, const set<SymbolP
|
||||
group->name = _("Group");
|
||||
FOR_EACH(p, symbol.parts) {
|
||||
if (parts.find(p) != parts.end()) {
|
||||
// add to group instead
|
||||
group->parts.push_back(p);
|
||||
if (!done) {
|
||||
done = true;
|
||||
@@ -449,6 +496,7 @@ GroupSymbolPartsAction::GroupSymbolPartsAction(Symbol& symbol, const set<SymbolP
|
||||
old_part_list.push_back(p);
|
||||
}
|
||||
}
|
||||
group->calculateBounds();
|
||||
}
|
||||
String GroupSymbolPartsAction::getName(bool to_undo) const {
|
||||
return _ACTION_("group parts");
|
||||
|
||||
+30
-17
@@ -20,16 +20,24 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : Transform symbol part
|
||||
|
||||
/// Anything that changes a part
|
||||
/// Anything that changes one or more parts
|
||||
class SymbolPartAction : public Action {};
|
||||
|
||||
/// Anything that changes a set of parts
|
||||
class SymbolPartsAction : public SymbolPartAction {
|
||||
public:
|
||||
SymbolPartsAction(const set<SymbolPartP>& parts);
|
||||
|
||||
const set<SymbolPartP> parts; ///< Affected parts
|
||||
};
|
||||
|
||||
/// Anything that changes a part as displayed in the part list
|
||||
class SymbolPartListAction : public SymbolPartAction {};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Moving symbol parts
|
||||
|
||||
/// Move some symbol parts
|
||||
class SymbolPartMoveAction : public SymbolPartAction {
|
||||
class SymbolPartMoveAction : public SymbolPartsAction {
|
||||
public:
|
||||
SymbolPartMoveAction(const set<SymbolPartP>& parts, const Vector2D& delta = Vector2D());
|
||||
|
||||
@@ -40,10 +48,11 @@ class SymbolPartMoveAction : public SymbolPartAction {
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
private:
|
||||
set<SymbolPartP> parts; ///< Parts to move
|
||||
Vector2D delta; ///< How much to move
|
||||
Vector2D moved; ///< How much has been moved
|
||||
Vector2D min_pos, max_pos; ///< Bounding box of the thing we are moving
|
||||
|
||||
void movePart(SymbolPart& part); ///< Move a single part
|
||||
public:
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
@@ -52,7 +61,7 @@ class SymbolPartMoveAction : public SymbolPartAction {
|
||||
// ----------------------------------------------------------------------------- : Rotating symbol parts
|
||||
|
||||
/// Transforming symbol parts using a matrix
|
||||
class SymbolPartMatrixAction : public SymbolPartAction {
|
||||
class SymbolPartMatrixAction : public SymbolPartsAction {
|
||||
public:
|
||||
SymbolPartMatrixAction(const set<SymbolPartP>& parts, const Vector2D& center);
|
||||
|
||||
@@ -61,10 +70,10 @@ class SymbolPartMatrixAction : public SymbolPartAction {
|
||||
|
||||
protected:
|
||||
/// Perform the transformation using the given matrix
|
||||
void transform(const Vector2D& mx, const Vector2D& my);
|
||||
void transform(const Matrix2D& m);
|
||||
void transform(SymbolPart& part, const Matrix2D& m);
|
||||
|
||||
set<SymbolPartP> parts; ///< Parts to transform
|
||||
Vector2D center; ///< Center to transform around
|
||||
Vector2D center; ///< Center to transform around
|
||||
};
|
||||
|
||||
/// Rotate some symbol parts
|
||||
@@ -114,7 +123,7 @@ class SymbolPartShearAction : public SymbolPartMatrixAction {
|
||||
// ----------------------------------------------------------------------------- : Scaling symbol parts
|
||||
|
||||
/// Scale some symbol parts
|
||||
class SymbolPartScaleAction : public SymbolPartAction {
|
||||
class SymbolPartScaleAction : public SymbolPartsAction {
|
||||
public:
|
||||
SymbolPartScaleAction(const set<SymbolPartP>& parts, int scaleX, int scaleY);
|
||||
|
||||
@@ -127,13 +136,13 @@ class SymbolPartScaleAction : public SymbolPartAction {
|
||||
void update();
|
||||
|
||||
private:
|
||||
set<SymbolPartP> parts; ///< Parts to scale
|
||||
Vector2D old_min, old_size; ///< the original pos/size
|
||||
Vector2D new_real_min, new_real_size; ///< the target pos/sizevoid shearBy(const Vector2D& shear)
|
||||
Vector2D new_min, new_size; ///< the target pos/size after applying constrains
|
||||
int scaleX, scaleY; ///< to what corner are we attached?
|
||||
/// Transform everything in the parts
|
||||
void transformAll();
|
||||
void transformPart(SymbolPart&);
|
||||
/// Transform a single vector
|
||||
inline Vector2D transform(const Vector2D& v);
|
||||
public:
|
||||
@@ -144,7 +153,7 @@ class SymbolPartScaleAction : public SymbolPartAction {
|
||||
// ----------------------------------------------------------------------------- : Change combine mode
|
||||
|
||||
/// Change the name of a symbol part
|
||||
class CombiningModeAction : public SymbolPartListAction {
|
||||
class CombiningModeAction : public SymbolPartsAction {
|
||||
public:
|
||||
// All parts must be SymbolParts
|
||||
CombiningModeAction(const set<SymbolPartP>& parts, SymbolShapeCombine mode);
|
||||
@@ -153,22 +162,26 @@ class CombiningModeAction : public SymbolPartListAction {
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
void add(const SymbolPartP&, SymbolShapeCombine mode);
|
||||
vector<pair<SymbolShapeP,SymbolShapeCombine> > parts; ///< Affected parts with new combining modes
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change name
|
||||
|
||||
/// Change the name of a symbol part
|
||||
class SymbolPartNameAction : public SymbolPartListAction {
|
||||
class SymbolPartNameAction : public SymbolPartAction {
|
||||
public:
|
||||
SymbolPartNameAction(const SymbolPartP& part, const String& name);
|
||||
SymbolPartNameAction(const SymbolPartP& part, const String& name, size_t old_cursor, size_t new_cursor);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
virtual bool merge(const Action& action);
|
||||
|
||||
private:
|
||||
public:
|
||||
SymbolPartP part; ///< Affected part
|
||||
String part_name; ///< New name
|
||||
size_t old_cursor; ///< Cursor position
|
||||
size_t new_cursor; ///< Cursor position
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Add symbol part
|
||||
@@ -224,18 +237,18 @@ class DuplicateSymbolPartsAction : public SymbolPartListAction {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reorder symbol parts
|
||||
|
||||
/// Change the position of a part in a symbol, by swapping two parts.
|
||||
/// Change the position of a part in a symbol, by moving a part.
|
||||
class ReorderSymbolPartsAction : public SymbolPartListAction {
|
||||
public:
|
||||
ReorderSymbolPartsAction(Symbol& symbol, size_t part_id1, size_t part_id2);
|
||||
ReorderSymbolPartsAction(Symbol& symbol, size_t old_position, size_t new_position);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
Symbol& symbol; ///< Symbol to swap the parts in
|
||||
Symbol& symbol; ///< Symbol to swap the parts in
|
||||
public:
|
||||
size_t part_id1, part_id2; ///< Indices of parts to swap
|
||||
size_t old_position, new_position; ///< Positions to move from and to
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -349,8 +349,8 @@ SinglePointRemoveAction::SinglePointRemoveAction(const SymbolShapeP& shape, UInt
|
||||
Vector2D p = c.pointAt(t);
|
||||
Vector2D distP = point->pos - p;
|
||||
// adjust handle sizes
|
||||
point1.other.delta_after *= ssqrt(distP.dot(point1.other.delta_after) /point1.other.delta_after.lengthSqr()) + 1;
|
||||
point2.other.delta_before *= ssqrt(distP.dot(point2.other.delta_before)/point2.other.delta_before.lengthSqr()) + 1;
|
||||
point1.other.delta_after *= ssqrt(dot(distP, point1.other.delta_after) /point1.other.delta_after.lengthSqr()) + 1;
|
||||
point2.other.delta_before *= ssqrt(dot(distP, point2.other.delta_before)/point2.other.delta_before.lengthSqr()) + 1;
|
||||
|
||||
// unlock if needed
|
||||
if (point1.other.lock == LOCK_SIZE) point1.other.lock = LOCK_DIR;
|
||||
|
||||
@@ -245,7 +245,7 @@ void mark_corners(SymbolShape& shape) {
|
||||
Vector2D after = .6 * shape.getPoint(i+1)->pos + .2 * shape.getPoint(i+2)->pos + .1 * shape.getPoint(i+3)->pos + .1 * shape.getPoint(i+4)->pos;
|
||||
before = (before - current.pos).normalized();
|
||||
after = (after - current.pos).normalized();
|
||||
if (before.dot(after) >= -0.25f) {
|
||||
if (dot(before,after) >= -0.25f) {
|
||||
// corner
|
||||
current.lock = LOCK_FREE;
|
||||
} else {
|
||||
@@ -285,8 +285,8 @@ void merge_corners(SymbolShape& shape) {
|
||||
for (int j = 0 ; j < 4 ; ++j) {
|
||||
Vector2D a_ = (shape.getPoint(i-j-1)->pos - prev.pos).normalized();
|
||||
Vector2D b_ = (shape.getPoint(i+j)->pos - cur.pos).normalized();
|
||||
double a_dot = a_.dot(ab);
|
||||
double b_dot = -b_.dot(ab);
|
||||
double a_dot = dot(a_, ab);
|
||||
double b_dot = -dot(b_, ab);
|
||||
if (a_dot < min_a_dot) {
|
||||
min_a_dot = a_dot;
|
||||
a = a_;
|
||||
@@ -300,8 +300,8 @@ void merge_corners(SymbolShape& shape) {
|
||||
// t a + ab = u b, solve for t,u
|
||||
// Gives us:
|
||||
// t = ab cross b / b cross a
|
||||
double tden = max(0.00000001, b.cross(a));
|
||||
double t = ab.cross(b) / tden;
|
||||
double tden = max(0.00000001, cross(b,a));
|
||||
double t = cross(ab,b) / tden;
|
||||
// do these tangent lines intersect, and not too far away?
|
||||
// if so, then the intersection point is the merged point
|
||||
if (t >= 0 && t < 20.0) {
|
||||
@@ -358,7 +358,7 @@ void straighten(SymbolShape& shape) {
|
||||
Vector2D bb = next.delta_before.normalized();
|
||||
// if the area beneath the polygon formed by the handles is small
|
||||
// then it is a straight line
|
||||
double cpDot = abs(aa.cross(ab)) + abs(bb.cross(ab));
|
||||
double cpDot = abs(cross(aa,ab)) + abs(cross(bb,ab));
|
||||
if (cpDot < treshold) {
|
||||
cur.segment_after = next.segment_before = SEGMENT_LINE;
|
||||
cur.delta_after = next.delta_before = Vector2D();
|
||||
|
||||
@@ -94,6 +94,11 @@ Vector2D& ControlPoint::getOther(WhichHandle wh) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolPart
|
||||
|
||||
void SymbolPart::calculateBounds() {
|
||||
min_pos = Vector2D::infinity();
|
||||
max_pos = -Vector2D::infinity();
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION(SymbolPart) {
|
||||
REFLECT_IF_NOT_READING {
|
||||
String type = typeName();
|
||||
@@ -235,6 +240,19 @@ SymbolPartP SymbolGroup::clone() const {
|
||||
return part;
|
||||
}
|
||||
|
||||
void SymbolGroup::calculateBounds() {
|
||||
FOR_EACH(p, parts) p->calculateBounds();
|
||||
calculateBoundsNonRec();
|
||||
}
|
||||
void SymbolGroup::calculateBoundsNonRec() {
|
||||
min_pos = Vector2D::infinity();
|
||||
max_pos = -Vector2D::infinity();
|
||||
FOR_EACH(p, parts) {
|
||||
min_pos = piecewise_min(min_pos, p->min_pos);
|
||||
max_pos = piecewise_max(max_pos, p->max_pos);
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION(SymbolGroup) {
|
||||
REFLECT_BASE(SymbolPart);
|
||||
REFLECT(parts);
|
||||
|
||||
+13
-8
@@ -112,6 +112,9 @@ class SymbolPart : public IntrusivePtrVirtualBase {
|
||||
public:
|
||||
/// Name/label for this part
|
||||
String name;
|
||||
/// Position and size of the part.
|
||||
/** this is the smallest axis aligned bounding box that fits around the part */
|
||||
Vector2D min_pos, max_pos;
|
||||
|
||||
/// Type of this part
|
||||
virtual String typeName() const = 0;
|
||||
@@ -130,6 +133,9 @@ class SymbolPart : public IntrusivePtrVirtualBase {
|
||||
virtual SymbolGroup* isSymbolGroup() { return nullptr; }
|
||||
virtual const SymbolGroup* isSymbolGroup() const { return nullptr; }
|
||||
|
||||
/// Calculate the position and size of the part (min_pos and max_pos)
|
||||
virtual void calculateBounds();
|
||||
|
||||
DECLARE_REFLECTION_VIRTUAL();
|
||||
};
|
||||
|
||||
@@ -162,9 +168,6 @@ class SymbolShape : public SymbolPart {
|
||||
SymbolShapeCombine combine;
|
||||
// Center of rotation, relative to the part, when the part is scaled to [0..1]
|
||||
Vector2D rotation_center;
|
||||
/// Position and size of the part
|
||||
/// this is the smallest axis aligned bounding box that fits around the part
|
||||
Vector2D min_pos, max_pos;
|
||||
|
||||
SymbolShape();
|
||||
|
||||
@@ -183,7 +186,7 @@ class SymbolShape : public SymbolPart {
|
||||
void enforceConstraints();
|
||||
|
||||
/// Calculate the position and size of the part
|
||||
void calculateBounds();
|
||||
virtual void calculateBounds();
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
@@ -221,7 +224,7 @@ class SymbolSymmetry : public SymbolPart {
|
||||
/// A group of symbol parts
|
||||
class SymbolGroup : public SymbolPart {
|
||||
public:
|
||||
vector<SymbolPartP> parts; ///< The parts in this group
|
||||
vector<SymbolPartP> parts; ///< The parts in this group, first item is on top
|
||||
|
||||
virtual String typeName() const;
|
||||
virtual SymbolPartP clone() const;
|
||||
@@ -229,16 +232,18 @@ class SymbolGroup : public SymbolPart {
|
||||
virtual SymbolGroup* isSymbolGroup() { return this; }
|
||||
virtual const SymbolGroup* isSymbolGroup() const { return this; }
|
||||
|
||||
virtual void calculateBounds();
|
||||
/// re-calculate the bounds, but not of the contained parts
|
||||
void calculateBoundsNonRec();
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Symbol
|
||||
|
||||
/// An editable symbol, consists of any number of SymbolParts
|
||||
class Symbol : public IntrusivePtrBase<Symbol> {
|
||||
class Symbol : public SymbolGroup {
|
||||
public:
|
||||
/// The parts of this symbol, first item is on top
|
||||
vector<SymbolPartP> parts;
|
||||
/// Actions performed on this symbol and the parts in it
|
||||
ActionStack actions;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user