mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-13 05:57:00 -04:00
Change tabs to two spaces.
This commit is contained in:
@@ -15,72 +15,72 @@
|
||||
// ----------------------------------------------------------------------------- : Symbol filtering
|
||||
|
||||
void filter_symbol(Image& symbol, const SymbolFilter& filter) {
|
||||
Byte* data = symbol.GetData();
|
||||
Byte* alpha = symbol.GetAlpha();
|
||||
UInt width = symbol.GetWidth(), height = symbol.GetHeight();
|
||||
// HACK: wxGTK seems to fail sometimes if you ask it to allocate the alpha channel.
|
||||
// This manually allocates the memory and gives it to the image to handle.
|
||||
if (!alpha) {
|
||||
alpha = (Byte*) malloc(width * height);
|
||||
symbol.SetAlpha(alpha);
|
||||
}
|
||||
for (UInt y = 0 ; y < height ; ++y) {
|
||||
for (UInt x = 0 ; x < width ; ++x) {
|
||||
// Determine set
|
||||
// green -> border or outside
|
||||
// green+red=white -> border
|
||||
if (data[0] != data[2]) {
|
||||
// yellow/blue = editing hint, leave alone
|
||||
} else {
|
||||
SymbolSet point = data[1] ? (data[0] ? SYMBOL_BORDER : SYMBOL_OUTSIDE) : SYMBOL_INSIDE;
|
||||
// Call filter
|
||||
AColor result = filter.color((double)x / width, (double)y / height, point);
|
||||
// Store color
|
||||
data[0] = result.Red();
|
||||
data[1] = result.Green();
|
||||
data[2] = result.Blue();
|
||||
alpha[0] = result.alpha;
|
||||
}
|
||||
// next
|
||||
data += 3;
|
||||
alpha += 1;
|
||||
}
|
||||
}
|
||||
Byte* data = symbol.GetData();
|
||||
Byte* alpha = symbol.GetAlpha();
|
||||
UInt width = symbol.GetWidth(), height = symbol.GetHeight();
|
||||
// HACK: wxGTK seems to fail sometimes if you ask it to allocate the alpha channel.
|
||||
// This manually allocates the memory and gives it to the image to handle.
|
||||
if (!alpha) {
|
||||
alpha = (Byte*) malloc(width * height);
|
||||
symbol.SetAlpha(alpha);
|
||||
}
|
||||
for (UInt y = 0 ; y < height ; ++y) {
|
||||
for (UInt x = 0 ; x < width ; ++x) {
|
||||
// Determine set
|
||||
// green -> border or outside
|
||||
// green+red=white -> border
|
||||
if (data[0] != data[2]) {
|
||||
// yellow/blue = editing hint, leave alone
|
||||
} else {
|
||||
SymbolSet point = data[1] ? (data[0] ? SYMBOL_BORDER : SYMBOL_OUTSIDE) : SYMBOL_INSIDE;
|
||||
// Call filter
|
||||
AColor result = filter.color((double)x / width, (double)y / height, point);
|
||||
// Store color
|
||||
data[0] = result.Red();
|
||||
data[1] = result.Green();
|
||||
data[2] = result.Blue();
|
||||
alpha[0] = result.alpha;
|
||||
}
|
||||
// next
|
||||
data += 3;
|
||||
alpha += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image render_symbol(const SymbolP& symbol, const SymbolFilter& filter, double border_radius, int width, int height, bool edit_hints, bool allow_smaller) {
|
||||
Image i = render_symbol(symbol, border_radius, width, height, edit_hints, allow_smaller);
|
||||
filter_symbol(i, filter);
|
||||
return i;
|
||||
Image i = render_symbol(symbol, border_radius, width, height, edit_hints, allow_smaller);
|
||||
filter_symbol(i, filter);
|
||||
return i;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolFilter
|
||||
|
||||
IMPLEMENT_REFLECTION_NO_SCRIPT(SymbolFilter) {
|
||||
REFLECT_IF_NOT_READING {
|
||||
String fill_type = fillType();
|
||||
REFLECT(fill_type);
|
||||
}
|
||||
REFLECT_IF_NOT_READING {
|
||||
String fill_type = fillType();
|
||||
REFLECT(fill_type);
|
||||
}
|
||||
}
|
||||
template <> void GetMember::handle(const intrusive_ptr<SymbolFilter>& f) {
|
||||
handle(*f);
|
||||
handle(*f);
|
||||
}
|
||||
|
||||
template <>
|
||||
intrusive_ptr<SymbolFilter> read_new<SymbolFilter>(Reader& reader) {
|
||||
// there must be a fill type specified
|
||||
String fill_type;
|
||||
reader.handle(_("fill type"), fill_type);
|
||||
if (fill_type == _("solid")) return intrusive(new SolidFillSymbolFilter);
|
||||
else if (fill_type == _("linear gradient")) return intrusive(new LinearGradientSymbolFilter);
|
||||
else if (fill_type == _("radial gradient")) return intrusive(new RadialGradientSymbolFilter);
|
||||
else if (fill_type.empty()) {
|
||||
reader.warning(_ERROR_1_("expected key", _("fill type")));
|
||||
throw ParseError(_ERROR_("aborting parsing"));
|
||||
} else {
|
||||
reader.warning(_ERROR_1_("unsupported fill type", fill_type));
|
||||
throw ParseError(_ERROR_("aborting parsing"));
|
||||
}
|
||||
// there must be a fill type specified
|
||||
String fill_type;
|
||||
reader.handle(_("fill type"), fill_type);
|
||||
if (fill_type == _("solid")) return intrusive(new SolidFillSymbolFilter);
|
||||
else if (fill_type == _("linear gradient")) return intrusive(new LinearGradientSymbolFilter);
|
||||
else if (fill_type == _("radial gradient")) return intrusive(new RadialGradientSymbolFilter);
|
||||
else if (fill_type.empty()) {
|
||||
reader.warning(_ERROR_1_("expected key", _("fill type")));
|
||||
throw ParseError(_ERROR_("aborting parsing"));
|
||||
} else {
|
||||
reader.warning(_ERROR_1_("unsupported fill type", fill_type));
|
||||
throw ParseError(_ERROR_("aborting parsing"));
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SolidFillSymbolFilter
|
||||
@@ -88,45 +88,45 @@ intrusive_ptr<SymbolFilter> read_new<SymbolFilter>(Reader& reader) {
|
||||
String SolidFillSymbolFilter::fillType() const { return _("solid"); }
|
||||
|
||||
AColor SolidFillSymbolFilter::color(double x, double y, SymbolSet point) const {
|
||||
if (point == SYMBOL_INSIDE) return fill_color;
|
||||
else if (point == SYMBOL_BORDER) return border_color;
|
||||
else return AColor(0,0,0,0);
|
||||
if (point == SYMBOL_INSIDE) return fill_color;
|
||||
else if (point == SYMBOL_BORDER) return border_color;
|
||||
else return AColor(0,0,0,0);
|
||||
}
|
||||
|
||||
bool SolidFillSymbolFilter::operator == (const SymbolFilter& that) const {
|
||||
const SolidFillSymbolFilter* that2 = dynamic_cast<const SolidFillSymbolFilter*>(&that);
|
||||
return that2 && fill_color == that2->fill_color
|
||||
&& border_color == that2->border_color;
|
||||
const SolidFillSymbolFilter* that2 = dynamic_cast<const SolidFillSymbolFilter*>(&that);
|
||||
return that2 && fill_color == that2->fill_color
|
||||
&& border_color == that2->border_color;
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION(SolidFillSymbolFilter) {
|
||||
REFLECT_BASE(SymbolFilter);
|
||||
REFLECT(fill_color);
|
||||
REFLECT(border_color);
|
||||
REFLECT_BASE(SymbolFilter);
|
||||
REFLECT(fill_color);
|
||||
REFLECT(border_color);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : GradientSymbolFilter
|
||||
|
||||
template <typename T>
|
||||
AColor GradientSymbolFilter::color(double x, double y, SymbolSet point, const T* t) const {
|
||||
if (point == SYMBOL_INSIDE) return lerp(fill_color_1, fill_color_2, t->t(x,y));
|
||||
else if (point == SYMBOL_BORDER) return lerp(border_color_1, border_color_2, t->t(x,y));
|
||||
else return AColor(0,0,0,0);
|
||||
if (point == SYMBOL_INSIDE) return lerp(fill_color_1, fill_color_2, t->t(x,y));
|
||||
else if (point == SYMBOL_BORDER) return lerp(border_color_1, border_color_2, t->t(x,y));
|
||||
else return AColor(0,0,0,0);
|
||||
}
|
||||
|
||||
bool GradientSymbolFilter::equal(const GradientSymbolFilter& that) const {
|
||||
return fill_color_1 == that.fill_color_1
|
||||
&& fill_color_2 == that.fill_color_2
|
||||
&& border_color_1 == that.border_color_1
|
||||
&& border_color_2 == that.border_color_2;
|
||||
return fill_color_1 == that.fill_color_1
|
||||
&& fill_color_2 == that.fill_color_2
|
||||
&& border_color_1 == that.border_color_1
|
||||
&& border_color_2 == that.border_color_2;
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION(GradientSymbolFilter) {
|
||||
REFLECT_BASE(SymbolFilter);
|
||||
REFLECT(fill_color_1);
|
||||
REFLECT(fill_color_2);
|
||||
REFLECT(border_color_1);
|
||||
REFLECT(border_color_2);
|
||||
REFLECT_BASE(SymbolFilter);
|
||||
REFLECT(fill_color_1);
|
||||
REFLECT(fill_color_2);
|
||||
REFLECT(border_color_1);
|
||||
REFLECT(border_color_2);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : LinearGradientSymbolFilter
|
||||
@@ -137,40 +137,40 @@ inline double sqr(double x) { return x * x; }
|
||||
String LinearGradientSymbolFilter::fillType() const { return _("linear gradient"); }
|
||||
|
||||
LinearGradientSymbolFilter::LinearGradientSymbolFilter()
|
||||
: center_x(0.5), center_y(0.5)
|
||||
, end_x(1), end_y(1)
|
||||
: center_x(0.5), center_y(0.5)
|
||||
, end_x(1), end_y(1)
|
||||
{}
|
||||
LinearGradientSymbolFilter::LinearGradientSymbolFilter
|
||||
( const Color& fill_color_1, const Color& border_color_1
|
||||
, const Color& fill_color_2, const Color& border_color_2
|
||||
, double center_x, double center_y, double end_x, double end_y)
|
||||
: GradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2)
|
||||
, center_x(center_x), center_y(center_y)
|
||||
, end_x(end_x), end_y(end_y)
|
||||
( const Color& fill_color_1, const Color& border_color_1
|
||||
, const Color& fill_color_2, const Color& border_color_2
|
||||
, double center_x, double center_y, double end_x, double end_y)
|
||||
: GradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2)
|
||||
, center_x(center_x), center_y(center_y)
|
||||
, end_x(end_x), end_y(end_y)
|
||||
{}
|
||||
|
||||
AColor LinearGradientSymbolFilter::color(double x, double y, SymbolSet point) const {
|
||||
len = sqr(end_x - center_x) + sqr(end_y - center_y);
|
||||
if (len == 0) len = 1; // prevent div by 0
|
||||
return GradientSymbolFilter::color(x,y,point,this);
|
||||
len = sqr(end_x - center_x) + sqr(end_y - center_y);
|
||||
if (len == 0) len = 1; // prevent div by 0
|
||||
return GradientSymbolFilter::color(x,y,point,this);
|
||||
}
|
||||
|
||||
double LinearGradientSymbolFilter::t(double x, double y) const {
|
||||
double t= fabs( (x - center_x) * (end_x - center_x) + (y - center_y) * (end_y - center_y)) / len;
|
||||
return min(1.,max(0.,t));
|
||||
double t= fabs( (x - center_x) * (end_x - center_x) + (y - center_y) * (end_y - center_y)) / len;
|
||||
return min(1.,max(0.,t));
|
||||
}
|
||||
|
||||
bool LinearGradientSymbolFilter::operator == (const SymbolFilter& that) const {
|
||||
const LinearGradientSymbolFilter* that2 = dynamic_cast<const LinearGradientSymbolFilter*>(&that);
|
||||
return that2 && equal(*that2)
|
||||
&& center_x == that2->center_x && end_x == that2->end_x
|
||||
&& center_y == that2->center_y && end_y == that2->end_y;
|
||||
const LinearGradientSymbolFilter* that2 = dynamic_cast<const LinearGradientSymbolFilter*>(&that);
|
||||
return that2 && equal(*that2)
|
||||
&& center_x == that2->center_x && end_x == that2->end_x
|
||||
&& center_y == that2->center_y && end_y == that2->end_y;
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION(LinearGradientSymbolFilter) {
|
||||
REFLECT_BASE(GradientSymbolFilter);
|
||||
REFLECT(center_x); REFLECT(center_y);
|
||||
REFLECT(end_x); REFLECT(end_y);
|
||||
REFLECT_BASE(GradientSymbolFilter);
|
||||
REFLECT(center_x); REFLECT(center_y);
|
||||
REFLECT(end_x); REFLECT(end_y);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : RadialGradientSymbolFilter
|
||||
@@ -178,14 +178,14 @@ IMPLEMENT_REFLECTION(LinearGradientSymbolFilter) {
|
||||
String RadialGradientSymbolFilter::fillType() const { return _("radial gradient"); }
|
||||
|
||||
AColor RadialGradientSymbolFilter::color(double x, double y, SymbolSet point) const {
|
||||
return GradientSymbolFilter::color(x,y,point,this);
|
||||
return GradientSymbolFilter::color(x,y,point,this);
|
||||
}
|
||||
|
||||
double RadialGradientSymbolFilter::t(double x, double y) const {
|
||||
return sqrt( (sqr(x - 0.5) + sqr(y - 0.5)) * 2);
|
||||
return sqrt( (sqr(x - 0.5) + sqr(y - 0.5)) * 2);
|
||||
}
|
||||
|
||||
bool RadialGradientSymbolFilter::operator == (const SymbolFilter& that) const {
|
||||
const RadialGradientSymbolFilter* that2 = dynamic_cast<const RadialGradientSymbolFilter*>(&that);
|
||||
return that2 && equal(*that2);
|
||||
const RadialGradientSymbolFilter* that2 = dynamic_cast<const RadialGradientSymbolFilter*>(&that);
|
||||
return that2 && equal(*that2);
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ Image render_symbol(const SymbolP& symbol, const SymbolFilter& filter, double bo
|
||||
|
||||
/// Is a point inside a symbol?
|
||||
enum SymbolSet
|
||||
{ SYMBOL_INSIDE
|
||||
, SYMBOL_BORDER
|
||||
, SYMBOL_OUTSIDE
|
||||
{ SYMBOL_INSIDE
|
||||
, SYMBOL_BORDER
|
||||
, SYMBOL_OUTSIDE
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolFilter
|
||||
@@ -39,16 +39,16 @@ enum SymbolSet
|
||||
/// Base class for symbol filters
|
||||
class SymbolFilter : public IntrusivePtrVirtualBase {
|
||||
public:
|
||||
virtual ~SymbolFilter() {}
|
||||
/// What color should the symbol have at location (x, y)?
|
||||
/** x,y are in the range [0...1) */
|
||||
virtual AColor color(double x, double y, SymbolSet point) const = 0;
|
||||
/// Name of this fill type
|
||||
virtual String fillType() const = 0;
|
||||
/// Comparision
|
||||
virtual bool operator == (const SymbolFilter& that) const = 0;
|
||||
|
||||
DECLARE_REFLECTION_VIRTUAL();
|
||||
virtual ~SymbolFilter() {}
|
||||
/// What color should the symbol have at location (x, y)?
|
||||
/** x,y are in the range [0...1) */
|
||||
virtual AColor color(double x, double y, SymbolSet point) const = 0;
|
||||
/// Name of this fill type
|
||||
virtual String fillType() const = 0;
|
||||
/// Comparision
|
||||
virtual bool operator == (const SymbolFilter& that) const = 0;
|
||||
|
||||
DECLARE_REFLECTION_VIRTUAL();
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -59,71 +59,71 @@ intrusive_ptr<SymbolFilter> read_new<SymbolFilter>(Reader& reader);
|
||||
/// Symbol filter that returns solid colors
|
||||
class SolidFillSymbolFilter : public SymbolFilter {
|
||||
public:
|
||||
inline SolidFillSymbolFilter() {}
|
||||
inline SolidFillSymbolFilter(const AColor& fill_color, const AColor& border_color)
|
||||
: fill_color(fill_color), border_color(border_color)
|
||||
{}
|
||||
virtual AColor color(double x, double y, SymbolSet point) const;
|
||||
virtual String fillType() const;
|
||||
virtual bool operator == (const SymbolFilter& that) const;
|
||||
inline SolidFillSymbolFilter() {}
|
||||
inline SolidFillSymbolFilter(const AColor& fill_color, const AColor& border_color)
|
||||
: fill_color(fill_color), border_color(border_color)
|
||||
{}
|
||||
virtual AColor color(double x, double y, SymbolSet point) const;
|
||||
virtual String fillType() const;
|
||||
virtual bool operator == (const SymbolFilter& that) const;
|
||||
private:
|
||||
AColor fill_color, border_color;
|
||||
DECLARE_REFLECTION();
|
||||
AColor fill_color, border_color;
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
/// Symbol filter that returns some gradient
|
||||
class GradientSymbolFilter : public SymbolFilter {
|
||||
public:
|
||||
inline GradientSymbolFilter() {}
|
||||
inline GradientSymbolFilter(const Color& fill_color_1, const Color& border_color_1, const Color& fill_color_2, const Color& border_color_2)
|
||||
: fill_color_1(fill_color_1), border_color_1(border_color_1)
|
||||
, fill_color_2(fill_color_2), border_color_2(border_color_2)
|
||||
{}
|
||||
inline GradientSymbolFilter() {}
|
||||
inline GradientSymbolFilter(const Color& fill_color_1, const Color& border_color_1, const Color& fill_color_2, const Color& border_color_2)
|
||||
: fill_color_1(fill_color_1), border_color_1(border_color_1)
|
||||
, fill_color_2(fill_color_2), border_color_2(border_color_2)
|
||||
{}
|
||||
protected:
|
||||
Color fill_color_1, border_color_1;
|
||||
Color fill_color_2, border_color_2;
|
||||
template <typename T>
|
||||
AColor color(double x, double y, SymbolSet point, const T* t) const;
|
||||
bool equal(const GradientSymbolFilter& that) const;
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
Color fill_color_1, border_color_1;
|
||||
Color fill_color_2, border_color_2;
|
||||
template <typename T>
|
||||
AColor color(double x, double y, SymbolSet point, const T* t) const;
|
||||
bool equal(const GradientSymbolFilter& that) const;
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
/// Symbol filter that returns a linear gradient
|
||||
class LinearGradientSymbolFilter : public GradientSymbolFilter {
|
||||
public:
|
||||
LinearGradientSymbolFilter();
|
||||
LinearGradientSymbolFilter(const Color& fill_color_1, const Color& border_color_1, const Color& fill_color_2, const Color& border_color_2
|
||||
,double center_x, double center_y, double end_x, double end_y);
|
||||
|
||||
virtual AColor color(double x, double y, SymbolSet point) const;
|
||||
virtual String fillType() const;
|
||||
virtual bool operator == (const SymbolFilter& that) const;
|
||||
|
||||
/// return time on the gradient, used by GradientSymbolFilter::color
|
||||
inline double t(double x, double y) const;
|
||||
|
||||
LinearGradientSymbolFilter();
|
||||
LinearGradientSymbolFilter(const Color& fill_color_1, const Color& border_color_1, const Color& fill_color_2, const Color& border_color_2
|
||||
,double center_x, double center_y, double end_x, double end_y);
|
||||
|
||||
virtual AColor color(double x, double y, SymbolSet point) const;
|
||||
virtual String fillType() const;
|
||||
virtual bool operator == (const SymbolFilter& that) const;
|
||||
|
||||
/// return time on the gradient, used by GradientSymbolFilter::color
|
||||
inline double t(double x, double y) const;
|
||||
|
||||
private:
|
||||
double center_x, center_y;
|
||||
double end_x, end_y;
|
||||
mutable double len;
|
||||
DECLARE_REFLECTION();
|
||||
double center_x, center_y;
|
||||
double end_x, end_y;
|
||||
mutable double len;
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
/// Symbol filter that returns a radial gradient
|
||||
class RadialGradientSymbolFilter : public GradientSymbolFilter {
|
||||
public:
|
||||
inline RadialGradientSymbolFilter() {}
|
||||
inline RadialGradientSymbolFilter(const Color& fill_color_1, const Color& border_color_1, const Color& fill_color_2, const Color& border_color_2)
|
||||
: GradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2)
|
||||
{}
|
||||
|
||||
virtual AColor color(double x, double y, SymbolSet point) const;
|
||||
virtual String fillType() const;
|
||||
virtual bool operator == (const SymbolFilter& that) const;
|
||||
|
||||
/// return time on the gradient, used by GradientSymbolFilter::color
|
||||
inline double t(double x, double y) const;
|
||||
inline RadialGradientSymbolFilter() {}
|
||||
inline RadialGradientSymbolFilter(const Color& fill_color_1, const Color& border_color_1, const Color& fill_color_2, const Color& border_color_2)
|
||||
: GradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2)
|
||||
{}
|
||||
|
||||
virtual AColor color(double x, double y, SymbolSet point) const;
|
||||
virtual String fillType() const;
|
||||
virtual bool operator == (const SymbolFilter& that) const;
|
||||
|
||||
/// return time on the gradient, used by GradientSymbolFilter::color
|
||||
inline double t(double x, double y) const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
+299
-299
@@ -16,53 +16,53 @@ DECLARE_TYPEOF_COLLECTION(SymbolPartP);
|
||||
// ----------------------------------------------------------------------------- : Simple rendering
|
||||
|
||||
Image render_symbol(const SymbolP& symbol, double border_radius, int width, int height, bool editing_hints, bool allow_smaller) {
|
||||
SymbolViewer viewer(symbol, editing_hints, width, border_radius);
|
||||
// limit width/height ratio to aspect ratio of symbol
|
||||
double ar = symbol->aspectRatio();
|
||||
double par = (double)width/height;
|
||||
if (par > ar && (ar > 1 || (allow_smaller && height < width))) {
|
||||
width = int(height * ar);
|
||||
} else if (par < ar && (ar < 1 || (allow_smaller && width < height))) {
|
||||
height = int(width / ar);
|
||||
}
|
||||
if (width > height) {
|
||||
viewer.setZoom(width);
|
||||
viewer.setOrigin(Vector2D(0,-(width-height) * 0.5));
|
||||
viewer.border_radius *= (double)height / width;
|
||||
} else {
|
||||
viewer.setZoom(height);
|
||||
viewer.setOrigin(Vector2D(-(height-width) * 0.5,0));
|
||||
viewer.border_radius *= (double)width / height;
|
||||
}
|
||||
Bitmap bmp(width, height);
|
||||
wxMemoryDC dc;
|
||||
dc.SelectObject(bmp);
|
||||
clearDC(dc, Color(0,128,0));
|
||||
viewer.draw(dc);
|
||||
dc.SelectObject(wxNullBitmap);
|
||||
return bmp.ConvertToImage();
|
||||
SymbolViewer viewer(symbol, editing_hints, width, border_radius);
|
||||
// limit width/height ratio to aspect ratio of symbol
|
||||
double ar = symbol->aspectRatio();
|
||||
double par = (double)width/height;
|
||||
if (par > ar && (ar > 1 || (allow_smaller && height < width))) {
|
||||
width = int(height * ar);
|
||||
} else if (par < ar && (ar < 1 || (allow_smaller && width < height))) {
|
||||
height = int(width / ar);
|
||||
}
|
||||
if (width > height) {
|
||||
viewer.setZoom(width);
|
||||
viewer.setOrigin(Vector2D(0,-(width-height) * 0.5));
|
||||
viewer.border_radius *= (double)height / width;
|
||||
} else {
|
||||
viewer.setZoom(height);
|
||||
viewer.setOrigin(Vector2D(-(height-width) * 0.5,0));
|
||||
viewer.border_radius *= (double)width / height;
|
||||
}
|
||||
Bitmap bmp(width, height);
|
||||
wxMemoryDC dc;
|
||||
dc.SelectObject(bmp);
|
||||
clearDC(dc, Color(0,128,0));
|
||||
viewer.draw(dc);
|
||||
dc.SelectObject(wxNullBitmap);
|
||||
return bmp.ConvertToImage();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Constructor
|
||||
|
||||
SymbolViewer::SymbolViewer(const SymbolP& symbol, bool editing_hints, double size, double border_radius)
|
||||
: border_radius(border_radius), editing_hints(editing_hints)
|
||||
, rotation(0, RealRect(0,0,size,size), size)
|
||||
, multiply(size,0,0,size)
|
||||
, origin(0,0)
|
||||
, in_symmetry(0)
|
||||
: border_radius(border_radius), editing_hints(editing_hints)
|
||||
, rotation(0, RealRect(0,0,size,size), size)
|
||||
, multiply(size,0,0,size)
|
||||
, origin(0,0)
|
||||
, in_symmetry(0)
|
||||
{
|
||||
setSymbol(symbol);
|
||||
setSymbol(symbol);
|
||||
}
|
||||
|
||||
void SymbolViewer::setZoom(double zoom) {
|
||||
rotation.setZoom(zoom);
|
||||
rotation.setOrigin(zoom * origin);
|
||||
multiply = Matrix2D(zoom,0, 0,zoom);
|
||||
rotation.setZoom(zoom);
|
||||
rotation.setOrigin(zoom * origin);
|
||||
multiply = Matrix2D(zoom,0, 0,zoom);
|
||||
}
|
||||
void SymbolViewer::setOrigin(const Vector2D& origin) {
|
||||
this->origin = origin;
|
||||
rotation.setOrigin(origin);
|
||||
this->origin = origin;
|
||||
rotation.setOrigin(origin);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Drawing : Combining
|
||||
@@ -71,185 +71,185 @@ typedef shared_ptr<wxMemoryDC> MemoryDCP;
|
||||
|
||||
// Return a temporary DC with the same size as the parameter
|
||||
MemoryDCP getTempDC(DC& dc) {
|
||||
wxSize s = dc.GetSize();
|
||||
#ifdef __WXMSW__
|
||||
Bitmap buffer(s.GetWidth(), s.GetHeight(), 1);
|
||||
#else
|
||||
Bitmap buffer(s.GetWidth(), s.GetHeight(), 24);
|
||||
#endif
|
||||
MemoryDCP newDC(new wxMemoryDC);
|
||||
newDC->SelectObject(buffer);
|
||||
clearDC(*newDC, *wxBLACK_BRUSH);
|
||||
return newDC;
|
||||
wxSize s = dc.GetSize();
|
||||
#ifdef __WXMSW__
|
||||
Bitmap buffer(s.GetWidth(), s.GetHeight(), 1);
|
||||
#else
|
||||
Bitmap buffer(s.GetWidth(), s.GetHeight(), 24);
|
||||
#endif
|
||||
MemoryDCP newDC(new wxMemoryDC);
|
||||
newDC->SelectObject(buffer);
|
||||
clearDC(*newDC, *wxBLACK_BRUSH);
|
||||
return newDC;
|
||||
}
|
||||
|
||||
// Combine the temporary DCs used in the drawing with the main dc
|
||||
void combineBuffers(DC& dc, DC* borders, DC* interior) {
|
||||
wxSize s = dc.GetSize();
|
||||
if (borders) dc.Blit(0, 0, s.GetWidth(), s.GetHeight(), borders, 0, 0, wxOR);
|
||||
if (interior) dc.Blit(0, 0, s.GetWidth(), s.GetHeight(), interior, 0, 0, wxAND_INVERT);
|
||||
wxSize s = dc.GetSize();
|
||||
if (borders) dc.Blit(0, 0, s.GetWidth(), s.GetHeight(), borders, 0, 0, wxOR);
|
||||
if (interior) dc.Blit(0, 0, s.GetWidth(), s.GetHeight(), interior, 0, 0, wxAND_INVERT);
|
||||
}
|
||||
|
||||
void SymbolViewer::draw(DC& dc) {
|
||||
bool paintedSomething = false;
|
||||
bool buffersFilled = false;
|
||||
in_symmetry = 0;
|
||||
// Temporary dcs
|
||||
MemoryDCP borderDC;
|
||||
MemoryDCP interiorDC;
|
||||
// Check if we can paint directly to the dc
|
||||
// This will fail if there are parts with combine == intersection
|
||||
FOR_EACH(p, symbol->parts) {
|
||||
if (SymbolShape* s = p->isSymbolShape()) {
|
||||
if (s->combine == SYMBOL_COMBINE_INTERSECTION) {
|
||||
paintedSomething = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Draw all parts
|
||||
combineSymbolPart(dc, *symbol, paintedSomething, buffersFilled, true, borderDC, interiorDC);
|
||||
// Output the final parts from the buffer
|
||||
if (buffersFilled) {
|
||||
combineBuffers(dc, borderDC.get(), interiorDC.get());
|
||||
}
|
||||
// Editing hints?
|
||||
if (editing_hints) {
|
||||
drawEditingHints(dc);
|
||||
}
|
||||
bool paintedSomething = false;
|
||||
bool buffersFilled = false;
|
||||
in_symmetry = 0;
|
||||
// Temporary dcs
|
||||
MemoryDCP borderDC;
|
||||
MemoryDCP interiorDC;
|
||||
// Check if we can paint directly to the dc
|
||||
// This will fail if there are parts with combine == intersection
|
||||
FOR_EACH(p, symbol->parts) {
|
||||
if (SymbolShape* s = p->isSymbolShape()) {
|
||||
if (s->combine == SYMBOL_COMBINE_INTERSECTION) {
|
||||
paintedSomething = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Draw all parts
|
||||
combineSymbolPart(dc, *symbol, paintedSomething, buffersFilled, true, borderDC, interiorDC);
|
||||
// Output the final parts from the buffer
|
||||
if (buffersFilled) {
|
||||
combineBuffers(dc, borderDC.get(), interiorDC.get());
|
||||
}
|
||||
// Editing hints?
|
||||
if (editing_hints) {
|
||||
drawEditingHints(dc);
|
||||
}
|
||||
}
|
||||
void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paintedSomething, bool& buffersFilled, bool allow_overlap, MemoryDCP& borderDC, MemoryDCP& interiorDC) {
|
||||
if (const SymbolShape* s = part.isSymbolShape()) {
|
||||
if (s->combine == SYMBOL_COMBINE_OVERLAP && buffersFilled && allow_overlap) {
|
||||
// We will be overlapping some previous parts, write them to the screen
|
||||
combineBuffers(dc, borderDC.get(), interiorDC.get());
|
||||
// Clear the buffers
|
||||
buffersFilled = false;
|
||||
paintedSomething = true;
|
||||
wxSize s = dc.GetSize();
|
||||
if (borderDC) {
|
||||
borderDC->SetBrush(*wxBLACK_BRUSH);
|
||||
borderDC->SetPen( *wxTRANSPARENT_PEN);
|
||||
borderDC->DrawRectangle(0, 0, s.GetWidth(), s.GetHeight());
|
||||
}
|
||||
interiorDC->SetBrush(*wxBLACK_BRUSH);
|
||||
interiorDC->DrawRectangle(0, 0, s.GetWidth(), s.GetHeight());
|
||||
}
|
||||
|
||||
// Paint the part itself
|
||||
if (!paintedSomething) {
|
||||
// No need to buffer
|
||||
if (!interiorDC) interiorDC = getTempDC(dc);
|
||||
combineSymbolShape(*s, dc, *interiorDC, true, false);
|
||||
buffersFilled = true;
|
||||
} else {
|
||||
if (!borderDC) borderDC = getTempDC(dc);
|
||||
if (!interiorDC) interiorDC = getTempDC(dc);
|
||||
// Draw this shape to the buffer
|
||||
combineSymbolShape(*s, *borderDC, *interiorDC, false, false);
|
||||
buffersFilled = true;
|
||||
}
|
||||
} else if (const SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
// Draw all parts, in reverse order (bottom to top), also draw rotated copies
|
||||
Radians b = 2 * s->handle.angle();
|
||||
Matrix2D old_m = multiply;
|
||||
Vector2D old_o = origin;
|
||||
int copies = s->kind == SYMMETRY_REFLECTION ? s->copies / 2 * 2 : s->copies;
|
||||
FOR_EACH_CONST_REVERSE(p, s->parts) {
|
||||
if (copies > 1) ++in_symmetry;
|
||||
for (int i = copies - 1 ; i >= 0 ; --i) {
|
||||
if (i == 0) --in_symmetry;
|
||||
if (s->clip) {
|
||||
// todo: clip
|
||||
}
|
||||
double a = i * 2 * M_PI / copies;
|
||||
if (s->kind == SYMMETRY_ROTATION || i % 2 == 0) {
|
||||
// set matrix
|
||||
// Calling:
|
||||
// - p the input point
|
||||
// - p' the output point
|
||||
// - rot our rotation matrix
|
||||
// - d out origin
|
||||
// - o the current origin (old_o)
|
||||
// - m the current matrix (old_m)
|
||||
// We want:
|
||||
// p' = ((p - d) * rot + d) * m + o
|
||||
// = (p * rot - d * rot + d) * m + o
|
||||
// = p * rot * m + (d - d * rot) * m + o
|
||||
Matrix2D rot(cos(a),-sin(a), sin(a),cos(a));
|
||||
multiply = rot * old_m;
|
||||
origin = old_o + (s->center - s->center * rot) * old_m;
|
||||
} else {
|
||||
// reflection
|
||||
// Calling angle = b
|
||||
// Matrix2D ref(cos(b),sin(b), sin(b),-cos(b));
|
||||
// Matrix2D rot(cos(a),-sin(a), sin(a),cos(a));
|
||||
//
|
||||
// ref * rot
|
||||
// [ cos b sin b ! [ cos a -sin a !
|
||||
// = ! sin b -cos b ] ! sin a cos a ]
|
||||
// = [ cos(a+b) sin(a+b) !
|
||||
// ! sin(a+b) -cos(a+b) ]
|
||||
Matrix2D rot(cos(a+b),sin(a+b), sin(a+b),-cos(a+b));
|
||||
multiply = rot * old_m;
|
||||
origin = old_o + (s->center - s->center * rot) * old_m;
|
||||
}
|
||||
// draw rotated copy
|
||||
combineSymbolPart(dc, *p, paintedSomething, buffersFilled, allow_overlap && i == copies - 1, borderDC, interiorDC);
|
||||
}
|
||||
}
|
||||
multiply = old_m;
|
||||
origin = old_o;
|
||||
if (editing_hints) {
|
||||
highlightPart(dc, *s, HIGHLIGHT_LESS);
|
||||
}
|
||||
} else if (const SymbolGroup* g = part.isSymbolGroup()) {
|
||||
// Draw all parts, in reverse order (bottom to top)
|
||||
FOR_EACH_CONST_REVERSE(p, g->parts) {
|
||||
combineSymbolPart(dc, *p, paintedSomething, buffersFilled, allow_overlap, borderDC, interiorDC);
|
||||
}
|
||||
}
|
||||
if (const SymbolShape* s = part.isSymbolShape()) {
|
||||
if (s->combine == SYMBOL_COMBINE_OVERLAP && buffersFilled && allow_overlap) {
|
||||
// We will be overlapping some previous parts, write them to the screen
|
||||
combineBuffers(dc, borderDC.get(), interiorDC.get());
|
||||
// Clear the buffers
|
||||
buffersFilled = false;
|
||||
paintedSomething = true;
|
||||
wxSize s = dc.GetSize();
|
||||
if (borderDC) {
|
||||
borderDC->SetBrush(*wxBLACK_BRUSH);
|
||||
borderDC->SetPen( *wxTRANSPARENT_PEN);
|
||||
borderDC->DrawRectangle(0, 0, s.GetWidth(), s.GetHeight());
|
||||
}
|
||||
interiorDC->SetBrush(*wxBLACK_BRUSH);
|
||||
interiorDC->DrawRectangle(0, 0, s.GetWidth(), s.GetHeight());
|
||||
}
|
||||
|
||||
// Paint the part itself
|
||||
if (!paintedSomething) {
|
||||
// No need to buffer
|
||||
if (!interiorDC) interiorDC = getTempDC(dc);
|
||||
combineSymbolShape(*s, dc, *interiorDC, true, false);
|
||||
buffersFilled = true;
|
||||
} else {
|
||||
if (!borderDC) borderDC = getTempDC(dc);
|
||||
if (!interiorDC) interiorDC = getTempDC(dc);
|
||||
// Draw this shape to the buffer
|
||||
combineSymbolShape(*s, *borderDC, *interiorDC, false, false);
|
||||
buffersFilled = true;
|
||||
}
|
||||
} else if (const SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
// Draw all parts, in reverse order (bottom to top), also draw rotated copies
|
||||
Radians b = 2 * s->handle.angle();
|
||||
Matrix2D old_m = multiply;
|
||||
Vector2D old_o = origin;
|
||||
int copies = s->kind == SYMMETRY_REFLECTION ? s->copies / 2 * 2 : s->copies;
|
||||
FOR_EACH_CONST_REVERSE(p, s->parts) {
|
||||
if (copies > 1) ++in_symmetry;
|
||||
for (int i = copies - 1 ; i >= 0 ; --i) {
|
||||
if (i == 0) --in_symmetry;
|
||||
if (s->clip) {
|
||||
// todo: clip
|
||||
}
|
||||
double a = i * 2 * M_PI / copies;
|
||||
if (s->kind == SYMMETRY_ROTATION || i % 2 == 0) {
|
||||
// set matrix
|
||||
// Calling:
|
||||
// - p the input point
|
||||
// - p' the output point
|
||||
// - rot our rotation matrix
|
||||
// - d out origin
|
||||
// - o the current origin (old_o)
|
||||
// - m the current matrix (old_m)
|
||||
// We want:
|
||||
// p' = ((p - d) * rot + d) * m + o
|
||||
// = (p * rot - d * rot + d) * m + o
|
||||
// = p * rot * m + (d - d * rot) * m + o
|
||||
Matrix2D rot(cos(a),-sin(a), sin(a),cos(a));
|
||||
multiply = rot * old_m;
|
||||
origin = old_o + (s->center - s->center * rot) * old_m;
|
||||
} else {
|
||||
// reflection
|
||||
// Calling angle = b
|
||||
// Matrix2D ref(cos(b),sin(b), sin(b),-cos(b));
|
||||
// Matrix2D rot(cos(a),-sin(a), sin(a),cos(a));
|
||||
//
|
||||
// ref * rot
|
||||
// [ cos b sin b ! [ cos a -sin a !
|
||||
// = ! sin b -cos b ] ! sin a cos a ]
|
||||
// = [ cos(a+b) sin(a+b) !
|
||||
// ! sin(a+b) -cos(a+b) ]
|
||||
Matrix2D rot(cos(a+b),sin(a+b), sin(a+b),-cos(a+b));
|
||||
multiply = rot * old_m;
|
||||
origin = old_o + (s->center - s->center * rot) * old_m;
|
||||
}
|
||||
// draw rotated copy
|
||||
combineSymbolPart(dc, *p, paintedSomething, buffersFilled, allow_overlap && i == copies - 1, borderDC, interiorDC);
|
||||
}
|
||||
}
|
||||
multiply = old_m;
|
||||
origin = old_o;
|
||||
if (editing_hints) {
|
||||
highlightPart(dc, *s, HIGHLIGHT_LESS);
|
||||
}
|
||||
} else if (const SymbolGroup* g = part.isSymbolGroup()) {
|
||||
// Draw all parts, in reverse order (bottom to top)
|
||||
FOR_EACH_CONST_REVERSE(p, g->parts) {
|
||||
combineSymbolPart(dc, *p, paintedSomething, buffersFilled, allow_overlap, borderDC, interiorDC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SymbolViewer::combineSymbolShape(const SymbolShape& shape, DC& border, DC& interior, bool directB, bool directI) {
|
||||
// what color should the interior be?
|
||||
// use black when drawing to the screen
|
||||
Byte interiorCol = directI ? 0 : 255;
|
||||
if (editing_hints && in_symmetry) {
|
||||
interiorCol = directI ? 16 : 240;
|
||||
}
|
||||
// how to draw depends on combining mode
|
||||
switch(shape.combine) {
|
||||
case SYMBOL_COMBINE_OVERLAP:
|
||||
case SYMBOL_COMBINE_MERGE: {
|
||||
drawSymbolShape(shape, &border, &interior, 255, interiorCol, directB, false);
|
||||
break;
|
||||
} case SYMBOL_COMBINE_SUBTRACT: {
|
||||
border.SetLogicalFunction(wxAND);
|
||||
drawSymbolShape(shape, &border, &interior, 0, ~interiorCol, directB, false);
|
||||
border.SetLogicalFunction(wxCOPY);
|
||||
break;
|
||||
} case SYMBOL_COMBINE_INTERSECTION: {
|
||||
MemoryDCP keepBorder = getTempDC(border);
|
||||
MemoryDCP keepInterior = getTempDC(interior);
|
||||
drawSymbolShape(shape, keepBorder.get(), keepInterior.get(), 255, 255, false, false);
|
||||
// combine the temporary dcs with the result using the AND operator
|
||||
wxSize s = border.GetSize();
|
||||
border .Blit(0, 0, s.GetWidth(), s.GetHeight(), &*keepBorder , 0, 0, wxAND);
|
||||
interior.Blit(0, 0, s.GetWidth(), s.GetHeight(), &*keepInterior, 0, 0, wxAND);
|
||||
break;
|
||||
} case SYMBOL_COMBINE_DIFFERENCE: {
|
||||
interior.SetLogicalFunction(wxXOR);
|
||||
drawSymbolShape(shape, &border, &interior, 0, interiorCol, directB, true);
|
||||
interior.SetLogicalFunction(wxCOPY);
|
||||
break;
|
||||
} case SYMBOL_COMBINE_BORDER: {
|
||||
// draw border as interior
|
||||
drawSymbolShape(shape, nullptr, &border, 0, 255, false, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// what color should the interior be?
|
||||
// use black when drawing to the screen
|
||||
Byte interiorCol = directI ? 0 : 255;
|
||||
if (editing_hints && in_symmetry) {
|
||||
interiorCol = directI ? 16 : 240;
|
||||
}
|
||||
// how to draw depends on combining mode
|
||||
switch(shape.combine) {
|
||||
case SYMBOL_COMBINE_OVERLAP:
|
||||
case SYMBOL_COMBINE_MERGE: {
|
||||
drawSymbolShape(shape, &border, &interior, 255, interiorCol, directB, false);
|
||||
break;
|
||||
} case SYMBOL_COMBINE_SUBTRACT: {
|
||||
border.SetLogicalFunction(wxAND);
|
||||
drawSymbolShape(shape, &border, &interior, 0, ~interiorCol, directB, false);
|
||||
border.SetLogicalFunction(wxCOPY);
|
||||
break;
|
||||
} case SYMBOL_COMBINE_INTERSECTION: {
|
||||
MemoryDCP keepBorder = getTempDC(border);
|
||||
MemoryDCP keepInterior = getTempDC(interior);
|
||||
drawSymbolShape(shape, keepBorder.get(), keepInterior.get(), 255, 255, false, false);
|
||||
// combine the temporary dcs with the result using the AND operator
|
||||
wxSize s = border.GetSize();
|
||||
border .Blit(0, 0, s.GetWidth(), s.GetHeight(), &*keepBorder , 0, 0, wxAND);
|
||||
interior.Blit(0, 0, s.GetWidth(), s.GetHeight(), &*keepInterior, 0, 0, wxAND);
|
||||
break;
|
||||
} case SYMBOL_COMBINE_DIFFERENCE: {
|
||||
interior.SetLogicalFunction(wxXOR);
|
||||
drawSymbolShape(shape, &border, &interior, 0, interiorCol, directB, true);
|
||||
interior.SetLogicalFunction(wxCOPY);
|
||||
break;
|
||||
} case SYMBOL_COMBINE_BORDER: {
|
||||
// draw border as interior
|
||||
drawSymbolShape(shape, nullptr, &border, 0, 255, false, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -257,121 +257,121 @@ void SymbolViewer::combineSymbolShape(const SymbolShape& shape, DC& border, DC&
|
||||
|
||||
|
||||
void SymbolViewer::drawSymbolShape(const SymbolShape& shape, DC* border, DC* interior, Byte borderCol, Byte interiorCol, bool directB, bool clear) {
|
||||
// create point list
|
||||
vector<wxPoint> points;
|
||||
size_t size = shape.points.size();
|
||||
for(size_t i = 0 ; i < size ; ++i) {
|
||||
segment_subdivide(*shape.getPoint((int)i), *shape.getPoint((int)i+1), origin, multiply, points);
|
||||
}
|
||||
// draw border
|
||||
if (border && border_radius > 0) {
|
||||
// white/black or, if directB white/green
|
||||
border->SetBrush(Color(borderCol, (directB && borderCol == 0 ? 128 : borderCol), borderCol));
|
||||
border->SetPen(wxPen(*wxWHITE, (int) rotation.trS(border_radius)));
|
||||
border->DrawPolygon((int)points.size(), &points[0]);
|
||||
// create point list
|
||||
vector<wxPoint> points;
|
||||
size_t size = shape.points.size();
|
||||
for(size_t i = 0 ; i < size ; ++i) {
|
||||
segment_subdivide(*shape.getPoint((int)i), *shape.getPoint((int)i+1), origin, multiply, points);
|
||||
}
|
||||
// draw border
|
||||
if (border && border_radius > 0) {
|
||||
// white/black or, if directB white/green
|
||||
border->SetBrush(Color(borderCol, (directB && borderCol == 0 ? 128 : borderCol), borderCol));
|
||||
border->SetPen(wxPen(*wxWHITE, (int) rotation.trS(border_radius)));
|
||||
border->DrawPolygon((int)points.size(), &points[0]);
|
||||
|
||||
if (clear) {
|
||||
border->SetPen(*wxTRANSPARENT_PEN);
|
||||
border->SetBrush(Color(0, (directB ? 128 : 0), 0));
|
||||
if (clear) {
|
||||
border->SetPen(*wxTRANSPARENT_PEN);
|
||||
border->SetBrush(Color(0, (directB ? 128 : 0), 0));
|
||||
|
||||
int func = border->GetLogicalFunction();
|
||||
border->SetLogicalFunction(wxCOPY);
|
||||
border->DrawPolygon((int)points.size(), &points[0]);
|
||||
border->SetLogicalFunction(func);
|
||||
}
|
||||
}
|
||||
// draw interior
|
||||
if (interior) {
|
||||
interior->SetBrush(Color(interiorCol,interiorCol,interiorCol));
|
||||
interior->SetPen(*wxTRANSPARENT_PEN);
|
||||
interior->DrawPolygon((int)points.size(), &points[0]);
|
||||
}
|
||||
int func = border->GetLogicalFunction();
|
||||
border->SetLogicalFunction(wxCOPY);
|
||||
border->DrawPolygon((int)points.size(), &points[0]);
|
||||
border->SetLogicalFunction(func);
|
||||
}
|
||||
}
|
||||
// draw interior
|
||||
if (interior) {
|
||||
interior->SetBrush(Color(interiorCol,interiorCol,interiorCol));
|
||||
interior->SetPen(*wxTRANSPARENT_PEN);
|
||||
interior->DrawPolygon((int)points.size(), &points[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Drawing : Highlighting
|
||||
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style) {
|
||||
if (const SymbolShape* s = part.isSymbolShape()) {
|
||||
highlightPart(dc, *s, style);
|
||||
} else if (const SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
highlightPart(dc, *s, style);
|
||||
} else if (const SymbolGroup* g = part.isSymbolGroup()) {
|
||||
highlightPart(dc, *g, style);
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
if (const SymbolShape* s = part.isSymbolShape()) {
|
||||
highlightPart(dc, *s, style);
|
||||
} else if (const SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
highlightPart(dc, *s, style);
|
||||
} else if (const SymbolGroup* g = part.isSymbolGroup()) {
|
||||
highlightPart(dc, *g, style);
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolShape& shape, HighlightStyle style) {
|
||||
if (style == HIGHLIGHT_LESS) return;
|
||||
// create point list
|
||||
vector<wxPoint> points;
|
||||
size_t size = shape.points.size();
|
||||
for(size_t i = 0 ; i < size ; ++i) {
|
||||
segment_subdivide(*shape.getPoint((int)i), *shape.getPoint((int)i+1), origin, multiply, points);
|
||||
}
|
||||
// draw
|
||||
if (style == HIGHLIGHT_BORDER) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 2));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
} else if (style == HIGHLIGHT_BORDER_DOT) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 1, wxDOT));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
} else {
|
||||
dc.SetLogicalFunction(wxOR);
|
||||
dc.SetBrush(Color(0,0,64));
|
||||
dc.SetPen (*wxTRANSPARENT_PEN);
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
if (shape.combine == SYMBOL_COMBINE_SUBTRACT || shape.combine == SYMBOL_COMBINE_BORDER) {
|
||||
dc.SetLogicalFunction(wxAND);
|
||||
dc.SetBrush(Color(191,191,255));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
}
|
||||
dc.SetLogicalFunction(wxCOPY);
|
||||
}
|
||||
if (style == HIGHLIGHT_LESS) return;
|
||||
// create point list
|
||||
vector<wxPoint> points;
|
||||
size_t size = shape.points.size();
|
||||
for(size_t i = 0 ; i < size ; ++i) {
|
||||
segment_subdivide(*shape.getPoint((int)i), *shape.getPoint((int)i+1), origin, multiply, points);
|
||||
}
|
||||
// draw
|
||||
if (style == HIGHLIGHT_BORDER) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 2));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
} else if (style == HIGHLIGHT_BORDER_DOT) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 1, wxDOT));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
} else {
|
||||
dc.SetLogicalFunction(wxOR);
|
||||
dc.SetBrush(Color(0,0,64));
|
||||
dc.SetPen (*wxTRANSPARENT_PEN);
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
if (shape.combine == SYMBOL_COMBINE_SUBTRACT || shape.combine == SYMBOL_COMBINE_BORDER) {
|
||||
dc.SetLogicalFunction(wxAND);
|
||||
dc.SetBrush(Color(191,191,255));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
}
|
||||
dc.SetLogicalFunction(wxCOPY);
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolSymmetry& sym, HighlightStyle style) {
|
||||
// highlight parts?
|
||||
FOR_EACH_CONST(part, sym.parts) {
|
||||
highlightPart(dc, *part, (HighlightStyle)(style | HIGHLIGHT_LESS));
|
||||
}
|
||||
// Color?
|
||||
Color color = style & HIGHLIGHT_BORDER ? Color(255,100,0)
|
||||
: style & HIGHLIGHT_INTERIOR ? Color(255,200,0)
|
||||
: Color(200,170,0);
|
||||
// center
|
||||
RealPoint center = rotation.tr(sym.center);
|
||||
// draw 'spokes'
|
||||
Radians angle = atan2(sym.handle.y, sym.handle.x);
|
||||
dc.SetPen(wxPen(color, sym.kind == SYMMETRY_ROTATION ? 1 : 3));
|
||||
int copies = sym.kind == SYMMETRY_REFLECTION ? sym.copies / 2 * 2 : sym.copies;
|
||||
for (int i = 0; i < copies ; ++i) {
|
||||
Radians a = angle + (i + 0.5) * 2 * M_PI / copies;
|
||||
Vector2D dir(cos(a), sin(a));
|
||||
Vector2D dir2 = rotation.tr(sym.center + 2 * dir);
|
||||
dc.DrawLine(int(center.x), int(center.y), int(dir2.x), int(dir2.y));
|
||||
}
|
||||
// draw center
|
||||
dc.SetPen(*wxBLACK_PEN);
|
||||
dc.SetBrush(color);
|
||||
dc.DrawCircle(int(center.x), int(center.y), sym.kind == SYMMETRY_ROTATION ? 7 : 5);
|
||||
// highlight parts?
|
||||
FOR_EACH_CONST(part, sym.parts) {
|
||||
highlightPart(dc, *part, (HighlightStyle)(style | HIGHLIGHT_LESS));
|
||||
}
|
||||
// Color?
|
||||
Color color = style & HIGHLIGHT_BORDER ? Color(255,100,0)
|
||||
: style & HIGHLIGHT_INTERIOR ? Color(255,200,0)
|
||||
: Color(200,170,0);
|
||||
// center
|
||||
RealPoint center = rotation.tr(sym.center);
|
||||
// draw 'spokes'
|
||||
Radians angle = atan2(sym.handle.y, sym.handle.x);
|
||||
dc.SetPen(wxPen(color, sym.kind == SYMMETRY_ROTATION ? 1 : 3));
|
||||
int copies = sym.kind == SYMMETRY_REFLECTION ? sym.copies / 2 * 2 : sym.copies;
|
||||
for (int i = 0; i < copies ; ++i) {
|
||||
Radians a = angle + (i + 0.5) * 2 * M_PI / copies;
|
||||
Vector2D dir(cos(a), sin(a));
|
||||
Vector2D dir2 = rotation.tr(sym.center + 2 * dir);
|
||||
dc.DrawLine(int(center.x), int(center.y), int(dir2.x), int(dir2.y));
|
||||
}
|
||||
// draw center
|
||||
dc.SetPen(*wxBLACK_PEN);
|
||||
dc.SetBrush(color);
|
||||
dc.DrawCircle(int(center.x), int(center.y), sym.kind == SYMMETRY_ROTATION ? 7 : 5);
|
||||
}
|
||||
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style) {
|
||||
if (style == HIGHLIGHT_BORDER) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 2));
|
||||
dc.DrawRectangle(rotation.trRectToBB(RealRect(group.bounds)));
|
||||
}
|
||||
FOR_EACH_CONST(part, group.parts) {
|
||||
highlightPart(dc, *part, (HighlightStyle)(style | HIGHLIGHT_LESS));
|
||||
}
|
||||
if (style == HIGHLIGHT_BORDER) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 2));
|
||||
dc.DrawRectangle(rotation.trRectToBB(RealRect(group.bounds)));
|
||||
}
|
||||
FOR_EACH_CONST(part, group.parts) {
|
||||
highlightPart(dc, *part, (HighlightStyle)(style | HIGHLIGHT_LESS));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SymbolViewer::drawEditingHints(DC& dc) {
|
||||
// TODO?
|
||||
// TODO?
|
||||
}
|
||||
|
||||
@@ -22,79 +22,79 @@ Image render_symbol(const SymbolP& symbol, double border_radius = 0.05, int widt
|
||||
// ----------------------------------------------------------------------------- : Symbol Viewer
|
||||
|
||||
enum HighlightStyle
|
||||
{ HIGHLIGHT_BORDER = 0x01
|
||||
, HIGHLIGHT_INTERIOR = 0x02
|
||||
, HIGHLIGHT_LESS = 0x10
|
||||
, HIGHLIGHT_BORDER_DOT = HIGHLIGHT_BORDER | HIGHLIGHT_LESS
|
||||
{ HIGHLIGHT_BORDER = 0x01
|
||||
, HIGHLIGHT_INTERIOR = 0x02
|
||||
, HIGHLIGHT_LESS = 0x10
|
||||
, HIGHLIGHT_BORDER_DOT = HIGHLIGHT_BORDER | HIGHLIGHT_LESS
|
||||
};
|
||||
|
||||
/// Class that knows how to draw a symbol
|
||||
class SymbolViewer : public SymbolView {
|
||||
public:
|
||||
// --------------------------------------------------- : Data
|
||||
SymbolViewer(const SymbolP& symbol, bool editing_hints, double size = 500, double border_radius = 0.05);
|
||||
|
||||
// drawing
|
||||
double border_radius;
|
||||
bool editing_hints;
|
||||
|
||||
// --------------------------------------------------- : Point translation
|
||||
|
||||
void setZoom(double zoom);
|
||||
void setOrigin(const Vector2D& origin);
|
||||
|
||||
Rotation rotation; ///< Object that handles rotation, scaling and translation
|
||||
Matrix2D multiply; ///< Scaling/rotation of actual parts
|
||||
Vector2D origin; ///< Origin of parts
|
||||
|
||||
// --------------------------------------------------- : Drawing
|
||||
|
||||
/// Draw the symbol to a dc
|
||||
void draw(DC& dc);
|
||||
|
||||
void highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolShape& shape, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolSymmetry& sym, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style);
|
||||
|
||||
void drawEditingHints(DC& dc);
|
||||
|
||||
void onAction(const Action&, bool) {}
|
||||
|
||||
|
||||
// --------------------------------------------------- : Data
|
||||
SymbolViewer(const SymbolP& symbol, bool editing_hints, double size = 500, double border_radius = 0.05);
|
||||
|
||||
// drawing
|
||||
double border_radius;
|
||||
bool editing_hints;
|
||||
|
||||
// --------------------------------------------------- : Point translation
|
||||
|
||||
void setZoom(double zoom);
|
||||
void setOrigin(const Vector2D& origin);
|
||||
|
||||
Rotation rotation; ///< Object that handles rotation, scaling and translation
|
||||
Matrix2D multiply; ///< Scaling/rotation of actual parts
|
||||
Vector2D origin; ///< Origin of parts
|
||||
|
||||
// --------------------------------------------------- : Drawing
|
||||
|
||||
/// Draw the symbol to a dc
|
||||
void draw(DC& dc);
|
||||
|
||||
void highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolShape& shape, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolSymmetry& sym, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style);
|
||||
|
||||
void drawEditingHints(DC& dc);
|
||||
|
||||
void onAction(const Action&, bool) {}
|
||||
|
||||
|
||||
private:
|
||||
typedef shared_ptr<wxMemoryDC> MemoryDCP;
|
||||
/// Inside a reflection?
|
||||
int in_symmetry;
|
||||
|
||||
/// Combine a symbol part with the dc
|
||||
void combineSymbolPart(DC& dc, const SymbolPart& part, bool& paintedSomething, bool& buffersFilled, bool allow_overlap, MemoryDCP& borderDC, MemoryDCP& interiorDC);
|
||||
|
||||
/// Combines a symbol part with what is currently drawn, the border and interior are drawn separatly
|
||||
/** directB/directI are true if the border/interior is the screen dc, false if it
|
||||
* is a temporary 1 bit one
|
||||
*/
|
||||
void combineSymbolShape(const SymbolShape& part, DC& border, DC& interior, bool directB, bool directI);
|
||||
|
||||
/// Draw a symbol part, draws the border and the interior to separate DCs
|
||||
/** The DCs may be null. directB should be true when drawing the border directly to the screen.
|
||||
* The **Col parameters give the color to use for the (interior of) the border and the interior
|
||||
* default should be white (255) border and black (0) interior.
|
||||
*/
|
||||
void drawSymbolShape(const SymbolShape& shape, DC* border, DC* interior, unsigned char borderCol, unsigned char interiorCol, bool directB, bool oppB);
|
||||
/*
|
||||
// ------------------- Bezier curve calculation
|
||||
|
||||
// Calculate the points on a bezier curve between p0 and p1
|
||||
// Stores the Points in p_out, at most count points are stored
|
||||
// after this call p_out points to just beyond the last point
|
||||
void calcBezierPoint(const ControlPointP& p0, const ControlPointP& p1, wxPoint*& p_out, UInt count);
|
||||
|
||||
// Subdivide a bezier curve by adding at most count points
|
||||
// p0 = c(t0), p1 = c(p1)
|
||||
// subdivides linearly between t0 and t1, and only when necessary
|
||||
// adds points to p_out and increments the pointer when a point is added
|
||||
void calcBezierOpt(const BezierCurve& c, const Vector2D& p0, const Vector2D& p1, double t0, double t1, wxPoint*& p_out, UInt count);
|
||||
typedef shared_ptr<wxMemoryDC> MemoryDCP;
|
||||
/// Inside a reflection?
|
||||
int in_symmetry;
|
||||
|
||||
/// Combine a symbol part with the dc
|
||||
void combineSymbolPart(DC& dc, const SymbolPart& part, bool& paintedSomething, bool& buffersFilled, bool allow_overlap, MemoryDCP& borderDC, MemoryDCP& interiorDC);
|
||||
|
||||
/// Combines a symbol part with what is currently drawn, the border and interior are drawn separatly
|
||||
/** directB/directI are true if the border/interior is the screen dc, false if it
|
||||
* is a temporary 1 bit one
|
||||
*/
|
||||
void combineSymbolShape(const SymbolShape& part, DC& border, DC& interior, bool directB, bool directI);
|
||||
|
||||
/// Draw a symbol part, draws the border and the interior to separate DCs
|
||||
/** The DCs may be null. directB should be true when drawing the border directly to the screen.
|
||||
* The **Col parameters give the color to use for the (interior of) the border and the interior
|
||||
* default should be white (255) border and black (0) interior.
|
||||
*/
|
||||
void drawSymbolShape(const SymbolShape& shape, DC* border, DC* interior, unsigned char borderCol, unsigned char interiorCol, bool directB, bool oppB);
|
||||
/*
|
||||
// ------------------- Bezier curve calculation
|
||||
|
||||
// Calculate the points on a bezier curve between p0 and p1
|
||||
// Stores the Points in p_out, at most count points are stored
|
||||
// after this call p_out points to just beyond the last point
|
||||
void calcBezierPoint(const ControlPointP& p0, const ControlPointP& p1, wxPoint*& p_out, UInt count);
|
||||
|
||||
// Subdivide a bezier curve by adding at most count points
|
||||
// p0 = c(t0), p1 = c(p1)
|
||||
// subdivides linearly between t0 and t1, and only when necessary
|
||||
// adds points to p_out and increments the pointer when a point is added
|
||||
void calcBezierOpt(const BezierCurve& c, const Vector2D& p0, const Vector2D& p1, double t0, double t1, wxPoint*& p_out, UInt count);
|
||||
*/};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
Reference in New Issue
Block a user