Transformable.cpp revision 750958b8
174994d13SStephan Aßmus/*
274994d13SStephan Aßmus * Copyright 2005, Stephan A��mus <superstippi@gmx.de>. All rights reserved.
374994d13SStephan Aßmus * Distributed under the terms of the MIT License.
474994d13SStephan Aßmus *
574994d13SStephan Aßmus * A handy front-end to agg::trans_affine transformation matrix.
674994d13SStephan Aßmus *
774994d13SStephan Aßmus */
84569b90dSStephan Aßmus
94569b90dSStephan Aßmus#include <stdio.h>
104569b90dSStephan Aßmus#include <string.h>
114569b90dSStephan Aßmus
124569b90dSStephan Aßmus#include <Message.h>
134569b90dSStephan Aßmus
144569b90dSStephan Aßmus#include "Transformable.h"
154569b90dSStephan Aßmus
164569b90dSStephan Aßmus// min4
174569b90dSStephan Aßmusinline float
184569b90dSStephan Aßmusmin4(float a, float b, float c, float d)
194569b90dSStephan Aßmus{
204569b90dSStephan Aßmus	return min_c(a, min_c(b, min_c(c, d)));
214569b90dSStephan Aßmus}
224569b90dSStephan Aßmus
234569b90dSStephan Aßmus// max4
244569b90dSStephan Aßmusinline float
254569b90dSStephan Aßmusmax4(float a, float b, float c, float d)
264569b90dSStephan Aßmus{
274569b90dSStephan Aßmus	return max_c(a, max_c(b, max_c(c, d)));
284569b90dSStephan Aßmus}
294569b90dSStephan Aßmus
304569b90dSStephan Aßmus// constructor
314569b90dSStephan AßmusTransformable::Transformable()
324569b90dSStephan Aßmus	: agg::trans_affine()
334569b90dSStephan Aßmus{
344569b90dSStephan Aßmus}
354569b90dSStephan Aßmus
364569b90dSStephan Aßmus// copy constructor
374569b90dSStephan AßmusTransformable::Transformable(const Transformable& other)
384569b90dSStephan Aßmus	: agg::trans_affine(other)
394569b90dSStephan Aßmus{
404569b90dSStephan Aßmus}
414569b90dSStephan Aßmus
424569b90dSStephan Aßmus// constructor
434569b90dSStephan AßmusTransformable::Transformable(const BMessage* archive)
444569b90dSStephan Aßmus	: agg::trans_affine()
454569b90dSStephan Aßmus{
464569b90dSStephan Aßmus	if (archive) {
474569b90dSStephan Aßmus		double storage[6];
484569b90dSStephan Aßmus		status_t ret = B_OK;
494569b90dSStephan Aßmus		for (int32 i = 0; i < 6; i++) {
504569b90dSStephan Aßmus			ret = archive->FindDouble("affine matrix", i, &storage[i]);
514569b90dSStephan Aßmus			if (ret < B_OK)
524569b90dSStephan Aßmus				break;
534569b90dSStephan Aßmus		}
544569b90dSStephan Aßmus		if (ret >= B_OK)
554569b90dSStephan Aßmus			load_from(storage);
564569b90dSStephan Aßmus	}
574569b90dSStephan Aßmus}
584569b90dSStephan Aßmus
594569b90dSStephan Aßmus// destructor
604569b90dSStephan AßmusTransformable::~Transformable()
614569b90dSStephan Aßmus{
624569b90dSStephan Aßmus}
634569b90dSStephan Aßmus
644569b90dSStephan Aßmus// Archive
654569b90dSStephan Aßmusstatus_t
664569b90dSStephan AßmusTransformable::Archive(BMessage* into, bool deep) const
674569b90dSStephan Aßmus{
684569b90dSStephan Aßmus	status_t ret = BArchivable::Archive(into, deep);
694569b90dSStephan Aßmus	if (ret >= B_OK) {
704569b90dSStephan Aßmus		double storage[6];
714569b90dSStephan Aßmus		store_to(storage);
724569b90dSStephan Aßmus		for (int32 i = 0; i < 6; i++) {
734569b90dSStephan Aßmus			ret = into->AddDouble("affine matrix", storage[i]);
744569b90dSStephan Aßmus			if (ret < B_OK)
754569b90dSStephan Aßmus				break;
764569b90dSStephan Aßmus		}
774569b90dSStephan Aßmus		// finish off
784569b90dSStephan Aßmus		if (ret >= B_OK)
794569b90dSStephan Aßmus			ret = into->AddString("class", "Transformable");
804569b90dSStephan Aßmus	}
814569b90dSStephan Aßmus	return ret;
824569b90dSStephan Aßmus}
834569b90dSStephan Aßmus
844569b90dSStephan Aßmus// StoreTo
854569b90dSStephan Aßmusvoid
864569b90dSStephan AßmusTransformable::StoreTo(double matrix[6]) const
874569b90dSStephan Aßmus{
884569b90dSStephan Aßmus	store_to(matrix);
894569b90dSStephan Aßmus}
904569b90dSStephan Aßmus
914569b90dSStephan Aßmus// LoadFrom
924569b90dSStephan Aßmusvoid
934569b90dSStephan AßmusTransformable::LoadFrom(double matrix[6])
944569b90dSStephan Aßmus{
954569b90dSStephan Aßmus	// before calling the potentially heavy TransformationChanged()
964569b90dSStephan Aßmus	// hook function, we make sure that it is actually true
974569b90dSStephan Aßmus	Transformable t;
984569b90dSStephan Aßmus	t.load_from(matrix);
994569b90dSStephan Aßmus	if (*this != t) {
1004569b90dSStephan Aßmus		load_from(matrix);
1014569b90dSStephan Aßmus		TransformationChanged();
1024569b90dSStephan Aßmus	}
1034569b90dSStephan Aßmus}
1044569b90dSStephan Aßmus
1054569b90dSStephan Aßmus// SetTransformable
1064569b90dSStephan Aßmusvoid
1074569b90dSStephan AßmusTransformable::SetTransformable(const Transformable& other)
1084569b90dSStephan Aßmus{
1094569b90dSStephan Aßmus	if (*this != other) {
1104569b90dSStephan Aßmus		*this = other;
1114569b90dSStephan Aßmus		TransformationChanged();
1124569b90dSStephan Aßmus	}
1134569b90dSStephan Aßmus}
1144569b90dSStephan Aßmus
1154569b90dSStephan Aßmus// operator=
1164569b90dSStephan AßmusTransformable&
1174569b90dSStephan AßmusTransformable::operator=(const Transformable& other)
1184569b90dSStephan Aßmus{
1194569b90dSStephan Aßmus	if (other != *this) {
1204569b90dSStephan Aßmus		reset();
1214569b90dSStephan Aßmus		multiply(other);
1224569b90dSStephan Aßmus		TransformationChanged();
1234569b90dSStephan Aßmus	}
1244569b90dSStephan Aßmus	return *this;
1254569b90dSStephan Aßmus}
1264569b90dSStephan Aßmus
1274569b90dSStephan Aßmus// Multiply
1284569b90dSStephan AßmusTransformable&
1294569b90dSStephan AßmusTransformable::Multiply(const Transformable& other)
1304569b90dSStephan Aßmus{
1314569b90dSStephan Aßmus	if (!other.IsIdentity()) {
1324569b90dSStephan Aßmus		multiply(other);
1334569b90dSStephan Aßmus		TransformationChanged();
1344569b90dSStephan Aßmus	}
1354569b90dSStephan Aßmus	return *this;
1364569b90dSStephan Aßmus}
1374569b90dSStephan Aßmus
1384569b90dSStephan Aßmus// Reset
1394569b90dSStephan Aßmusvoid
1404569b90dSStephan AßmusTransformable::Reset()
1414569b90dSStephan Aßmus{
1424569b90dSStephan Aßmus	reset();
1434569b90dSStephan Aßmus}
1444569b90dSStephan Aßmus
1454569b90dSStephan Aßmus// IsIdentity
1464569b90dSStephan Aßmusbool
1474569b90dSStephan AßmusTransformable::IsIdentity() const
1484569b90dSStephan Aßmus{
1494569b90dSStephan Aßmus	double m[6];
1504569b90dSStephan Aßmus	store_to(m);
1514569b90dSStephan Aßmus	if (m[0] == 1.0 &&
1524569b90dSStephan Aßmus		m[1] == 0.0 &&
1534569b90dSStephan Aßmus		m[2] == 0.0 &&
1544569b90dSStephan Aßmus		m[3] == 1.0 &&
1554569b90dSStephan Aßmus		m[4] == 0.0 &&
1564569b90dSStephan Aßmus		m[5] == 0.0)
1574569b90dSStephan Aßmus		return true;
1584569b90dSStephan Aßmus	return false;
1594569b90dSStephan Aßmus}
1604569b90dSStephan Aßmus
1614569b90dSStephan Aßmus// operator==
1624569b90dSStephan Aßmusbool
1634569b90dSStephan AßmusTransformable::operator==(const Transformable& other) const
1644569b90dSStephan Aßmus{
1654569b90dSStephan Aßmus	double m1[6];
1664569b90dSStephan Aßmus	other.store_to(m1);
1674569b90dSStephan Aßmus	double m2[6];
1684569b90dSStephan Aßmus	store_to(m2);
1694569b90dSStephan Aßmus	if (m1[0] == m2[0] &&
1704569b90dSStephan Aßmus		m1[1] == m2[1] &&
1714569b90dSStephan Aßmus		m1[2] == m2[2] &&
1724569b90dSStephan Aßmus		m1[3] == m2[3] &&
1734569b90dSStephan Aßmus		m1[4] == m2[4] &&
1744569b90dSStephan Aßmus		m1[5] == m2[5])
1754569b90dSStephan Aßmus		return true;
1764569b90dSStephan Aßmus	return false;
1774569b90dSStephan Aßmus}
1784569b90dSStephan Aßmus
1794569b90dSStephan Aßmus// operator!=
1804569b90dSStephan Aßmusbool
1814569b90dSStephan AßmusTransformable::operator!=(const Transformable& other) const
1824569b90dSStephan Aßmus{
1834569b90dSStephan Aßmus	return !(*this == other);
1844569b90dSStephan Aßmus}
1854569b90dSStephan Aßmus
1864569b90dSStephan Aßmus// Transform
1874569b90dSStephan Aßmusvoid
1884569b90dSStephan AßmusTransformable::Transform(double* x, double* y) const
1894569b90dSStephan Aßmus{
1904569b90dSStephan Aßmus	transform(x, y);
1914569b90dSStephan Aßmus}
1924569b90dSStephan Aßmus
1934569b90dSStephan Aßmus// Transform
1944569b90dSStephan Aßmusvoid
1954569b90dSStephan AßmusTransformable::Transform(BPoint* point) const
1964569b90dSStephan Aßmus{
1974569b90dSStephan Aßmus	if (point) {
1984569b90dSStephan Aßmus		double x = point->x;
1994569b90dSStephan Aßmus		double y = point->y;
2004569b90dSStephan Aßmus
2014569b90dSStephan Aßmus		transform(&x, &y);
2024569b90dSStephan Aßmus
2034569b90dSStephan Aßmus		point->x = x;
2044569b90dSStephan Aßmus		point->y = y;
2054569b90dSStephan Aßmus	}
2064569b90dSStephan Aßmus}
2074569b90dSStephan Aßmus
2084569b90dSStephan Aßmus// Transform
2094569b90dSStephan AßmusBPoint
2104569b90dSStephan AßmusTransformable::Transform(const BPoint& point) const
2114569b90dSStephan Aßmus{
2124569b90dSStephan Aßmus	BPoint p(point);
2134569b90dSStephan Aßmus	Transform(&p);
2144569b90dSStephan Aßmus	return p;
2154569b90dSStephan Aßmus}
2164569b90dSStephan Aßmus
2174569b90dSStephan Aßmus// InverseTransform
2184569b90dSStephan Aßmusvoid
2194569b90dSStephan AßmusTransformable::InverseTransform(double* x, double* y) const
2204569b90dSStephan Aßmus{
2214569b90dSStephan Aßmus	inverse_transform(x, y);
2224569b90dSStephan Aßmus}
2234569b90dSStephan Aßmus
2244569b90dSStephan Aßmus// InverseTransform
2254569b90dSStephan Aßmusvoid
2264569b90dSStephan AßmusTransformable::InverseTransform(BPoint* point) const
2274569b90dSStephan Aßmus{
2284569b90dSStephan Aßmus	if (point) {
2294569b90dSStephan Aßmus		double x = point->x;
2304569b90dSStephan Aßmus		double y = point->y;
2314569b90dSStephan Aßmus
2324569b90dSStephan Aßmus		inverse_transform(&x, &y);
2334569b90dSStephan Aßmus
2344569b90dSStephan Aßmus		point->x = x;
2354569b90dSStephan Aßmus		point->y = y;
2364569b90dSStephan Aßmus	}
2374569b90dSStephan Aßmus}
2384569b90dSStephan Aßmus
2394569b90dSStephan Aßmus// InverseTransform
2404569b90dSStephan AßmusBPoint
2414569b90dSStephan AßmusTransformable::InverseTransform(const BPoint& point) const
2424569b90dSStephan Aßmus{
2434569b90dSStephan Aßmus	BPoint p(point);
2444569b90dSStephan Aßmus	InverseTransform(&p);
2454569b90dSStephan Aßmus	return p;
2464569b90dSStephan Aßmus}
2474569b90dSStephan Aßmus
2484569b90dSStephan Aßmus// TransformBounds
2494569b90dSStephan AßmusBRect
2504389b702SStephan AßmusTransformable::TransformBounds(const BRect& bounds) const
2514569b90dSStephan Aßmus{
2524569b90dSStephan Aßmus	if (bounds.IsValid()) {
2534569b90dSStephan Aßmus		BPoint lt(bounds.left, bounds.top);
2544569b90dSStephan Aßmus		BPoint rt(bounds.right, bounds.top);
2554569b90dSStephan Aßmus		BPoint lb(bounds.left, bounds.bottom);
2564569b90dSStephan Aßmus		BPoint rb(bounds.right, bounds.bottom);
2574569b90dSStephan Aßmus
2584569b90dSStephan Aßmus		Transform(&lt);
2594569b90dSStephan Aßmus		Transform(&rt);
2604569b90dSStephan Aßmus		Transform(&lb);
2614569b90dSStephan Aßmus		Transform(&rb);
2624569b90dSStephan Aßmus
2634569b90dSStephan Aßmus		return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)),
2644569b90dSStephan Aßmus					 floorf(min4(lt.y, rt.y, lb.y, rb.y)),
2654569b90dSStephan Aßmus					 ceilf(max4(lt.x, rt.x, lb.x, rb.x)),
2664569b90dSStephan Aßmus					 ceilf(max4(lt.y, rt.y, lb.y, rb.y)));
2674569b90dSStephan Aßmus	}
2684569b90dSStephan Aßmus	return bounds;
2694569b90dSStephan Aßmus}
2704569b90dSStephan Aßmus
271750958b8SStephan Aßmus
272750958b8SStephan Aßmusbool
273750958b8SStephan AßmusTransformable::IsTranslationOnly() const
274750958b8SStephan Aßmus{
275750958b8SStephan Aßmus	double matrix[6];
276750958b8SStephan Aßmus	store_to(matrix);
277750958b8SStephan Aßmus	return matrix[0] == 1.0 && matrix[1] == 0.0
278750958b8SStephan Aßmus		&& matrix[2] == 0.0 && matrix[3] == 1.0;
279750958b8SStephan Aßmus}
280750958b8SStephan Aßmus
281750958b8SStephan Aßmus
2824569b90dSStephan Aßmus// TranslateBy
2834569b90dSStephan Aßmusvoid
2844569b90dSStephan AßmusTransformable::TranslateBy(BPoint offset)
2854569b90dSStephan Aßmus{
2864569b90dSStephan Aßmus	if (offset.x != 0.0 || offset.y != 0.0) {
2874569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(offset.x, offset.y));
2884569b90dSStephan Aßmus		TransformationChanged();
2894569b90dSStephan Aßmus	}
2904569b90dSStephan Aßmus}
2914569b90dSStephan Aßmus
2924569b90dSStephan Aßmus// RotateBy
2934569b90dSStephan Aßmusvoid
294a37ea917SJérôme DuvalTransformable::RotateBy(BPoint origin, double radians)
2954569b90dSStephan Aßmus{
296a37ea917SJérôme Duval	if (radians != 0.0) {
2974569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
298a37ea917SJérôme Duval		multiply(agg::trans_affine_rotation(radians));
2994569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(origin.x, origin.y));
3004569b90dSStephan Aßmus		TransformationChanged();
3014569b90dSStephan Aßmus	}
3024569b90dSStephan Aßmus}
3034569b90dSStephan Aßmus
3044569b90dSStephan Aßmus// ScaleBy
3054569b90dSStephan Aßmusvoid
3064569b90dSStephan AßmusTransformable::ScaleBy(BPoint origin, double xScale, double yScale)
3074569b90dSStephan Aßmus{
3084569b90dSStephan Aßmus	if (xScale != 1.0 || yScale != 1.0) {
3094569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
3104569b90dSStephan Aßmus		multiply(agg::trans_affine_scaling(xScale, yScale));
3114569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(origin.x, origin.y));
3124569b90dSStephan Aßmus		TransformationChanged();
3134569b90dSStephan Aßmus	}
3144569b90dSStephan Aßmus}
3154569b90dSStephan Aßmus
3164569b90dSStephan Aßmus// ShearBy
3174569b90dSStephan Aßmusvoid
3184569b90dSStephan AßmusTransformable::ShearBy(BPoint origin, double xShear, double yShear)
3194569b90dSStephan Aßmus{
3204569b90dSStephan Aßmus	if (xShear != 0.0 || yShear != 0.0) {
3214569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
3224569b90dSStephan Aßmus		multiply(agg::trans_affine_skewing(xShear, yShear));
3234569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(origin.x, origin.y));
3244569b90dSStephan Aßmus		TransformationChanged();
3254569b90dSStephan Aßmus	}
3264569b90dSStephan Aßmus}
327