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
1613e393dfSStephan Aßmus
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
2313e393dfSStephan Aßmus
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
3013e393dfSStephan Aßmus
314569b90dSStephan AßmusTransformable::Transformable()
324569b90dSStephan Aßmus	: agg::trans_affine()
334569b90dSStephan Aßmus{
344569b90dSStephan Aßmus}
354569b90dSStephan Aßmus
3613e393dfSStephan Aßmus
374569b90dSStephan AßmusTransformable::Transformable(const Transformable& other)
384569b90dSStephan Aßmus	: agg::trans_affine(other)
394569b90dSStephan Aßmus{
404569b90dSStephan Aßmus}
414569b90dSStephan Aßmus
4213e393dfSStephan Aßmus
434569b90dSStephan AßmusTransformable::Transformable(const BMessage* archive)
444569b90dSStephan Aßmus	: agg::trans_affine()
454569b90dSStephan Aßmus{
4613e393dfSStephan Aßmus	if (archive != NULL) {
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
5913e393dfSStephan Aßmus
604569b90dSStephan AßmusTransformable::~Transformable()
614569b90dSStephan Aßmus{
624569b90dSStephan Aßmus}
634569b90dSStephan Aßmus
6413e393dfSStephan Aßmus
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);
6913e393dfSStephan 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
7813e393dfSStephan 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
8413e393dfSStephan Aßmus
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
9113e393dfSStephan Aßmus
924569b90dSStephan Aßmusvoid
934569b90dSStephan AßmusTransformable::LoadFrom(double matrix[6])
944569b90dSStephan Aßmus{
9513e393dfSStephan 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
10513e393dfSStephan Aßmus
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
11513e393dfSStephan Aßmus
1164569b90dSStephan AßmusTransformable&
1174569b90dSStephan AßmusTransformable::operator=(const Transformable& other)
1184569b90dSStephan Aßmus{
1194569b90dSStephan Aßmus	if (other != *this) {
12013e393dfSStephan Aßmus		agg::trans_affine::operator=(other);
12113e393dfSStephan Aßmus		TransformationChanged();
12213e393dfSStephan Aßmus	}
12313e393dfSStephan Aßmus	return *this;
12413e393dfSStephan Aßmus}
12513e393dfSStephan Aßmus
12613e393dfSStephan Aßmus
12713e393dfSStephan AßmusTransformable&
12813e393dfSStephan AßmusTransformable::operator=(const agg::trans_affine& other)
12913e393dfSStephan Aßmus{
13013e393dfSStephan Aßmus	if (other != *this) {
13113e393dfSStephan Aßmus		agg::trans_affine::operator=(other);
1324569b90dSStephan Aßmus		TransformationChanged();
1334569b90dSStephan Aßmus	}
1344569b90dSStephan Aßmus	return *this;
1354569b90dSStephan Aßmus}
1364569b90dSStephan Aßmus
13713e393dfSStephan Aßmus
1384569b90dSStephan AßmusTransformable&
1394569b90dSStephan AßmusTransformable::Multiply(const Transformable& other)
1404569b90dSStephan Aßmus{
1414569b90dSStephan Aßmus	if (!other.IsIdentity()) {
1424569b90dSStephan Aßmus		multiply(other);
1434569b90dSStephan Aßmus		TransformationChanged();
1444569b90dSStephan Aßmus	}
1454569b90dSStephan Aßmus	return *this;
1464569b90dSStephan Aßmus}
1474569b90dSStephan Aßmus
14813e393dfSStephan Aßmus
1494569b90dSStephan Aßmusvoid
1504569b90dSStephan AßmusTransformable::Reset()
1514569b90dSStephan Aßmus{
1524569b90dSStephan Aßmus	reset();
1534569b90dSStephan Aßmus}
1544569b90dSStephan Aßmus
15513e393dfSStephan Aßmus
1564569b90dSStephan Aßmusbool
1574569b90dSStephan AßmusTransformable::IsIdentity() const
1584569b90dSStephan Aßmus{
1594569b90dSStephan Aßmus	double m[6];
1604569b90dSStephan Aßmus	store_to(m);
1614569b90dSStephan Aßmus	if (m[0] == 1.0 &&
1624569b90dSStephan Aßmus		m[1] == 0.0 &&
1634569b90dSStephan Aßmus		m[2] == 0.0 &&
1644569b90dSStephan Aßmus		m[3] == 1.0 &&
1654569b90dSStephan Aßmus		m[4] == 0.0 &&
1664569b90dSStephan Aßmus		m[5] == 0.0)
1674569b90dSStephan Aßmus		return true;
1684569b90dSStephan Aßmus	return false;
1694569b90dSStephan Aßmus}
1704569b90dSStephan Aßmus
1714569b90dSStephan Aßmus
17208135223SJulian Harnathbool
17308135223SJulian HarnathTransformable::IsDilation() const
17408135223SJulian Harnath{
17508135223SJulian Harnath	double m[6];
17608135223SJulian Harnath	store_to(m);
17708135223SJulian Harnath	return m[1] == 0.0 && m[2] == 0.0;
17808135223SJulian Harnath}
17908135223SJulian Harnath
18008135223SJulian Harnath
1814569b90dSStephan Aßmusvoid
1824569b90dSStephan AßmusTransformable::Transform(double* x, double* y) const
1834569b90dSStephan Aßmus{
1844569b90dSStephan Aßmus	transform(x, y);
1854569b90dSStephan Aßmus}
1864569b90dSStephan Aßmus
18713e393dfSStephan Aßmus
1884569b90dSStephan Aßmusvoid
1894569b90dSStephan AßmusTransformable::Transform(BPoint* point) const
1904569b90dSStephan Aßmus{
1914569b90dSStephan Aßmus	if (point) {
1924569b90dSStephan Aßmus		double x = point->x;
1934569b90dSStephan Aßmus		double y = point->y;
1944569b90dSStephan Aßmus
1954569b90dSStephan Aßmus		transform(&x, &y);
1964569b90dSStephan Aßmus
1974569b90dSStephan Aßmus		point->x = x;
1984569b90dSStephan Aßmus		point->y = y;
1994569b90dSStephan Aßmus	}
2004569b90dSStephan Aßmus}
2014569b90dSStephan Aßmus
20213e393dfSStephan Aßmus
2034569b90dSStephan AßmusBPoint
2044569b90dSStephan AßmusTransformable::Transform(const BPoint& point) const
2054569b90dSStephan Aßmus{
2064569b90dSStephan Aßmus	BPoint p(point);
2074569b90dSStephan Aßmus	Transform(&p);
2084569b90dSStephan Aßmus	return p;
2094569b90dSStephan Aßmus}
2104569b90dSStephan Aßmus
21113e393dfSStephan Aßmus
2124569b90dSStephan Aßmusvoid
2134569b90dSStephan AßmusTransformable::InverseTransform(double* x, double* y) const
2144569b90dSStephan Aßmus{
2154569b90dSStephan Aßmus	inverse_transform(x, y);
2164569b90dSStephan Aßmus}
2174569b90dSStephan Aßmus
21813e393dfSStephan Aßmus
2194569b90dSStephan Aßmusvoid
2204569b90dSStephan AßmusTransformable::InverseTransform(BPoint* point) const
2214569b90dSStephan Aßmus{
2224569b90dSStephan Aßmus	if (point) {
2234569b90dSStephan Aßmus		double x = point->x;
2244569b90dSStephan Aßmus		double y = point->y;
2254569b90dSStephan Aßmus
2264569b90dSStephan Aßmus		inverse_transform(&x, &y);
2274569b90dSStephan Aßmus
2284569b90dSStephan Aßmus		point->x = x;
2294569b90dSStephan Aßmus		point->y = y;
2304569b90dSStephan Aßmus	}
2314569b90dSStephan Aßmus}
2324569b90dSStephan Aßmus
23313e393dfSStephan Aßmus
2344569b90dSStephan AßmusBPoint
2354569b90dSStephan AßmusTransformable::InverseTransform(const BPoint& point) const
2364569b90dSStephan Aßmus{
2374569b90dSStephan Aßmus	BPoint p(point);
2384569b90dSStephan Aßmus	InverseTransform(&p);
2394569b90dSStephan Aßmus	return p;
2404569b90dSStephan Aßmus}
2414569b90dSStephan Aßmus
24213e393dfSStephan Aßmus
2434569b90dSStephan AßmusBRect
2444389b702SStephan AßmusTransformable::TransformBounds(const BRect& bounds) const
2454569b90dSStephan Aßmus{
2464569b90dSStephan Aßmus	if (bounds.IsValid()) {
2474569b90dSStephan Aßmus		BPoint lt(bounds.left, bounds.top);
2484569b90dSStephan Aßmus		BPoint rt(bounds.right, bounds.top);
2494569b90dSStephan Aßmus		BPoint lb(bounds.left, bounds.bottom);
2504569b90dSStephan Aßmus		BPoint rb(bounds.right, bounds.bottom);
2514569b90dSStephan Aßmus
2524569b90dSStephan Aßmus		Transform(&lt);
2534569b90dSStephan Aßmus		Transform(&rt);
2544569b90dSStephan Aßmus		Transform(&lb);
2554569b90dSStephan Aßmus		Transform(&rb);
2564569b90dSStephan Aßmus
2574569b90dSStephan Aßmus		return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)),
2584569b90dSStephan Aßmus					 floorf(min4(lt.y, rt.y, lb.y, rb.y)),
2594569b90dSStephan Aßmus					 ceilf(max4(lt.x, rt.x, lb.x, rb.x)),
2604569b90dSStephan Aßmus					 ceilf(max4(lt.y, rt.y, lb.y, rb.y)));
2614569b90dSStephan Aßmus	}
2624569b90dSStephan Aßmus	return bounds;
2634569b90dSStephan Aßmus}
2644569b90dSStephan Aßmus
265750958b8SStephan Aßmus
266750958b8SStephan Aßmusbool
267750958b8SStephan AßmusTransformable::IsTranslationOnly() const
268750958b8SStephan Aßmus{
269750958b8SStephan Aßmus	double matrix[6];
270750958b8SStephan Aßmus	store_to(matrix);
271750958b8SStephan Aßmus	return matrix[0] == 1.0 && matrix[1] == 0.0
272750958b8SStephan Aßmus		&& matrix[2] == 0.0 && matrix[3] == 1.0;
273750958b8SStephan Aßmus}
274750958b8SStephan Aßmus
275750958b8SStephan Aßmus
27613e393dfSStephan Aßmus
2774569b90dSStephan Aßmusvoid
2784569b90dSStephan AßmusTransformable::TranslateBy(BPoint offset)
2794569b90dSStephan Aßmus{
2804569b90dSStephan Aßmus	if (offset.x != 0.0 || offset.y != 0.0) {
2814569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(offset.x, offset.y));
2824569b90dSStephan Aßmus		TransformationChanged();
2834569b90dSStephan Aßmus	}
2844569b90dSStephan Aßmus}
2854569b90dSStephan Aßmus
28613e393dfSStephan Aßmus
2874569b90dSStephan Aßmusvoid
288a37ea917SJérôme DuvalTransformable::RotateBy(BPoint origin, double radians)
2894569b90dSStephan Aßmus{
290a37ea917SJérôme Duval	if (radians != 0.0) {
2914569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
292a37ea917SJérôme Duval		multiply(agg::trans_affine_rotation(radians));
2934569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(origin.x, origin.y));
2944569b90dSStephan Aßmus		TransformationChanged();
2954569b90dSStephan Aßmus	}
2964569b90dSStephan Aßmus}
2974569b90dSStephan Aßmus
29813e393dfSStephan Aßmus
2994569b90dSStephan Aßmusvoid
3004569b90dSStephan AßmusTransformable::ScaleBy(BPoint origin, double xScale, double yScale)
3014569b90dSStephan Aßmus{
3024569b90dSStephan Aßmus	if (xScale != 1.0 || yScale != 1.0) {
3034569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
3044569b90dSStephan Aßmus		multiply(agg::trans_affine_scaling(xScale, yScale));
3054569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(origin.x, origin.y));
3064569b90dSStephan Aßmus		TransformationChanged();
3074569b90dSStephan Aßmus	}
3084569b90dSStephan Aßmus}
3094569b90dSStephan Aßmus
31013e393dfSStephan Aßmus
3114569b90dSStephan Aßmusvoid
3124569b90dSStephan AßmusTransformable::ShearBy(BPoint origin, double xShear, double yShear)
3134569b90dSStephan Aßmus{
3144569b90dSStephan Aßmus	if (xShear != 0.0 || yShear != 0.0) {
3154569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
3164569b90dSStephan Aßmus		multiply(agg::trans_affine_skewing(xShear, yShear));
3174569b90dSStephan Aßmus		multiply(agg::trans_affine_translation(origin.x, origin.y));
3184569b90dSStephan Aßmus		TransformationChanged();
3194569b90dSStephan Aßmus	}
3204569b90dSStephan Aßmus}
321