1 // Affine manipulation routines for PLplot.
2 //
3 // Copyright (C) 2009-2014 Alan W. Irwin
4 //
5 // This file is part of PLplot.
6 //
7 // PLplot is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU Library General Public License as published
9 // by the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // PLplot is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public License
18 // along with PLplot; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 //
22 
23 #include "plplotP.h"
24 
25 //! @file
26 //!  These function perform variuos affine transformations.
27 //!
28 //! For background on these affine functions see SVG specification, e.g.,
29 //! http://www.w3.org/TR/SVGTiny12/coords.html#EstablishingANewUserSpace.
30 //! Affine 3x3 matrices with elements A_i,j always have a last row of
31 //! 0, 0, 1 so the elements are conveniently stored in a vector in the order
32 //! A_1_1, A_2_1, A_1_2, A_2_2, A_1_3, A_2_3, with the last row implied.
33 //!
34 //! N.B.  The PLplot affine interpretation of translate, scale, etc., is
35 //! as actions on coordinate systems, rather than actions on objects.  This
36 //! is identical to the SVG specficiation interpretation.  However, the
37 //! SVG specification interprets the affine matrix as follows:
38 //! old_coord_vector = affine_matrix * new_coordinate vector.  In PLplot
39 //! we use the alternative interpretation
40 //! new_coord_vector = affine_matrix * old_coordinate vector.
41 //! The result is all affine matrices below are the inverses of the SVG
42 //! equivalents.
43 //!
44 //! N.B. All PLplot affine functions below return the affine matrix result (in
45 //! vector form) as the first argument).  It is the calling routine's
46 //! responsibility to provide the space for all affine matrix arguments,
47 //! i.e., a PLFLT array with a dimension of 6.
48 //!
49 //
50 
51 //! Returns affine identity matrix
52 //!
53 //! @param affine_vector Initialize a (pre-allocated) transform matrix.
54 //!
55 void
plP_affine_identity(PLFLT * affine_vector)56 plP_affine_identity( PLFLT *affine_vector )
57 {
58     affine_vector[0] = 1.;
59     affine_vector[1] = 0.;
60     affine_vector[2] = 0.;
61     affine_vector[3] = 1.;
62     affine_vector[4] = 0.;
63     affine_vector[5] = 0.;
64 }
65 
66 //! Translate new coordinate system axes relative to the old.
67 //!
68 //! @param affine_vector Pre-allocated storage for a translation matrix.
69 //! @param xtranslate Amount to translate in x.
70 //! @param ytranslate Amount to translate in y.
71 //!
72 void
plP_affine_translate(PLFLT * affine_vector,PLFLT xtranslate,PLFLT ytranslate)73 plP_affine_translate( PLFLT *affine_vector, PLFLT xtranslate, PLFLT ytranslate )
74 {
75     affine_vector[0] = 1.;
76     affine_vector[1] = 0.;
77     affine_vector[2] = 0.;
78     affine_vector[3] = 1.;
79     // If the new coordinate system axis is shifted by xtranslate and ytranslate
80     // relative to the old, then the actual new coordinates are shifted in
81     // the opposite direction.
82     affine_vector[4] = -xtranslate;
83     affine_vector[5] = -ytranslate;
84 }
85 
86 //! Scale new coordinate system axes relative to the old.
87 //!
88 //! @param affine_vector Pre-allocate storage for a scale matrix.
89 //! @param xscale Amount to scale in x.
90 //! @param yscale Amount to scale in y.
91 //!
92 void
plP_affine_scale(PLFLT * affine_vector,PLFLT xscale,PLFLT yscale)93 plP_affine_scale( PLFLT *affine_vector, PLFLT xscale, PLFLT yscale )
94 {
95     // If the new coordinate system axes are scaled by xscale and yscale
96     // relative to the old, then the actual new coordinates are scaled
97     // by the inverses.
98     if ( xscale == 0. )
99     {
100         plwarn( "plP_affine_scale: attempt to scale X coordinates by zero." );
101         xscale = 1.;
102     }
103     if ( yscale == 0. )
104     {
105         plwarn( "plP_affine_scale: attempt to scale Y coordinates by zero." );
106         yscale = 1.;
107     }
108     affine_vector[0] = 1. / xscale;
109     affine_vector[1] = 0.;
110     affine_vector[2] = 0.;
111     affine_vector[3] = 1. / yscale;
112     affine_vector[4] = 0.;
113     affine_vector[5] = 0.;
114 }
115 
116 //! Rotate new coordinate system axes relative to the old.
117 //! angle is in degrees.
118 //!
119 //! @param affine_vector Pre-allocated storage for a rotation matrix.
120 //! @param angle Amount to rotate in degrees.
121 //!
122 void
plP_affine_rotate(PLFLT * affine_vector,PLFLT angle)123 plP_affine_rotate( PLFLT *affine_vector, PLFLT angle )
124 {
125     PLFLT cosangle = cos( PI * angle / 180. );
126     PLFLT sinangle = sin( PI * angle / 180. );
127     affine_vector[0] = cosangle;
128     affine_vector[1] = -sinangle;
129     affine_vector[2] = sinangle;
130     affine_vector[3] = cosangle;
131     affine_vector[4] = 0.;
132     affine_vector[5] = 0.;
133 }
134 
135 //! Skew new X coordinate axis relative to the old.
136 //! angle is in degrees.
137 //!
138 //! @param affine_vector Pre-allocated storage for a skew (in x) matrix.
139 //! @param angle Amount to skew in degrees.
140 //!
141 
142 void
plP_affine_xskew(PLFLT * affine_vector,PLFLT angle)143 plP_affine_xskew( PLFLT *affine_vector, PLFLT angle )
144 {
145     PLFLT tanangle = tan( PI * angle / 180. );
146     affine_vector[0] = 1.;
147     affine_vector[1] = 0.;
148     affine_vector[2] = -tanangle;
149     affine_vector[3] = 1.;
150     affine_vector[4] = 0.;
151     affine_vector[5] = 0.;
152 }
153 
154 //! Skew new Y coordinate axis relative to the old.
155 //! angle is in degrees.
156 //!
157 //! @param affine_vector Pre-allocated storage for a skew (in y) matrix.
158 //! @param angle Amount to skew in degrees.
159 //!
160 
161 void
plP_affine_yskew(PLFLT * affine_vector,PLFLT angle)162 plP_affine_yskew( PLFLT *affine_vector, PLFLT angle )
163 {
164     PLFLT tanangle = tan( PI * angle / 180. );
165     affine_vector[0] = 1.;
166     affine_vector[1] = -tanangle;
167     affine_vector[2] = 0.;
168     affine_vector[3] = 1.;
169     affine_vector[4] = 0.;
170     affine_vector[5] = 0.;
171 }
172 
173 //! Multiply two affine transformation matrices to form a third.
174 //!
175 //! A = B * C
176 //!
177 //! @param affine_vectorA Pre-allocated storage for the result of
178 //! multiplying matrix affine_vectorB by matrix affine_vectorC.
179 //! @param affine_vectorB First matrix to multiply.
180 //! @param affine_vectorC Second matrix to multiply.
181 //!
182 
183 void
plP_affine_multiply(PLFLT * affine_vectorA,PLFLT_VECTOR affine_vectorB,PLFLT_VECTOR affine_vectorC)184 plP_affine_multiply(
185     PLFLT *affine_vectorA,
186     PLFLT_VECTOR affine_vectorB,
187     PLFLT_VECTOR affine_vectorC )
188 {
189     int   i;
190     PLFLT result[NAFFINE];
191     // Multiply two affine matrices stored in affine vector form.
192     result[0] = affine_vectorB[0] * affine_vectorC[0] +
193                 affine_vectorB[2] * affine_vectorC[1];
194     result[2] = affine_vectorB[0] * affine_vectorC[2] +
195                 affine_vectorB[2] * affine_vectorC[3];
196     result[4] = affine_vectorB[0] * affine_vectorC[4] +
197                 affine_vectorB[2] * affine_vectorC[5] +
198                 affine_vectorB[4];
199 
200     result[1] = affine_vectorB[1] * affine_vectorC[0] +
201                 affine_vectorB[3] * affine_vectorC[1];
202     result[3] = affine_vectorB[1] * affine_vectorC[2] +
203                 affine_vectorB[3] * affine_vectorC[3];
204     result[5] = affine_vectorB[1] * affine_vectorC[4] +
205                 affine_vectorB[3] * affine_vectorC[5] +
206                 affine_vectorB[5];
207 
208     for ( i = 0; i < NAFFINE; i++ )
209         affine_vectorA[i] = result[i];
210 }
211