Code

switch nr-filter to 2geom
[inkscape.git] / src / display / nr-filter-units.cpp
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     }
115 Geom::Matrix FilterUnits::get_matrix_filterunits2pb() const {
116     return get_matrix_units2pb(filterUnits);
119 Geom::Matrix FilterUnits::get_matrix_primitiveunits2pb() const {
120     return get_matrix_units2pb(primitiveUnits);
123 Geom::Matrix FilterUnits::get_matrix_display2pb() const {
124     Geom::Matrix d2pb = ctm.inverse();
125     d2pb *= get_matrix_user2pb();
126     return d2pb;
129 Geom::Matrix FilterUnits::get_matrix_pb2display() const {
130     Geom::Matrix pb2d = get_matrix_user2pb().inverse();
131     pb2d *= ctm;
132     return pb2d;
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     }
155 Geom::Matrix FilterUnits::get_matrix_user2filterunits() const {
156     return get_matrix_user2units(filterUnits);
159 Geom::Matrix FilterUnits::get_matrix_user2primitiveunits() const {
160     return get_matrix_user2units(primitiveUnits);
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;
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;
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 :