1 /*
2 * Utilities for handling coordinate system transformations in filters
3 *
4 * Author:
5 * Niko Kiirala <niko@kiirala.com>
6 *
7 * Copyright (C) 2007 Niko Kiirala
8 *
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
12 #include <glib.h>
14 #include "display/nr-filter-units.h"
15 #include "libnr/nr-matrix.h"
16 #include "libnr/nr-matrix-fns.h"
17 #include "libnr/nr-matrix-ops.h"
18 #include "libnr/nr-matrix-scale-ops.h"
19 #include "libnr/nr-rect.h"
20 #include "libnr/nr-rect-l.h"
21 #include "libnr/nr-scale.h"
22 #include "sp-filter-units.h"
23 #include <2geom/transforms.h>
25 namespace NR {
27 FilterUnits::FilterUnits() :
28 filterUnits(SP_FILTER_UNITS_OBJECTBOUNDINGBOX),
29 primitiveUnits(SP_FILTER_UNITS_USERSPACEONUSE),
30 resolution_x(-1), resolution_y(-1),
31 paraller_axis(false), automatic_resolution(true)
32 {}
34 FilterUnits::FilterUnits(SPFilterUnits const filterUnits, SPFilterUnits const primitiveUnits) :
35 filterUnits(filterUnits), primitiveUnits(primitiveUnits),
36 resolution_x(-1), resolution_y(-1),
37 paraller_axis(false), automatic_resolution(true)
38 {}
40 void FilterUnits::set_ctm(Geom::Matrix const &ctm) {
41 this->ctm = ctm;
42 }
44 void FilterUnits::set_resolution(double const x_res, double const y_res) {
45 g_assert(x_res > 0);
46 g_assert(y_res > 0);
48 resolution_x = x_res;
49 resolution_y = y_res;
50 }
52 void FilterUnits::set_item_bbox(Geom::OptRect const &bbox) {
53 item_bbox = bbox;
54 }
56 void FilterUnits::set_filter_area(Geom::OptRect const &area) {
57 filter_area = area;
58 }
60 void FilterUnits::set_paraller(bool const paraller) {
61 paraller_axis = paraller;
62 }
64 void FilterUnits::set_automatic_resolution(bool const automatic) {
65 automatic_resolution = automatic;
66 }
68 Geom::Matrix FilterUnits::get_matrix_user2pb() const {
69 g_assert(resolution_x > 0);
70 g_assert(resolution_y > 0);
71 g_assert(filter_area);
73 Geom::Matrix u2pb = ctm;
75 if (paraller_axis || !automatic_resolution) {
76 u2pb[0] = resolution_x / (filter_area->max()[X] - filter_area->min()[X]);
77 u2pb[1] = 0;
78 u2pb[2] = 0;
79 u2pb[3] = resolution_y / (filter_area->max()[Y] - filter_area->min()[Y]);
80 u2pb[4] = ctm[4];
81 u2pb[5] = ctm[5];
82 }
84 return u2pb;
85 }
87 Geom::Matrix FilterUnits::get_matrix_units2pb(SPFilterUnits units) const {
88 if ( item_bbox && (units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) ) {
89 Geom::Matrix u2pb = get_matrix_user2pb();
90 Geom::Point origo(item_bbox->min());
91 origo *= u2pb;
92 Geom::Point i_end(item_bbox->max()[X], item_bbox->min()[Y]);
93 i_end *= u2pb;
94 Geom::Point j_end(item_bbox->min()[X], item_bbox->max()[Y]);
95 j_end *= u2pb;
97 double len_i = sqrt((origo[X] - i_end[X]) * (origo[X] - i_end[X])
98 + (origo[Y] - i_end[Y]) * (origo[Y] - i_end[Y]));
99 double len_j = sqrt((origo[X] - j_end[X]) * (origo[X] - j_end[X])
100 + (origo[Y] - j_end[Y]) * (origo[Y] - j_end[Y]));
102 /* TODO: make sure that user coordinate system (0,0) is in correct
103 * place in pixblock coordinates */
104 Geom::Scale scaling(1.0 / len_i, 1.0 / len_j);
105 u2pb *= scaling;
106 return u2pb;
107 } else if (units == SP_FILTER_UNITS_USERSPACEONUSE) {
108 return get_matrix_user2pb();
109 } else {
110 g_warning("Error in NR::FilterUnits::get_matrix_units2pb: unrecognized unit type (%d)", units);
111 return Geom::Matrix();
112 }
113 }
115 Geom::Matrix FilterUnits::get_matrix_filterunits2pb() const {
116 return get_matrix_units2pb(filterUnits);
117 }
119 Geom::Matrix FilterUnits::get_matrix_primitiveunits2pb() const {
120 return get_matrix_units2pb(primitiveUnits);
121 }
123 Geom::Matrix FilterUnits::get_matrix_display2pb() const {
124 Geom::Matrix d2pb = ctm.inverse();
125 d2pb *= get_matrix_user2pb();
126 return d2pb;
127 }
129 Geom::Matrix FilterUnits::get_matrix_pb2display() const {
130 Geom::Matrix pb2d = get_matrix_user2pb().inverse();
131 pb2d *= ctm;
132 return pb2d;
133 }
135 Geom::Matrix FilterUnits::get_matrix_user2units(SPFilterUnits units) const {
136 if (item_bbox && units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) {
137 /* No need to worry about rotations: bounding box coordinates
138 * always have base vectors paraller with userspace coordinates */
139 Point min(item_bbox->min());
140 Point max(item_bbox->max());
141 double scale_x = 1.0 / (max[X] - min[X]);
142 double scale_y = 1.0 / (max[Y] - min[Y]);
143 //return Geom::Translate(min) * Geom::Scale(scale_x,scale_y); ?
144 return Geom::Matrix(scale_x, 0,
145 0, scale_y,
146 min[X] * scale_x, min[Y] * scale_y);
147 } else if (units == SP_FILTER_UNITS_USERSPACEONUSE) {
148 return Geom::identity();
149 } else {
150 g_warning("Error in NR::FilterUnits::get_matrix_user2units: unrecognized unit type (%d)", units);
151 return Geom::Matrix();
152 }
153 }
155 Geom::Matrix FilterUnits::get_matrix_user2filterunits() const {
156 return get_matrix_user2units(filterUnits);
157 }
159 Geom::Matrix FilterUnits::get_matrix_user2primitiveunits() const {
160 return get_matrix_user2units(primitiveUnits);
161 }
163 IRect FilterUnits::get_pixblock_filterarea_paraller() const {
164 g_assert(filter_area);
166 int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN;
167 Geom::Matrix u2pb = get_matrix_user2pb();
169 for (int i = 0 ; i < 4 ; i++) {
170 Geom::Point p = filter_area->corner(i);
171 p *= u2pb;
172 if (p[X] < min_x) min_x = (int)std::floor(p[X]);
173 if (p[X] > max_x) max_x = (int)std::ceil(p[X]);
174 if (p[Y] < min_y) min_y = (int)std::floor(p[Y]);
175 if (p[Y] > max_y) max_y = (int)std::ceil(p[Y]);
176 }
177 IRect ret(IPoint(min_x, min_y), IPoint(max_x, max_y));
178 return ret;
179 }
181 FilterUnits& FilterUnits::operator=(FilterUnits const &other) {
182 filterUnits = other.filterUnits;
183 primitiveUnits = other.primitiveUnits;
184 resolution_x = other.resolution_x;
185 resolution_y = other.resolution_y;
186 paraller_axis = other.paraller_axis;
187 automatic_resolution = other.automatic_resolution;
188 ctm = other.ctm;
189 item_bbox = other.item_bbox;
190 filter_area = other.filter_area;
191 return *this;
192 }
194 } // namespace NR
197 /*
198 Local Variables:
199 mode:c++
200 c-file-style:"stroustrup"
201 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
202 indent-tabs-mode:nil
203 fill-column:99
204 End:
205 */
206 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :